diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /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-x | sys/src/cmd/aquarela/smbcomwrite.c | 229 |
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; +} |