xref: /plan9/sys/src/cmd/aquarela/smbcomopen.c (revision ec59a3ddbfceee0efe34584c2c9981a5e5ff1ec4)
1 #include "headers.h"
2 
3 static void
4 smblogprintattr(int cmd, ushort attr)
5 {
6 	if (attr & SMB_ATTR_READ_ONLY)
7 		smblogprint(cmd, " readonly");
8 	if (attr & SMB_ATTR_HIDDEN)
9 		smblogprint(cmd, " hidden");
10 	if (attr & SMB_ATTR_SYSTEM)
11 		smblogprint(cmd, " system");
12 	if (attr & SMB_ATTR_DIRECTORY)
13 		smblogprint(cmd, " directory");
14 	if (attr & SMB_ATTR_ARCHIVE)
15 		smblogprint(cmd, " archive");
16 }
17 
18 static SmbFile *
19 openfile(SmbSession *s, SmbTree *t, char *path, ushort mode, ushort attr, ushort ofun, ulong createoptions, uvlong createsize,
20 	ushort *fidp, Dir **dp, ushort *actionp)
21 {
22 	int p9mode;
23 	int share;
24 	Dir *d = nil;
25 	int fd = -1;
26 	ushort action;
27 	SmbFile *f = nil;
28 	SmbSharedFile *sf = nil;
29 	char *fullpath = nil;
30 	int diropen = 0;
31 
32 	p9mode = (mode >> SMB_OPEN_MODE_ACCESS_SHIFT) & SMB_OPEN_MODE_ACCESS_MASK;
33 	share = (mode >> SMB_OPEN_MODE_SHARE_SHIFT) & SMB_OPEN_MODE_SHARE_MASK;
34 	if (share == SMB_OPEN_MODE_SHARE_COMPATIBILITY) {
35 	badshare:
36 		smbseterror(s, ERRDOS, ERRbadshare);
37 		goto done;
38 	}
39 	smbstringprint(&fullpath, "%s%s", t->serv->path, path);
40 	d = dirstat(fullpath);
41 	if (d) {
42 		/* file exists */
43 		int ofunexist;
44 		if (d->mode & DMDIR) {
45 			if (createoptions & SMB_CO_FILE) {
46 				smbseterror(s, ERRDOS, ERRnoaccess);
47 				goto done;
48 			}
49 		}
50 		else if (createoptions & SMB_CO_DIRECTORY) {
51 			smbseterror(s, ERRDOS, ERRnoaccess);
52 			goto done;
53 		}
54 
55 		sf = smbsharedfileget(d, p9mode, &share);
56 		if (sf == nil)
57 			goto badshare;
58 		action = 1;
59 		ofunexist = (ofun >> SMB_OFUN_EXIST_SHIFT) & SMB_OFUN_EXIST_MASK;
60 		if (ofunexist == SMB_OFUN_EXIST_FAIL) {
61 			smbseterror(s, ERRDOS, ERRfilexists);
62 			goto done;
63 		}
64 		else if (ofunexist == SMB_OFUN_EXIST_TRUNCATE) {
65 			if ((d->mode & DMDIR) || (p9mode != OWRITE && p9mode != ORDWR)) {
66 				smbseterror(s, ERRDOS, ERRbadaccess);
67 				goto done;
68 			}
69 			p9mode |= OTRUNC;
70 			action = 3;
71 		}
72 		else if (ofunexist != SMB_OFUN_EXIST_OPEN) {
73 			smbseterror(s, ERRDOS, ERRbadaccess);
74 			goto done;
75 		}
76 		if (d->mode & DMDIR)
77 			diropen = 1;
78 		else
79 			fd = open(fullpath, p9mode);
80 	}
81 	else {
82 		/* file does not exist */
83 		ulong p9attr;
84 		action = 3;
85 		if ((ofun & SMB_OFUN_NOEXIST_CREATE) == 0) {
86 			smbseterror(s, ERRDOS, ERRbadfile);
87 			goto done;
88 		}
89 		if (createsize != 0) {
90 			smbseterror(s, ERRDOS, ERRunsup);
91 			goto done;
92 		}
93 //smblogprint(-1, "creating: attr 0x%.4ux co 0x%.8lux\n", attr, createoptions);
94 		if (createoptions & SMB_CO_FILE) {
95 			attr &= SMB_ATTR_DIRECTORY;
96 			if (attr == 0)
97 				attr = SMB_ATTR_NORMAL;
98 		}
99 		else if (createoptions & SMB_CO_DIRECTORY) {
100 			attr &= ~SMB_ATTR_NORMAL;
101 			attr |= SMB_ATTR_DIRECTORY;
102 		}
103 //smblogprint(-1, "creating: before conversion attr 0x%.4ux\n", attr);
104 		p9attr = smbdosattr2plan9mode(attr);
105 //smblogprint(-1, "creating: after conversion p9attr 0%.uo\n", p9attr);
106 		fd = create(fullpath, p9mode, p9attr);
107 		if (fd >= 0) {
108 			d = dirfstat(fd);
109 			sf = smbsharedfileget(d, p9mode, &share);
110 			if (sf == nil) {
111 				close(fd);
112 				remove(path);
113 				goto badshare;
114 			}
115 		}
116 	}
117 	if (!diropen && fd < 0) {
118 		smbseterror(s, ERRSRV, ERRaccess);
119 		goto done;
120 	}
121 	f = smbemalloc(sizeof(SmbFile));
122 	if (diropen) {
123 		f->ioallowed = 0;
124 		f->fd = -1;
125 	}
126 	else {
127 		f->ioallowed = 1;
128 		f->fd = fd;
129 	}
130 	f->name = smbestrdup(path);
131 	f->sf = sf;
132 	sf = nil;
133 	f->share = share;
134 	f->p9mode = p9mode;
135 	f->t = t;
136 	if (s->fidmap == nil)
137 		s->fidmap = smbidmapnew();
138 	*fidp = smbidmapadd(s->fidmap, f);
139 	smblogprintif(smbglobals.log.fids, "openfile: 0x%.4ux/0x%.4ux %s\n", t->id, *fidp, path);
140 	if (actionp)
141 		*actionp = action;
142 	if (dp) {
143 		*dp = d;
144 		d = nil;
145 	}
146 done:
147 	if (sf)
148 		smbsharedfileput(nil, sf, share);
149 	free(d);
150 	free(fullpath);
151 	return f;
152 }
153 
154 SmbProcessResult
155 smbcomopenandx(SmbSession *s, SmbHeader *h, uchar *pdata, SmbBuffer *b)
156 {
157 	uchar andxcommand;
158 	ushort andxoffset, flags, mode, sattr, attr;
159 	ulong createtime;
160 	ushort ofun;
161 	ulong createsize, timeout;
162 	char *path = nil;
163 	ulong andxoffsetfixupoffset;
164 	SmbProcessResult pr;
165 	ushort action;
166 	Dir *d = nil;
167 	SmbFile *f;
168 	SmbTree *t;
169 	ushort fid;
170 
171 	if (!smbcheckwordcount("comopenandx", h, 15))
172 		return SmbProcessResultFormat;
173 
174 	andxcommand = *pdata++;
175 	pdata++;
176 	andxoffset = smbnhgets(pdata); pdata += 2;
177 	flags = smbnhgets(pdata); pdata += 2;
178 	mode = smbnhgets(pdata); pdata += 2;
179 	sattr = smbnhgets(pdata); pdata += 2;
180 	attr = smbnhgets(pdata); pdata += 2;
181 	createtime = smbnhgetl(pdata); pdata += 4;
182 	ofun = smbnhgets(pdata); pdata += 2;
183 	createsize = smbnhgetl(pdata); pdata += 4;
184 	timeout = smbnhgetl(pdata); pdata += 4;
185 	pdata += 4;
186 	USED(pdata);
187 	if (!smbbuffergetstring(b, h, SMB_STRING_PATH, &path)) {
188 		pr = SmbProcessResultFormat;
189 		goto done;
190 	}
191 
192 	smbloglock();
193 	smblogprint(h->command, "flags 0x%.4ux", flags);
194 	if (flags & SMB_OPEN_FLAGS_ADDITIONAL)
195 		smblogprint(h->command, " additional");
196 	if (flags & SMB_OPEN_FLAGS_OPLOCK)
197 		smblogprint(h->command, " oplock");
198 	if (flags & SMB_OPEN_FLAGS_OPBATCH)
199 		smblogprint(h->command, " opbatch");
200 	smblogprint(h->command, "\n");
201 	smblogprint(h->command, "mode 0x%.4ux", mode);
202 	switch ((mode >> SMB_OPEN_MODE_ACCESS_SHIFT) & SMB_OPEN_MODE_ACCESS_MASK) {
203 	case OREAD:
204 		smblogprint(h->command, " OREAD");
205 		break;
206 	case OWRITE:
207 		smblogprint(h->command, " OWRITE");
208 		break;
209 	case ORDWR:
210 		smblogprint(h->command, " ORDWR");
211 		break;
212 	case OEXEC:
213 		smblogprint(h->command, " OEXEC");
214 		break;
215 	}
216 	switch ((mode >> SMB_OPEN_MODE_SHARE_SHIFT) & SMB_OPEN_MODE_SHARE_MASK) {
217 	case SMB_OPEN_MODE_SHARE_COMPATIBILITY:
218 		smblogprint(h->command, " compatinility");
219 		break;
220 	case SMB_OPEN_MODE_SHARE_EXCLUSIVE:
221 		smblogprint(h->command, " exclusive");
222 		break;
223 	case SMB_OPEN_MODE_SHARE_DENY_WRITE:
224 		smblogprint(h->command, " deny write");
225 		break;
226 	case SMB_OPEN_MODE_SHARE_DENY_READOREXEC:
227 		smblogprint(h->command, " deny readorxec");
228 		break;
229 	case SMB_OPEN_MODE_SHARE_DENY_NONE:
230 		smblogprint(h->command, " deny none");
231 		break;
232 	}
233 	if (mode & SMB_OPEN_MODE_WRITE_THROUGH)
234 		smblogprint(h->command, " write through");
235 	smblogprint(h->command, "\n");
236 	smblogprint(h->command, "sattr 0x%.4ux", sattr);
237 	smblogprintattr(h->command, sattr);
238 	smblogprint(h->command, "\n");
239 	smblogprint(h->command, "attr 0x%.4ux", attr);
240 	smblogprintattr(h->command, attr);
241 	smblogprint(h->command, "\n");
242 	smblogprint(h->command, "createtime 0x%.8lux\n", createtime);
243 	smblogprint(h->command, "ofun 0x%.4ux", ofun);
244 	if (ofun & SMB_OFUN_NOEXIST_CREATE)
245 		smblogprint(h->command, " noexistscreate");
246 	else
247 		smblogprint(h->command, " noexistfail");
248 	switch ((ofun >> SMB_OFUN_EXIST_SHIFT) & SMB_OFUN_EXIST_MASK) {
249 	case SMB_OFUN_EXIST_FAIL:
250 		smblogprint(h->command, " existfail");
251 		break;
252 	case SMB_OFUN_EXIST_OPEN:
253 		smblogprint(h->command, " existopen");
254 		break;
255 	case SMB_OFUN_EXIST_TRUNCATE:
256 		smblogprint(h->command, " existtruncate");
257 		break;
258 	}
259 	smblogprint(h->command, "\n");
260 	smblogprint(h->command, "createsize 0x%.8lux\n", createsize);
261 	smblogprint(h->command, "timeout 0x%.8lux\n", timeout);
262 	smblogprint(h->command, "path %s\n", path);
263 	smblogunlock();
264 
265 	t = smbidmapfind(s->tidmap, h->tid);
266 	if (t == nil) {
267 		smbseterror(s, ERRSRV, ERRinvtid);
268 		goto errordone;
269 	}
270 
271 	f = openfile(s, t, path, mode, attr, ofun, 0, createsize, &fid, &d, &action);
272 	if (f == nil) {
273 		pr = SmbProcessResultError;
274 		goto done;
275 	}
276 	h->wordcount = 15;
277 	if (!smbbufferputandxheader(s->response, h, &s->peerinfo, andxcommand, &andxoffsetfixupoffset)
278 		|| !smbbufferputs(s->response, fid)
279 		|| !smbbufferputs(s->response, smbplan9mode2dosattr(d->mode))
280 		|| !smbbufferputl(s->response, smbplan9time2utime(d->mtime, s->tzoff))
281 		|| !smbbufferputl(s->response, smbplan9length2size32(d->length))
282 		|| !smbbufferputs(s->response, smbplan9mode2dosattr(d->mode)) // probbaly bogus
283 		|| !smbbufferputs(s->response, 0)	// all files are files
284 		|| !smbbufferputs(s->response, 0)	// pipe state
285 		|| !smbbufferputs(s->response, action)
286 		|| !smbbufferputl(s->response, 0)	// fileID
287 		|| !smbbufferputs(s->response, 0)
288 		|| !smbbufferputs(s->response, 0)) {	// bytecount 0
289 		smbfileclose(s, f);
290 		pr = SmbProcessResultMisc;
291 		goto done;
292 	}
293 	if (andxcommand != SMB_COM_NO_ANDX_COMMAND)
294 		pr = smbchaincommand(s, h, andxoffsetfixupoffset, andxcommand, andxoffset, b);
295 	else
296 		pr = SmbProcessResultReply;
297 	goto done;
298 errordone:
299 	pr = SmbProcessResultError;
300 done:
301 	free(path);
302 	free(d);
303 	return pr;
304 }
305 
306 SmbProcessResult
307 smbcomopen(SmbSession *s, SmbHeader *h, uchar *pdata, SmbBuffer *b)
308 {
309 	uchar fmt;
310 	char *path;
311 	ushort mode, attr;
312 	SmbTree *t;
313 	ushort fid;
314 	Dir *d = nil;
315 	SmbFile *f;
316 	SmbProcessResult pr;
317 
318 	if (!smbcheckwordcount("comopen", h, 2))
319 		return SmbProcessResultFormat;
320 	mode = smbnhgets(pdata);
321 	attr = smbnhgets(pdata + 2);
322 	if (!smbbuffergetb(b, &fmt)
323 		|| fmt != 4
324 		|| !smbbuffergetstring(b, h, SMB_STRING_PATH, &path)) {
325 		pr = SmbProcessResultFormat;
326 		goto done;
327 	}
328 	t = smbidmapfind(s->tidmap, h->tid);
329 	if (t == nil) {
330 		smbseterror(s, ERRSRV, ERRinvtid);
331 	error:
332 		pr = SmbProcessResultError;
333 		goto done;
334 	}
335 	f = openfile(s, t, path, mode, attr,
336 		SMB_OFUN_EXIST_OPEN << SMB_OFUN_EXIST_SHIFT,
337 		0, 0, &fid, &d, nil);
338 	if (f == nil)
339 		goto error;
340 	h->wordcount = 7;
341 	if (!smbbufferputheader(s->response, h, &s->peerinfo)
342 		|| !smbbufferputs(s->response, fid)
343 		|| !smbbufferputs(s->response, smbplan9mode2dosattr(d->mode))
344 		|| !smbbufferputl(s->response, smbplan9time2utime(d->mtime, s->tzoff))
345 		|| !smbbufferputl(s->response, smbplan9length2size32(d->length))
346 		|| !smbbufferputs(s->response, 2)		// lies - this should be the actual access allowed
347 		|| !smbbufferputs(s->response, 0))
348 		pr = SmbProcessResultMisc;
349 	else
350 		pr = SmbProcessResultReply;
351 done:
352 	free(path);
353 	free(d);
354 	return pr;
355 }
356 
357 typedef struct SmbSblut {
358 	char *s;
359 	ulong mask;
360 } SmbSblut;
361 
362 static SmbSblut dasblut[] = {
363 	{ "SMB_DA_SPECIFIC_READ_DATA", SMB_DA_SPECIFIC_READ_DATA },
364 	{ "SMB_DA_SPECIFIC_WRITE_DATA", SMB_DA_SPECIFIC_WRITE_DATA },
365 	{ "SMB_DA_SPECIFIC_APPEND_DATA", SMB_DA_SPECIFIC_APPEND_DATA },
366 	{ "SMB_DA_SPECIFIC_READ_EA", SMB_DA_SPECIFIC_READ_EA },
367 	{ "SMB_DA_SPECIFIC_WRITE_EA", SMB_DA_SPECIFIC_WRITE_EA },
368 	{ "SMB_DA_SPECIFIC_EXECUTE", SMB_DA_SPECIFIC_EXECUTE },
369 	{ "SMB_DA_SPECIFIC_DELETE_CHILD", SMB_DA_SPECIFIC_DELETE_CHILD },
370 	{ "SMB_DA_SPECIFIC_READ_ATTRIBUTES", SMB_DA_SPECIFIC_READ_ATTRIBUTES },
371 	{ "SMB_DA_SPECIFIC_WRITE_ATTRIBUTES", SMB_DA_SPECIFIC_WRITE_ATTRIBUTES },
372 	{ "SMB_DA_STANDARD_DELETE_ACCESS", SMB_DA_STANDARD_DELETE_ACCESS },
373 	{ "SMB_DA_STANDARD_READ_CONTROL_ACCESS", SMB_DA_STANDARD_READ_CONTROL_ACCESS },
374 	{ "SMB_DA_STANDARD_WRITE_DAC_ACCESS", SMB_DA_STANDARD_WRITE_DAC_ACCESS },
375 	{ "SMB_DA_STANDARD_WRITE_OWNER_ACCESS", SMB_DA_STANDARD_WRITE_OWNER_ACCESS },
376 	{ "SMB_DA_STANDARD_SYNCHRONIZE_ACCESS", SMB_DA_STANDARD_SYNCHRONIZE_ACCESS },
377 	{ "SMB_DA_GENERIC_ALL_ACCESS", SMB_DA_GENERIC_ALL_ACCESS },
378 	{ "SMB_DA_GENERIC_EXECUTE_ACCESS", SMB_DA_GENERIC_EXECUTE_ACCESS },
379 	{ "SMB_DA_GENERIC_WRITE_ACCESS", SMB_DA_GENERIC_WRITE_ACCESS },
380 	{ "SMB_DA_GENERIC_READ_ACCESS", SMB_DA_GENERIC_READ_ACCESS },
381 	{ 0 }
382 };
383 
384 static SmbSblut efasblut[] = {
385 	{ "SMB_ATTR_READ_ONLY", SMB_ATTR_READ_ONLY },
386 	{ "SMB_ATTR_HIDDEN", SMB_ATTR_HIDDEN },
387 	{ "SMB_ATTR_SYSTEM", SMB_ATTR_SYSTEM },
388 	{ "SMB_ATTR_DIRECTORY", SMB_ATTR_DIRECTORY },
389 	{ "SMB_ATTR_ARCHIVE", SMB_ATTR_ARCHIVE },
390 	{ "SMB_ATTR_NORMAL", SMB_ATTR_NORMAL },
391 	{ "SMB_ATTR_COMPRESSED", SMB_ATTR_COMPRESSED },
392 	{ "SMB_ATTR_TEMPORARY", SMB_ATTR_TEMPORARY },
393 	{ "SMB_ATTR_WRITETHROUGH", SMB_ATTR_WRITETHROUGH },
394 	{ "SMB_ATTR_NO_BUFFERING", SMB_ATTR_NO_BUFFERING },
395 	{ "SMB_ATTR_RANDOM_ACCESS", SMB_ATTR_RANDOM_ACCESS },
396 	{ 0 }
397 };
398 
399 static SmbSblut sasblut[] = {
400 	{ "SMB_SA_SHARE_READ", SMB_SA_SHARE_READ },
401 	{ "SMB_SA_SHARE_WRITE", SMB_SA_SHARE_WRITE },
402 	{ "SMB_SA_SHARE_DELETE", SMB_SA_SHARE_DELETE },
403 	{ "SMB_SA_NO_SHARE", SMB_SA_NO_SHARE },
404 	{ 0 }
405 };
406 
407 static SmbSblut cosblut[] = {
408 	{ "SMB_CO_DIRECTORY", SMB_CO_DIRECTORY },
409 	{ "SMB_CO_WRITETHROUGH", SMB_CO_WRITETHROUGH },
410 	{ "SMB_CO_SEQUENTIAL_ONLY", SMB_CO_SEQUENTIAL_ONLY },
411 	{ "SMB_CO_FILE", SMB_CO_FILE },
412 	{ "SMB_CO_NO_EA_KNOWLEDGE", SMB_CO_NO_EA_KNOWLEDGE },
413 	{ "SMB_CO_EIGHT_DOT_THREE_ONLY", SMB_CO_EIGHT_DOT_THREE_ONLY },
414 	{ "SMB_CO_RANDOM_ACCESS", SMB_CO_RANDOM_ACCESS },
415 	{ "SMB_CO_DELETE_ON_CLOSE", SMB_CO_DELETE_ON_CLOSE },
416 	{ 0 }
417 };
418 
419 static SmbSlut cdslut[] = {
420 	{ "SMB_CD_SUPERCEDE", SMB_CD_SUPERCEDE },
421 	{ "SMB_CD_OPEN", SMB_CD_OPEN },
422 	{ "SMB_CD_CREATE", SMB_CD_CREATE },
423 	{ "SMB_CD_OPEN_IF", SMB_CD_OPEN_IF },
424 	{ "SMB_CD_OVERWRITE", SMB_CD_OVERWRITE },
425 	{ "SMB_CD_OVERWRITE_IF", SMB_CD_OVERWRITE_IF },
426 	{ 0 }
427 };
428 
429 static void
430 smbsblutlogprint(uchar cmd, SmbSblut *sblut, ulong mask)
431 {
432 	while (sblut->s) {
433 		if (mask && (sblut->mask & mask) || (mask == 0 && sblut->mask == 0))
434 			smblogprint(cmd, " %s", sblut->s);
435 		sblut++;
436 	}
437 }
438 
439 SmbProcessResult
440 smbcomntcreateandx(SmbSession *s, SmbHeader *h, uchar *pdata, SmbBuffer *b)
441 {
442 	uchar andxcommand;
443 	ushort andxoffset;
444 	char *path = nil;
445 	SmbProcessResult pr;
446 	ulong namelength;
447 	ulong flags;
448 	ulong rootdirectoryfid, desiredaccess;
449 	uvlong allocationsize;
450 	ulong extfileattributes, shareaccess, createdisposition, createoptions, impersonationlevel;
451 	uchar securityflags;
452 	int p9mode;
453 	int sharemode;
454 	ushort mode;
455 	SmbTree *t;
456 	ushort ofun;
457 	SmbFile *f;
458 	ushort fid;
459 	Dir *d = nil;
460 	ushort action;
461 	uvlong mtime;
462 	ulong andxoffsetfixup;
463 
464 	if (!smbcheckwordcount("comntcreateandx", h, 24))
465 		return SmbProcessResultFormat;
466 
467 	andxcommand = *pdata++;
468 	pdata++;
469 	andxoffset = smbnhgets(pdata); pdata += 2;
470 	pdata++;
471 	namelength = smbnhgets(pdata); pdata += 2;
472 	flags = smbnhgetl(pdata); pdata += 4;
473 	rootdirectoryfid = smbnhgetl(pdata); pdata += 4;
474 	desiredaccess = smbnhgetl(pdata); pdata += 4;
475 	allocationsize = smbnhgetv(pdata); pdata += 8;
476 	extfileattributes = smbnhgetl(pdata); pdata += 4;
477 	shareaccess = smbnhgetl(pdata); pdata += 4;
478 	createdisposition = smbnhgetl(pdata); pdata += 4;
479 	createoptions = smbnhgetl(pdata); pdata += 4;
480 	impersonationlevel = smbnhgetl(pdata); pdata += 4;
481 	securityflags = *pdata++;
482 	USED(pdata);
483 
484 	if (!smbbuffergetstring(b, h, SMB_STRING_PATH, &path)) {
485 		pr = SmbProcessResultFormat;
486 		goto done;
487 	}
488 
489 	smblogprint(h->command, "namelength %d\n", namelength);
490 	smblogprint(h->command, "flags 0x%.8lux\n", flags);
491 	smblogprint(h->command, "rootdirectoryfid %lud\n", rootdirectoryfid);
492 	smblogprint(h->command, "desiredaccess 0x%.8lux", desiredaccess);
493 	smbsblutlogprint(h->command, dasblut, desiredaccess);
494 	smblogprint(h->command, "\n");
495 	smblogprint(h->command, "allocationsize %llud\n", allocationsize);
496 	smblogprint(h->command, "extfileattributes 0x%.8lux", extfileattributes);
497 	smbsblutlogprint(h->command, efasblut, extfileattributes);
498 	smblogprint(h->command, "\n");
499 	smblogprint(h->command, "shareaccess 0x%.8lux", shareaccess);
500 	smbsblutlogprint(h->command, sasblut, shareaccess);
501 	smblogprint(h->command, "\n");
502 	smblogprint(h->command, "createdisposition 0x%.8lux %s\n",
503 		createdisposition, smbrevslut(cdslut, createdisposition));
504 	smblogprint(h->command, "createoptions 0x%.8lux", createoptions);
505 	smbsblutlogprint(h->command, cosblut, createoptions);
506 	smblogprint(h->command, "\n");
507 	smblogprint(h->command, "impersonationlevel 0x%.8lux\n", impersonationlevel);
508 	smblogprint(h->command, "securityflags 0x%.2ux\n", securityflags);
509 	smblogprint(h->command, "path %s\n", path);
510 
511 	if (rootdirectoryfid != 0) {
512 		smblogprint(-1, "smbcomntcreateandx: fid relative not implemented\n");
513 		goto unimp;
514 	}
515 
516 	if (desiredaccess & SMB_DA_GENERIC_MASK) {
517 		smblogprint(-1, "smbcomntcreateandx: generic bits in desiredaccess not implemented\n");
518 		goto unimp;
519 	}
520 
521 	if (desiredaccess & SMB_DA_SPECIFIC_READ_DATA)
522 		if (desiredaccess & (SMB_DA_SPECIFIC_WRITE_DATA | SMB_DA_SPECIFIC_APPEND_DATA))
523 			p9mode = ORDWR;
524 		else
525 			p9mode = OREAD;
526 	else if (desiredaccess & (SMB_DA_SPECIFIC_WRITE_DATA | SMB_DA_SPECIFIC_APPEND_DATA))
527 		p9mode = ORDWR;
528 	else
529 		p9mode = OREAD;
530 
531 	if (shareaccess == SMB_SA_NO_SHARE)
532 		sharemode = SMB_OPEN_MODE_SHARE_EXCLUSIVE;
533 	else if (shareaccess & (SMB_SA_SHARE_READ | SMB_SA_SHARE_WRITE) ==
534 		(SMB_SA_SHARE_READ | SMB_SA_SHARE_WRITE))
535 		sharemode = SMB_OPEN_MODE_SHARE_DENY_NONE;
536 	else if (shareaccess & SMB_SA_SHARE_READ)
537 		sharemode = SMB_OPEN_MODE_SHARE_DENY_WRITE;
538 	else if (shareaccess & SMB_SA_SHARE_WRITE)
539 		sharemode = SMB_OPEN_MODE_SHARE_DENY_READOREXEC;
540 	else
541 		sharemode = SMB_OPEN_MODE_SHARE_DENY_NONE;
542 
543 	mode = (sharemode << SMB_OPEN_MODE_SHARE_SHIFT) | (p9mode << SMB_OPEN_MODE_ACCESS_SHIFT);
544 
545 	switch (createdisposition) {
546 	default:
547 		smblogprint(-1, "smbcomntcreateandx: createdisposition 0x%.8lux not implemented\n", createdisposition);
548 		goto unimp;
549 	case SMB_CD_OPEN:
550 		ofun = SMB_OFUN_EXIST_OPEN;
551 		break;
552 	case SMB_CD_CREATE:
553 		ofun = SMB_OFUN_EXIST_FAIL | SMB_OFUN_NOEXIST_CREATE;
554 		break;
555 	case SMB_CD_OPEN_IF:
556 		ofun = SMB_OFUN_EXIST_OPEN | SMB_OFUN_NOEXIST_CREATE;
557 		break;
558 	case SMB_CD_OVERWRITE:
559 		ofun = SMB_OFUN_EXIST_TRUNCATE;
560 		break;
561 	case SMB_CD_OVERWRITE_IF:
562 		ofun = SMB_OFUN_EXIST_TRUNCATE | SMB_OFUN_NOEXIST_CREATE;
563 		break;
564 	}
565 
566 	t = smbidmapfind(s->tidmap, h->tid);
567 	if (t == nil) {
568 		smbseterror(s, ERRSRV, ERRinvtid);
569 		pr = SmbProcessResultError;
570 		goto done;
571 	}
572 
573 	f = openfile(s, t, path, mode, extfileattributes, ofun, createoptions, allocationsize, &fid, &d, &action);
574 
575 	if (f == nil) {
576 		pr = SmbProcessResultError;
577 		goto done;
578 	}
579 
580 	h->wordcount = 42;
581 	mtime =  smbplan9time2time(d->mtime);
582 	if (!smbbufferputandxheader(s->response, h, &s->peerinfo, andxcommand, &andxoffsetfixup)
583 		|| !smbbufferputb(s->response, 0)		// oplocks? pah
584 		|| !smbbufferputs(s->response, fid)
585 		|| !smbbufferputl(s->response, action)
586 		|| !smbbufferputv(s->response, mtime)
587 		|| !smbbufferputv(s->response, smbplan9time2time(d->atime))
588 		|| !smbbufferputv(s->response, mtime)
589 		|| !smbbufferputv(s->response, mtime)
590 		|| !smbbufferputl(s->response, smbplan9mode2dosattr(d->mode))
591 		|| !smbbufferputv(s->response, smbl2roundupvlong(d->length, smbglobals.l2allocationsize))
592 		|| !smbbufferputv(s->response, d->length)
593 		|| !smbbufferputbytes(s->response, nil, 4)
594 		|| !smbbufferputb(s->response, (d->qid.type & QTDIR) != 0)
595 		|| !smbbufferputbytes(s->response, nil, 8)
596 		|| !smbbufferputs(s->response, 0)) {
597 		pr = SmbProcessResultMisc;
598 		goto done;
599 	}
600 
601 	if (andxcommand != SMB_COM_NO_ANDX_COMMAND)
602 		pr = smbchaincommand(s, h, andxoffsetfixup, andxcommand, andxoffset, b);
603 	else
604 		pr = SmbProcessResultReply;
605 
606 	goto done;
607 
608 unimp:
609 	pr = SmbProcessResultUnimp;
610 
611 done:
612 	free(path);
613 	free(d);
614 
615 	return pr;
616 }
617 
618