18ccd4a63SDavid du Colombier #include "headers.h"
28ccd4a63SDavid du Colombier
38ccd4a63SDavid du Colombier #define INMEMORYTRUNCTHRESH (256 * 1024)
48ccd4a63SDavid du Colombier
58ccd4a63SDavid du Colombier static int
dirfwstatlength(int fd,vlong offset)68ccd4a63SDavid du Colombier dirfwstatlength(int fd, vlong offset)
78ccd4a63SDavid du Colombier {
88ccd4a63SDavid du Colombier Dir d;
98ccd4a63SDavid du Colombier memset(&d, 0xff, sizeof(d));
108ccd4a63SDavid du Colombier d.name = d.uid = d.gid = d.muid = nil;
118ccd4a63SDavid du Colombier d.length = offset;
128ccd4a63SDavid du Colombier return dirfwstat(fd, &d);
138ccd4a63SDavid du Colombier }
148ccd4a63SDavid du Colombier
158ccd4a63SDavid du Colombier SmbProcessResult
smbtruncatefile(SmbSession * s,SmbFile * f,vlong offset)168ccd4a63SDavid du Colombier smbtruncatefile(SmbSession *s, SmbFile *f, vlong offset)
178ccd4a63SDavid du Colombier {
188ccd4a63SDavid du Colombier Dir *d;
198ccd4a63SDavid du Colombier ulong o;
208ccd4a63SDavid du Colombier uchar *db = nil;
218ccd4a63SDavid du Colombier vlong length;
228ccd4a63SDavid du Colombier int rv;
238ccd4a63SDavid du Colombier SmbProcessResult pr;
248ccd4a63SDavid du Colombier
258ccd4a63SDavid du Colombier d = dirfstat(f->fd);
268ccd4a63SDavid du Colombier assert(d);
278ccd4a63SDavid du Colombier length = d->length;
288ccd4a63SDavid du Colombier free(d);
298ccd4a63SDavid du Colombier
308ccd4a63SDavid du Colombier if (length == offset)
318ccd4a63SDavid du Colombier return SmbProcessResultReply;
328ccd4a63SDavid du Colombier
338ccd4a63SDavid du Colombier rv = dirfwstatlength(f->fd, offset);
348ccd4a63SDavid du Colombier if (rv == 0) {
358ccd4a63SDavid du Colombier pr = SmbProcessResultReply;
368ccd4a63SDavid du Colombier goto done;
378ccd4a63SDavid du Colombier }
388ccd4a63SDavid du Colombier //smblogprint(-1, "dirfwstatlength failed: %r\n");
398ccd4a63SDavid du Colombier if (length > offset) {
408ccd4a63SDavid du Colombier int nfd;
418ccd4a63SDavid du Colombier char *fullpath;
428ccd4a63SDavid du Colombier if (offset > INMEMORYTRUNCTHRESH) {
438ccd4a63SDavid du Colombier smblogprint(-1, "smbcomwrite: truncation beyond %lud not supported\n", offset);
448ccd4a63SDavid du Colombier pr = SmbProcessResultUnimp;
458ccd4a63SDavid du Colombier goto done;
468ccd4a63SDavid du Colombier }
478ccd4a63SDavid du Colombier db = smbemalloc(offset);
488ccd4a63SDavid du Colombier if (pread(f->fd, db, offset, 0) != offset) {
498ccd4a63SDavid du Colombier pr = SmbProcessResultMisc;
508ccd4a63SDavid du Colombier goto done;
518ccd4a63SDavid du Colombier }
528ccd4a63SDavid du Colombier fullpath = nil;
538ccd4a63SDavid du Colombier smbstringprint(&fullpath, "%s%s", f->t->serv->path, f->name);
548ccd4a63SDavid du Colombier nfd = open(fullpath, f->p9mode | OTRUNC);
558ccd4a63SDavid du Colombier free(fullpath);
568ccd4a63SDavid du Colombier if (nfd < 0) {
578ccd4a63SDavid du Colombier smbseterror(s, ERRDOS, ERRnoaccess);
588ccd4a63SDavid du Colombier pr = SmbProcessResultError;
598ccd4a63SDavid du Colombier goto done;
608ccd4a63SDavid du Colombier }
618ccd4a63SDavid du Colombier close(nfd);
628ccd4a63SDavid du Colombier if (pwrite(f->fd, db, offset, 0) != offset) {
638ccd4a63SDavid du Colombier pr = SmbProcessResultMisc;
648ccd4a63SDavid du Colombier goto done;
658ccd4a63SDavid du Colombier }
668ccd4a63SDavid du Colombier pr = SmbProcessResultReply;
678ccd4a63SDavid du Colombier }
688ccd4a63SDavid du Colombier else {
698ccd4a63SDavid du Colombier db = smbemalloc(16384);
708ccd4a63SDavid du Colombier memset(db, 0, 16384);
718ccd4a63SDavid du Colombier o = length;
728ccd4a63SDavid du Colombier while (o < offset) {
738ccd4a63SDavid du Colombier long tt = 16384;
748ccd4a63SDavid du Colombier if (tt > offset - o)
758ccd4a63SDavid du Colombier tt = offset - o;
768ccd4a63SDavid du Colombier if (pwrite(f->fd, db, tt, o) != tt) {
778ccd4a63SDavid du Colombier smbseterror(s, ERRDOS, ERRnoaccess);
788ccd4a63SDavid du Colombier pr = SmbProcessResultError;
798ccd4a63SDavid du Colombier goto done;
808ccd4a63SDavid du Colombier }
818ccd4a63SDavid du Colombier o += tt;
828ccd4a63SDavid du Colombier }
838ccd4a63SDavid du Colombier pr = SmbProcessResultReply;
848ccd4a63SDavid du Colombier }
858ccd4a63SDavid du Colombier done:
868ccd4a63SDavid du Colombier free(db);
878ccd4a63SDavid du Colombier return pr;
888ccd4a63SDavid du Colombier }
898ccd4a63SDavid du Colombier
908ccd4a63SDavid du Colombier SmbProcessResult
smbcomwrite(SmbSession * s,SmbHeader * h,uchar * pdata,SmbBuffer * b)918ccd4a63SDavid du Colombier smbcomwrite(SmbSession *s, SmbHeader *h, uchar *pdata, SmbBuffer *b)
928ccd4a63SDavid du Colombier {
938ccd4a63SDavid du Colombier SmbTree *t;
948ccd4a63SDavid du Colombier SmbFile *f;
958ccd4a63SDavid du Colombier ushort fid;
968ccd4a63SDavid du Colombier ushort count;
978ccd4a63SDavid du Colombier ulong offset;
988ccd4a63SDavid du Colombier long nb;
998ccd4a63SDavid du Colombier ushort yacount;
1008ccd4a63SDavid du Colombier uchar fmt;
1018ccd4a63SDavid du Colombier
1028ccd4a63SDavid du Colombier if (h->wordcount != 5)
1038ccd4a63SDavid du Colombier return SmbProcessResultFormat;
1048ccd4a63SDavid du Colombier
1058ccd4a63SDavid du Colombier fid = smbnhgets(pdata); pdata += 2;
1068ccd4a63SDavid du Colombier count = smbnhgets(pdata); pdata += 2;
1078ccd4a63SDavid du Colombier offset = smbnhgetl(pdata);
1088ccd4a63SDavid du Colombier
1098ccd4a63SDavid du Colombier smblogprint(SMB_COM_WRITE, "smbcomwrite: fid 0x%.4ux count 0x%.4ux offset 0x%.8lux\n",
1108ccd4a63SDavid du Colombier fid, count, offset);
1118ccd4a63SDavid du Colombier
1128ccd4a63SDavid du Colombier if (!smbbuffergetb(b, &fmt)
1138ccd4a63SDavid du Colombier || fmt != 1
1148ccd4a63SDavid du Colombier || !smbbuffergets(b, &yacount)
1158ccd4a63SDavid du Colombier || yacount != count
1168ccd4a63SDavid du Colombier || smbbufferreadspace(b) < count)
1178ccd4a63SDavid du Colombier return SmbProcessResultFormat;
1188ccd4a63SDavid du Colombier
1198ccd4a63SDavid du Colombier t = smbidmapfind(s->tidmap, h->tid);
1208ccd4a63SDavid du Colombier if (t == nil) {
1218ccd4a63SDavid du Colombier smbseterror(s, ERRSRV, ERRinvtid);
1228ccd4a63SDavid du Colombier return SmbProcessResultError;
1238ccd4a63SDavid du Colombier }
1248ccd4a63SDavid du Colombier f = smbidmapfind(s->fidmap, fid);
1258ccd4a63SDavid du Colombier if (f == nil) {
1268ccd4a63SDavid du Colombier smbseterror(s, ERRDOS, ERRbadfid);
1278ccd4a63SDavid du Colombier return SmbProcessResultError;
1288ccd4a63SDavid du Colombier }
1298ccd4a63SDavid du Colombier
1308ccd4a63SDavid du Colombier if (!f->ioallowed) {
1318ccd4a63SDavid du Colombier smbseterror(s, ERRDOS, ERRbadaccess);
1328ccd4a63SDavid du Colombier return SmbProcessResultError;
1338ccd4a63SDavid du Colombier }
1348ccd4a63SDavid du Colombier
1358ccd4a63SDavid du Colombier if (count == 0) {
1368ccd4a63SDavid du Colombier SmbProcessResult pr = smbtruncatefile(s, f, offset);
1378ccd4a63SDavid du Colombier if (pr != SmbProcessResultReply)
1388ccd4a63SDavid du Colombier return pr;
1398ccd4a63SDavid du Colombier nb = 0;
1408ccd4a63SDavid du Colombier }
1418ccd4a63SDavid du Colombier else {
1428ccd4a63SDavid du Colombier seek(f->fd, offset, 0);
1438ccd4a63SDavid du Colombier nb = write(f->fd, smbbufferreadpointer(b), count);
1448ccd4a63SDavid du Colombier if (nb < 0) {
1458ccd4a63SDavid du Colombier smbseterror(s, ERRDOS, ERRnoaccess);
1468ccd4a63SDavid du Colombier return SmbProcessResultError;
1478ccd4a63SDavid du Colombier }
1488ccd4a63SDavid du Colombier }
1498ccd4a63SDavid du Colombier h->wordcount = 1;
1508ccd4a63SDavid du Colombier if (!smbbufferputheader(s->response, h, &s->peerinfo)
1518ccd4a63SDavid du Colombier || !smbbufferputs(s->response, nb)
1528ccd4a63SDavid du Colombier || !smbbufferputs(s->response, 0))
1538ccd4a63SDavid du Colombier return SmbProcessResultMisc;
1548ccd4a63SDavid du Colombier return SmbProcessResultReply;
1558ccd4a63SDavid du Colombier }
15686a363ceSDavid du Colombier
15786a363ceSDavid du Colombier SmbProcessResult
smbcomwriteandx(SmbSession * s,SmbHeader * h,uchar * pdata,SmbBuffer * b)15886a363ceSDavid du Colombier smbcomwriteandx(SmbSession *s, SmbHeader *h, uchar *pdata, SmbBuffer *b)
15986a363ceSDavid du Colombier {
16086a363ceSDavid du Colombier uchar andxcommand;
16186a363ceSDavid du Colombier ushort andxoffset;
16286a363ceSDavid du Colombier ulong andxoffsetfixup;
16386a363ceSDavid du Colombier SmbTree *t;
16486a363ceSDavid du Colombier SmbFile *f;
16586a363ceSDavid du Colombier ushort dataoff, fid, count;
166*f7b899b1SDavid du Colombier vlong offset;
16786a363ceSDavid du Colombier long nb;
16886a363ceSDavid du Colombier
16986a363ceSDavid du Colombier if (h->wordcount != 12 && h->wordcount != 14)
17086a363ceSDavid du Colombier return SmbProcessResultFormat;
17186a363ceSDavid du Colombier
17286a363ceSDavid du Colombier andxcommand = *pdata++; // andx command
17386a363ceSDavid du Colombier pdata++; // reserved
17486a363ceSDavid du Colombier andxoffset = smbnhgets(pdata); pdata += 2; // andx offset
17586a363ceSDavid du Colombier fid = smbnhgets(pdata); pdata += 2; // fid
17686a363ceSDavid du Colombier offset = smbnhgetl(pdata); pdata += 4; // offset in file
177*f7b899b1SDavid du Colombier pdata += 4; // timeout
17886a363ceSDavid du Colombier pdata += 2; // write mode
179*f7b899b1SDavid du Colombier pdata += 2; // (Remaining) bytes waiting to be written
180*f7b899b1SDavid du Colombier pdata += 2; // Reserved
181*f7b899b1SDavid du Colombier count = smbnhgets(pdata); pdata += 2; // LSBs of length
18286a363ceSDavid du Colombier dataoff = smbnhgets(pdata); pdata += 2; // offset to data in packet
183*f7b899b1SDavid du Colombier if (dataoff + count > smbbufferwriteoffset(b))
184*f7b899b1SDavid du Colombier return SmbProcessResultFormat;
1859b004bddSDavid du Colombier if(h->wordcount == 14)
186*f7b899b1SDavid du Colombier offset |= (vlong)smbnhgetl(pdata)<<32;
18786a363ceSDavid du Colombier
188*f7b899b1SDavid du Colombier smblogprint(SMB_COM_WRITE_ANDX, "smbcomwriteandx: fid 0x%.4ux count 0x%.4ux offset 0x%.llux\n",
18986a363ceSDavid du Colombier fid, count, offset);
19086a363ceSDavid du Colombier
191*f7b899b1SDavid du Colombier
19286a363ceSDavid du Colombier t = smbidmapfind(s->tidmap, h->tid);
19386a363ceSDavid du Colombier if (t == nil) {
19486a363ceSDavid du Colombier smbseterror(s, ERRSRV, ERRinvtid);
19586a363ceSDavid du Colombier return SmbProcessResultError;
19686a363ceSDavid du Colombier }
19786a363ceSDavid du Colombier f = smbidmapfind(s->fidmap, fid);
19886a363ceSDavid du Colombier if (f == nil) {
19986a363ceSDavid du Colombier smbseterror(s, ERRDOS, ERRbadfid);
20086a363ceSDavid du Colombier return SmbProcessResultError;
20186a363ceSDavid du Colombier }
20286a363ceSDavid du Colombier
20386a363ceSDavid du Colombier if (!f->ioallowed) {
20486a363ceSDavid du Colombier smbseterror(s, ERRDOS, ERRbadaccess);
20586a363ceSDavid du Colombier return SmbProcessResultError;
20686a363ceSDavid du Colombier }
20786a363ceSDavid du Colombier
20886a363ceSDavid du Colombier seek(f->fd, offset, 0);
20986a363ceSDavid du Colombier nb = write(f->fd, smbbufferpointer(b, dataoff), count);
21086a363ceSDavid du Colombier if (nb < 0) {
21186a363ceSDavid du Colombier smbseterror(s, ERRDOS, ERRnoaccess);
21286a363ceSDavid du Colombier return SmbProcessResultError;
21386a363ceSDavid du Colombier }
21486a363ceSDavid du Colombier
21586a363ceSDavid du Colombier h->wordcount = 6;
21686a363ceSDavid du Colombier if (!smbbufferputandxheader(s->response, h, &s->peerinfo, andxcommand, &andxoffsetfixup))
21786a363ceSDavid du Colombier return SmbProcessResultMisc;
21886a363ceSDavid du Colombier
219*f7b899b1SDavid du Colombier if (!smbbufferputs(s->response, nb) // Count
220*f7b899b1SDavid du Colombier || !smbbufferputs(s->response, 0) // Available
221*f7b899b1SDavid du Colombier || !smbbufferputl(s->response, 0) // Reserved
22286a363ceSDavid du Colombier || !smbbufferputs(s->response, 0)) // byte count in reply
22386a363ceSDavid du Colombier return SmbProcessResultMisc;
22486a363ceSDavid du Colombier
22586a363ceSDavid du Colombier if (andxcommand != SMB_COM_NO_ANDX_COMMAND)
22686a363ceSDavid du Colombier return smbchaincommand(s, h, andxoffsetfixup, andxcommand, andxoffset, b);
22786a363ceSDavid du Colombier
22886a363ceSDavid du Colombier return SmbProcessResultReply;
22986a363ceSDavid du Colombier }
230