/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include "headers.h" #define INMEMORYTRUNCTHRESH (256 * 1024) static intdirfwstatlength(int fd, vlong offset){ Dir d; memset(&d, 0xff, sizeof(d)); d.name = d.uid = d.gid = d.muid = nil; d.length = offset; return dirfwstat(fd, &d);} SmbProcessResultsmbtruncatefile(SmbSession *s, SmbFile *f, vlong offset){ Dir *d; ulong o; uchar *db = nil; vlong length; int rv; SmbProcessResult pr; d = dirfstat(f->fd); assert(d); length = d->length; free(d); if (length == offset) return SmbProcessResultReply; rv = dirfwstatlength(f->fd, offset); if (rv == 0) { pr = SmbProcessResultReply; goto done; }//smblogprint(-1, "dirfwstatlength failed: %r\n"); if (length > offset) { int nfd; char *fullpath; if (offset > INMEMORYTRUNCTHRESH) { smblogprint(-1, "smbcomwrite: truncation beyond %lud not supported\n", offset); pr = SmbProcessResultUnimp; goto done; } db = smbemalloc(offset); if (pread(f->fd, db, offset, 0) != offset) { pr = SmbProcessResultMisc; goto done; } fullpath = nil; smbstringprint(&fullpath, "%s%s", f->t->serv->path, f->name); nfd = open(fullpath, f->p9mode | OTRUNC); free(fullpath); if (nfd < 0) { smbseterror(s, ERRDOS, ERRnoaccess); pr = SmbProcessResultError; goto done; } close(nfd); if (pwrite(f->fd, db, offset, 0) != offset) { pr = SmbProcessResultMisc; goto done; } pr = SmbProcessResultReply; } else { db = smbemalloc(16384); memset(db, 0, 16384); o = length; while (o < offset) { long tt = 16384; if (tt > offset - o) tt = offset - o; if (pwrite(f->fd, db, tt, o) != tt) { smbseterror(s, ERRDOS, ERRnoaccess); pr = SmbProcessResultError; goto done; } o += tt; } pr = SmbProcessResultReply; }done: free(db); return pr;} SmbProcessResultsmbcomwrite(SmbSession *s, SmbHeader *h, uchar *pdata, SmbBuffer *b){ SmbTree *t; SmbFile *f; ushort fid; ushort count; ulong offset; long nb; ushort yacount; uchar fmt; if (h->wordcount != 5) return SmbProcessResultFormat; fid = smbnhgets(pdata); pdata += 2; count = smbnhgets(pdata); pdata += 2; offset = smbnhgetl(pdata); smblogprint(SMB_COM_WRITE, "smbcomwrite: fid 0x%.4ux count 0x%.4ux offset 0x%.8lux\n", fid, count, offset); if (!smbbuffergetb(b, &fmt) || fmt != 1 || !smbbuffergets(b, &yacount) || yacount != count || smbbufferreadspace(b) < count) return SmbProcessResultFormat; t = smbidmapfind(s->tidmap, h->tid); if (t == nil) { smbseterror(s, ERRSRV, ERRinvtid); return SmbProcessResultError; } f = smbidmapfind(s->fidmap, fid); if (f == nil) { smbseterror(s, ERRDOS, ERRbadfid); return SmbProcessResultError; } if (!f->ioallowed) { smbseterror(s, ERRDOS, ERRbadaccess); return SmbProcessResultError; } if (count == 0) { SmbProcessResult pr = smbtruncatefile(s, f, offset); if (pr != SmbProcessResultReply) return pr; nb = 0; } else { seek(f->fd, offset, 0); nb = write(f->fd, smbbufferreadpointer(b), count); if (nb < 0) { smbseterror(s, ERRDOS, ERRnoaccess); return SmbProcessResultError; } } h->wordcount = 1; if (!smbbufferputheader(s->response, h, &s->peerinfo) || !smbbufferputs(s->response, nb) || !smbbufferputs(s->response, 0)) return SmbProcessResultMisc; return SmbProcessResultReply;} SmbProcessResultsmbcomwriteandx(SmbSession *s, SmbHeader *h, uchar *pdata, SmbBuffer *b){ uchar andxcommand; ushort andxoffset; ulong andxoffsetfixup; SmbTree *t; SmbFile *f; ushort dataoff, fid, count; vlong offset; long nb; if (h->wordcount != 12 && h->wordcount != 14) return SmbProcessResultFormat; andxcommand = *pdata++; // andx command pdata++; // reserved andxoffset = smbnhgets(pdata); pdata += 2; // andx offset fid = smbnhgets(pdata); pdata += 2; // fid offset = smbnhgetl(pdata); pdata += 4; // offset in file pdata += 4; // timeout pdata += 2; // write mode pdata += 2; // (Remaining) bytes waiting to be written pdata += 2; // Reserved count = smbnhgets(pdata); pdata += 2; // LSBs of length dataoff = smbnhgets(pdata); pdata += 2; // offset to data in packet if (dataoff + count > smbbufferwriteoffset(b)) return SmbProcessResultFormat; if(h->wordcount == 14) offset |= (vlong)smbnhgetl(pdata)<<32; smblogprint(SMB_COM_WRITE_ANDX, "smbcomwriteandx: fid 0x%.4ux count 0x%.4ux offset 0x%.llux\n", fid, count, offset); t = smbidmapfind(s->tidmap, h->tid); if (t == nil) { smbseterror(s, ERRSRV, ERRinvtid); return SmbProcessResultError; } f = smbidmapfind(s->fidmap, fid); if (f == nil) { smbseterror(s, ERRDOS, ERRbadfid); return SmbProcessResultError; } if (!f->ioallowed) { smbseterror(s, ERRDOS, ERRbadaccess); return SmbProcessResultError; } seek(f->fd, offset, 0); nb = write(f->fd, smbbufferpointer(b, dataoff), count); if (nb < 0) { smbseterror(s, ERRDOS, ERRnoaccess); return SmbProcessResultError; } h->wordcount = 6; if (!smbbufferputandxheader(s->response, h, &s->peerinfo, andxcommand, &andxoffsetfixup)) return SmbProcessResultMisc; if (!smbbufferputs(s->response, nb) // Count || !smbbufferputs(s->response, 0) // Available || !smbbufferputl(s->response, 0) // Reserved || !smbbufferputs(s->response, 0)) // byte count in reply return SmbProcessResultMisc; if (andxcommand != SMB_COM_NO_ANDX_COMMAND) return smbchaincommand(s, h, andxoffsetfixup, andxcommand, andxoffset, b); return SmbProcessResultReply;}
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include "headers.h"
#define INMEMORYTRUNCTHRESH (256 * 1024)
static int
dirfwstatlength(int fd, vlong offset)
{
Dir d;
memset(&d, 0xff, sizeof(d));
d.name = d.uid = d.gid = d.muid = nil;
d.length = offset;
return dirfwstat(fd, &d);
}
SmbProcessResult
smbtruncatefile(SmbSession *s, SmbFile *f, vlong offset)
{
Dir *d;
ulong o;
uchar *db = nil;
vlong length;
int rv;
SmbProcessResult pr;
d = dirfstat(f->fd);
assert(d);
length = d->length;
free(d);
if (length == offset)
return SmbProcessResultReply;
rv = dirfwstatlength(f->fd, offset);
if (rv == 0) {
pr = SmbProcessResultReply;
goto done;
}
//smblogprint(-1, "dirfwstatlength failed: %r\n");
if (length > offset) {
int nfd;
char *fullpath;
if (offset > INMEMORYTRUNCTHRESH) {
smblogprint(-1, "smbcomwrite: truncation beyond %lud not supported\n", offset);
pr = SmbProcessResultUnimp;
goto done;
}
db = smbemalloc(offset);
if (pread(f->fd, db, offset, 0) != offset) {
pr = SmbProcessResultMisc;
goto done;
}
fullpath = nil;
smbstringprint(&fullpath, "%s%s", f->t->serv->path, f->name);
nfd = open(fullpath, f->p9mode | OTRUNC);
free(fullpath);
if (nfd < 0) {
smbseterror(s, ERRDOS, ERRnoaccess);
pr = SmbProcessResultError;
goto done;
}
close(nfd);
if (pwrite(f->fd, db, offset, 0) != offset) {
pr = SmbProcessResultMisc;
goto done;
}
pr = SmbProcessResultReply;
}
else {
db = smbemalloc(16384);
memset(db, 0, 16384);
o = length;
while (o < offset) {
long tt = 16384;
if (tt > offset - o)
tt = offset - o;
if (pwrite(f->fd, db, tt, o) != tt) {
smbseterror(s, ERRDOS, ERRnoaccess);
pr = SmbProcessResultError;
goto done;
}
o += tt;
}
pr = SmbProcessResultReply;
}
done:
free(db);
return pr;
}
SmbProcessResult
smbcomwrite(SmbSession *s, SmbHeader *h, uchar *pdata, SmbBuffer *b)
{
SmbTree *t;
SmbFile *f;
ushort fid;
ushort count;
ulong offset;
long nb;
ushort yacount;
uchar fmt;
if (h->wordcount != 5)
return SmbProcessResultFormat;
fid = smbnhgets(pdata); pdata += 2;
count = smbnhgets(pdata); pdata += 2;
offset = smbnhgetl(pdata);
smblogprint(SMB_COM_WRITE, "smbcomwrite: fid 0x%.4ux count 0x%.4ux offset 0x%.8lux\n",
fid, count, offset);
if (!smbbuffergetb(b, &fmt)
|| fmt != 1
|| !smbbuffergets(b, &yacount)
|| yacount != count
|| smbbufferreadspace(b) < count)
return SmbProcessResultFormat;
t = smbidmapfind(s->tidmap, h->tid);
if (t == nil) {
smbseterror(s, ERRSRV, ERRinvtid);
return SmbProcessResultError;
}
f = smbidmapfind(s->fidmap, fid);
if (f == nil) {
smbseterror(s, ERRDOS, ERRbadfid);
return SmbProcessResultError;
}
if (!f->ioallowed) {
smbseterror(s, ERRDOS, ERRbadaccess);
return SmbProcessResultError;
}
if (count == 0) {
SmbProcessResult pr = smbtruncatefile(s, f, offset);
if (pr != SmbProcessResultReply)
return pr;
nb = 0;
}
else {
seek(f->fd, offset, 0);
nb = write(f->fd, smbbufferreadpointer(b), count);
if (nb < 0) {
smbseterror(s, ERRDOS, ERRnoaccess);
return SmbProcessResultError;
}
}
h->wordcount = 1;
if (!smbbufferputheader(s->response, h, &s->peerinfo)
|| !smbbufferputs(s->response, nb)
|| !smbbufferputs(s->response, 0))
return SmbProcessResultMisc;
return SmbProcessResultReply;
}
SmbProcessResult
smbcomwriteandx(SmbSession *s, SmbHeader *h, uchar *pdata, SmbBuffer *b)
{
uchar andxcommand;
ushort andxoffset;
ulong andxoffsetfixup;
SmbTree *t;
SmbFile *f;
ushort dataoff, fid, count;
vlong offset;
long nb;
if (h->wordcount != 12 && h->wordcount != 14)
return SmbProcessResultFormat;
andxcommand = *pdata++; // andx command
pdata++; // reserved
andxoffset = smbnhgets(pdata); pdata += 2; // andx offset
fid = smbnhgets(pdata); pdata += 2; // fid
offset = smbnhgetl(pdata); pdata += 4; // offset in file
pdata += 4; // timeout
pdata += 2; // write mode
pdata += 2; // (Remaining) bytes waiting to be written
pdata += 2; // Reserved
count = smbnhgets(pdata); pdata += 2; // LSBs of length
dataoff = smbnhgets(pdata); pdata += 2; // offset to data in packet
if (dataoff + count > smbbufferwriteoffset(b))
return SmbProcessResultFormat;
if(h->wordcount == 14)
offset |= (vlong)smbnhgetl(pdata)<<32;
smblogprint(SMB_COM_WRITE_ANDX, "smbcomwriteandx: fid 0x%.4ux count 0x%.4ux offset 0x%.llux\n",
fid, count, offset);
t = smbidmapfind(s->tidmap, h->tid);
if (t == nil) {
smbseterror(s, ERRSRV, ERRinvtid);
return SmbProcessResultError;
}
f = smbidmapfind(s->fidmap, fid);
if (f == nil) {
smbseterror(s, ERRDOS, ERRbadfid);
return SmbProcessResultError;
}
if (!f->ioallowed) {
smbseterror(s, ERRDOS, ERRbadaccess);
return SmbProcessResultError;
}
seek(f->fd, offset, 0);
nb = write(f->fd, smbbufferpointer(b, dataoff), count);
if (nb < 0) {
smbseterror(s, ERRDOS, ERRnoaccess);
return SmbProcessResultError;
}
h->wordcount = 6;
if (!smbbufferputandxheader(s->response, h, &s->peerinfo, andxcommand, &andxoffsetfixup))
return SmbProcessResultMisc;
if (!smbbufferputs(s->response, nb) // Count
|| !smbbufferputs(s->response, 0) // Available
|| !smbbufferputl(s->response, 0) // Reserved
|| !smbbufferputs(s->response, 0)) // byte count in reply
return SmbProcessResultMisc;
if (andxcommand != SMB_COM_NO_ANDX_COMMAND)
return smbchaincommand(s, h, andxoffsetfixup, andxcommand, andxoffset, b);
return SmbProcessResultReply;
}