xref: /plan9/sys/src/cmd/aquarela/smbcomwrite.c (revision f7b899b1d34eae18b845f4a1a7b97544dad3f3b4)
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