mirror of
https://github.com/samba-team/samba.git
synced 2025-01-28 17:47:29 +03:00
b83ba93eae
This version does the following: 1) talloc_free(), talloc_realloc() and talloc_steal() lose their (redundent) first arguments 2) you can use _any_ talloc pointer as a talloc context to allocate more memory. This allows you to create complex data structures where the top level structure is the logical parent of the next level down, and those are the parents of the level below that. Then destroy either the lot with a single talloc_free() or destroy any sub-part with a talloc_free() of that part 3) you can name any pointer. Use talloc_named() which is just like talloc() but takes the printf style name argument as well as the parent context and the size. The whole thing ends up being a very simple piece of code, although some of the pointer walking gets hairy. So far, I'm just using the new talloc() like the old one. The next step is to actually take advantage of the new interface properly. Expect some new commits soon that simplify some common coding styles in samba4 by using the new talloc(). (This used to be commit e35bb094c52e550b3105dd1638d8d90de71d854f)
323 lines
11 KiB
C
323 lines
11 KiB
C
/*
|
|
Unix SMB/CIFS implementation.
|
|
client file read/write routines
|
|
Copyright (C) Andrew Tridgell 1994-1998
|
|
Copyright (C) James Myers 2003
|
|
|
|
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
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
|
|
#include "includes.h"
|
|
|
|
#define SETUP_REQUEST(cmd, wct, buflen) do { \
|
|
req = smbcli_request_setup(tree, cmd, wct, buflen); \
|
|
if (!req) return NULL; \
|
|
} while (0)
|
|
|
|
|
|
/****************************************************************************
|
|
low level read operation (async send)
|
|
****************************************************************************/
|
|
struct smbcli_request *smb_raw_read_send(struct smbcli_tree *tree, union smb_read *parms)
|
|
{
|
|
BOOL bigoffset = False;
|
|
struct smbcli_request *req = NULL;
|
|
|
|
switch (parms->generic.level) {
|
|
case RAW_READ_GENERIC:
|
|
return NULL;
|
|
|
|
case RAW_READ_READBRAW:
|
|
if (tree->session->transport->negotiate.capabilities & CAP_LARGE_FILES) {
|
|
bigoffset = True;
|
|
}
|
|
SETUP_REQUEST(SMBreadbraw, bigoffset? 10:8, 0);
|
|
SSVAL(req->out.vwv, VWV(0), parms->readbraw.in.fnum);
|
|
SIVAL(req->out.vwv, VWV(1), parms->readbraw.in.offset);
|
|
SSVAL(req->out.vwv, VWV(3), parms->readbraw.in.maxcnt);
|
|
SSVAL(req->out.vwv, VWV(4), parms->readbraw.in.mincnt);
|
|
SIVAL(req->out.vwv, VWV(5), parms->readbraw.in.timeout);
|
|
SSVAL(req->out.vwv, VWV(7), 0); /* reserved */
|
|
if (bigoffset) {
|
|
SIVAL(req->out.vwv, VWV(8),parms->readbraw.in.offset>>32);
|
|
}
|
|
break;
|
|
|
|
case RAW_READ_LOCKREAD:
|
|
SETUP_REQUEST(SMBlockread, 5, 0);
|
|
SSVAL(req->out.vwv, VWV(0), parms->lockread.in.fnum);
|
|
SSVAL(req->out.vwv, VWV(1), parms->lockread.in.count);
|
|
SIVAL(req->out.vwv, VWV(2), parms->lockread.in.offset);
|
|
SSVAL(req->out.vwv, VWV(4), parms->lockread.in.remaining);
|
|
break;
|
|
|
|
case RAW_READ_READ:
|
|
SETUP_REQUEST(SMBread, 5, 0);
|
|
SSVAL(req->out.vwv, VWV(0), parms->read.in.fnum);
|
|
SSVAL(req->out.vwv, VWV(1), parms->read.in.count);
|
|
SIVAL(req->out.vwv, VWV(2), parms->read.in.offset);
|
|
SSVAL(req->out.vwv, VWV(4), parms->read.in.remaining);
|
|
break;
|
|
|
|
case RAW_READ_READX:
|
|
if (tree->session->transport->negotiate.capabilities & CAP_LARGE_FILES) {
|
|
bigoffset = True;
|
|
}
|
|
SETUP_REQUEST(SMBreadX, bigoffset ? 12 : 10, 0);
|
|
SSVAL(req->out.vwv, VWV(0), 0xFF);
|
|
SSVAL(req->out.vwv, VWV(1), 0);
|
|
SSVAL(req->out.vwv, VWV(2), parms->readx.in.fnum);
|
|
SIVAL(req->out.vwv, VWV(3), parms->readx.in.offset);
|
|
SSVAL(req->out.vwv, VWV(5), parms->readx.in.maxcnt);
|
|
SSVAL(req->out.vwv, VWV(6), parms->readx.in.mincnt);
|
|
SIVAL(req->out.vwv, VWV(7), 0); /* reserved */
|
|
SSVAL(req->out.vwv, VWV(9), parms->readx.in.remaining);
|
|
if (bigoffset) {
|
|
SIVAL(req->out.vwv, VWV(10),parms->readx.in.offset>>32);
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (!smbcli_request_send(req)) {
|
|
smbcli_request_destroy(req);
|
|
return NULL;
|
|
}
|
|
|
|
/* the transport layer needs to know that a readbraw is pending
|
|
and handle receives a little differently */
|
|
if (parms->generic.level == RAW_READ_READBRAW) {
|
|
tree->session->transport->readbraw_pending = 1;
|
|
}
|
|
|
|
return req;
|
|
}
|
|
|
|
/****************************************************************************
|
|
low level read operation (async recv)
|
|
****************************************************************************/
|
|
NTSTATUS smb_raw_read_recv(struct smbcli_request *req, union smb_read *parms)
|
|
{
|
|
if (!smbcli_request_receive(req) ||
|
|
smbcli_request_is_error(req)) {
|
|
goto failed;
|
|
}
|
|
|
|
switch (parms->generic.level) {
|
|
case RAW_READ_GENERIC:
|
|
/* handled in _send() */
|
|
break;
|
|
|
|
case RAW_READ_READBRAW:
|
|
parms->readbraw.out.nread = req->in.size - NBT_HDR_SIZE;
|
|
if (parms->readbraw.out.nread >
|
|
MAX(parms->readx.in.mincnt, parms->readx.in.maxcnt)) {
|
|
req->status = NT_STATUS_BUFFER_TOO_SMALL;
|
|
goto failed;
|
|
}
|
|
memcpy(parms->readbraw.out.data, req->in.buffer + NBT_HDR_SIZE, parms->readbraw.out.nread);
|
|
break;
|
|
|
|
case RAW_READ_LOCKREAD:
|
|
SMBCLI_CHECK_WCT(req, 5);
|
|
parms->lockread.out.nread = SVAL(req->in.vwv, VWV(0));
|
|
if (parms->lockread.out.nread > parms->lockread.in.count ||
|
|
!smbcli_raw_pull_data(req, req->in.data+3,
|
|
parms->lockread.out.nread, parms->lockread.out.data)) {
|
|
req->status = NT_STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
break;
|
|
|
|
case RAW_READ_READ:
|
|
/* there are 4 reserved words in the reply */
|
|
SMBCLI_CHECK_WCT(req, 5);
|
|
parms->read.out.nread = SVAL(req->in.vwv, VWV(0));
|
|
if (parms->read.out.nread > parms->read.in.count ||
|
|
!smbcli_raw_pull_data(req, req->in.data+3,
|
|
parms->read.out.nread, parms->read.out.data)) {
|
|
req->status = NT_STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
break;
|
|
|
|
case RAW_READ_READX:
|
|
/* there are 5 reserved words in the reply */
|
|
SMBCLI_CHECK_WCT(req, 12);
|
|
parms->readx.out.remaining = SVAL(req->in.vwv, VWV(2));
|
|
parms->readx.out.compaction_mode = SVAL(req->in.vwv, VWV(3));
|
|
parms->readx.out.nread = SVAL(req->in.vwv, VWV(5));
|
|
if (parms->readx.out.nread > MAX(parms->readx.in.mincnt, parms->readx.in.maxcnt) ||
|
|
!smbcli_raw_pull_data(req, req->in.hdr + SVAL(req->in.vwv, VWV(6)),
|
|
parms->readx.out.nread,
|
|
parms->readx.out.data)) {
|
|
req->status = NT_STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
break;
|
|
}
|
|
|
|
failed:
|
|
return smbcli_request_destroy(req);
|
|
}
|
|
|
|
/****************************************************************************
|
|
low level read operation (sync interface)
|
|
****************************************************************************/
|
|
NTSTATUS smb_raw_read(struct smbcli_tree *tree, union smb_read *parms)
|
|
{
|
|
struct smbcli_request *req = smb_raw_read_send(tree, parms);
|
|
return smb_raw_read_recv(req, parms);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
raw write interface (async send)
|
|
****************************************************************************/
|
|
struct smbcli_request *smb_raw_write_send(struct smbcli_tree *tree, union smb_write *parms)
|
|
{
|
|
BOOL bigoffset = False;
|
|
struct smbcli_request *req = NULL;
|
|
|
|
switch (parms->generic.level) {
|
|
case RAW_WRITE_GENERIC:
|
|
return NULL;
|
|
|
|
case RAW_WRITE_WRITEUNLOCK:
|
|
SETUP_REQUEST(SMBwriteunlock, 5, 3 + parms->writeunlock.in.count);
|
|
SSVAL(req->out.vwv, VWV(0), parms->writeunlock.in.fnum);
|
|
SSVAL(req->out.vwv, VWV(1), parms->writeunlock.in.count);
|
|
SIVAL(req->out.vwv, VWV(2), parms->writeunlock.in.offset);
|
|
SSVAL(req->out.vwv, VWV(4), parms->writeunlock.in.remaining);
|
|
SCVAL(req->out.data, 0, SMB_DATA_BLOCK);
|
|
SSVAL(req->out.data, 1, parms->writeunlock.in.count);
|
|
if (parms->writeunlock.in.count > 0) {
|
|
memcpy(req->out.data+3, parms->writeunlock.in.data,
|
|
parms->writeunlock.in.count);
|
|
}
|
|
break;
|
|
|
|
case RAW_WRITE_WRITE:
|
|
SETUP_REQUEST(SMBwrite, 5, 3 + parms->write.in.count);
|
|
SSVAL(req->out.vwv, VWV(0), parms->write.in.fnum);
|
|
SSVAL(req->out.vwv, VWV(1), parms->write.in.count);
|
|
SIVAL(req->out.vwv, VWV(2), parms->write.in.offset);
|
|
SSVAL(req->out.vwv, VWV(4), parms->write.in.remaining);
|
|
SCVAL(req->out.data, 0, SMB_DATA_BLOCK);
|
|
SSVAL(req->out.data, 1, parms->write.in.count);
|
|
if (parms->write.in.count > 0) {
|
|
memcpy(req->out.data+3, parms->write.in.data, parms->write.in.count);
|
|
}
|
|
break;
|
|
|
|
case RAW_WRITE_WRITECLOSE:
|
|
SETUP_REQUEST(SMBwriteclose, 6, 1 + parms->writeclose.in.count);
|
|
SSVAL(req->out.vwv, VWV(0), parms->writeclose.in.fnum);
|
|
SSVAL(req->out.vwv, VWV(1), parms->writeclose.in.count);
|
|
SIVAL(req->out.vwv, VWV(2), parms->writeclose.in.offset);
|
|
raw_push_dos_date3(tree->session->transport,
|
|
req->out.vwv, VWV(4), parms->writeclose.in.mtime);
|
|
SCVAL(req->out.data, 0, 0);
|
|
if (parms->writeclose.in.count > 0) {
|
|
memcpy(req->out.data+1, parms->writeclose.in.data,
|
|
parms->writeclose.in.count);
|
|
}
|
|
break;
|
|
|
|
case RAW_WRITE_WRITEX:
|
|
if (tree->session->transport->negotiate.capabilities & CAP_LARGE_FILES) {
|
|
bigoffset = True;
|
|
}
|
|
SETUP_REQUEST(SMBwriteX, bigoffset ? 14 : 12, parms->writex.in.count);
|
|
SSVAL(req->out.vwv, VWV(0), 0xFF);
|
|
SSVAL(req->out.vwv, VWV(1), 0);
|
|
SSVAL(req->out.vwv, VWV(2), parms->writex.in.fnum);
|
|
SIVAL(req->out.vwv, VWV(3), parms->writex.in.offset);
|
|
SIVAL(req->out.vwv, VWV(5), 0); /* reserved */
|
|
SSVAL(req->out.vwv, VWV(7), parms->writex.in.wmode);
|
|
SSVAL(req->out.vwv, VWV(8), parms->writex.in.remaining);
|
|
SSVAL(req->out.vwv, VWV(9), parms->writex.in.count>>16);
|
|
SSVAL(req->out.vwv, VWV(10), parms->writex.in.count);
|
|
SSVAL(req->out.vwv, VWV(11), PTR_DIFF(req->out.data, req->out.hdr));
|
|
if (bigoffset) {
|
|
SIVAL(req->out.vwv,VWV(12),parms->writex.in.offset>>32);
|
|
}
|
|
if (parms->writex.in.count > 0) {
|
|
memcpy(req->out.data, parms->writex.in.data, parms->writex.in.count);
|
|
}
|
|
break;
|
|
|
|
case RAW_WRITE_SPLWRITE:
|
|
SETUP_REQUEST(SMBsplwr, 1, parms->splwrite.in.count);
|
|
SSVAL(req->out.vwv, VWV(0), parms->splwrite.in.fnum);
|
|
if (parms->splwrite.in.count > 0) {
|
|
memcpy(req->out.data, parms->splwrite.in.data, parms->splwrite.in.count);
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (!smbcli_request_send(req)) {
|
|
smbcli_request_destroy(req);
|
|
return NULL;
|
|
}
|
|
|
|
return req;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
raw write interface (async recv)
|
|
****************************************************************************/
|
|
NTSTATUS smb_raw_write_recv(struct smbcli_request *req, union smb_write *parms)
|
|
{
|
|
if (!smbcli_request_receive(req) ||
|
|
smbcli_request_is_error(req)) {
|
|
goto failed;
|
|
}
|
|
|
|
switch (parms->generic.level) {
|
|
case RAW_WRITE_GENERIC:
|
|
break;
|
|
case RAW_WRITE_WRITEUNLOCK:
|
|
SMBCLI_CHECK_WCT(req, 1);
|
|
parms->writeunlock.out.nwritten = SVAL(req->in.vwv, VWV(0));
|
|
break;
|
|
case RAW_WRITE_WRITE:
|
|
SMBCLI_CHECK_WCT(req, 1);
|
|
parms->write.out.nwritten = SVAL(req->in.vwv, VWV(0));
|
|
break;
|
|
case RAW_WRITE_WRITECLOSE:
|
|
SMBCLI_CHECK_WCT(req, 1);
|
|
parms->writeclose.out.nwritten = SVAL(req->in.vwv, VWV(0));
|
|
break;
|
|
case RAW_WRITE_WRITEX:
|
|
SMBCLI_CHECK_WCT(req, 6);
|
|
parms->writex.out.nwritten = SVAL(req->in.vwv, VWV(2));
|
|
parms->writex.out.nwritten += (CVAL(req->in.vwv, VWV(4)) << 16);
|
|
parms->writex.out.remaining = SVAL(req->in.vwv, VWV(3));
|
|
break;
|
|
case RAW_WRITE_SPLWRITE:
|
|
break;
|
|
}
|
|
|
|
failed:
|
|
return smbcli_request_destroy(req);
|
|
}
|
|
|
|
/****************************************************************************
|
|
raw write interface (sync interface)
|
|
****************************************************************************/
|
|
NTSTATUS smb_raw_write(struct smbcli_tree *tree, union smb_write *parms)
|
|
{
|
|
struct smbcli_request *req = smb_raw_write_send(tree, parms);
|
|
return smb_raw_write_recv(req, parms);
|
|
}
|