1
0
mirror of https://github.com/samba-team/samba.git synced 2025-02-02 09:47:23 +03:00

r22920: Add in the UNIX capability for 24-bit readX, as discussed

with the Apple guys and Linux kernel guys. Still looking
at how to do writeX as there's no recvfile().
Jeremy.
(This used to be commit a53268fb2082de586e2df250d8ddfcff53379102)
This commit is contained in:
Jeremy Allison 2007-05-16 00:07:38 +00:00 committed by Gerald (Jerry) Carter
parent 074af4b39d
commit 32106b2395
10 changed files with 298 additions and 97 deletions

View File

@ -29,6 +29,7 @@
#define CLI_BUFFER_SIZE (0xFFFF) #define CLI_BUFFER_SIZE (0xFFFF)
#define CLI_SAMBA_MAX_LARGE_READX_SIZE (127*1024) /* Works for Samba servers */ #define CLI_SAMBA_MAX_LARGE_READX_SIZE (127*1024) /* Works for Samba servers */
#define CLI_WINDOWS_MAX_LARGE_READX_SIZE ((64*1024)-2) /* Windows servers are broken.... */ #define CLI_WINDOWS_MAX_LARGE_READX_SIZE ((64*1024)-2) /* Windows servers are broken.... */
#define CLI_SAMBA_MAX_POSIX_LARGE_READX_SIZE (0xFFFF00) /* 24-bit len. */
/* /*
* These definitions depend on smb.h * These definitions depend on smb.h
@ -152,6 +153,7 @@ struct cli_state {
int win95; int win95;
BOOL is_samba; BOOL is_samba;
uint32 capabilities; uint32 capabilities;
uint32 posix_capabilities;
BOOL dfsroot; BOOL dfsroot;
TALLOC_CTX *mem_ctx; TALLOC_CTX *mem_ctx;

View File

@ -191,6 +191,10 @@
#define _smb_setlen(buf,len) do { buf[0] = 0; buf[1] = (len&0x10000)>>16; \ #define _smb_setlen(buf,len) do { buf[0] = 0; buf[1] = (len&0x10000)>>16; \
buf[2] = (len&0xFF00)>>8; buf[3] = len&0xFF; } while (0) buf[2] = (len&0xFF00)>>8; buf[3] = len&0xFF; } while (0)
#define smb_len_large(buf) (PVAL(buf,3)|(PVAL(buf,2)<<8)|(PVAL(buf,1)<<16))
#define _smb_setlen_large(buf,len) do { buf[0] = 0; buf[1] = (len&0xFF0000)>>16; \
buf[2] = (len&0xFF00)>>8; buf[3] = len&0xFF; } while (0)
/******************************************************************* /*******************************************************************
find the difference in milliseconds between two struct timeval find the difference in milliseconds between two struct timeval
values values

View File

@ -529,8 +529,10 @@ findfirst/findnext is SMB_FIND_FILE_UNIX_INFO2.
(chflags) and lsattr */ (chflags) and lsattr */
#define CIFS_UNIX_POSIX_PATHNAMES_CAP 0x10 /* Use POSIX pathnames on the wire. */ #define CIFS_UNIX_POSIX_PATHNAMES_CAP 0x10 /* Use POSIX pathnames on the wire. */
#define CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP 0x20 /* We can cope with POSIX open/mkdir/unlink etc. */ #define CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP 0x20 /* We can cope with POSIX open/mkdir/unlink etc. */
#define CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP 0x40 /* We can do SPNEGO negotiations for encryption. */ #define CIFS_UNIX_LARGE_READ_CAP 0x40 /* We can cope with 24 bit reads in readX. */
#define CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP 0x80 /* We *must* SPNEGO negotiations for encryption. */ #define CIFS_UNIX_LARGE_WRITE_CAP 0x80 /* We can cope with 24 bit writes in writeX. */
#define CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP 0x100 /* We can do SPNEGO negotiations for encryption. */
#define CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP 0x200 /* We *must* SPNEGO negotiations for encryption. */
#define SMB_QUERY_POSIX_FS_INFO 0x201 #define SMB_QUERY_POSIX_FS_INFO 0x201

View File

@ -658,10 +658,12 @@ ssize_t read_smb_length(int fd, char *inbuf, unsigned int timeout)
BUFFER_SIZE+SAFETY_MARGIN. BUFFER_SIZE+SAFETY_MARGIN.
The timeout is in milliseconds. The timeout is in milliseconds.
This function will return on receipt of a session keepalive packet. This function will return on receipt of a session keepalive packet.
maxlen is the max number of bytes to return, not including the 4 byte
length. If zero it means BUFFER_SIZE+SAFETY_MARGIN limit.
Doesn't check the MAC on signed packets. Doesn't check the MAC on signed packets.
****************************************************************************/ ****************************************************************************/
BOOL receive_smb_raw(int fd, char *buffer, unsigned int timeout) ssize_t receive_smb_raw(int fd, char *buffer, unsigned int timeout, size_t maxlen)
{ {
ssize_t len,ret; ssize_t len,ret;
@ -679,7 +681,7 @@ BOOL receive_smb_raw(int fd, char *buffer, unsigned int timeout)
if (smb_read_error == 0) if (smb_read_error == 0)
smb_read_error = READ_ERROR; smb_read_error = READ_ERROR;
return False; return -1;
} }
/* /*
@ -699,11 +701,15 @@ BOOL receive_smb_raw(int fd, char *buffer, unsigned int timeout)
if (smb_read_error == 0) if (smb_read_error == 0)
smb_read_error = READ_ERROR; smb_read_error = READ_ERROR;
return False; return -1;
} }
} }
if(len > 0) { if(len > 0) {
if (maxlen) {
len = MIN(len,maxlen);
}
if (timeout > 0) { if (timeout > 0) {
ret = read_socket_with_timeout(fd,buffer+4,len,len,timeout); ret = read_socket_with_timeout(fd,buffer+4,len,len,timeout);
} else { } else {
@ -714,7 +720,7 @@ BOOL receive_smb_raw(int fd, char *buffer, unsigned int timeout)
if (smb_read_error == 0) { if (smb_read_error == 0) {
smb_read_error = READ_ERROR; smb_read_error = READ_ERROR;
} }
return False; return -1;
} }
/* not all of samba3 properly checks for packet-termination of strings. This /* not all of samba3 properly checks for packet-termination of strings. This
@ -722,7 +728,7 @@ BOOL receive_smb_raw(int fd, char *buffer, unsigned int timeout)
SSVAL(buffer+4,len, 0); SSVAL(buffer+4,len, 0);
} }
return True; return len;
} }
/**************************************************************************** /****************************************************************************
@ -732,7 +738,7 @@ BOOL receive_smb_raw(int fd, char *buffer, unsigned int timeout)
BOOL receive_smb(int fd, char *buffer, unsigned int timeout) BOOL receive_smb(int fd, char *buffer, unsigned int timeout)
{ {
if (!receive_smb_raw(fd, buffer, timeout)) { if (!receive_smb_raw(fd, buffer, timeout, 0)) {
return False; return False;
} }

View File

@ -2,6 +2,7 @@
Unix SMB/CIFS implementation. Unix SMB/CIFS implementation.
SMB client generic functions SMB client generic functions
Copyright (C) Andrew Tridgell 1994-1998 Copyright (C) Andrew Tridgell 1994-1998
Copyright (C) Jeremy Allison 2007.
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -54,20 +55,20 @@ int cli_set_port(struct cli_state *cli, int port)
should never go into a blocking read. should never go into a blocking read.
****************************************************************************/ ****************************************************************************/
static BOOL client_receive_smb(struct cli_state *cli, BOOL eat_keepalives) static ssize_t client_receive_smb(struct cli_state *cli, BOOL eat_keepalives, size_t maxlen)
{ {
BOOL ret; ssize_t len;
int fd = cli->fd; int fd = cli->fd;
char *buffer = cli->inbuf; char *buffer = cli->inbuf;
unsigned int timeout = cli->timeout; unsigned int timeout = cli->timeout;
for(;;) { for(;;) {
ret = receive_smb_raw(fd, buffer, timeout); len = receive_smb_raw(fd, buffer, timeout, maxlen);
if (!ret) { if (len < 0) {
DEBUG(10,("client_receive_smb failed\n")); DEBUG(10,("client_receive_smb failed\n"));
show_msg(buffer); show_msg(buffer);
return ret; return len;
} }
/* Ignore session keepalive packets. */ /* Ignore session keepalive packets. */
@ -85,11 +86,11 @@ static BOOL client_receive_smb(struct cli_state *cli, BOOL eat_keepalives)
cli->smb_rw_error = READ_BAD_DECRYPT; cli->smb_rw_error = READ_BAD_DECRYPT;
close(cli->fd); close(cli->fd);
cli->fd = -1; cli->fd = -1;
return False; return -1;
} }
} }
show_msg(buffer); show_msg(buffer);
return ret; return len;
} }
/**************************************************************************** /****************************************************************************
@ -98,21 +99,21 @@ static BOOL client_receive_smb(struct cli_state *cli, BOOL eat_keepalives)
BOOL cli_receive_smb_internal(struct cli_state *cli, BOOL eat_keepalives) BOOL cli_receive_smb_internal(struct cli_state *cli, BOOL eat_keepalives)
{ {
BOOL ret; ssize_t len;
/* fd == -1 causes segfaults -- Tom (tom@ninja.nl) */ /* fd == -1 causes segfaults -- Tom (tom@ninja.nl) */
if (cli->fd == -1) if (cli->fd == -1)
return False; return False;
again: again:
ret = client_receive_smb(cli, eat_keepalives); len = client_receive_smb(cli, eat_keepalives, 0);
if (ret && !eat_keepalives && (CVAL(cli->inbuf,0) == SMBkeepalive)) { if (len >= 0 && !eat_keepalives && (CVAL(cli->inbuf,0) == SMBkeepalive)) {
/* Give back the keepalive. */ /* Give back the keepalive. */
return True; return True;
} }
if (ret) { if (len > 0) {
/* it might be an oplock break request */ /* it might be an oplock break request */
if (!(CVAL(cli->inbuf, smb_flg) & FLAG_REPLY) && if (!(CVAL(cli->inbuf, smb_flg) & FLAG_REPLY) &&
CVAL(cli->inbuf,smb_com) == SMBlockingX && CVAL(cli->inbuf,smb_com) == SMBlockingX &&
@ -121,7 +122,9 @@ BOOL cli_receive_smb_internal(struct cli_state *cli, BOOL eat_keepalives)
if (cli->oplock_handler) { if (cli->oplock_handler) {
int fnum = SVAL(cli->inbuf,smb_vwv2); int fnum = SVAL(cli->inbuf,smb_vwv2);
unsigned char level = CVAL(cli->inbuf,smb_vwv3+1); unsigned char level = CVAL(cli->inbuf,smb_vwv3+1);
if (!cli->oplock_handler(cli, fnum, level)) return False; if (!cli->oplock_handler(cli, fnum, level)) {
return False;
}
} }
/* try to prevent loops */ /* try to prevent loops */
SCVAL(cli->inbuf,smb_com,0xFF); SCVAL(cli->inbuf,smb_com,0xFF);
@ -130,12 +133,12 @@ BOOL cli_receive_smb_internal(struct cli_state *cli, BOOL eat_keepalives)
} }
/* If the server is not responding, note that now */ /* If the server is not responding, note that now */
if (!ret) { if (len <= 0) {
DEBUG(0, ("Receiving SMB: Server stopped responding\n")); DEBUG(0, ("Receiving SMB: Server stopped responding\n"));
cli->smb_rw_error = smb_read_error; cli->smb_rw_error = smb_read_error;
close(cli->fd); close(cli->fd);
cli->fd = -1; cli->fd = -1;
return ret; return False;
} }
if (!cli_check_sign_mac(cli)) { if (!cli_check_sign_mac(cli)) {
@ -187,6 +190,102 @@ BOOL cli_receive_smb_return_keepalive(struct cli_state *cli)
return cli_receive_smb_internal(cli, False); return cli_receive_smb_internal(cli, False);
} }
/****************************************************************************
Read the data portion of a readX smb.
The timeout is in milliseconds
****************************************************************************/
ssize_t cli_receive_smb_data(struct cli_state *cli, char *buffer, size_t len)
{
if (cli->timeout > 0) {
return read_socket_with_timeout(cli->fd, buffer, len, len, cli->timeout);
} else {
return read_data(cli->fd, buffer, len);
}
}
/****************************************************************************
Read a smb readX header.
We can only use this if encryption and signing are off.
****************************************************************************/
BOOL cli_receive_smb_readX_header(struct cli_state *cli)
{
ssize_t len, offset;
if (cli->fd == -1)
return False;
again:
/* Read up to the size of a readX header reply. */
len = client_receive_smb(cli, True, (smb_size - 4) + 24);
if (len > 0) {
/* it might be an oplock break request */
if (!(CVAL(cli->inbuf, smb_flg) & FLAG_REPLY) &&
CVAL(cli->inbuf,smb_com) == SMBlockingX &&
SVAL(cli->inbuf,smb_vwv6) == 0 &&
SVAL(cli->inbuf,smb_vwv7) == 0) {
ssize_t total_len = smb_len(cli->inbuf);
if (total_len > CLI_SAMBA_MAX_LARGE_READX_SIZE+SAFETY_MARGIN) {
goto read_err;
}
/* Read the rest of the data. */
if (!cli_receive_smb_data(cli,cli->inbuf+len,total_len - len)) {
goto read_err;
}
if (cli->oplock_handler) {
int fnum = SVAL(cli->inbuf,smb_vwv2);
unsigned char level = CVAL(cli->inbuf,smb_vwv3+1);
if (!cli->oplock_handler(cli, fnum, level)) return False;
}
/* try to prevent loops */
SCVAL(cli->inbuf,smb_com,0xFF);
goto again;
}
}
/* Check it's a non-chained readX reply. */
if (!(CVAL(cli->inbuf, smb_flg) & FLAG_REPLY) ||
(CVAL(cli->inbuf,smb_vwv0) != 0xFF) ||
(CVAL(cli->inbuf,smb_com) != SMBreadX)) {
/*
* We're not coping here with asnyc replies to
* other calls. Punt here - we need async client
* libs for this.
*/
goto read_err;
}
/*
* We know it's a readX reply - ensure we've read the
* padding bytes also.
*/
offset = SVAL(cli->inbuf,smb_vwv6);
if (offset > len) {
ssize_t ret;
size_t padbytes = offset - len;
ret = cli_receive_smb_data(cli,smb_buf(cli->inbuf),padbytes);
if (ret != padbytes) {
goto read_err;
}
}
return True;
read_err:
cli->smb_rw_error = smb_read_error = READ_ERROR;
close(cli->fd);
cli->fd = -1;
return False;
}
static ssize_t write_socket(int fd, const char *buf, size_t len) static ssize_t write_socket(int fd, const char *buf, size_t len)
{ {
ssize_t ret=0; ssize_t ret=0;

View File

@ -66,7 +66,7 @@ BOOL cli_unix_extensions_version(struct cli_state *cli, uint16 *pmajor, uint16 *
*pmajor = SVAL(rdata,0); *pmajor = SVAL(rdata,0);
*pminor = SVAL(rdata,2); *pminor = SVAL(rdata,2);
*pcaplow = IVAL(rdata,4); cli->posix_capabilities = *pcaplow = IVAL(rdata,4);
*pcaphigh = IVAL(rdata,8); *pcaphigh = IVAL(rdata,8);
/* todo: but not yet needed /* todo: but not yet needed

View File

@ -46,7 +46,7 @@ static BOOL cli_issue_read(struct cli_state *cli, int fnum, off_t offset,
SIVAL(cli->outbuf,smb_vwv3,offset); SIVAL(cli->outbuf,smb_vwv3,offset);
SSVAL(cli->outbuf,smb_vwv5,size); SSVAL(cli->outbuf,smb_vwv5,size);
SSVAL(cli->outbuf,smb_vwv6,size); SSVAL(cli->outbuf,smb_vwv6,size);
SSVAL(cli->outbuf,smb_vwv7,((size >> 16) & 1)); SSVAL(cli->outbuf,smb_vwv7,(size >> 16));
SSVAL(cli->outbuf,smb_mid,cli->mid + i); SSVAL(cli->outbuf,smb_mid,cli->mid + i);
if (bigoffset) { if (bigoffset) {
@ -63,9 +63,11 @@ static BOOL cli_issue_read(struct cli_state *cli, int fnum, off_t offset,
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; char *p;
int size2; size_t size2;
int readsize; size_t readsize;
ssize_t total = 0; ssize_t total = 0;
/* We can only do direct reads if not signing. */
BOOL direct_reads = !client_is_signing_on(cli);
if (size == 0) if (size == 0)
return 0; return 0;
@ -75,7 +77,11 @@ ssize_t cli_read(struct cli_state *cli, int fnum, char *buf, off_t offset, size_
* rounded down to a multiple of 1024. * rounded down to a multiple of 1024.
*/ */
if (cli->capabilities & CAP_LARGE_READX) { 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) { if (cli->is_samba) {
readsize = CLI_SAMBA_MAX_LARGE_READX_SIZE; readsize = CLI_SAMBA_MAX_LARGE_READX_SIZE;
} else { } else {
@ -93,8 +99,13 @@ ssize_t cli_read(struct cli_state *cli, int fnum, char *buf, off_t offset, size_
if (!cli_issue_read(cli, fnum, offset, readsize, 0)) if (!cli_issue_read(cli, fnum, offset, readsize, 0))
return -1; return -1;
if (!cli_receive_smb(cli)) if (direct_reads) {
return -1; 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 /* Check for error. Make sure to check for DOS and NT
errors. */ errors. */
@ -125,7 +136,7 @@ ssize_t cli_read(struct cli_state *cli, int fnum, char *buf, off_t offset, size_
} }
size2 = SVAL(cli->inbuf, smb_vwv5); size2 = SVAL(cli->inbuf, smb_vwv5);
size2 |= (((unsigned int)(SVAL(cli->inbuf, smb_vwv7) & 1)) << 16); size2 |= (((unsigned int)(SVAL(cli->inbuf, smb_vwv7))) << 16);
if (size2 > readsize) { if (size2 > readsize) {
DEBUG(5,("server returned more than we wanted!\n")); DEBUG(5,("server returned more than we wanted!\n"));
@ -135,10 +146,29 @@ ssize_t cli_read(struct cli_state *cli, int fnum, char *buf, off_t offset, size_
return -1; return -1;
} }
/* Copy data into buffer */ 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);
p = smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_vwv6); /* Ensure the size is correct. */
memcpy(buf + total, p, size2); 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; total += size2;
offset += size2; offset += size2;

View File

@ -657,6 +657,16 @@ BOOL client_set_trans_sign_state_off(struct cli_state *cli, uint16 mid)
return True; return True;
} }
/***********************************************************
Is client signing on ?
************************************************************/
BOOL client_is_signing_on(struct cli_state *cli)
{
struct smb_sign_info *si = &cli->sign_info;
return si->doing_signing;
}
/*********************************************************** /***********************************************************
SMB signing - Server implementation - send the MAC. SMB signing - Server implementation - send the MAC.
************************************************************/ ************************************************************/

View File

@ -2149,39 +2149,42 @@ static void fail_readraw(void)
exit_server_cleanly(errstr); exit_server_cleanly(errstr);
} }
#if defined(WITH_SENDFILE)
/**************************************************************************** /****************************************************************************
Fake (read/write) sendfile. Returns -1 on read or write fail. Fake (read/write) sendfile. Returns -1 on read or write fail.
****************************************************************************/ ****************************************************************************/
static ssize_t fake_sendfile(files_struct *fsp, SMB_OFF_T startpos, size_t nread, char *buf, int bufsize) static ssize_t fake_sendfile(files_struct *fsp, SMB_OFF_T startpos, size_t nread, char *buf, size_t bufsize)
{ {
ssize_t ret=0; size_t tosend = nread;
/* Paranioa check... */ while (tosend > 0) {
if (nread > bufsize) { ssize_t ret;
fail_readraw(); size_t cur_read;
}
if (nread > 0) { if (tosend > bufsize) {
ret = read_file(fsp,buf,startpos,nread); cur_read = bufsize;
} else {
cur_read = tosend;
}
ret = read_file(fsp,buf,startpos,cur_read);
if (ret == -1) { if (ret == -1) {
return -1; return -1;
} }
}
/* If we had a short read, fill with zeros. */ /* If we had a short read, fill with zeros. */
if (ret < nread) { if (ret < cur_read) {
memset(buf, '\0', nread - ret); memset(buf, '\0', cur_read - ret);
} }
if (write_data(smbd_server_fd(),buf,nread) != nread) { if (write_data(smbd_server_fd(),buf,cur_read) != cur_read) {
return -1; return -1;
} }
tosend -= cur_read;
startpos += cur_read;
}
return (ssize_t)nread; return (ssize_t)nread;
} }
#endif
/**************************************************************************** /****************************************************************************
Use sendfile in readbraw. Use sendfile in readbraw.
@ -2525,6 +2528,27 @@ Returning short read of maximum allowed for compatibility with Windows 2000.\n",
return(outsize); return(outsize);
} }
/****************************************************************************
Setup readX header.
****************************************************************************/
static int setup_readX_header(char *inbuf, char *outbuf, size_t smb_maxcnt)
{
int outsize;
char *data = smb_buf(outbuf);
SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
SSVAL(outbuf,smb_vwv5,smb_maxcnt);
SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
SSVAL(smb_buf(outbuf),-2,smb_maxcnt);
SCVAL(outbuf,smb_vwv0,0xFF);
outsize = set_message(inbuf, outbuf,12,smb_maxcnt,False);
/* Reset the outgoing length, set_message truncates at 0x1FFFF. */
_smb_setlen_large(outbuf,(smb_size + 12*2 + smb_maxcnt - 4));
return outsize;
}
/**************************************************************************** /****************************************************************************
Reply to a read and X - possibly using sendfile. Reply to a read and X - possibly using sendfile.
****************************************************************************/ ****************************************************************************/
@ -2532,10 +2556,27 @@ Returning short read of maximum allowed for compatibility with Windows 2000.\n",
int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length, int len_outbuf, int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length, int len_outbuf,
files_struct *fsp, SMB_OFF_T startpos, size_t smb_maxcnt) files_struct *fsp, SMB_OFF_T startpos, size_t smb_maxcnt)
{ {
SMB_STRUCT_STAT sbuf;
int outsize = 0; int outsize = 0;
ssize_t nread = -1; ssize_t nread = -1;
char *data = smb_buf(outbuf); char *data = smb_buf(outbuf);
if(SMB_VFS_FSTAT(fsp,fsp->fh->fd, &sbuf) == -1) {
return(UNIXERROR(ERRDOS,ERRnoaccess));
}
if (startpos > sbuf.st_size) {
smb_maxcnt = 0;
}
if (smb_maxcnt > (sbuf.st_size - startpos)) {
smb_maxcnt = (sbuf.st_size - startpos);
}
if (smb_maxcnt == 0) {
goto normal_read;
}
#if defined(WITH_SENDFILE) #if defined(WITH_SENDFILE)
/* /*
* We can only use sendfile on a non-chained packet * We can only use sendfile on a non-chained packet
@ -2545,33 +2586,15 @@ int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length
if ((chain_size == 0) && (CVAL(inbuf,smb_vwv0) == 0xFF) && if ((chain_size == 0) && (CVAL(inbuf,smb_vwv0) == 0xFF) &&
lp_use_sendfile(SNUM(conn)) && (fsp->wcp == NULL) ) { lp_use_sendfile(SNUM(conn)) && (fsp->wcp == NULL) ) {
SMB_STRUCT_STAT sbuf;
DATA_BLOB header; DATA_BLOB header;
if(SMB_VFS_FSTAT(fsp,fsp->fh->fd, &sbuf) == -1)
return(UNIXERROR(ERRDOS,ERRnoaccess));
if (startpos > sbuf.st_size)
goto normal_read;
if (smb_maxcnt > (sbuf.st_size - startpos))
smb_maxcnt = (sbuf.st_size - startpos);
if (smb_maxcnt == 0)
goto normal_read;
/* /*
* Set up the packet header before send. We * Set up the packet header before send. We
* assume here the sendfile will work (get the * assume here the sendfile will work (get the
* correct amount of data). * correct amount of data).
*/ */
SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */ setup_readX_header(inbuf,outbuf,smb_maxcnt);
SSVAL(outbuf,smb_vwv5,smb_maxcnt);
SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
SSVAL(outbuf,smb_vwv7,((smb_maxcnt >> 16) & 1));
SSVAL(smb_buf(outbuf),-2,smb_maxcnt);
SCVAL(outbuf,smb_vwv0,0xFF);
set_message(inbuf,outbuf,12,smb_maxcnt,False); set_message(inbuf,outbuf,12,smb_maxcnt,False);
header.data = (uint8 *)outbuf; header.data = (uint8 *)outbuf;
header.length = data - outbuf; header.length = data - outbuf;
@ -2621,24 +2644,41 @@ int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length
#endif #endif
nread = read_file(fsp,data,startpos,smb_maxcnt); if ((smb_maxcnt && 0xFF0000) > 0x10000) {
int sendlen = setup_readX_header(inbuf,outbuf,smb_maxcnt) - smb_maxcnt;
if (nread < 0) { /* Send out the header. */
return(UNIXERROR(ERRDOS,ERRnoaccess)); if (write_data(smbd_server_fd(),outbuf,sendlen) != sendlen) {
DEBUG(0,("send_file_readX: write_data failed for file %s (%s). Terminating\n",
fsp->fsp_name, strerror(errno) ));
exit_server_cleanly("send_file_readX sendfile failed");
}
if ((nread = fake_sendfile(fsp, startpos, smb_maxcnt, data,
len_outbuf - (data-outbuf))) == -1) {
DEBUG(0,("send_file_readX: fake_sendfile failed for file %s (%s).\n",
fsp->fsp_name, strerror(errno) ));
exit_server_cleanly("send_file_readX: fake_sendfile failed");
}
return -1;
} else {
nread = read_file(fsp,data,startpos,smb_maxcnt);
if (nread < 0) {
return(UNIXERROR(ERRDOS,ERRnoaccess));
}
outsize = set_message(inbuf, outbuf,12,nread,False);
SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
SSVAL(outbuf,smb_vwv5,nread);
SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
SSVAL(outbuf,smb_vwv7,((nread >> 16) & 1));
SSVAL(smb_buf(outbuf),-2,nread);
DEBUG( 3, ( "send_file_readX fnum=%d max=%d nread=%d\n",
fsp->fnum, (int)smb_maxcnt, (int)nread ) );
/* Returning the number of bytes we want to send back - including header. */
return outsize;
} }
outsize = set_message(inbuf,outbuf,12,nread,False);
SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
SSVAL(outbuf,smb_vwv5,nread);
SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
SSVAL(outbuf,smb_vwv7,((nread >> 16) & 1));
SSVAL(smb_buf(outbuf),-2,nread);
DEBUG( 3, ( "send_file_readX fnum=%d max=%d nread=%d\n",
fsp->fnum, (int)smb_maxcnt, (int)nread ) );
/* Returning the number of bytes we want to send back - including header. */
return outsize;
} }
/**************************************************************************** /****************************************************************************
@ -2651,6 +2691,7 @@ int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
SMB_OFF_T startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv3); SMB_OFF_T startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv3);
ssize_t nread = -1; ssize_t nread = -1;
size_t smb_maxcnt = SVAL(inbuf,smb_vwv5); size_t smb_maxcnt = SVAL(inbuf,smb_vwv5);
BOOL big_readX = False;
#if 0 #if 0
size_t smb_mincnt = SVAL(inbuf,smb_vwv6); size_t smb_mincnt = SVAL(inbuf,smb_vwv6);
#endif #endif
@ -2671,14 +2712,18 @@ int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
set_message(inbuf,outbuf,12,0,True); set_message(inbuf,outbuf,12,0,True);
if (global_client_caps & CAP_LARGE_READX) { if (global_client_caps & CAP_LARGE_READX) {
if (SVAL(inbuf,smb_vwv7) == 1) { size_t upper_size = SVAL(inbuf,smb_vwv7);
smb_maxcnt |= (1<<16); smb_maxcnt |= (upper_size<<16);
} if (upper_size > 1) {
if (smb_maxcnt > BUFFER_SIZE) { /* Can't do this on a chained packet. */
DEBUG(0,("reply_read_and_X - read too large (%u) for reply buffer %u\n", if ((CVAL(inbuf,smb_vwv0) != 0xFF)) {
(unsigned int)smb_maxcnt, (unsigned int)BUFFER_SIZE)); return ERROR_NT(NT_STATUS_NOT_SUPPORTED);
END_PROFILE(SMBreadX); }
return ERROR_NT(NT_STATUS_INVALID_PARAMETER); /* We currently don't do this on signed or sealed data. */
if (srv_is_signing_active() || srv_encryption_on()) {
return ERROR_NT(NT_STATUS_NOT_SUPPORTED);
}
big_readX = True;
} }
} }
@ -2711,7 +2756,7 @@ int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
return ERROR_DOS(ERRDOS,ERRlock); return ERROR_DOS(ERRDOS,ERRlock);
} }
if (schedule_aio_read_and_X(conn, inbuf, outbuf, length, bufsize, fsp, startpos, smb_maxcnt)) { if (!big_readX && schedule_aio_read_and_X(conn, inbuf, outbuf, length, bufsize, fsp, startpos, smb_maxcnt)) {
END_PROFILE(SMBreadX); END_PROFILE(SMBreadX);
return -1; return -1;
} }

View File

@ -2556,7 +2556,10 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
CIFS_UNIX_POSIX_PATHNAMES_CAP| CIFS_UNIX_POSIX_PATHNAMES_CAP|
CIFS_UNIX_FCNTL_LOCKS_CAP| CIFS_UNIX_FCNTL_LOCKS_CAP|
CIFS_UNIX_EXTATTR_CAP| CIFS_UNIX_EXTATTR_CAP|
CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP))); CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP|
/* Ensure we don't do this on signed or sealed data. */
(srv_is_signing_active() ? 0 : CIFS_UNIX_LARGE_READ_CAP)
)));
break; break;
case SMB_QUERY_POSIX_FS_INFO: case SMB_QUERY_POSIX_FS_INFO: