diff options
-rw-r--r-- | source3/libsmb/clireadwrite.c | 178 |
1 files changed, 15 insertions, 163 deletions
diff --git a/source3/libsmb/clireadwrite.c b/source3/libsmb/clireadwrite.c index 5aee8f18bd..c618509f01 100644 --- a/source3/libsmb/clireadwrite.c +++ b/source3/libsmb/clireadwrite.c @@ -444,175 +444,27 @@ NTSTATUS cli_pull(struct cli_state *cli, uint16_t fnum, return result; } -/**************************************************************************** -Issue a single SMBread and don't wait for a reply. -****************************************************************************/ - -static bool cli_issue_read(struct cli_state *cli, int fnum, off_t offset, - size_t size, int i) +static NTSTATUS cli_read_sink(char *buf, size_t n, void *priv) { - bool bigoffset = False; - - memset(cli->outbuf,'\0',smb_size); - memset(cli->inbuf,'\0',smb_size); - - if ((SMB_BIG_UINT)offset >> 32) - bigoffset = True; - - cli_set_message(cli->outbuf,bigoffset ? 12 : 10,0,True); - - SCVAL(cli->outbuf,smb_com,SMBreadX); - SSVAL(cli->outbuf,smb_tid,cli->cnum); - cli_setup_packet(cli); - - SCVAL(cli->outbuf,smb_vwv0,0xFF); - SSVAL(cli->outbuf,smb_vwv2,fnum); - SIVAL(cli->outbuf,smb_vwv3,offset); - SSVAL(cli->outbuf,smb_vwv5,size); - SSVAL(cli->outbuf,smb_vwv6,size); - SSVAL(cli->outbuf,smb_vwv7,(size >> 16)); - SSVAL(cli->outbuf,smb_mid,cli->mid + i); - - if (bigoffset) { - SIVAL(cli->outbuf,smb_vwv10,(((SMB_BIG_UINT)offset)>>32) & 0xffffffff); - } - - return cli_send_smb(cli); + char **pbuf = (char **)priv; + memcpy(*pbuf, buf, n); + *pbuf += n; + return NT_STATUS_OK; } -/**************************************************************************** - Read size bytes at offset offset using SMBreadX. -****************************************************************************/ - -ssize_t cli_read(struct cli_state *cli, int fnum, char *buf, off_t offset, size_t size) +ssize_t cli_read(struct cli_state *cli, int fnum, char *buf, + off_t offset, size_t size) { - char *p; - size_t size2; - size_t readsize; - ssize_t total = 0; - /* We can only do direct reads if not signing or encrypting. */ - bool direct_reads = !client_is_signing_on(cli) && !cli_encryption_on(cli); - - if (size == 0) - return 0; - - /* - * Set readsize to the maximum size we can handle in one readX, - * rounded down to a multiple of 1024. - */ - - if (client_is_signing_on(cli) == false && - cli_encryption_on(cli) == false && - (cli->posix_capabilities & CIFS_UNIX_LARGE_READ_CAP)) { - readsize = CLI_SAMBA_MAX_POSIX_LARGE_READX_SIZE; - } else if (cli->capabilities & CAP_LARGE_READX) { - if (cli->is_samba) { - readsize = CLI_SAMBA_MAX_LARGE_READX_SIZE; - } else { - readsize = CLI_WINDOWS_MAX_LARGE_READX_SIZE; - } - } else { - readsize = (cli->max_xmit - (smb_size+32)) & ~1023; - } - - while (total < size) { - readsize = MIN(readsize, size-total); - - /* Issue a read and receive a reply */ - - if (!cli_issue_read(cli, fnum, offset, readsize, 0)) - return -1; - - if (direct_reads) { - if (!cli_receive_smb_readX_header(cli)) - return -1; - } else { - if (!cli_receive_smb(cli)) - return -1; - } - - /* Check for error. Make sure to check for DOS and NT - errors. */ - - if (cli_is_error(cli)) { - bool recoverable_error = False; - NTSTATUS status = NT_STATUS_OK; - uint8 eclass = 0; - uint32 ecode = 0; - - if (cli_is_nt_error(cli)) - status = cli_nt_error(cli); - else - cli_dos_error(cli, &eclass, &ecode); - - /* - * ERRDOS ERRmoredata or STATUS_MORE_ENRTIES is a - * recoverable error, plus we have valid data in the - * packet so don't error out here. - */ - - if ((eclass == ERRDOS && ecode == ERRmoredata) || - NT_STATUS_V(status) == NT_STATUS_V(STATUS_MORE_ENTRIES)) - recoverable_error = True; - - if (!recoverable_error) - return -1; - } - - /* size2 is the number of bytes the server returned. - * Might be zero. */ - size2 = SVAL(cli->inbuf, smb_vwv5); - size2 |= (((unsigned int)(SVAL(cli->inbuf, smb_vwv7))) << 16); - - if (size2 > readsize) { - DEBUG(5,("server returned more than we wanted!\n")); - return -1; - } else if (size2 < 0) { - DEBUG(5,("read return < 0!\n")); - return -1; - } - - if (size2) { - /* smb_vwv6 is the offset in the packet of the returned - * data bytes. Only valid if size2 != 0. */ - - if (!direct_reads) { - /* Copy data into buffer */ - p = smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_vwv6); - memcpy(buf + total, p, size2); - } else { - /* Ensure the remaining data matches the return size. */ - ssize_t toread = smb_len_large(cli->inbuf) - SVAL(cli->inbuf,smb_vwv6); - - /* Ensure the size is correct. */ - if (toread != size2) { - DEBUG(5,("direct read logic fail toread (%d) != size2 (%u)\n", - (int)toread, (unsigned int)size2 )); - return -1; - } - - /* Read data directly into buffer */ - toread = cli_receive_smb_data(cli,buf+total,size2); - if (toread != size2) { - DEBUG(5,("direct read read failure toread (%d) != size2 (%u)\n", - (int)toread, (unsigned int)size2 )); - return -1; - } - } - } - - total += size2; - offset += size2; - - /* - * If the server returned less than we asked for we're at EOF. - */ + NTSTATUS status; + ssize_t ret; - if (size2 < readsize) - break; + status = cli_pull(cli, fnum, offset, size, size, + cli_read_sink, &buf, &ret); + if (!NT_STATUS_IS_OK(status)) { + cli_set_error(cli, status); + return -1; } - - return total; + return ret; } #if 0 /* relies on client_receive_smb(), now a static in libsmb/clientgen.c */ |