xref: /plan9/sys/src/cmd/aquarela/smbcomwrite.c (revision f7b899b1d34eae18b845f4a1a7b97544dad3f3b4)
1 #include "headers.h"
2 
3 #define INMEMORYTRUNCTHRESH (256 * 1024)
4 
5 static int
dirfwstatlength(int fd,vlong offset)6 dirfwstatlength(int fd, vlong offset)
7 {
8 	Dir d;
9 	memset(&d, 0xff, sizeof(d));
10 	d.name = d.uid = d.gid = d.muid = nil;
11 	d.length = offset;
12 	return dirfwstat(fd, &d);
13 }
14 
15 SmbProcessResult
smbtruncatefile(SmbSession * s,SmbFile * f,vlong offset)16 smbtruncatefile(SmbSession *s, SmbFile *f, vlong offset)
17 {
18 	Dir *d;
19 	ulong o;
20 	uchar *db = nil;
21 	vlong length;
22 	int rv;
23 	SmbProcessResult pr;
24 
25 	d = dirfstat(f->fd);
26 	assert(d);
27 	length = d->length;
28 	free(d);
29 
30 	if (length == offset)
31 		return SmbProcessResultReply;
32 
33 	rv = dirfwstatlength(f->fd, offset);
34 	if (rv == 0) {
35 		pr = SmbProcessResultReply;
36 		goto done;
37 	}
38 //smblogprint(-1, "dirfwstatlength failed: %r\n");
39 	if (length > offset) {
40 		int nfd;
41 		char *fullpath;
42 		if (offset > INMEMORYTRUNCTHRESH) {
43 			smblogprint(-1, "smbcomwrite: truncation beyond %lud not supported\n", offset);
44 			pr = SmbProcessResultUnimp;
45 			goto done;
46 		}
47 		db = smbemalloc(offset);
48 		if (pread(f->fd, db, offset, 0) != offset) {
49 			pr = SmbProcessResultMisc;
50 			goto done;
51 		}
52 		fullpath = nil;
53 		smbstringprint(&fullpath, "%s%s", f->t->serv->path, f->name);
54 		nfd = open(fullpath, f->p9mode | OTRUNC);
55 		free(fullpath);
56 		if (nfd < 0) {
57 			smbseterror(s, ERRDOS, ERRnoaccess);
58 			pr = SmbProcessResultError;
59 			goto done;
60 		}
61 		close(nfd);
62 		if (pwrite(f->fd, db, offset, 0) != offset) {
63 			pr = SmbProcessResultMisc;
64 			goto done;
65 		}
66 		pr = SmbProcessResultReply;
67 	}
68 	else {
69 		db = smbemalloc(16384);
70 		memset(db, 0, 16384);
71 		o = length;
72 		while (o < offset) {
73 			long tt = 16384;
74 			if (tt > offset - o)
75 				tt = offset - o;
76 			if (pwrite(f->fd, db, tt, o) != tt) {
77 				smbseterror(s, ERRDOS, ERRnoaccess);
78 				pr = SmbProcessResultError;
79 				goto done;
80 			}
81 			o += tt;
82 		}
83 		pr = SmbProcessResultReply;
84 	}
85 done:
86 	free(db);
87 	return pr;
88 }
89 
90 SmbProcessResult
smbcomwrite(SmbSession * s,SmbHeader * h,uchar * pdata,SmbBuffer * b)91 smbcomwrite(SmbSession *s, SmbHeader *h, uchar *pdata, SmbBuffer *b)
92 {
93 	SmbTree *t;
94 	SmbFile *f;
95 	ushort fid;
96 	ushort count;
97 	ulong offset;
98 	long nb;
99 	ushort yacount;
100 	uchar fmt;
101 
102 	if (h->wordcount != 5)
103 		return SmbProcessResultFormat;
104 
105 	fid = smbnhgets(pdata); pdata += 2;
106 	count = smbnhgets(pdata); pdata += 2;
107 	offset = smbnhgetl(pdata);
108 
109 	smblogprint(SMB_COM_WRITE, "smbcomwrite: fid 0x%.4ux count 0x%.4ux offset 0x%.8lux\n",
110 		fid, count, offset);
111 
112 	if (!smbbuffergetb(b, &fmt)
113 		|| fmt != 1
114 		|| !smbbuffergets(b, &yacount)
115 		|| yacount != count
116 		|| smbbufferreadspace(b) < count)
117 		return SmbProcessResultFormat;
118 
119 	t = smbidmapfind(s->tidmap, h->tid);
120 	if (t == nil) {
121 		smbseterror(s, ERRSRV, ERRinvtid);
122 		return SmbProcessResultError;
123 	}
124 	f = smbidmapfind(s->fidmap, fid);
125 	if (f == nil) {
126 		smbseterror(s, ERRDOS, ERRbadfid);
127 		return SmbProcessResultError;
128 	}
129 
130 	if (!f->ioallowed) {
131 		smbseterror(s, ERRDOS, ERRbadaccess);
132 		return SmbProcessResultError;
133 	}
134 
135 	if (count == 0) {
136 		SmbProcessResult pr = smbtruncatefile(s, f, offset);
137 		if (pr != SmbProcessResultReply)
138 			return pr;
139 		nb = 0;
140 	}
141 	else {
142 		seek(f->fd, offset, 0);
143 		nb = write(f->fd, smbbufferreadpointer(b), count);
144 		if (nb < 0) {
145 			smbseterror(s, ERRDOS, ERRnoaccess);
146 			return SmbProcessResultError;
147 		}
148 	}
149 	h->wordcount = 1;
150 	if (!smbbufferputheader(s->response, h, &s->peerinfo)
151 		|| !smbbufferputs(s->response, nb)
152 		|| !smbbufferputs(s->response, 0))
153 		return SmbProcessResultMisc;
154 	return SmbProcessResultReply;
155 }
156 
157 SmbProcessResult
smbcomwriteandx(SmbSession * s,SmbHeader * h,uchar * pdata,SmbBuffer * b)158 smbcomwriteandx(SmbSession *s, SmbHeader *h, uchar *pdata, SmbBuffer *b)
159 {
160 	uchar andxcommand;
161 	ushort andxoffset;
162 	ulong andxoffsetfixup;
163 	SmbTree *t;
164 	SmbFile *f;
165 	ushort dataoff, fid, count;
166 	vlong offset;
167 	long nb;
168 
169 	if (h->wordcount != 12 && h->wordcount != 14)
170 		return SmbProcessResultFormat;
171 
172 	andxcommand = *pdata++;				// andx command
173 	pdata++;					// reserved
174 	andxoffset = smbnhgets(pdata); pdata += 2;	// andx offset
175 	fid = smbnhgets(pdata); pdata += 2;		// fid
176 	offset = smbnhgetl(pdata); pdata += 4;		// offset in file
177 	pdata += 4;					// timeout
178 	pdata += 2;					// write mode
179 	pdata += 2;					// (Remaining) bytes waiting to be written
180 	pdata += 2;					// Reserved
181 	count = smbnhgets(pdata); pdata += 2;		// LSBs of length
182 	dataoff = smbnhgets(pdata); pdata += 2;		// offset to data in packet
183 	if (dataoff + count > smbbufferwriteoffset(b))
184 		return SmbProcessResultFormat;
185 	if(h->wordcount == 14)
186 		offset |= (vlong)smbnhgetl(pdata)<<32;
187 
188 	smblogprint(SMB_COM_WRITE_ANDX, "smbcomwriteandx: fid 0x%.4ux count 0x%.4ux offset 0x%.llux\n",
189 		fid, count, offset);
190 
191 
192 	t = smbidmapfind(s->tidmap, h->tid);
193 	if (t == nil) {
194 		smbseterror(s, ERRSRV, ERRinvtid);
195 		return SmbProcessResultError;
196 	}
197 	f = smbidmapfind(s->fidmap, fid);
198 	if (f == nil) {
199 		smbseterror(s, ERRDOS, ERRbadfid);
200 		return SmbProcessResultError;
201 	}
202 
203 	if (!f->ioallowed) {
204 		smbseterror(s, ERRDOS, ERRbadaccess);
205 		return SmbProcessResultError;
206 	}
207 
208 	seek(f->fd, offset, 0);
209 	nb = write(f->fd, smbbufferpointer(b, dataoff), count);
210 	if (nb < 0) {
211 		smbseterror(s, ERRDOS, ERRnoaccess);
212 		return SmbProcessResultError;
213 	}
214 
215 	h->wordcount = 6;
216 	if (!smbbufferputandxheader(s->response, h, &s->peerinfo, andxcommand, &andxoffsetfixup))
217 		return SmbProcessResultMisc;
218 
219 	if (!smbbufferputs(s->response, nb)			// Count
220 		|| !smbbufferputs(s->response, 0)		// Available
221 		|| !smbbufferputl(s->response, 0)		// Reserved
222 		|| !smbbufferputs(s->response, 0))		// byte count in reply
223 		return SmbProcessResultMisc;
224 
225 	if (andxcommand != SMB_COM_NO_ANDX_COMMAND)
226 		return smbchaincommand(s, h, andxoffsetfixup, andxcommand, andxoffset, b);
227 
228 	return SmbProcessResultReply;
229 }
230