summaryrefslogtreecommitdiff
path: root/sys/src/cmd/aquarela/smbcomwrite.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/aquarela/smbcomwrite.c
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/aquarela/smbcomwrite.c')
-rwxr-xr-xsys/src/cmd/aquarela/smbcomwrite.c229
1 files changed, 229 insertions, 0 deletions
diff --git a/sys/src/cmd/aquarela/smbcomwrite.c b/sys/src/cmd/aquarela/smbcomwrite.c
new file mode 100755
index 000000000..8021ca1ff
--- /dev/null
+++ b/sys/src/cmd/aquarela/smbcomwrite.c
@@ -0,0 +1,229 @@
+#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;
+}