diff --git a/source/lib/system.c b/source/lib/system.c index eabb6d6..5b06d3c 100644 --- a/source/lib/system.c +++ b/source/lib/system.c @@ -142,6 +142,20 @@ ssize_t sys_write(int fd, const void *buf, size_t count) } /******************************************************************* +A writev wrapper that will deal with EINTR. +********************************************************************/ + +ssize_t sys_writev(int fd, const struct iovec *iov, int iovcnt) +{ + ssize_t ret; + + do { + ret = writev(fd, iov, iovcnt); + } while (ret == -1 && errno == EINTR); + return ret; +} + +/******************************************************************* A pread wrapper that will deal with EINTR and 64-bit file offsets. ********************************************************************/ diff --git a/source/lib/util_sock.c b/source/lib/util_sock.c index e64b003..9c37e0c 100644 --- a/source/lib/util_sock.c +++ b/source/lib/util_sock.c @@ -1037,40 +1037,109 @@ NTSTATUS read_data(int fd, char *buffer, size_t N) } /**************************************************************************** - Write data to a fd. + Write all data from an iov array ****************************************************************************/ -ssize_t write_data(int fd, const char *buffer, size_t N) +ssize_t write_data_iov(int fd, const struct iovec *orig_iov, int iovcnt) { - size_t total=0; - ssize_t ret; - char addr[INET6_ADDRSTRLEN]; + int i; + size_t to_send; + ssize_t thistime; + size_t sent; + struct iovec *iov_copy, *iov; - while (total < N) { - ret = sys_write(fd,buffer + total,N - total); + to_send = 0; + for (i=0; i 0) { + if (thistime < iov[0].iov_len) { + char *new_base = + (char *)iov[0].iov_base + thistime; + iov[0].iov_base = new_base; + iov[0].iov_len -= thistime; + break; } - return -1; + thistime -= iov[0].iov_len; + iov += 1; + iovcnt -= 1; } - if (ret == 0) { - return total; + thistime = sys_writev(fd, iov, iovcnt); + if (thistime <= 0) { + break; } + sent += thistime; + } + + TALLOC_FREE(iov_copy); + return sent; +} + +/**************************************************************************** + Write data to a fd. +****************************************************************************/ + +/**************************************************************************** + Write data to a fd. +****************************************************************************/ + +ssize_t write_data(int fd, const char *buffer, size_t N) +{ + ssize_t ret; + struct iovec iov; + + iov.iov_base = CONST_DISCARD(char *, buffer); + iov.iov_len = N; + + ret = write_data_iov(fd, &iov, 1); + if (ret >= 0) { + return ret; + } - total += ret; + if (fd == get_client_fd()) { + char addr[INET6_ADDRSTRLEN]; + /* + * Try and give an error message saying what client failed. + */ + DEBUG(0, ("write_data: write failure in writing to client %s. " + "Error %s\n", get_peer_addr(fd,addr,sizeof(addr)), + strerror(errno))); + } else { + DEBUG(0,("write_data: write failure. Error = %s\n", + strerror(errno) )); } - return (ssize_t)total; + + return -1; } /**************************************************************************** diff --git a/source/libsmb/clientgen.c b/source/libsmb/clientgen.c index d6d26e4..aeb1c28 100644 --- a/source/libsmb/clientgen.c +++ b/source/libsmb/clientgen.c @@ -315,7 +315,7 @@ bool cli_send_smb_direct_writeX(struct cli_state *cli, /* First length to send is the offset to the data. */ size_t len = SVAL(cli->outbuf,smb_vwv11) + 4; size_t nwritten=0; - ssize_t ret; + struct iovec iov[2]; /* fd == -1 causes segfaults -- Tom (tom@ninja.nl) */ if (cli->fd == -1) { @@ -327,33 +327,19 @@ bool cli_send_smb_direct_writeX(struct cli_state *cli, return false; } - while (nwritten < len) { - ret = write_socket(cli->fd,cli->outbuf+nwritten,len - nwritten); - if (ret <= 0) { - close(cli->fd); - cli->fd = -1; - cli->smb_rw_error = SMB_WRITE_ERROR; - DEBUG(0,("Error writing %d bytes to client. %d (%s)\n", - (int)len,(int)ret, strerror(errno) )); - return false; - } - nwritten += ret; - } + iov[0].iov_base = cli->outbuf; + iov[0].iov_len = len; + iov[1].iov_base = CONST_DISCARD(char *, p); + iov[1].iov_len = extradata; - /* Now write the extra data. */ - nwritten=0; - while (nwritten < extradata) { - ret = write_socket(cli->fd,p+nwritten,extradata - nwritten); - if (ret <= 0) { - close(cli->fd); - cli->fd = -1; - cli->smb_rw_error = SMB_WRITE_ERROR; - DEBUG(0,("Error writing %d extradata " - "bytes to client. %d (%s)\n", - (int)extradata,(int)ret, strerror(errno) )); - return false; - } - nwritten += ret; + nwritten = write_data_iov(cli->fd, iov, 2); + if (nwritten < (len + extradata)) { + close(cli->fd); + cli->fd = -1; + cli->smb_rw_error = SMB_WRITE_ERROR; + DEBUG(0,("Error writing %d bytes to client. (%s)\n", + (int)(len+extradata), strerror(errno))); + return false; } /* Increment the mid so we can tell between responses. */ diff --git a/source/libsmb/clilist.c b/source/libsmb/clilist.c index cebafc6..1431b80 100644 --- a/source/libsmb/clilist.c +++ b/source/libsmb/clilist.c @@ -79,16 +79,17 @@ static size_t interpret_long_filename(TALLOC_CTX *ctx, p += 27; p += clistr_align_in(cli, p, 0); - /* We can safely use +1 here (which is required by OS/2) - * instead of +2 as the STR_TERMINATE flag below is + /* We can safely use len here (which is required by OS/2) + * and the NAS-BASIC server instead of +2 or +1 as the + * STR_TERMINATE flag below is * actually used as the length calculation. - * The len+2 is merely an upper bound. + * The len is merely an upper bound. * Due to the explicit 2 byte null termination * in cli_receive_trans/cli_receive_nt_trans * we know this is safe. JRA + kukks */ - if (p + len + 1 > pdata_end) { + if (p + len > pdata_end) { return pdata_end - base; }