xref: /plan9/sys/src/cmd/aquarela/smbtrans2find.c (revision 8ccd4a6360d974db7bd7bbd4f37e7018419ea908)
1 #include "headers.h"
2 #include <pool.h>
3 
4 void
smbsearchfree(SmbSearch ** searchp)5 smbsearchfree(SmbSearch **searchp)
6 {
7 	SmbSearch *search = *searchp;
8 	if (search) {
9 		smbdircachefree(&search->dc);
10 		free(search->rep);
11 		free(search);
12 		*searchp = nil;
13 	}
14 }
15 
16 void
smbsearchclose(SmbSession * s,SmbSearch * search)17 smbsearchclose(SmbSession *s, SmbSearch *search)
18 {
19 	if (search) {
20 		smblogprintif(smbglobals.log.sids, "smbsearchclose: tid 0x%.4ux sid 0x%.4ux\n", search->t->id, search->id);
21 		smbidmapremove(s->sidmap, search);
22 		smbsearchfree(&search);
23 	}
24 }
25 
26 void
smbsearchclosebyid(SmbSession * s,ushort sid)27 smbsearchclosebyid(SmbSession *s, ushort sid)
28 {
29 	smbsearchclose(s,  smbidmapfind(s->sidmap, sid));
30 }
31 
32 SmbSearch *
smbsearchnew(SmbSession * s,SmbDirCache * dc,Reprog * r,SmbTree * t)33 smbsearchnew(SmbSession *s, SmbDirCache *dc, Reprog *r, SmbTree *t)
34 {
35 	SmbSearch *search;
36 	if (s->sidmap == nil)
37 		s->sidmap = smbidmapnew();
38 	search = smbemalloc(sizeof(SmbSearch));
39 	smbidmapadd(s->sidmap, search);
40 	search->dc = dc;
41 	search->rep = r;
42 	search->t = t;
43 	smblogprintif(smbglobals.log.sids, "smbsearchnew: 0x%.4ux\n", search->id);
44 	return search;
45 }
46 
47 static int
standardflatten(SmbSession * s,SmbBuffer * b,Dir * d,ulong * nameoffsetp)48 standardflatten(SmbSession *s, SmbBuffer *b, Dir *d, ulong *nameoffsetp)
49 {
50 	ushort mdate, mtime;
51 	ushort adate, atime;
52 	ushort fnlfixupoffset;
53 
54 	smbplan9time2datetime(d->mtime, s->tzoff, &mdate, &mtime);
55 	smbplan9time2datetime(d->atime, s->tzoff, &adate, &atime);
56 	if (!smbbufferputs(b, mdate)
57 		|| !smbbufferputs(b, mtime)
58 		|| !smbbufferputs(b, adate)
59 		|| !smbbufferputs(b, atime)
60 		|| !smbbufferputs(b, mdate)
61 		|| !smbbufferputs(b, mtime)
62 		|| !smbbufferputl(b, d->length)
63 		|| !smbbufferputl(b, 512)			// ha
64 		|| !smbbufferputs(b, (d->qid.type & QTDIR) ? 0x10 : 0))
65 		return 0;
66 	fnlfixupoffset = smbbufferwriteoffset(b);
67 	if (!smbbufferputs(b, 0))
68 		return 0;
69 	*nameoffsetp = smbbufferwriteoffset(b);
70 	if (!smbbufferputstring(b, &s->peerinfo, 0, d->name))
71 		return 0;
72 	return smbbufferfixuprelatives(b, fnlfixupoffset);
73 }
74 
75 static int
findbothflatten(SmbBuffer * b,SmbPeerInfo * p,Dir * d,ulong resumekey,ulong * nameoffsetp)76 findbothflatten(SmbBuffer *b, SmbPeerInfo *p, Dir *d, ulong resumekey, ulong *nameoffsetp)
77 {
78 	vlong mtime, atime;
79 	ulong fixup;
80 
81 	fixup = smbbufferwriteoffset(b);
82 	mtime = smbplan9time2time(d->mtime);
83 	atime = smbplan9time2time(d->atime);
84 poolcheck(mainmem);
85 	if (!smbbufferputl(b, 0)
86 		|| !smbbufferputl(b, resumekey)
87 		|| !smbbufferputv(b, mtime)
88 		|| !smbbufferputv(b, atime)
89 		|| !smbbufferputv(b, mtime)
90 		|| !smbbufferputv(b, mtime)
91 		|| !smbbufferputv(b, d->length)
92 		|| !smbbufferputv(b, smbl2roundupvlong(d->length, smbglobals.l2allocationsize))			// ha
93 		|| !smbbufferputl(b, (d->qid.type & QTDIR) ? 0x10 : 0x80)
94 		|| !smbbufferputl(b, smbstringlen(p, d->name))
95 		|| !smbbufferputl(b, 0)
96 		|| !smbbufferputb(b, 0)
97 		|| !smbbufferputb(b, 0)
98 		|| !smbbufferfill(b, 0, 24))
99 		return 0;
100 poolcheck(mainmem);
101 	*nameoffsetp = smbbufferwriteoffset(b);
102 	if (!smbbufferputstring(b, p, 0, d->name) || !smbbufferalignl2(b, 2))
103 		return 0;
104 poolcheck(mainmem);
105 	return smbbufferfixuprelativeinclusivel(b, fixup);
106 }
107 
108 static void
populate(SmbSession * s,SmbDirCache * dc,Reprog * r,ushort informationlevel,ushort flags,ushort scount,ushort * ep,ulong * nameoffsetp)109 populate(SmbSession *s, SmbDirCache *dc, Reprog *r, ushort informationlevel, ushort flags, ushort scount,
110 	ushort *ep, ulong *nameoffsetp)
111 {
112 	ushort e;
113 	ulong nameoffset;
114 	e = 0;
115 	nameoffset = 0;
116 	while (dc->i < dc->n && e < scount) {
117 		ulong backup;
118 		int rv;
119 
120 		if (!smbmatch(dc->buf[dc->i].name, r)) {
121 			dc->i++;
122 			continue;
123 		}
124 		rv = 0;
125 		backup = smbbufferwriteoffset(s->transaction.out.data);
126 		switch (informationlevel) {
127 		case SMB_INFO_STANDARD:
128 			if (flags & SMB_FIND_RETURN_RESUME_KEYS) {
129 				if (!smbbufferputl(s->transaction.out.data, dc->i)) {
130 					rv = 0;
131 					break;
132 				}
133 			}
134 			rv = standardflatten(s, s->transaction.out.data, dc->buf + dc->i, &nameoffset);
135 			break;
136 		case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
137 			rv = findbothflatten(s->transaction.out.data, &s->peerinfo, dc->buf + dc->i, dc->i, &nameoffset);
138 			break;
139 		}
140 		if (rv == 0) {
141 			smbbufferwritebackup(s->transaction.out.data, backup);
142 			break;
143 		}
144 		dc->i++;
145 		e++;
146 	}
147 	*ep = e;
148 	*nameoffsetp = nameoffset;
149 }
150 
151 SmbProcessResult
smbtrans2findfirst2(SmbSession * s,SmbHeader * h)152 smbtrans2findfirst2(SmbSession *s, SmbHeader *h)
153 {
154 	SmbBuffer *b;
155 	char *pattern = nil;
156 	char *dir = nil;
157 	char *name = nil;
158 	ushort searchattributes, searchcount, flags, informationlevel;
159 	ulong searchstoragetype;
160 	SmbDirCache *dc = nil;
161 	ushort e;
162 	ulong nameoffset;
163 	ushort eos;
164 	SmbSearch *search;
165 	SmbProcessResult pr;
166 	Reprog *r = nil;
167 	SmbTree *t;
168 	int debug;
169 
170 	debug = smboptable[h->command].debug
171 		|| smbtrans2optable[SMB_TRANS2_FIND_FIRST2].debug
172 		|| smbglobals.log.find;
173 poolcheck(mainmem);
174 	b = smbbufferinit(s->transaction.in.parameters, s->transaction.in.parameters, s->transaction.in.tpcount);
175 	if (!smbbuffergets(b, &searchattributes)
176 		|| !smbbuffergets(b, &searchcount)
177 		|| !smbbuffergets(b, &flags)
178 		|| !smbbuffergets(b, &informationlevel)
179 		|| !smbbuffergetl(b, &searchstoragetype)
180 		|| !smbbuffergetstring(b, h, SMB_STRING_PATH, &pattern)) {
181 		pr = SmbProcessResultFormat;
182 		goto done;
183 	}
184 	smbloglock();
185 	smblogprintif(debug, "searchattributes: 0x%.4ux\n", searchattributes);
186 	smblogprintif(debug, "searchcount: 0x%.4ux\n", searchcount);
187 	smblogprintif(debug, "flags: 0x%.4ux\n", flags);
188 	smblogprintif(debug, "informationlevel: 0x%.4ux\n", informationlevel);
189 	smblogprintif(debug, "searchstoragetype: 0x%.8lux\n", searchstoragetype);
190 	smblogprintif(debug, "pattern: %s\n", pattern);
191 	smblogunlock();
192 	smbpathsplit(pattern, &dir, &name);
193 	if (informationlevel != SMB_INFO_STANDARD && informationlevel != SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
194 		smblogprint(-1, "smbtrans2findfirst2: infolevel 0x%.4ux not implemented\n", informationlevel);
195 		smbseterror(s, ERRDOS, ERRunknownlevel);
196 		pr = SmbProcessResultError;
197 		goto done;
198 	}
199 
200 	t = smbidmapfind(s->tidmap, h->tid);
201 	if (t == nil) {
202 		smbseterror(s, ERRSRV, ERRinvtid);
203 		pr = SmbProcessResultError;
204 		goto done;
205 	}
206 
207 	dc = smbmkdircache(t, dir);
208 	if (dc == nil) {
209 		smbseterror(s, ERRDOS, ERRnoaccess);
210 		pr = SmbProcessResultError;
211 		goto done;
212 	}
213 poolcheck(mainmem);
214 	r = smbmkrep(name);
215 	populate(s, dc, r, informationlevel, flags, searchcount, &e, &nameoffset);
216 poolcheck(mainmem);
217 	eos = dc->i >= dc->n;
218 	if ((flags & SMB_FIND_CLOSE) != 0 || ((flags & SMB_FIND_CLOSE_EOS) != 0 && eos))
219 		smbdircachefree(&dc);
220 poolcheck(mainmem);
221 	if (dc) {
222 		/* create a search handle */
223 		search = smbsearchnew(s, dc, r, t);
224 		r = nil;
225 		dc = nil;
226 	}
227 	else
228 		search = nil;
229 	smbbufferputs(s->transaction.out.parameters, search ? search->id : 0);
230 	smbbufferputs(s->transaction.out.parameters, e);
231 	smbbufferputs(s->transaction.out.parameters, eos);
232 	smbbufferputs(s->transaction.out.parameters, 0);
233 	smbbufferputs(s->transaction.out.parameters, nameoffset);
234 	pr = SmbProcessResultReply;
235 done:
236 	smbbufferfree(&b);
237 	free(pattern);
238 	free(dir);
239 	free(name);
240 	smbdircachefree(&dc);
241 	free(r);
242 	return pr;
243 }
244 
245 SmbProcessResult
smbtrans2findnext2(SmbSession * s,SmbHeader * h)246 smbtrans2findnext2(SmbSession *s, SmbHeader *h)
247 {
248 	SmbBuffer *b;
249 	int debug;
250 	ushort sid, scount, infolevel;
251 	ulong resumekey;
252 	ushort flags;
253 	char *filename = nil;
254 	SmbProcessResult pr;
255 	ushort e;
256 	ulong nameoffset;
257 	ushort eos;
258 	SmbTree *t;
259 	SmbSearch *search;
260 
261 	debug = smboptable[h->command].debug
262 		|| smbtrans2optable[SMB_TRANS2_FIND_NEXT2].debug
263 		|| smbglobals.log.find;
264 	b = smbbufferinit(s->transaction.in.parameters, s->transaction.in.parameters, s->transaction.in.tpcount);
265 	if (!smbbuffergets(b, &sid)
266 		|| !smbbuffergets(b, &scount)
267 		|| !smbbuffergets(b, &infolevel)
268 		|| !smbbuffergetl(b, &resumekey)
269 		|| !smbbuffergets(b, &flags)
270 		|| !smbbuffergetstring(b, h, 0, &filename)) {
271 		pr = SmbProcessResultFormat;
272 		goto done;
273 	}
274 	smblogprintif(debug,
275 		"smbtrans2findnext2: sid %d scount %d infolevel 0x%.4ux resumekey %lud flags 0x%.4ux filename %s\n",
276 		sid, scount, infolevel, resumekey, flags, filename);
277 
278 	if (infolevel != SMB_INFO_STANDARD && infolevel != SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
279 		smblogprint(-1, "smbtrans2findnext2: infolevel 0x%.4ux not implemented\n", infolevel);
280 		smbseterror(s, ERRDOS, ERRunknownlevel);
281 		pr = SmbProcessResultError;
282 		goto done;
283 	}
284 
285 	t = smbidmapfind(s->tidmap, h->tid);
286 	if (t == nil) {
287 		smbseterror(s, ERRSRV, ERRinvtid);
288 		pr = SmbProcessResultError;
289 		goto done;
290 	}
291 
292 	search = smbidmapfind(s->sidmap, sid);
293 	if (search == nil) {
294 		smbseterror(s, ERRDOS, ERRnofiles);
295 		pr = SmbProcessResultError;
296 		goto done;
297 	}
298 
299 	if (search->t != t) {
300 		smbseterror(s, ERRSRV, ERRinvtid);
301 		pr = SmbProcessResultError;
302 		goto done;
303 	}
304 
305 	if ((flags & (1 << 3)) == 0) {
306 		long i;
307 		if (filename == nil) {
308 			smbseterror(s, ERRDOS, ERRnofiles);
309 			pr = SmbProcessResultError;
310 			goto done;
311 		}
312 		for (i = 0; i < search->dc->n; i++)
313 			if (strcmp(search->dc->buf[i].name, filename) == 0) {
314 				search->dc->i = i + 1;
315 				break;
316 			}
317 	}
318 
319 	populate(s, search->dc, search->rep, infolevel, flags, scount, &e, &nameoffset);
320 
321 	eos = search->dc->i >= search->dc->n;
322 	if ((flags & SMB_FIND_CLOSE) != 0 || ((flags & SMB_FIND_CLOSE_EOS) != 0 && eos))
323 		smbsearchclose(s, search);
324 	smbbufferputs(s->transaction.out.parameters, e);
325 	smbbufferputs(s->transaction.out.parameters, eos);
326 	smbbufferputs(s->transaction.out.parameters, 0);
327 	smbbufferputs(s->transaction.out.parameters, nameoffset);
328 	pr = SmbProcessResultReply;
329 done:
330 	smbbufferfree(&b);
331 	free(filename);
332 	return pr;
333 }
334