mirror of
https://github.com/samba-team/samba.git
synced 2025-08-03 04:22:09 +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 a53268fb20
)
This commit is contained in:
committed by
Gerald (Jerry) Carter
parent
074af4b39d
commit
32106b2395
@ -29,6 +29,7 @@
|
||||
#define CLI_BUFFER_SIZE (0xFFFF)
|
||||
#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_SAMBA_MAX_POSIX_LARGE_READX_SIZE (0xFFFF00) /* 24-bit len. */
|
||||
|
||||
/*
|
||||
* These definitions depend on smb.h
|
||||
@ -152,6 +153,7 @@ struct cli_state {
|
||||
int win95;
|
||||
BOOL is_samba;
|
||||
uint32 capabilities;
|
||||
uint32 posix_capabilities;
|
||||
BOOL dfsroot;
|
||||
|
||||
TALLOC_CTX *mem_ctx;
|
||||
|
@ -191,6 +191,10 @@
|
||||
#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)
|
||||
|
||||
#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
|
||||
values
|
||||
|
@ -529,8 +529,10 @@ findfirst/findnext is SMB_FIND_FILE_UNIX_INFO2.
|
||||
(chflags) and lsattr */
|
||||
#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_TRANSPORT_ENCRYPTION_CAP 0x40 /* We can do SPNEGO negotiations for encryption. */
|
||||
#define CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP 0x80 /* We *must* SPNEGO negotiations for encryption. */
|
||||
#define CIFS_UNIX_LARGE_READ_CAP 0x40 /* We can cope with 24 bit reads in readX. */
|
||||
#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
|
||||
|
||||
|
@ -658,10 +658,12 @@ ssize_t read_smb_length(int fd, char *inbuf, unsigned int timeout)
|
||||
BUFFER_SIZE+SAFETY_MARGIN.
|
||||
The timeout is in milliseconds.
|
||||
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.
|
||||
****************************************************************************/
|
||||
|
||||
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;
|
||||
|
||||
@ -679,7 +681,7 @@ BOOL receive_smb_raw(int fd, char *buffer, unsigned int timeout)
|
||||
|
||||
if (smb_read_error == 0)
|
||||
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)
|
||||
smb_read_error = READ_ERROR;
|
||||
return False;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if(len > 0) {
|
||||
if (maxlen) {
|
||||
len = MIN(len,maxlen);
|
||||
}
|
||||
|
||||
if (timeout > 0) {
|
||||
ret = read_socket_with_timeout(fd,buffer+4,len,len,timeout);
|
||||
} else {
|
||||
@ -714,7 +720,7 @@ BOOL receive_smb_raw(int fd, char *buffer, unsigned int timeout)
|
||||
if (smb_read_error == 0) {
|
||||
smb_read_error = READ_ERROR;
|
||||
}
|
||||
return False;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (!receive_smb_raw(fd, buffer, timeout)) {
|
||||
if (!receive_smb_raw(fd, buffer, timeout, 0)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
Unix SMB/CIFS implementation.
|
||||
SMB client generic functions
|
||||
Copyright (C) Andrew Tridgell 1994-1998
|
||||
Copyright (C) Jeremy Allison 2007.
|
||||
|
||||
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
|
||||
@ -54,20 +55,20 @@ int cli_set_port(struct cli_state *cli, int port)
|
||||
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;
|
||||
char *buffer = cli->inbuf;
|
||||
unsigned int timeout = cli->timeout;
|
||||
|
||||
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"));
|
||||
show_msg(buffer);
|
||||
return ret;
|
||||
return len;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
close(cli->fd);
|
||||
cli->fd = -1;
|
||||
return False;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
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 ret;
|
||||
ssize_t len;
|
||||
|
||||
/* fd == -1 causes segfaults -- Tom (tom@ninja.nl) */
|
||||
if (cli->fd == -1)
|
||||
return False;
|
||||
|
||||
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. */
|
||||
return True;
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
if (len > 0) {
|
||||
/* it might be an oplock break request */
|
||||
if (!(CVAL(cli->inbuf, smb_flg) & FLAG_REPLY) &&
|
||||
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) {
|
||||
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;
|
||||
if (!cli->oplock_handler(cli, fnum, level)) {
|
||||
return False;
|
||||
}
|
||||
}
|
||||
/* try to prevent loops */
|
||||
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 (!ret) {
|
||||
if (len <= 0) {
|
||||
DEBUG(0, ("Receiving SMB: Server stopped responding\n"));
|
||||
cli->smb_rw_error = smb_read_error;
|
||||
close(cli->fd);
|
||||
cli->fd = -1;
|
||||
return ret;
|
||||
return False;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
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)
|
||||
{
|
||||
ssize_t ret=0;
|
||||
|
@ -66,7 +66,7 @@ BOOL cli_unix_extensions_version(struct cli_state *cli, uint16 *pmajor, uint16 *
|
||||
|
||||
*pmajor = SVAL(rdata,0);
|
||||
*pminor = SVAL(rdata,2);
|
||||
*pcaplow = IVAL(rdata,4);
|
||||
cli->posix_capabilities = *pcaplow = IVAL(rdata,4);
|
||||
*pcaphigh = IVAL(rdata,8);
|
||||
|
||||
/* todo: but not yet needed
|
||||
|
@ -46,7 +46,7 @@ static BOOL cli_issue_read(struct cli_state *cli, int fnum, off_t offset,
|
||||
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) & 1));
|
||||
SSVAL(cli->outbuf,smb_vwv7,(size >> 16));
|
||||
SSVAL(cli->outbuf,smb_mid,cli->mid + i);
|
||||
|
||||
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)
|
||||
{
|
||||
char *p;
|
||||
int size2;
|
||||
int readsize;
|
||||
size_t size2;
|
||||
size_t readsize;
|
||||
ssize_t total = 0;
|
||||
/* We can only do direct reads if not signing. */
|
||||
BOOL direct_reads = !client_is_signing_on(cli);
|
||||
|
||||
if (size == 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.
|
||||
*/
|
||||
|
||||
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) {
|
||||
readsize = CLI_SAMBA_MAX_LARGE_READX_SIZE;
|
||||
} 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))
|
||||
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. */
|
||||
@ -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 |= (((unsigned int)(SVAL(cli->inbuf, smb_vwv7) & 1)) << 16);
|
||||
size2 |= (((unsigned int)(SVAL(cli->inbuf, smb_vwv7))) << 16);
|
||||
|
||||
if (size2 > readsize) {
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -657,6 +657,16 @@ BOOL client_set_trans_sign_state_off(struct cli_state *cli, uint16 mid)
|
||||
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.
|
||||
************************************************************/
|
||||
|
@ -2149,39 +2149,42 @@ static void fail_readraw(void)
|
||||
exit_server_cleanly(errstr);
|
||||
}
|
||||
|
||||
#if defined(WITH_SENDFILE)
|
||||
/****************************************************************************
|
||||
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... */
|
||||
if (nread > bufsize) {
|
||||
fail_readraw();
|
||||
while (tosend > 0) {
|
||||
ssize_t ret;
|
||||
size_t cur_read;
|
||||
|
||||
if (tosend > bufsize) {
|
||||
cur_read = bufsize;
|
||||
} else {
|
||||
cur_read = tosend;
|
||||
}
|
||||
|
||||
if (nread > 0) {
|
||||
ret = read_file(fsp,buf,startpos,nread);
|
||||
ret = read_file(fsp,buf,startpos,cur_read);
|
||||
if (ret == -1) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we had a short read, fill with zeros. */
|
||||
if (ret < nread) {
|
||||
memset(buf, '\0', nread - ret);
|
||||
if (ret < cur_read) {
|
||||
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;
|
||||
}
|
||||
tosend -= cur_read;
|
||||
startpos += cur_read;
|
||||
}
|
||||
|
||||
return (ssize_t)nread;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
Use sendfile in readbraw.
|
||||
@ -2525,6 +2528,27 @@ Returning short read of maximum allowed for compatibility with Windows 2000.\n",
|
||||
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.
|
||||
****************************************************************************/
|
||||
@ -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,
|
||||
files_struct *fsp, SMB_OFF_T startpos, size_t smb_maxcnt)
|
||||
{
|
||||
SMB_STRUCT_STAT sbuf;
|
||||
int outsize = 0;
|
||||
ssize_t nread = -1;
|
||||
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)
|
||||
/*
|
||||
* 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) &&
|
||||
lp_use_sendfile(SNUM(conn)) && (fsp->wcp == NULL) ) {
|
||||
SMB_STRUCT_STAT sbuf;
|
||||
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
|
||||
* assume here the sendfile will work (get the
|
||||
* correct amount of data).
|
||||
*/
|
||||
|
||||
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) & 1));
|
||||
SSVAL(smb_buf(outbuf),-2,smb_maxcnt);
|
||||
SCVAL(outbuf,smb_vwv0,0xFF);
|
||||
setup_readX_header(inbuf,outbuf,smb_maxcnt);
|
||||
set_message(inbuf,outbuf,12,smb_maxcnt,False);
|
||||
header.data = (uint8 *)outbuf;
|
||||
header.length = data - outbuf;
|
||||
@ -2621,6 +2644,22 @@ int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length
|
||||
|
||||
#endif
|
||||
|
||||
if ((smb_maxcnt && 0xFF0000) > 0x10000) {
|
||||
int sendlen = setup_readX_header(inbuf,outbuf,smb_maxcnt) - smb_maxcnt;
|
||||
/* Send out the header. */
|
||||
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) {
|
||||
@ -2640,6 +2679,7 @@ int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length
|
||||
/* Returning the number of bytes we want to send back - including header. */
|
||||
return outsize;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Reply to a read and X.
|
||||
@ -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);
|
||||
ssize_t nread = -1;
|
||||
size_t smb_maxcnt = SVAL(inbuf,smb_vwv5);
|
||||
BOOL big_readX = False;
|
||||
#if 0
|
||||
size_t smb_mincnt = SVAL(inbuf,smb_vwv6);
|
||||
#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);
|
||||
|
||||
if (global_client_caps & CAP_LARGE_READX) {
|
||||
if (SVAL(inbuf,smb_vwv7) == 1) {
|
||||
smb_maxcnt |= (1<<16);
|
||||
size_t upper_size = SVAL(inbuf,smb_vwv7);
|
||||
smb_maxcnt |= (upper_size<<16);
|
||||
if (upper_size > 1) {
|
||||
/* Can't do this on a chained packet. */
|
||||
if ((CVAL(inbuf,smb_vwv0) != 0xFF)) {
|
||||
return ERROR_NT(NT_STATUS_NOT_SUPPORTED);
|
||||
}
|
||||
if (smb_maxcnt > BUFFER_SIZE) {
|
||||
DEBUG(0,("reply_read_and_X - read too large (%u) for reply buffer %u\n",
|
||||
(unsigned int)smb_maxcnt, (unsigned int)BUFFER_SIZE));
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
return -1;
|
||||
}
|
||||
|
@ -2556,7 +2556,10 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
|
||||
CIFS_UNIX_POSIX_PATHNAMES_CAP|
|
||||
CIFS_UNIX_FCNTL_LOCKS_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;
|
||||
|
||||
case SMB_QUERY_POSIX_FS_INFO:
|
||||
|
Reference in New Issue
Block a user