The branch, master has been updated
       via  95f7fc8 Ensure the RECVFILE path in vfs_pwrite_data() operates on a 
blocking socket.
       via  1ed710c Ensure the RECVFILE path in vfs_write_data() operates on a 
blocking socket.
       via  1b46db7 Ensure drain_socket() operates on a blocking socket.
       via  1a7cec3 Add the internals of is_smb2_recvfile_write.
       via  53b87f2 The guts of the receivefile code changes.
       via  fdcaf0f Add stub static function that will turn on/off receivefile 
code path.
       via  4b91097 Add extra fields into struct smbd_smb2_request_read_state 
to support receivefile.
       via  36d4b9d Add macro SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN.
       via  61da7f0 Add utility function get_min_receive_file_size().
       via  6373944 Allow smbd_smb2_request_error_ex() to cope with unread 
bytes on error.
       via  a36d763 Add function smbd_smb2_unread_bytes().
       via  ec9fc98 If we already have an smb1req attached to the struct 
smbd_smb2_request, don't recreate it.
       via  9791c1a Ensure we don't do an SMB2 aio write if RECVFILE is active.
       via  8543a7b samba-tool/dns: Fix a typo in ttl variable name
       via  aad5eeb fileserver: raise the debug level for share connection from 
non IPC to 2
      from  d51b498 s3:locking add NDR debug in share_mode_forall

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 95f7fc83b251efefcc2a603b936b55e2f0308a72
Author: Jeremy Allison <[email protected]>
Date:   Mon Apr 8 10:49:03 2013 -0700

    Ensure the RECVFILE path in vfs_pwrite_data() operates on a blocking socket.
    
    Signed-off-by: Jeremy Allison <[email protected]>
    Reviewed-by: Stefan (metze) Metzmacher <[email protected]>
    
    Autobuild-User(master): Jeremy Allison <[email protected]>
    Autobuild-Date(master): Sat Apr 20 01:04:05 CEST 2013 on sn-devel-104

commit 1ed710c2ffc91d8b33b87e572a6075e0126b5826
Author: Jeremy Allison <[email protected]>
Date:   Mon Apr 8 10:32:10 2013 -0700

    Ensure the RECVFILE path in vfs_write_data() operates on a blocking socket.
    
    Signed-off-by: Jeremy Allison <[email protected]>
    Reviewed-by: Stefan (metze) Metzmacher <[email protected]>

commit 1b46db7b24a4f064706c2c7e712452135a3fed34
Author: Jeremy Allison <[email protected]>
Date:   Mon Apr 8 10:16:48 2013 -0700

    Ensure drain_socket() operates on a blocking socket.
    
    Signed-off-by: Jeremy Allison <[email protected]>
    Reviewed-by: Stefan (metze) Metzmacher <[email protected]>

commit 1a7cec37e725c9f29fd71788e15623d904b41c8a
Author: Jeremy Allison <[email protected]>
Date:   Mon Apr 1 11:16:01 2013 -0700

    Add the internals of is_smb2_recvfile_write.
    
    This turns on the real receivefile detection, and completes
    the receivefile code path changes.
    
    Signed-off-by: Jeremy Allison <[email protected]>
    Reviewed-by: Stefan (metze) Metzmacher <[email protected]>

commit 53b87f2fbabe3a2dcb5df6f6c494ef332bea81e7
Author: Jeremy Allison <[email protected]>
Date:   Mon Apr 1 13:24:07 2013 -0700

    The guts of the receivefile code changes.
    
    If an incoming PDU might qualify, only read
    SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN = (SMB2_HEADER + SMB2_WRITE_BODY_LEN)
    bytes rather than the whole PDU.
    
    Next time we're called, use is_smb2_recvfile_write() to decide if
    this is an SMB2_WRITE that fit the receivefile criteria, otherwise
    just read the rest of the PDU.
    
    If we did do a short receivefile read, set up the 
smb2_req->smb1req->unread_bytes
    value to show what bytes remain in the TCP buffers.
    
    Signed-off-by: Jeremy Allison <[email protected]>
    Reviewed-by: Stefan (metze) Metzmacher <[email protected]>

commit fdcaf0fa360b9590114605d24af545b1d42b9fd5
Author: Jeremy Allison <[email protected]>
Date:   Mon Apr 1 13:19:01 2013 -0700

    Add stub static function that will turn on/off receivefile code path.
    
    Signed-off-by: Jeremy Allison <[email protected]>
    Reviewed-by: Stefan (metze) Metzmacher <[email protected]>

commit 4b91097002d73ae5dd2d4ac225f8e9eecca11e49
Author: Jeremy Allison <[email protected]>
Date:   Mon Apr 1 13:17:09 2013 -0700

    Add extra fields into struct smbd_smb2_request_read_state to support 
receivefile.
    
    Initialize min_recv_size with the size that will trigger the
    receivefile write path.
    
    Signed-off-by: Jeremy Allison <[email protected]>
    Reviewed-by: Stefan (metze) Metzmacher <[email protected]>

commit 36d4b9d208c0025f054ad8ae4062ca3c81e345d5
Author: Jeremy Allison <[email protected]>
Date:   Mon Apr 1 13:14:13 2013 -0700

    Add macro SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN.
    
    This is the 'short' length we'll read in the SMB2_WRITE receivefile
    code path.
    
    Signed-off-by: Jeremy Allison <[email protected]>
    Reviewed-by: Stefan (metze) Metzmacher <[email protected]>

commit 61da7f00b3f3daebb82e6a5d987883e0897dc4e9
Author: Jeremy Allison <[email protected]>
Date:   Mon Apr 1 13:12:55 2013 -0700

    Add utility function get_min_receive_file_size().
    
    Signed-off-by: Jeremy Allison <[email protected]>
    Reviewed-by: Stefan (metze) Metzmacher <[email protected]>

commit 63739440f128229a6a99d0653562d3735ae909fb
Author: Jeremy Allison <[email protected]>
Date:   Tue Mar 19 12:36:52 2013 -0700

    Allow smbd_smb2_request_error_ex() to cope with unread bytes on error.
    
    Drain the socket if a RECVFILE write failed.
    
    Signed-off-by: Jeremy Allison <[email protected]>
    Reviewed-by: Stefan (metze) Metzmacher <[email protected]>

commit a36d7633bd3608b71f610fc9df2ad9c66bfdd9c6
Author: Jeremy Allison <[email protected]>
Date:   Tue Mar 19 12:24:17 2013 -0700

    Add function smbd_smb2_unread_bytes().
    
    Returns number of bytes left to read for recvfile. Will be
    used in SMB_2_WRITE_FILE code path.
    
    Signed-off-by: Jeremy Allison <[email protected]>
    Reviewed-by: Stefan (metze) Metzmacher <[email protected]>

commit ec9fc986da8279f15338b7682c629bfdfc36d016
Author: Jeremy Allison <[email protected]>
Date:   Tue Mar 19 12:16:32 2013 -0700

    If we already have an smb1req attached to the struct smbd_smb2_request, 
don't recreate it.
    
    Signed-off-by: Jeremy Allison <[email protected]>
    Reviewed-by: Stefan (metze) Metzmacher <[email protected]>

commit 9791c1a24822d8b46bf7dd231b615d281b58540b
Author: Jeremy Allison <[email protected]>
Date:   Mon Mar 18 12:00:25 2013 -0700

    Ensure we don't do an SMB2 aio write if RECVFILE is active.
    
    Signed-off-by: Jeremy Allison <[email protected]>
    Reviewed-by: Stefan (metze) Metzmacher <[email protected]>

commit 8543a7b9b3b1efe2911b32c5f7c1cd3db85681b1
Author: Amitay Isaacs <[email protected]>
Date:   Sat Apr 20 00:46:19 2013 +1000

    samba-tool/dns: Fix a typo in ttl variable name
    
    Signed-off-by: Amitay Isaacs <[email protected]>
    Reviewed-by: Jeremy Allison <[email protected]>

commit aad5eeb9b4f67b03988ceefb7888cb63ecefcf30
Author: Matthieu Patou <[email protected]>
Date:   Sat Jan 26 14:42:57 2013 -0800

    fileserver: raise the debug level for share connection from non IPC to 2
    
    So that logs of make test are not spamed, the code dates from 1999 maybe
    at that moment we wanted to have some warning I think nodays it's pretty
    stable.
    
    Reviewed-by: Jeremy Allison <[email protected]>

-----------------------------------------------------------------------

Summary of changes:
 python/samba/netcmd/dns.py |    2 +-
 source3/lib/recvfile.c     |   17 +++++-
 source3/smbd/aio.c         |    5 ++
 source3/smbd/globals.h     |    3 +
 source3/smbd/service.c     |    2 +-
 source3/smbd/smb2_glue.c   |   22 +++++++-
 source3/smbd/smb2_server.c |  130 ++++++++++++++++++++++++++++++++++++++++++--
 source3/smbd/vfs.c         |   26 ++++++++-
 8 files changed, 193 insertions(+), 14 deletions(-)


Changeset truncated at 500 lines:

diff --git a/python/samba/netcmd/dns.py b/python/samba/netcmd/dns.py
index 309951d..439b02d 100644
--- a/python/samba/netcmd/dns.py
+++ b/python/samba/netcmd/dns.py
@@ -424,7 +424,7 @@ class PTRRecord(dnsserver.DNS_RPC_RECORD):
         self.wType = dnsp.DNS_TYPE_PTR
         self.dwFlags = rank | node_flag
         self.dwSerial = serial
-        self.dwTtleSeconds = ttl
+        self.dwTtlSeconds = ttl
         self._ptr = ptr[:]
         ptr_name = dnsserver.DNS_RPC_NAME()
         ptr_name.str = self._ptr
diff --git a/source3/lib/recvfile.c b/source3/lib/recvfile.c
index c53ba77..72f4257 100644
--- a/source3/lib/recvfile.c
+++ b/source3/lib/recvfile.c
@@ -240,6 +240,7 @@ ssize_t sys_recvfile(int fromfd,
 /*****************************************************************
  Throw away "count" bytes from the client socket.
  Returns count or -1 on error.
+ Must only operate on a blocking socket.
 *****************************************************************/
 
 ssize_t drain_socket(int sockfd, size_t count)
@@ -247,6 +248,7 @@ ssize_t drain_socket(int sockfd, size_t count)
        size_t total = 0;
        size_t bufsize = MIN(TRANSFER_BUF_SIZE,count);
        char *buffer = NULL;
+       int old_flags = 0;
 
        if (count == 0) {
                return 0;
@@ -257,6 +259,12 @@ ssize_t drain_socket(int sockfd, size_t count)
                return -1;
        }
 
+       old_flags = fcntl(sockfd, F_GETFL, 0);
+       if (set_blocking(sockfd, true) == -1) {
+               free(buffer);
+               return -1;
+       }
+
        while (total < count) {
                ssize_t read_ret;
                size_t toread = MIN(bufsize,count - total);
@@ -265,12 +273,17 @@ ssize_t drain_socket(int sockfd, size_t count)
                read_ret = sys_read(sockfd, buffer, toread);
                if (read_ret <= 0) {
                        /* EOF or socket error. */
-                       free(buffer);
-                       return -1;
+                       count = (size_t)-1;
+                       goto out;
                }
                total += read_ret;
        }
 
+  out:
+
        free(buffer);
+       if (fcntl(sockfd, F_SETFL, old_flags) == -1) {
+               return -1;
+       }
        return count;
 }
diff --git a/source3/smbd/aio.c b/source3/smbd/aio.c
index 3f553eb..e8be408 100644
--- a/source3/smbd/aio.c
+++ b/source3/smbd/aio.c
@@ -861,6 +861,11 @@ NTSTATUS schedule_aio_smb2_write(connection_struct *conn,
                return NT_STATUS_RETRY;
        }
 
+       if (smbreq->unread_bytes) {
+               /* Can't do async with recvfile. */
+               return NT_STATUS_RETRY;
+       }
+
        if (!(aio_ex = create_aio_extra(smbreq->smb2req, fsp, 0))) {
                return NT_STATUS_NO_MEMORY;
        }
diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h
index 1502758..46baeed 100644
--- a/source3/smbd/globals.h
+++ b/source3/smbd/globals.h
@@ -247,6 +247,7 @@ NTSTATUS smbd_smb2_request_pending_queue(struct 
smbd_smb2_request *req,
                                         uint32_t defer_time);
 
 struct smb_request *smbd_smb2_fake_smb_request(struct smbd_smb2_request *req);
+size_t smbd_smb2_unread_bytes(struct smbd_smb2_request *req);
 void remove_smb2_chained_fsp(files_struct *fsp);
 
 NTSTATUS smbd_smb2_request_verify_creditcharge(struct smbd_smb2_request *req,
@@ -548,6 +549,8 @@ struct smbd_smb2_request {
 #define SMBD_SMB2_OUT_DYN_PTR(req)   (uint8_t 
*)(SMBD_SMB2_OUT_DYN_IOV(req)->iov_base)
 #define SMBD_SMB2_OUT_DYN_LEN(req)   (SMBD_SMB2_OUT_DYN_IOV(req)->iov_len)
 
+#define SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN (SMB2_HDR_BODY + 0x30)
+
        struct {
                /*
                 * vector[0] TRANSPORT HEADER (empty)
diff --git a/source3/smbd/service.c b/source3/smbd/service.c
index 4c0832a..a7464f0 100644
--- a/source3/smbd/service.c
+++ b/source3/smbd/service.c
@@ -845,7 +845,7 @@ static NTSTATUS make_connection_snum(struct 
smbd_server_connection *sconn,
         * (at least initially).
         */
 
-       if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
+       if( DEBUGLVL( IS_IPC(conn) ? 3 : 2 ) ) {
                dbgtext( "%s (%s) ", get_remote_machine_name(),
                         tsocket_address_string(conn->sconn->remote_address,
                                                talloc_tos()) );
diff --git a/source3/smbd/smb2_glue.c b/source3/smbd/smb2_glue.c
index 1b2b4dd..54135b5 100644
--- a/source3/smbd/smb2_glue.c
+++ b/source3/smbd/smb2_glue.c
@@ -28,9 +28,13 @@ struct smb_request *smbd_smb2_fake_smb_request(struct 
smbd_smb2_request *req)
        struct smb_request *smbreq;
        const uint8_t *inhdr = SMBD_SMB2_IN_HDR_PTR(req);
 
-       smbreq = talloc_zero(req, struct smb_request);
-       if (smbreq == NULL) {
-               return NULL;
+       if (req->smb1req) {
+               smbreq = req->smb1req;
+       } else {
+               smbreq = talloc_zero(req, struct smb_request);
+               if (smbreq == NULL) {
+                       return NULL;
+               }
        }
 
        smbreq->request_time = req->request_time;
@@ -55,6 +59,18 @@ struct smb_request *smbd_smb2_fake_smb_request(struct 
smbd_smb2_request *req)
 }
 
 /*********************************************************
+ Are there unread bytes for recvfile ?
+*********************************************************/
+
+size_t smbd_smb2_unread_bytes(struct smbd_smb2_request *req)
+{
+       if (req->smb1req) {
+               return req->smb1req->unread_bytes;
+       }
+       return 0;
+}
+
+/*********************************************************
  Called from file_free() to remove any chained fsp pointers.
 *********************************************************/
 
diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c
index eb7059e..57e9c7b 100644
--- a/source3/smbd/smb2_server.c
+++ b/source3/smbd/smb2_server.c
@@ -2621,11 +2621,21 @@ NTSTATUS smbd_smb2_request_error_ex(struct 
smbd_smb2_request *req,
 {
        DATA_BLOB body;
        uint8_t *outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
+       size_t unread_bytes = smbd_smb2_unread_bytes(req);
 
        DEBUG(10,("smbd_smb2_request_error_ex: idx[%d] status[%s] |%s| at %s\n",
                  req->current_idx, nt_errstr(status), info ? " +info" : "",
                  location));
 
+       if (unread_bytes) {
+               /* Recvfile error. Drain incoming socket. */
+               size_t ret = drain_socket(req->sconn->sock, unread_bytes);
+               if (ret != unread_bytes) {
+                       smbd_server_connection_terminate(req->sconn,
+                               "Failed to drain SMB2 socket\n");
+               }
+       }
+
        body.data = outhdr + SMB2_HDR_BODY;
        body.length = 8;
        SSVAL(body.data, 0, 9);
@@ -2821,6 +2831,8 @@ struct smbd_smb2_request_read_state {
                uint8_t nbt[NBT_HDR_SIZE];
                bool done;
        } hdr;
+       bool doing_receivefile;
+       size_t min_recv_size;
        size_t pktlen;
        uint8_t *pktbuf;
 };
@@ -2832,6 +2844,17 @@ static int smbd_smb2_request_next_vector(struct 
tstream_context *stream,
                                         size_t *_count);
 static void smbd_smb2_request_read_done(struct tevent_req *subreq);
 
+static size_t get_min_receive_file_size(struct smbd_smb2_request *smb2_req)
+{
+       if (smb2_req->do_signing) {
+               return 0;
+       }
+       if (smb2_req->do_encryption) {
+               return 0;
+       }
+       return (size_t)lp_min_receive_file_size();
+}
+
 static struct tevent_req *smbd_smb2_request_read_send(TALLOC_CTX *mem_ctx,
                                        struct tevent_context *ev,
                                        struct smbd_server_connection *sconn)
@@ -2853,6 +2876,7 @@ static struct tevent_req 
*smbd_smb2_request_read_send(TALLOC_CTX *mem_ctx,
                return tevent_req_post(req, ev);
        }
        state->smb2_req->sconn = sconn;
+       state->min_recv_size = get_min_receive_file_size(state->smb2_req);
 
        subreq = tstream_readv_pdu_queue_send(state->smb2_req,
                                        state->ev,
@@ -2868,6 +2892,47 @@ static struct tevent_req 
*smbd_smb2_request_read_send(TALLOC_CTX *mem_ctx,
        return req;
 }
 
+static bool is_smb2_recvfile_write(struct smbd_smb2_request_read_state *state)
+{
+       uint32_t flags;
+
+       if (IVAL(state->pktbuf, 0) == SMB2_TF_MAGIC) {
+               /* Transform header. Cannot recvfile. */
+               return false;
+       }
+       if (IVAL(state->pktbuf, 0) != SMB2_MAGIC) {
+               /* Not SMB2. Normal error path will cope. */
+               return false;
+       }
+       if (SVAL(state->pktbuf, 4) != SMB2_HDR_BODY) {
+               /* Not SMB2. Normal error path will cope. */
+               return false;
+       }
+       if (SVAL(state->pktbuf, SMB2_HDR_OPCODE) != SMB2_OP_WRITE) {
+               /* Needs to be a WRITE. */
+               return false;
+       }
+       if (IVAL(state->pktbuf, SMB2_HDR_NEXT_COMMAND) != 0) {
+               /* Chained. Cannot recvfile. */
+               return false;
+       }
+       flags = IVAL(state->pktbuf, SMB2_HDR_FLAGS);
+       if (flags & SMB2_HDR_FLAG_CHAINED) {
+               /* Chained. Cannot recvfile. */
+               return false;
+       }
+       if (flags & SMB2_HDR_FLAG_SIGNED) {
+               /* Signed. Cannot recvfile. */
+               return false;
+       }
+
+       DEBUG(10,("Doing recvfile write len = %u\n",
+               (unsigned int)(state->pktlen -
+               SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN)));
+
+       return true;
+}
+
 static int smbd_smb2_request_next_vector(struct tstream_context *stream,
                                         void *private_data,
                                         TALLOC_CTX *mem_ctx,
@@ -2877,12 +2942,38 @@ static int smbd_smb2_request_next_vector(struct 
tstream_context *stream,
        struct smbd_smb2_request_read_state *state =
                talloc_get_type_abort(private_data,
                struct smbd_smb2_request_read_state);
-       struct iovec *vector;
+       struct iovec *vector = NULL;
+       size_t min_recvfile_size = UINT32_MAX;
 
        if (state->pktlen > 0) {
-               /* if there're no remaining bytes, we're done */
-               *_vector = NULL;
-               *_count = 0;
+               if (state->doing_receivefile && !is_smb2_recvfile_write(state)) 
{
+                       /*
+                        * Not a possible receivefile write.
+                        * Read the rest of the data.
+                        */
+                       state->doing_receivefile = false;
+                       vector = talloc_array(mem_ctx, struct iovec, 1);
+                       if (vector == NULL) {
+                               return -1;
+                       }
+                       vector[0].iov_base = (void *)(state->pktbuf +
+                               SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN);
+                       vector[0].iov_len = (state->pktlen -
+                               SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN);
+                       *_vector = vector;
+                       *_count = 1;
+               } else {
+                       /*
+                        * Either this is a receivefile write so we've
+                        * done a short read, or if not we have all the data.
+                        * Either way, we're done and
+                        * smbd_smb2_request_read_done() will handle
+                        * and short read case by looking at the
+                        * state->doing_receivefile value.
+                        */
+                       *_vector = NULL;
+                       *_count = 0;
+               }
                return 0;
        }
 
@@ -2928,7 +3019,26 @@ static int smbd_smb2_request_next_vector(struct 
tstream_context *stream,
        }
 
        vector[0].iov_base = (void *)state->pktbuf;
-       vector[0].iov_len = state->pktlen;
+
+       if (state->min_recv_size != 0) {
+               min_recvfile_size = SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN;
+               min_recvfile_size += state->min_recv_size;
+       }
+
+       if (state->pktlen > min_recvfile_size) {
+               /*
+                * Might be a receivefile write. Read the SMB2 HEADER +
+                * SMB2_WRITE header first. Set 'doing_receivefile'
+                * as we're *attempting* receivefile write. If this
+                * turns out not to be a SMB2_WRITE request or otherwise
+                * not suitable then we'll just read the rest of the data
+                * the next time this function is called.
+                */
+               vector[0].iov_len = SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN;
+               state->doing_receivefile = true;
+       } else {
+               vector[0].iov_len = state->pktlen;
+       }
 
        *_vector = vector;
        *_count = 1;
@@ -2991,6 +3101,16 @@ static void smbd_smb2_request_read_done(struct 
tevent_req *subreq)
                return;
        }
 
+       if (state->doing_receivefile) {
+               state->smb2_req->smb1req = talloc_zero(state->smb2_req,
+                                               struct smb_request);
+               if (tevent_req_nomem(state->smb2_req->smb1req, req)) {
+                       return;
+               }
+               state->smb2_req->smb1req->unread_bytes =
+                       state->pktlen - SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN;
+       }
+
        state->smb2_req->current_idx = 1;
 
        tevent_req_done(req);
diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c
index 856e090..49609d0 100644
--- a/source3/smbd/vfs.c
+++ b/source3/smbd/vfs.c
@@ -428,14 +428,25 @@ ssize_t vfs_write_data(struct smb_request *req,
        ssize_t ret;
 
        if (req && req->unread_bytes) {
+               int sockfd = req->sconn->sock;
+               int old_flags;
                SMB_ASSERT(req->unread_bytes == N);
                /* VFS_RECVFILE must drain the socket
                 * before returning. */
                req->unread_bytes = 0;
-               return SMB_VFS_RECVFILE(req->sconn->sock,
+               /* Ensure the socket is blocking. */
+               old_flags = fcntl(sockfd, F_GETFL, 0);
+               if (set_blocking(sockfd, true) == -1) {
+                       return (ssize_t)-1;
+               }
+               ret = SMB_VFS_RECVFILE(sockfd,
                                        fsp,
                                        (off_t)-1,
                                        N);
+               if (fcntl(sockfd, F_SETFL, old_flags) == -1) {
+                       return (ssize_t)-1;
+               }
+               return ret;
        }
 
        while (total < N) {
@@ -461,14 +472,25 @@ ssize_t vfs_pwrite_data(struct smb_request *req,
        ssize_t ret;
 
        if (req && req->unread_bytes) {
+               int sockfd = req->sconn->sock;
+               int old_flags;
                SMB_ASSERT(req->unread_bytes == N);
                /* VFS_RECVFILE must drain the socket
                 * before returning. */
                req->unread_bytes = 0;
-               return SMB_VFS_RECVFILE(req->sconn->sock,
+               /* Ensure the socket is blocking. */
+               old_flags = fcntl(sockfd, F_GETFL, 0);
+               if (set_blocking(sockfd, true) == -1) {
+                       return (ssize_t)-1;
+               }
+               ret = SMB_VFS_RECVFILE(sockfd,
                                        fsp,
                                        offset,
                                        N);
+               if (fcntl(sockfd, F_SETFL, old_flags) == -1) {
+                       return (ssize_t)-1;
+               }
+               return ret;
        }
 
        while (total < N) {


-- 
Samba Shared Repository

Reply via email to