1 /*	$NetBSD: smbfs_smb.c,v 1.47 2014/12/21 10:48:53 hannken Exp $	*/
2 
3 /*-
4  * Copyright (c) 2003 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Jaromir Dolecek.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * Copyright (c) 2000-2001 Boris Popov
34  * All rights reserved.
35  *
36  * Redistribution and use in source and binary forms, with or without
37  * modification, are permitted provided that the following conditions
38  * are met:
39  * 1. Redistributions of source code must retain the above copyright
40  *    notice, this list of conditions and the following disclaimer.
41  * 2. Redistributions in binary form must reproduce the above copyright
42  *    notice, this list of conditions and the following disclaimer in the
43  *    documentation and/or other materials provided with the distribution.
44  * 3. All advertising materials mentioning features or use of this software
45  *    must display the following acknowledgement:
46  *    This product includes software developed by Boris Popov.
47  * 4. Neither the name of the author nor the names of any co-contributors
48  *    may be used to endorse or promote products derived from this software
49  *    without specific prior written permission.
50  *
51  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
52  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
55  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61  * SUCH DAMAGE.
62  *
63  * FreeBSD: src/sys/fs/smbfs/smbfs_smb.c,v 1.3 2001/12/10 08:09:46 obrien Exp
64  */
65 
66 #include <sys/cdefs.h>
67 __KERNEL_RCSID(0, "$NetBSD: smbfs_smb.c,v 1.47 2014/12/21 10:48:53 hannken Exp $");
68 
69 #include <sys/param.h>
70 #include <sys/systm.h>
71 #include <sys/kernel.h>
72 #include <sys/malloc.h>
73 #include <sys/proc.h>
74 #include <sys/lock.h>
75 #include <sys/vnode.h>
76 #include <sys/mbuf.h>
77 #include <sys/mount.h>
78 
79 #ifdef USE_MD5_HASH
80 #include <sys/md5.h>
81 #endif
82 
83 #include <netsmb/smb.h>
84 #include <netsmb/smb_subr.h>
85 #include <netsmb/smb_rq.h>
86 #include <netsmb/smb_conn.h>
87 
88 #include <fs/smbfs/smbfs.h>
89 #include <fs/smbfs/smbfs_node.h>
90 #include <fs/smbfs/smbfs_subr.h>
91 
92 /*
93  * Lack of inode numbers leads us to the problem of generating them.
94  * Partially this problem can be solved by having a dir/file cache
95  * with inode numbers generated from the incremented by one counter.
96  * However this way will require too much kernel memory, gives all
97  * sorts of locking and consistency problems, not to mentinon counter overflows.
98  * So, I'm decided to use a hash function to generate pseudo random (and unique)
99  * inode numbers.
100  */
101 static long
smbfs_getino(struct smbnode * dnp,const char * name,int nmlen)102 smbfs_getino(struct smbnode *dnp, const char *name, int nmlen)
103 {
104 #ifdef USE_MD5_HASH
105 	MD5_CTX md5;
106 	u_int32_t state[4];
107 	long ino;
108 	int i;
109 
110 	MD5Init(&md5);
111 	MD5Update(&md5, name, nmlen);
112 	MD5Final((u_char *)state, &md5);
113 	for (i = 0, ino = 0; i < 4; i++)
114 		ino += state[i];
115 	return dnp->n_ino + ino;
116 #endif
117 	u_int32_t ino;
118 
119 	ino = dnp->n_ino + hash32_strn(name, nmlen, HASH32_STR_INIT);
120 	if (ino <= 2)
121 		ino += 3;
122 	return ino;
123 }
124 
125 static int
smbfs_smb_lockandx(struct smbnode * np,int op,void * id,off_t start,off_t end,struct smb_cred * scred)126 smbfs_smb_lockandx(struct smbnode *np, int op, void *id, off_t start, off_t end,
127 	struct smb_cred *scred)
128 {
129 	struct smb_share *ssp = np->n_mount->sm_share;
130 	struct smb_rq *rqp;
131 	struct mbchain *mbp;
132 	u_char ltype = 0;
133 	int error;
134 
135 	if (op == SMB_LOCK_SHARED)
136 		ltype |= SMB_LOCKING_ANDX_SHARED_LOCK;
137 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_LOCKING_ANDX, scred, &rqp);
138 	if (error)
139 		return error;
140 	smb_rq_getrequest(rqp, &mbp);
141 	smb_rq_wstart(rqp);
142 	mb_put_uint8(mbp, 0xff);	/* secondary command */
143 	mb_put_uint8(mbp, 0);		/* MBZ */
144 	mb_put_uint16le(mbp, 0);
145 	mb_put_mem(mbp, (void *)&np->n_fid, 2, MB_MSYSTEM);
146 	mb_put_uint8(mbp, ltype);	/* locktype */
147 	mb_put_uint8(mbp, 0);		/* oplocklevel - 0 seems is NO_OPLOCK */
148 	mb_put_uint32le(mbp, 0);	/* timeout - break immediately */
149 	mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 1 : 0);
150 	mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 0 : 1);
151 	smb_rq_wend(rqp);
152 	smb_rq_bstart(rqp);
153 	mb_put_uint16le(mbp, (((long) id) & 0xffff));	/* process ID */
154 	mb_put_uint32le(mbp, start);
155 	mb_put_uint32le(mbp, end - start);
156 	smb_rq_bend(rqp);
157 	error = smb_rq_simple(rqp);
158 	smb_rq_done(rqp);
159 	return error;
160 }
161 
162 int
smbfs_smb_lock(struct smbnode * np,int op,void * id,off_t start,off_t end,struct smb_cred * scred)163 smbfs_smb_lock(struct smbnode *np, int op, void *id,
164 	off_t start, off_t end,	struct smb_cred *scred)
165 {
166 	struct smb_share *ssp = np->n_mount->sm_share;
167 
168 	if (SMB_DIALECT(SSTOVC(ssp)) < SMB_DIALECT_LANMAN1_0)
169 		/*
170 		 * TODO: use LOCK_BYTE_RANGE here.
171 		 */
172 		return EINVAL;
173 	else
174 		return smbfs_smb_lockandx(np, op, id, start, end, scred);
175 }
176 
177 int
smbfs_smb_statvfs(struct smb_share * ssp,struct statvfs * sbp,struct smb_cred * scred)178 smbfs_smb_statvfs(struct smb_share *ssp, struct statvfs *sbp,
179 	struct smb_cred *scred)
180 {
181 	unsigned long bsize;	/* Block (allocation unit) size */
182 	unsigned long bavail, bfree;
183 
184 	/*
185 	 * The SMB request work with notion of sector size and
186 	 * allocation units. Allocation unit is what 'block'
187 	 * means in Unix context, sector size might be HW sector size.
188 	 */
189 
190 	if (SMB_DIALECT(SSTOVC(ssp)) >= SMB_DIALECT_LANMAN2_0) {
191 		struct smb_t2rq *t2p;
192 		struct mbchain *mbp;
193 		struct mdchain *mdp;
194 		u_int16_t secsz;
195 		u_int32_t units, bpu, funits;
196 		int error;
197 
198 		error = smb_t2_alloc(SSTOCP(ssp),
199 		    SMB_TRANS2_QUERY_FS_INFORMATION, scred, &t2p);
200 		if (error)
201 			return error;
202 		mbp = &t2p->t2_tparam;
203 		mb_init(mbp);
204 		mb_put_uint16le(mbp, SMB_INFO_ALLOCATION);
205 		t2p->t2_maxpcount = 4;
206 		t2p->t2_maxdcount = 4 * 4 + 2;
207 		error = smb_t2_request(t2p);
208 		if (error) {
209 			smb_t2_done(t2p);
210 			return error;
211 		}
212 		mdp = &t2p->t2_rdata;
213 		md_get_uint32(mdp, NULL);	/* fs id */
214 		md_get_uint32le(mdp, &bpu);	/* Number of sectors per unit */
215 		md_get_uint32le(mdp, &units);	/* Total number of units */
216 		md_get_uint32le(mdp, &funits);	/* Number of available units */
217 		md_get_uint16le(mdp, &secsz);	/* Number of bytes per sector */
218 		smb_t2_done(t2p);
219 
220 		bsize = bpu * secsz;
221 		bavail = units;
222 		bfree = funits;
223 	} else {
224 		struct smb_rq *rqp;
225 		struct mdchain *mdp;
226 		u_int16_t units, bpu, secsz, funits;
227 		int error;
228 
229 		error = smb_rq_alloc(SSTOCP(ssp),
230 		    SMB_COM_QUERY_INFORMATION_DISK, scred, &rqp);
231 		if (error)
232 			return error;
233 		smb_rq_wstart(rqp);
234 		smb_rq_wend(rqp);
235 		smb_rq_bstart(rqp);
236 		smb_rq_bend(rqp);
237 		error = smb_rq_simple(rqp);
238 		if (error) {
239 			smb_rq_done(rqp);
240 			return error;
241 		}
242 		smb_rq_getreply(rqp, &mdp);
243 		md_get_uint16le(mdp, &units);	/* Total units per server */
244 		md_get_uint16le(mdp, &bpu);	/* Blocks per allocation unit */
245 		md_get_uint16le(mdp, &secsz);	/* Block size (in bytes) */
246 		md_get_uint16le(mdp, &funits);	/* Number of free units */
247 		smb_rq_done(rqp);
248 
249 		bsize = bpu * secsz;
250 		bavail = units;
251 		bfree = funits;
252 	}
253 
254 	sbp->f_bsize = bsize;		/* fundamental file system block size */
255 	sbp->f_frsize = bsize;		/* fundamental file system frag size */
256 	sbp->f_iosize = bsize;		/* optimal I/O size */
257 	sbp->f_blocks = bavail;		/* total data blocks in file system */
258 	sbp->f_bfree = bfree;		/* free blocks in fs */
259 	sbp->f_bresvd = 0;		/* reserved blocks in fs */
260 	sbp->f_bavail= bfree;		/* free blocks avail to non-superuser */
261 	sbp->f_files = 0xffff;		/* total file nodes in file system */
262 	sbp->f_ffree = 0xffff;		/* free file nodes to non-superuser */
263 	sbp->f_favail = 0xffff;		/* free file nodes in fs */
264 	sbp->f_fresvd = 0;		/* reserved file nodes in fs */
265 	return 0;
266 }
267 
268 static int
smbfs_smb_seteof(struct smbnode * np,int64_t newsize,struct smb_cred * scred)269 smbfs_smb_seteof(struct smbnode *np, int64_t newsize, struct smb_cred *scred)
270 {
271 	struct smb_t2rq *t2p;
272 	struct smb_share *ssp = np->n_mount->sm_share;
273 	struct mbchain *mbp;
274 	int error;
275 
276 	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
277 	    scred, &t2p);
278 	if (error)
279 		return error;
280 	mbp = &t2p->t2_tparam;
281 	mb_init(mbp);
282 	mb_put_mem(mbp, (void *)&np->n_fid, 2, MB_MSYSTEM);
283 	mb_put_uint16le(mbp, SMB_SET_FILE_END_OF_FILE_INFO);
284 	mb_put_uint32le(mbp, 0);
285 	mbp = &t2p->t2_tdata;
286 	mb_init(mbp);
287 	mb_put_int64le(mbp, newsize);
288 	mb_put_uint32le(mbp, 0);			/* padding */
289 	mb_put_uint16le(mbp, 0);
290 	t2p->t2_maxpcount = 2;
291 	t2p->t2_maxdcount = 0;
292 	error = smb_t2_request(t2p);
293 	smb_t2_done(t2p);
294 	return error;
295 }
296 
297 int
smbfs_smb_setfsize(struct smbnode * np,u_quad_t newsize,struct smb_cred * scred)298 smbfs_smb_setfsize(struct smbnode *np, u_quad_t newsize,
299 		   struct smb_cred *scred)
300 {
301 	struct smb_share *ssp = np->n_mount->sm_share;
302 	struct smb_rq *rqp;
303 	struct mbchain *mbp;
304 	int error;
305 
306 	if (newsize >= (1LL << 32)) {
307 		if (!(SMB_CAPS(SSTOVC(ssp)) & SMB_CAP_LARGE_FILES))
308 			return EFBIG;
309 		return smbfs_smb_seteof(np, (int64_t)newsize, scred);
310 	}
311 
312 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE, scred, &rqp);
313 	if (error)
314 		return error;
315 	smb_rq_getrequest(rqp, &mbp);
316 	smb_rq_wstart(rqp);
317 	mb_put_mem(mbp, (void *)&np->n_fid, 2, MB_MSYSTEM);
318 	mb_put_uint16le(mbp, 0);
319 	mb_put_uint32le(mbp, newsize);
320 	mb_put_uint16le(mbp, 0);
321 	smb_rq_wend(rqp);
322 	smb_rq_bstart(rqp);
323 	mb_put_uint8(mbp, SMB_DT_DATA);
324 	mb_put_uint16le(mbp, 0);
325 	smb_rq_bend(rqp);
326 	error = smb_rq_simple(rqp);
327 	smb_rq_done(rqp);
328 	return error;
329 }
330 
331 
332 /*
333  * Set DOS file attributes. mtime should be NULL for dialects above lm10
334  */
335 int
smbfs_smb_setpattr(struct smbnode * np,u_int16_t attr,struct timespec * mtime,struct smb_cred * scred)336 smbfs_smb_setpattr(struct smbnode *np, u_int16_t attr, struct timespec *mtime,
337 	struct smb_cred *scred)
338 {
339 	struct smb_rq *rqp;
340 	struct smb_share *ssp = np->n_mount->sm_share;
341 	struct mbchain *mbp;
342 	u_long xtime;
343 	int error, svtz;
344 
345 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_SET_INFORMATION, scred, &rqp);
346 	if (error)
347 		return error;
348 	svtz = SSTOVC(ssp)->vc_sopt.sv_tz;
349 	smb_rq_getrequest(rqp, &mbp);
350 	smb_rq_wstart(rqp);
351 	mb_put_uint16le(mbp, attr);
352 	if (mtime) {
353 		smb_time_local2server(mtime, svtz, &xtime);
354 	} else
355 		xtime = 0;
356 	mb_put_uint32le(mbp, xtime);		/* mtime */
357 	mb_put_mem(mbp, NULL, 5 * 2, MB_MZERO);
358 	smb_rq_wend(rqp);
359 	smb_rq_bstart(rqp);
360 	mb_put_uint8(mbp, SMB_DT_ASCII);
361 	do {
362 		error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
363 		if (error)
364 			break;
365 		mb_put_uint8(mbp, SMB_DT_ASCII);
366 		mb_put_uint8(mbp, 0);
367 		smb_rq_bend(rqp);
368 		error = smb_rq_simple(rqp);
369 		if (error)
370 			break;
371 	} while(0);
372 	smb_rq_done(rqp);
373 	return error;
374 }
375 
376 /*
377  * Note, win95 doesn't support this call.
378  */
379 int
smbfs_smb_setptime2(struct smbnode * np,struct timespec * mtime,struct timespec * atime,int attr,struct smb_cred * scred)380 smbfs_smb_setptime2(struct smbnode *np, struct timespec *mtime,
381 	struct timespec *atime, int attr, struct smb_cred *scred)
382 {
383 	struct smb_t2rq *t2p;
384 	struct smb_share *ssp = np->n_mount->sm_share;
385 	struct smb_vc *vcp = SSTOVC(ssp);
386 	struct mbchain *mbp;
387 	u_int16_t xdate, xtime;
388 	int error, tzoff;
389 
390 	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION,
391 	    scred, &t2p);
392 	if (error)
393 		return error;
394 	mbp = &t2p->t2_tparam;
395 	mb_init(mbp);
396 	mb_put_uint16le(mbp, SMB_INFO_STANDARD);
397 	mb_put_uint32le(mbp, 0);		/* MBZ */
398 	error = smbfs_fullpath(mbp, vcp, np, NULL, 0);
399 	if (error) {
400 		smb_t2_done(t2p);
401 		return error;
402 	}
403 	tzoff = vcp->vc_sopt.sv_tz;
404 	mbp = &t2p->t2_tdata;
405 	mb_init(mbp);
406 	mb_put_uint32le(mbp, 0);		/* creation time */
407 	if (atime)
408 		smb_time_unix2dos(atime, tzoff, &xdate, &xtime, NULL);
409 	else
410 		xtime = xdate = 0;
411 	mb_put_uint16le(mbp, xdate);
412 	mb_put_uint16le(mbp, xtime);
413 	if (mtime)
414 		smb_time_unix2dos(mtime, tzoff, &xdate, &xtime, NULL);
415 	else
416 		xtime = xdate = 0;
417 	mb_put_uint16le(mbp, xdate);
418 	mb_put_uint16le(mbp, xtime);
419 	mb_put_uint32le(mbp, 0);		/* file size */
420 	mb_put_uint32le(mbp, 0);		/* allocation unit size */
421 	mb_put_uint16le(mbp, attr);	/* DOS attr */
422 	mb_put_uint32le(mbp, 0);		/* EA size */
423 	t2p->t2_maxpcount = 5 * 2;
424 	t2p->t2_maxdcount = vcp->vc_txmax;
425 	error = smb_t2_request(t2p);
426 	smb_t2_done(t2p);
427 	return error;
428 }
429 
430 /*
431  * NT level. Specially for win9x
432  */
433 int
smbfs_smb_setpattrNT(struct smbnode * np,u_short attr,struct timespec * mtime,struct timespec * atime,struct smb_cred * scred)434 smbfs_smb_setpattrNT(struct smbnode *np, u_short attr, struct timespec *mtime,
435 	struct timespec *atime, struct smb_cred *scred)
436 {
437 	struct smb_t2rq *t2p;
438 	struct smb_share *ssp = np->n_mount->sm_share;
439 	struct smb_vc *vcp = SSTOVC(ssp);
440 	struct mbchain *mbp;
441 	int64_t tm;
442 	int error, tzoff;
443 
444 	/*
445 	 * SMB_SET_FILE_BASIC_INFO isn't supported for
446 	 * SMB_TRANS2_SET_PATH_INFORMATION,
447 	 * so use SMB_SET_FILE_BASIC_INFORMATION instead,
448 	 * but it requires SMB_CAP_INFOLEVEL_PASSTHRU capability.
449 	 */
450 	if ((SMB_CAPS(vcp) & SMB_CAP_INFOLEVEL_PASSTHRU) == 0)
451 		return smbfs_smb_setptime2(np, mtime, atime, attr, scred);
452 
453 	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION,
454 	    scred, &t2p);
455 	if (error)
456 		return error;
457 	mbp = &t2p->t2_tparam;
458 	mb_init(mbp);
459 	mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFORMATION);
460 	mb_put_uint32le(mbp, 0);		/* MBZ */
461 	error = smbfs_fullpath(mbp, vcp, np, NULL, 0);
462 	if (error) {
463 		smb_t2_done(t2p);
464 		return error;
465 	}
466 	tzoff = vcp->vc_sopt.sv_tz;
467 	mbp = &t2p->t2_tdata;
468 	mb_init(mbp);
469 	mb_put_int64le(mbp, 0);		/* creation time */
470 	if (atime) {
471 		smb_time_local2NT(atime, tzoff, &tm);
472 	} else
473 		tm = 0;
474 	mb_put_int64le(mbp, tm);
475 	if (mtime) {
476 		smb_time_local2NT(mtime, tzoff, &tm);
477 	} else
478 		tm = 0;
479 	mb_put_int64le(mbp, tm);
480 	mb_put_int64le(mbp, tm);		/* change time */
481 	mb_put_uint32le(mbp, attr);		/* attr */
482 	mb_put_uint32le(mbp, 0);		/* padding */
483 	t2p->t2_maxpcount = 2;
484 	t2p->t2_maxdcount = 0;
485 	error = smb_t2_request(t2p);
486 	smb_t2_done(t2p);
487 	return error;
488 }
489 
490 /*
491  * Set file atime and mtime. Doesn't supported by core dialect.
492  */
493 int
smbfs_smb_setftime(struct smbnode * np,struct timespec * mtime,struct timespec * atime,struct smb_cred * scred)494 smbfs_smb_setftime(struct smbnode *np, struct timespec *mtime,
495 	struct timespec *atime, struct smb_cred *scred)
496 {
497 	struct smb_rq *rqp;
498 	struct smb_share *ssp = np->n_mount->sm_share;
499 	struct mbchain *mbp;
500 	u_int16_t xdate, xtime;
501 	int error, tzoff;
502 
503 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_SET_INFORMATION2, scred, &rqp);
504 	if (error)
505 		return error;
506 	tzoff = SSTOVC(ssp)->vc_sopt.sv_tz;
507 	smb_rq_getrequest(rqp, &mbp);
508 	smb_rq_wstart(rqp);
509 	mb_put_mem(mbp, (void *)&np->n_fid, 2, MB_MSYSTEM);
510 	mb_put_uint32le(mbp, 0);		/* creation time */
511 
512 	if (atime)
513 		smb_time_unix2dos(atime, tzoff, &xdate, &xtime, NULL);
514 	else
515 		xtime = xdate = 0;
516 	mb_put_uint16le(mbp, xdate);
517 	mb_put_uint16le(mbp, xtime);
518 	if (mtime)
519 		smb_time_unix2dos(mtime, tzoff, &xdate, &xtime, NULL);
520 	else
521 		xtime = xdate = 0;
522 	mb_put_uint16le(mbp, xdate);
523 	mb_put_uint16le(mbp, xtime);
524 	smb_rq_wend(rqp);
525 	smb_rq_bstart(rqp);
526 	smb_rq_bend(rqp);
527 	error = smb_rq_simple(rqp);
528 	SMBSDEBUG(("%d\n", error));
529 	smb_rq_done(rqp);
530 	return error;
531 }
532 
533 /*
534  * Set DOS file attributes.
535  * Looks like this call can be used only if CAP_NT_SMBS bit is on.
536  */
537 int
smbfs_smb_setfattrNT(struct smbnode * np,u_int16_t attr,struct timespec * mtime,struct timespec * atime,struct smb_cred * scred)538 smbfs_smb_setfattrNT(struct smbnode *np, u_int16_t attr, struct timespec *mtime,
539 	struct timespec *atime, struct smb_cred *scred)
540 {
541 	struct smb_t2rq *t2p;
542 	struct smb_share *ssp = np->n_mount->sm_share;
543 	struct mbchain *mbp;
544 	int64_t tm;
545 	int error, svtz;
546 
547 	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
548 	    scred, &t2p);
549 	if (error)
550 		return error;
551 	svtz = SSTOVC(ssp)->vc_sopt.sv_tz;
552 	mbp = &t2p->t2_tparam;
553 	mb_init(mbp);
554 	mb_put_mem(mbp, (void *)&np->n_fid, 2, MB_MSYSTEM); 	/* FID */
555 	mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFO);		/* info level */
556 	mb_put_uint32le(mbp, 0);				/* reserved */
557 	mbp = &t2p->t2_tdata;
558 	mb_init(mbp);
559 	mb_put_int64le(mbp, 0);		/* creation time */
560 	if (atime) {
561 		smb_time_local2NT(atime, svtz, &tm);
562 	} else
563 		tm = 0;
564 	mb_put_int64le(mbp, tm);
565 	if (mtime) {
566 		smb_time_local2NT(mtime, svtz, &tm);
567 	} else
568 		tm = 0;
569 	mb_put_int64le(mbp, tm);
570 	mb_put_int64le(mbp, tm);		/* change time */
571 	mb_put_uint32le(mbp, attr);		/* attr */
572 	mb_put_uint32le(mbp, 0);		/* padding */
573 	t2p->t2_maxpcount = 2;
574 	t2p->t2_maxdcount = 0;
575 	error = smb_t2_request(t2p);
576 	smb_t2_done(t2p);
577 	return error;
578 }
579 
580 
581 int
smbfs_smb_open(struct smbnode * np,int accmode,struct smb_cred * scred)582 smbfs_smb_open(struct smbnode *np, int accmode, struct smb_cred *scred)
583 {
584 	struct smb_rq *rqp;
585 	struct smb_share *ssp = np->n_mount->sm_share;
586 	struct mbchain *mbp;
587 	struct mdchain *mdp;
588 	u_int8_t wc;
589 	u_int16_t fid, wattr, grantedmode;
590 	int error;
591 
592 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_OPEN, scred, &rqp);
593 	if (error)
594 		return error;
595 	smb_rq_getrequest(rqp, &mbp);
596 	smb_rq_wstart(rqp);
597 	mb_put_uint16le(mbp, accmode);
598 	mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
599 	smb_rq_wend(rqp);
600 	smb_rq_bstart(rqp);
601 	mb_put_uint8(mbp, SMB_DT_ASCII);
602 	do {
603 		error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
604 		if (error)
605 			break;
606 		smb_rq_bend(rqp);
607 		error = smb_rq_simple(rqp);
608 		if (error)
609 			break;
610 		smb_rq_getreply(rqp, &mdp);
611 		if (md_get_uint8(mdp, &wc) != 0 || wc != 7) {
612 			error = EBADRPC;
613 			break;
614 		}
615 		md_get_uint16(mdp, &fid);
616 		md_get_uint16le(mdp, &wattr);
617 		md_get_uint32(mdp, NULL);	/* mtime */
618 		md_get_uint32(mdp, NULL);	/* fsize */
619 		md_get_uint16le(mdp, &grantedmode);
620 		/*
621 		 * TODO: refresh attributes from this reply
622 		 */
623 	} while(0);
624 	smb_rq_done(rqp);
625 	if (error)
626 		return error;
627 	np->n_fid = fid;
628 	np->n_rwstate = grantedmode;
629 	return 0;
630 }
631 
632 
633 int
smbfs_smb_close(struct smb_share * ssp,u_int16_t fid,struct timespec * mtime,struct smb_cred * scred)634 smbfs_smb_close(struct smb_share *ssp, u_int16_t fid, struct timespec *mtime,
635 	struct smb_cred *scred)
636 {
637 	struct smb_rq *rqp;
638 	struct mbchain *mbp;
639 	u_long xtime;
640 	int error;
641 
642 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_CLOSE, scred, &rqp);
643 	if (error)
644 		return error;
645 	smb_rq_getrequest(rqp, &mbp);
646 	smb_rq_wstart(rqp);
647 	mb_put_mem(mbp, (void *)&fid, sizeof(fid), MB_MSYSTEM);
648 	if (mtime) {
649 		smb_time_local2server(mtime, SSTOVC(ssp)->vc_sopt.sv_tz, &xtime);
650 	} else
651 		xtime = 0;
652 	mb_put_uint32le(mbp, xtime);
653 	smb_rq_wend(rqp);
654 	smb_rq_bstart(rqp);
655 	smb_rq_bend(rqp);
656 	error = smb_rq_simple(rqp);
657 	smb_rq_done(rqp);
658 	return error;
659 }
660 
661 int
smbfs_smb_create(struct smbnode * dnp,const char * name,int nmlen,struct smb_cred * scred)662 smbfs_smb_create(struct smbnode *dnp, const char *name, int nmlen,
663 	struct smb_cred *scred)
664 {
665 	struct smb_rq *rqp;
666 	struct smb_share *ssp = dnp->n_mount->sm_share;
667 	struct mbchain *mbp;
668 	struct mdchain *mdp;
669 	struct timespec ctime;
670 	u_int8_t wc;
671 	u_int16_t fid;
672 	u_long tm;
673 	int error;
674 
675 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_CREATE_NEW, scred, &rqp);
676 	if (error)
677 		return error;
678 	smb_rq_getrequest(rqp, &mbp);
679 
680 	/* get current time */
681 	getnanotime(&ctime);
682 	smb_time_local2server(&ctime, SSTOVC(ssp)->vc_sopt.sv_tz, &tm);
683 
684 	smb_rq_wstart(rqp);
685 	mb_put_uint16le(mbp, SMB_FA_ARCHIVE);	/* attributes  */
686 	mb_put_uint32le(mbp, tm);
687 	smb_rq_wend(rqp);
688 
689 	smb_rq_bstart(rqp);
690 	mb_put_uint8(mbp, SMB_DT_ASCII);
691 	error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, nmlen);
692 	if (!error) {
693 		smb_rq_bend(rqp);
694 		error = smb_rq_simple(rqp);
695 		if (!error) {
696 			smb_rq_getreply(rqp, &mdp);
697 			md_get_uint8(mdp, &wc);
698 			if (wc == 1)
699 				md_get_uint16(mdp, &fid);
700 			else
701 				error = EBADRPC;
702 		}
703 	}
704 
705 	smb_rq_done(rqp);
706 	if (!error)
707 		smbfs_smb_close(ssp, fid, &ctime, scred);
708 
709 	return (error);
710 }
711 
712 int
smbfs_smb_delete(struct smbnode * np,struct smb_cred * scred)713 smbfs_smb_delete(struct smbnode *np, struct smb_cred *scred)
714 {
715 	struct smb_rq *rqp;
716 	struct smb_share *ssp = np->n_mount->sm_share;
717 	struct mbchain *mbp;
718 	int error;
719 
720 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_DELETE, scred, &rqp);
721 	if (error)
722 		return error;
723 	smb_rq_getrequest(rqp, &mbp);
724 	smb_rq_wstart(rqp);
725 	mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
726 	smb_rq_wend(rqp);
727 	smb_rq_bstart(rqp);
728 	mb_put_uint8(mbp, SMB_DT_ASCII);
729 	error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
730 	if (!error) {
731 		smb_rq_bend(rqp);
732 		error = smb_rq_simple(rqp);
733 	}
734 	smb_rq_done(rqp);
735 	return error;
736 }
737 
738 int
smbfs_smb_rename(struct smbnode * src,struct smbnode * tdnp,const char * tname,int tnmlen,struct smb_cred * scred)739 smbfs_smb_rename(struct smbnode *src, struct smbnode *tdnp,
740 	const char *tname, int tnmlen, struct smb_cred *scred)
741 {
742 	struct smb_rq *rqp;
743 	struct smb_share *ssp = src->n_mount->sm_share;
744 	struct mbchain *mbp;
745 	int error;
746 
747 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_RENAME, scred, &rqp);
748 	if (error)
749 		return error;
750 	smb_rq_getrequest(rqp, &mbp);
751 	smb_rq_wstart(rqp);
752 	mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
753 	smb_rq_wend(rqp);
754 	smb_rq_bstart(rqp);
755 	mb_put_uint8(mbp, SMB_DT_ASCII);
756 	do {
757 		error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0);
758 		if (error)
759 			break;
760 		mb_put_uint8(mbp, SMB_DT_ASCII);
761 		error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen);
762 		if (error)
763 			break;
764 		smb_rq_bend(rqp);
765 		error = smb_rq_simple(rqp);
766 	} while(0);
767 	smb_rq_done(rqp);
768 	return error;
769 }
770 
771 #ifdef notnow
772 int
smbfs_smb_move(struct smbnode * src,struct smbnode * tdnp,const char * tname,int tnmlen,u_int16_t flags,struct smb_cred * scred)773 smbfs_smb_move(struct smbnode *src, struct smbnode *tdnp,
774 	const char *tname, int tnmlen, u_int16_t flags, struct smb_cred *scred)
775 {
776 	struct smb_rq *rqp;
777 	struct smb_share *ssp = src->n_mount->sm_share;
778 	struct mbchain *mbp;
779 	int error;
780 
781 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_MOVE, scred, &rqp);
782 	if (error)
783 		return error;
784 	smb_rq_getrequest(rqp, &mbp);
785 	smb_rq_wstart(rqp);
786 	mb_put_uint16le(mbp, SMB_TID_UNKNOWN);
787 	mb_put_uint16le(mbp, 0x20);	/* delete target file */
788 	mb_put_uint16le(mbp, flags);
789 	smb_rq_wend(rqp);
790 	smb_rq_bstart(rqp);
791 	mb_put_uint8(mbp, SMB_DT_ASCII);
792 	do {
793 		error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0);
794 		if (error)
795 			break;
796 		mb_put_uint8(mbp, SMB_DT_ASCII);
797 		error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen);
798 		if (error)
799 			break;
800 		smb_rq_bend(rqp);
801 		error = smb_rq_simple(rqp);
802 	} while(0);
803 	smb_rq_done(rqp);
804 	return error;
805 }
806 #endif
807 
808 int
smbfs_smb_mkdir(struct smbnode * dnp,const char * name,int len,struct smb_cred * scred)809 smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int len,
810 	struct smb_cred *scred)
811 {
812 	struct smb_rq *rqp;
813 	struct smb_share *ssp = dnp->n_mount->sm_share;
814 	struct mbchain *mbp;
815 	int error;
816 
817 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_CREATE_DIRECTORY, scred, &rqp);
818 	if (error)
819 		return error;
820 	smb_rq_getrequest(rqp, &mbp);
821 	smb_rq_wstart(rqp);
822 	smb_rq_wend(rqp);
823 	smb_rq_bstart(rqp);
824 	mb_put_uint8(mbp, SMB_DT_ASCII);
825 	error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, len);
826 	if (!error) {
827 		smb_rq_bend(rqp);
828 		error = smb_rq_simple(rqp);
829 	}
830 	smb_rq_done(rqp);
831 	return error;
832 }
833 
834 int
smbfs_smb_rmdir(struct smbnode * np,struct smb_cred * scred)835 smbfs_smb_rmdir(struct smbnode *np, struct smb_cred *scred)
836 {
837 	struct smb_rq *rqp;
838 	struct smb_share *ssp = np->n_mount->sm_share;
839 	struct mbchain *mbp;
840 	int error;
841 
842 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_DELETE_DIRECTORY, scred, &rqp);
843 	if (error)
844 		return error;
845 	smb_rq_getrequest(rqp, &mbp);
846 	smb_rq_wstart(rqp);
847 	smb_rq_wend(rqp);
848 	smb_rq_bstart(rqp);
849 	mb_put_uint8(mbp, SMB_DT_ASCII);
850 	error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
851 	if (!error) {
852 		smb_rq_bend(rqp);
853 		error = smb_rq_simple(rqp);
854 	}
855 	smb_rq_done(rqp);
856 	return error;
857 }
858 
859 static int
smbfs_smb_search(struct smbfs_fctx * ctx)860 smbfs_smb_search(struct smbfs_fctx *ctx)
861 {
862 	struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
863 	struct smb_rq *rqp;
864 	struct mbchain *mbp;
865 	struct mdchain *mdp;
866 	u_int8_t wc, bt;
867 	u_int16_t ec, dlen, bc;
868 	int maxent, error;
869 
870 	maxent = min(ctx->f_left, (vcp->vc_txmax - SMB_HDRLEN - 3) / SMB_DENTRYLEN);
871 	if (ctx->f_rq) {
872 		smb_rq_done(ctx->f_rq);
873 		ctx->f_rq = NULL;
874 	}
875 	error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_SEARCH, ctx->f_scred, &rqp);
876 	if (error)
877 		return error;
878 	ctx->f_rq = rqp;
879 	smb_rq_getrequest(rqp, &mbp);
880 	smb_rq_wstart(rqp);
881 	mb_put_uint16le(mbp, maxent);	/* max entries to return */
882 	mb_put_uint16le(mbp, ctx->f_attrmask);
883 	smb_rq_wend(rqp);
884 	smb_rq_bstart(rqp);
885 	mb_put_uint8(mbp, SMB_DT_ASCII);	/* buffer format */
886 	if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
887 		error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, ctx->f_wclen);
888 		if (error)
889 			return error;
890 		mb_put_uint8(mbp, SMB_DT_VARIABLE);
891 		mb_put_uint16le(mbp, 0);	/* context length */
892 		ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
893 	} else {
894 		mb_put_uint8(mbp, 0);	/* file name length */
895 		mb_put_uint8(mbp, SMB_DT_VARIABLE);
896 		mb_put_uint16le(mbp, SMB_SKEYLEN);
897 		mb_put_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
898 	}
899 	smb_rq_bend(rqp);
900 	error = smb_rq_simple(rqp);
901 	if (error) {
902 		if (error == ENOENT)
903 			ctx->f_flags |= SMBFS_RDD_EOF;
904 
905 		return error;
906 	}
907 	smb_rq_getreply(rqp, &mdp);
908 	md_get_uint8(mdp, &wc);
909 	if (wc != 1)
910 		return EBADRPC;
911 	md_get_uint16le(mdp, &ec);
912 	if (ec == 0)
913 		return ENOENT;
914 	ctx->f_ecnt = ec;
915 	md_get_uint16le(mdp, &bc);
916 	if (bc < 3)
917 		return EBADRPC;
918 	bc -= 3;
919 	md_get_uint8(mdp, &bt);
920 	if (bt != SMB_DT_VARIABLE)
921 		return EBADRPC;
922 	md_get_uint16le(mdp, &dlen);
923 	if (dlen != bc || dlen % SMB_DENTRYLEN != 0)
924 		return EBADRPC;
925 	return 0;
926 }
927 
928 static int
smbfs_findopenLM1(struct smbfs_fctx * ctx,struct smbnode * dnp,const char * wildcard,int wclen,int attr,struct smb_cred * scred)929 smbfs_findopenLM1(struct smbfs_fctx *ctx, struct smbnode *dnp,
930     const char *wildcard, int wclen, int attr, struct smb_cred *scred)
931 {
932 	ctx->f_attrmask = attr;
933 	if (wildcard) {
934 		if (wclen == 1 && wildcard[0] == '*') {
935 			ctx->f_wildcard = "*.*";
936 			ctx->f_wclen = 3;
937 		} else {
938 			ctx->f_wildcard = wildcard;
939 			ctx->f_wclen = wclen;
940 		}
941 	} else {
942 		ctx->f_wildcard = NULL;
943 		ctx->f_wclen = 0;
944 	}
945 	ctx->f_name = ctx->f_fname;
946 	return 0;
947 }
948 
949 static int
smbfs_findnextLM1(struct smbfs_fctx * ctx,int limit)950 smbfs_findnextLM1(struct smbfs_fctx *ctx, int limit)
951 {
952 	struct mdchain *mbp;
953 	struct smb_rq *rqp;
954 	char *cp;
955 	u_int8_t battr;
956 	u_int16_t xdate, xtime;
957 	u_int32_t size;
958 	int error;
959 
960 	if (ctx->f_ecnt == 0) {
961 		if (ctx->f_flags & SMBFS_RDD_EOF)
962 			return ENOENT;
963 		ctx->f_left = ctx->f_limit = limit;
964 		error = smbfs_smb_search(ctx);
965 		if (error)
966 			return error;
967 	}
968 	rqp = ctx->f_rq;
969 	smb_rq_getreply(rqp, &mbp);
970 	md_get_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
971 	md_get_uint8(mbp, &battr);
972 	md_get_uint16le(mbp, &xtime);
973 	md_get_uint16le(mbp, &xdate);
974 	md_get_uint32le(mbp, &size);
975 	KASSERT(ctx->f_name == ctx->f_fname);
976 	cp = ctx->f_name;
977 	md_get_mem(mbp, cp, sizeof(ctx->f_fname), MB_MSYSTEM);
978 	cp[sizeof(ctx->f_fname) - 1] = '\0';
979 	cp += strlen(cp) - 1;
980 	while(*cp == ' ' && cp > ctx->f_name)
981 		*cp-- = '\0';
982 	ctx->f_attr.fa_attr = battr;
983 	smb_dos2unixtime(xdate, xtime, 0, rqp->sr_vc->vc_sopt.sv_tz,
984 	    &ctx->f_attr.fa_mtime);
985 	ctx->f_attr.fa_size = size;
986 	ctx->f_nmlen = strlen(ctx->f_name);
987 	ctx->f_ecnt--;
988 	ctx->f_left--;
989 	return 0;
990 }
991 
992 static int
smbfs_findcloseLM1(struct smbfs_fctx * ctx)993 smbfs_findcloseLM1(struct smbfs_fctx *ctx)
994 {
995 	if (ctx->f_rq)
996 		smb_rq_done(ctx->f_rq);
997 	return 0;
998 }
999 
1000 /*
1001  * TRANS2_FIND_FIRST2/NEXT2, used for NT LM12 dialect
1002  */
1003 static int
smbfs_smb_trans2find2(struct smbfs_fctx * ctx)1004 smbfs_smb_trans2find2(struct smbfs_fctx *ctx)
1005 {
1006 	struct smb_t2rq *t2p;
1007 	struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
1008 	struct mbchain *mbp;
1009 	struct mdchain *mdp;
1010 	u_int16_t tw, flags;
1011 	int error;
1012 
1013 	if (ctx->f_t2) {
1014 		smb_t2_done(ctx->f_t2);
1015 		ctx->f_t2 = NULL;
1016 	}
1017 	ctx->f_flags &= ~SMBFS_RDD_GOTRNAME;
1018 	flags = 8 | 2;			/* <resume> | <close if EOS> */
1019 	if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) {
1020 		flags |= 1;		/* close search after this request */
1021 		ctx->f_flags |= SMBFS_RDD_NOCLOSE;
1022 	}
1023 	if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
1024 		error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_FIRST2,
1025 		    ctx->f_scred, &t2p);
1026 		if (error)
1027 			return error;
1028 		ctx->f_t2 = t2p;
1029 		mbp = &t2p->t2_tparam;
1030 		mb_init(mbp);
1031 		mb_put_uint16le(mbp, ctx->f_attrmask);
1032 		mb_put_uint16le(mbp, ctx->f_limit);
1033 		mb_put_uint16le(mbp, flags);
1034 		mb_put_uint16le(mbp, ctx->f_infolevel);
1035 		mb_put_uint32le(mbp, 0);
1036 		error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, ctx->f_wclen);
1037 		if (error)
1038 			return error;
1039 	} else	{
1040 		error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_NEXT2,
1041 		    ctx->f_scred, &t2p);
1042 		if (error)
1043 			return error;
1044 		ctx->f_t2 = t2p;
1045 		mbp = &t2p->t2_tparam;
1046 		mb_init(mbp);
1047 		mb_put_mem(mbp, (void *)&ctx->f_Sid, 2, MB_MSYSTEM);
1048 		mb_put_uint16le(mbp, ctx->f_limit);
1049 		mb_put_uint16le(mbp, ctx->f_infolevel);
1050 		mb_put_uint32le(mbp, 0);		/* resume key */
1051 		mb_put_uint16le(mbp, flags);
1052 		if (ctx->f_rname)
1053 			mb_put_mem(mbp, ctx->f_rname, strlen(ctx->f_rname) + 1, MB_MSYSTEM);
1054 		else
1055 			mb_put_uint8(mbp, 0);	/* resume file name */
1056 #if 0
1057 	struct timeval tv;
1058 	tv.tv_sec = 0;
1059 	tv.tv_usec = 200 * 1000;	/* 200ms */
1060 		if (vcp->vc_flags & SMBC_WIN95) {
1061 			/*
1062 			 * some implementations suggests to sleep here
1063 			 * for 200ms, due to the bug in the Win95.
1064 			 * I've didn't notice any problem, but put code
1065 			 * for it.
1066 			 */
1067 			 tsleep(&flags, PVFS, "fix95", tvtohz(&tv));
1068 		}
1069 #endif
1070 	}
1071 	t2p->t2_maxpcount = 5 * 2;
1072 	t2p->t2_maxdcount = vcp->vc_txmax;
1073 	error = smb_t2_request(t2p);
1074 	if (error)
1075 		return error;
1076 	mdp = &t2p->t2_rparam;
1077 	if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
1078 		if ((error = md_get_uint16(mdp, &ctx->f_Sid)) != 0)
1079 			return error;
1080 		ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
1081 	}
1082 	if ((error = md_get_uint16le(mdp, &tw)) != 0)
1083 		return error;
1084 	ctx->f_ecnt = tw;
1085 	if ((error = md_get_uint16le(mdp, &tw)) != 0)
1086 		return error;
1087 	if (tw)
1088 		ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE;
1089 	if ((error = md_get_uint16le(mdp, &tw)) != 0)
1090 		return error;
1091 	if ((error = md_get_uint16le(mdp, &tw)) != 0)
1092 		return error;
1093 	if (ctx->f_ecnt == 0) {
1094 		ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE;
1095 		return ENOENT;
1096 	}
1097 	ctx->f_rnameofs = tw;
1098 	mdp = &t2p->t2_rdata;
1099 
1100 	KASSERT(mdp->md_top != NULL);
1101 	KASSERT(mdp->md_top->m_len != 0);
1102 
1103 	ctx->f_eofs = 0;
1104 	return 0;
1105 }
1106 
1107 static int
smbfs_smb_findclose2(struct smbfs_fctx * ctx)1108 smbfs_smb_findclose2(struct smbfs_fctx *ctx)
1109 {
1110 	struct smb_rq *rqp;
1111 	struct mbchain *mbp;
1112 	int error;
1113 
1114 	error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_FIND_CLOSE2, ctx->f_scred, &rqp);
1115 	if (error)
1116 		return error;
1117 	smb_rq_getrequest(rqp, &mbp);
1118 	smb_rq_wstart(rqp);
1119 	mb_put_mem(mbp, (void *)&ctx->f_Sid, 2, MB_MSYSTEM);
1120 	smb_rq_wend(rqp);
1121 	smb_rq_bstart(rqp);
1122 	smb_rq_bend(rqp);
1123 	error = smb_rq_simple(rqp);
1124 	smb_rq_done(rqp);
1125 	return error;
1126 }
1127 
1128 static int
smbfs_findopenLM2(struct smbfs_fctx * ctx,struct smbnode * dnp,const char * wildcard,int wclen,int attr,struct smb_cred * scred)1129 smbfs_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp,
1130     const char *wildcard, int wclen, int attr, struct smb_cred *scred)
1131 {
1132 	ctx->f_name = malloc(SMB_MAXNAMLEN * 2, M_SMBFSDATA, M_WAITOK);
1133 	if (ctx->f_name == NULL)
1134 		return ENOMEM;
1135 	ctx->f_infolevel = SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_NTLM0_12 ?
1136 	    SMB_INFO_STANDARD : SMB_FIND_FILE_DIRECTORY_INFO;
1137 	ctx->f_attrmask = attr;
1138 	ctx->f_wildcard = wildcard;
1139 	ctx->f_wclen = wclen;
1140 	return 0;
1141 }
1142 
1143 static int
smbfs_findnextLM2(struct smbfs_fctx * ctx,int limit)1144 smbfs_findnextLM2(struct smbfs_fctx *ctx, int limit)
1145 {
1146 	struct mdchain *mbp;
1147 	struct smb_t2rq *t2p;
1148 	char *cp;
1149 	u_int8_t tb;
1150 	u_int16_t xdate, xtime, wattr;
1151 	u_int32_t size, next, dattr;
1152 	int64_t tmp;
1153 	int error, svtz, cnt, fxsz, nmlen, recsz;
1154 
1155 	if (ctx->f_ecnt == 0) {
1156 		if (ctx->f_flags & SMBFS_RDD_EOF)
1157 			return ENOENT;
1158 		ctx->f_left = ctx->f_limit = limit;
1159 		error = smbfs_smb_trans2find2(ctx);
1160 		if (error)
1161 			return error;
1162 	}
1163 	t2p = ctx->f_t2;
1164 	mbp = &t2p->t2_rdata;
1165 	svtz = SSTOVC(ctx->f_ssp)->vc_sopt.sv_tz;
1166 	switch (ctx->f_infolevel) {
1167 	case SMB_INFO_STANDARD:
1168 		next = 0;
1169 		fxsz = 0;
1170 		md_get_uint16le(mbp, &xdate);
1171 		md_get_uint16le(mbp, &xtime);	/* creation time */
1172 		md_get_uint16le(mbp, &xdate);
1173 		md_get_uint16le(mbp, &xtime);	/* access time */
1174 		smb_dos2unixtime(xdate, xtime, 0, svtz, &ctx->f_attr.fa_atime);
1175 		md_get_uint16le(mbp, &xdate);
1176 		md_get_uint16le(mbp, &xtime);	/* access time */
1177 		smb_dos2unixtime(xdate, xtime, 0, svtz, &ctx->f_attr.fa_mtime);
1178 		md_get_uint32le(mbp, &size);
1179 		ctx->f_attr.fa_size = size;
1180 		md_get_uint32(mbp, NULL);	/* allocation size */
1181 		md_get_uint16le(mbp, &wattr);
1182 		ctx->f_attr.fa_attr = wattr;
1183 		md_get_uint8(mbp, &tb);
1184 		size = nmlen = tb;
1185 		fxsz = 23;
1186 		recsz = next = 24 + nmlen;	/* docs misses zero byte at end */
1187 		break;
1188 	case SMB_FIND_FILE_DIRECTORY_INFO:
1189 		md_get_uint32le(mbp, &next);
1190 		md_get_uint32(mbp, NULL);	/* file index */
1191 		md_get_int64(mbp, NULL);	/* creation time */
1192 		md_get_int64le(mbp, &tmp);
1193 		smb_time_NT2local(tmp, svtz, &ctx->f_attr.fa_atime);
1194 		md_get_int64le(mbp, &tmp);
1195 		smb_time_NT2local(tmp, svtz, &ctx->f_attr.fa_mtime);
1196 		md_get_int64le(mbp, &tmp);
1197 		smb_time_NT2local(tmp, svtz, &ctx->f_attr.fa_ctime);
1198 		md_get_int64le(mbp, &tmp);	/* file size */
1199 		ctx->f_attr.fa_size = tmp;
1200 		md_get_int64(mbp, NULL);	/* real size (should use) */
1201 		md_get_uint32le(mbp, &dattr);	/* EA */
1202 		ctx->f_attr.fa_attr = dattr;
1203 		md_get_uint32le(mbp, &size);	/* name len */
1204 		fxsz = 64;
1205 		recsz = next ? next : fxsz + size;
1206 		break;
1207 	default:
1208 #ifdef DIAGNOSTIC
1209 		panic("smbfs_findnextLM2: unexpected info level %d\n",
1210 		    ctx->f_infolevel);
1211 #else
1212 		return EINVAL;
1213 #endif
1214 	}
1215 	nmlen = min(size, SMB_MAXNAMLEN * 2);
1216 	cp = ctx->f_name;
1217 	error = md_get_mem(mbp, cp, nmlen, MB_MSYSTEM);
1218 	if (error)
1219 		return error;
1220 	if (next) {
1221 		cnt = next - nmlen - fxsz;
1222 		if (cnt > 0)
1223 			md_get_mem(mbp, NULL, cnt, MB_MSYSTEM);
1224 #ifdef DIAGNOSTIC
1225 		else if (cnt < 0)
1226 			panic("smbfs_findnextLM2: out of sync");
1227 #endif
1228 	}
1229 	if (nmlen && cp[nmlen - 1] == 0)
1230 		nmlen--;
1231 	if (nmlen == 0)
1232 		return EBADRPC;
1233 
1234 	next = ctx->f_eofs + recsz;
1235 	if (ctx->f_rnameofs && (ctx->f_flags & SMBFS_RDD_GOTRNAME) == 0 &&
1236 	    (ctx->f_rnameofs >= ctx->f_eofs && ctx->f_rnameofs < next)) {
1237 		/*
1238 		 * Server needs a resume filename.
1239 		 */
1240 		if (ctx->f_rnamelen <= nmlen) {
1241 			if (ctx->f_rname)
1242 				free(ctx->f_rname, M_SMBFSDATA);
1243 			ctx->f_rname = malloc(nmlen + 1, M_SMBFSDATA, M_WAITOK);
1244 			ctx->f_rnamelen = nmlen;
1245 		}
1246 		memcpy(ctx->f_rname, ctx->f_name, nmlen);
1247 		ctx->f_rname[nmlen] = 0;
1248 		ctx->f_flags |= SMBFS_RDD_GOTRNAME;
1249 	}
1250 	ctx->f_nmlen = nmlen;
1251 	ctx->f_eofs = next;
1252 	ctx->f_ecnt--;
1253 	ctx->f_left--;
1254 	return 0;
1255 }
1256 
1257 static int
smbfs_findcloseLM2(struct smbfs_fctx * ctx)1258 smbfs_findcloseLM2(struct smbfs_fctx *ctx)
1259 {
1260 	if (ctx->f_name)
1261 		free(ctx->f_name, M_SMBFSDATA);
1262 	if (ctx->f_t2)
1263 		smb_t2_done(ctx->f_t2);
1264 	if ((ctx->f_flags & SMBFS_RDD_NOCLOSE) == 0)
1265 		smbfs_smb_findclose2(ctx);
1266 	return 0;
1267 }
1268 
1269 int
smbfs_findopen(struct smbnode * dnp,const char * wildcard,int wclen,int attr,struct smb_cred * scred,struct smbfs_fctx ** ctxpp)1270 smbfs_findopen(struct smbnode *dnp, const char *wildcard, int wclen, int attr,
1271 	struct smb_cred *scred, struct smbfs_fctx **ctxpp)
1272 {
1273 	struct smbfs_fctx *ctx;
1274 	int error;
1275 
1276 	ctx = malloc(sizeof(*ctx), M_SMBFSDATA, M_WAITOK|M_ZERO);
1277 	ctx->f_ssp = dnp->n_mount->sm_share;
1278 	ctx->f_dnp = dnp;
1279 	ctx->f_flags = SMBFS_RDD_FINDFIRST;
1280 	ctx->f_scred = scred;
1281 	if (SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_LANMAN2_0 ||
1282 	    (dnp->n_mount->sm_args.flags & SMBFS_MOUNT_NO_LONG)) {
1283 		ctx->f_flags |= SMBFS_RDD_USESEARCH;
1284 		error = smbfs_findopenLM1(ctx, dnp, wildcard, wclen, attr, scred);
1285 	} else
1286 		error = smbfs_findopenLM2(ctx, dnp, wildcard, wclen, attr, scred);
1287 	if (error)
1288 		smbfs_findclose(ctx, scred);
1289 	else
1290 		*ctxpp = ctx;
1291 	return error;
1292 }
1293 
1294 int
smbfs_findnext(struct smbfs_fctx * ctx,int limit,struct smb_cred * scred)1295 smbfs_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scred)
1296 {
1297 	int error;
1298 
1299 	if (limit == 0)
1300 		limit = 1000000;
1301 	else if (limit > 1)
1302 		limit *= 4;	/* empirical */
1303 	ctx->f_scred = scred;
1304 	for (;;) {
1305 		if (ctx->f_flags & SMBFS_RDD_USESEARCH) {
1306 			error = smbfs_findnextLM1(ctx, limit);
1307 		} else
1308 			error = smbfs_findnextLM2(ctx, limit);
1309 		if (error)
1310 			return error;
1311 
1312 		/* Skip '.' and '..' */
1313 		if ((ctx->f_nmlen == 1 && ctx->f_name[0] == '.') ||
1314 		    (ctx->f_nmlen == 2 && ctx->f_name[0] == '.' &&
1315 		     ctx->f_name[1] == '.'))
1316 			continue;
1317 		break;
1318 	}
1319 	smbfs_fname_tolocal(SSTOVC(ctx->f_ssp), ctx->f_name, &ctx->f_nmlen,
1320 	    ctx->f_dnp->n_mount->sm_caseopt);
1321 	ctx->f_attr.fa_ino = smbfs_getino(ctx->f_dnp, ctx->f_name, ctx->f_nmlen);
1322 	return 0;
1323 }
1324 
1325 int
smbfs_findclose(struct smbfs_fctx * ctx,struct smb_cred * scred)1326 smbfs_findclose(struct smbfs_fctx *ctx, struct smb_cred *scred)
1327 {
1328 	ctx->f_scred = scred;
1329 	if (ctx->f_flags & SMBFS_RDD_USESEARCH) {
1330 		smbfs_findcloseLM1(ctx);
1331 	} else
1332 		smbfs_findcloseLM2(ctx);
1333 	if (ctx->f_rname)
1334 		free(ctx->f_rname, M_SMBFSDATA);
1335 	free(ctx, M_SMBFSDATA);
1336 	return 0;
1337 }
1338 
1339 int
smbfs_smb_lookup(struct smbnode * dnp,const char * name,int nmlen,struct smbfattr * fap,struct smb_cred * scred)1340 smbfs_smb_lookup(struct smbnode *dnp, const char *name, int nmlen,
1341 	struct smbfattr *fap, struct smb_cred *scred)
1342 {
1343 	struct smbfs_fctx *ctx;
1344 	int error;
1345 
1346 	if (dnp == NULL || (dnp->n_ino == 2 && name == NULL)) {
1347 		memset(fap, 0, sizeof(*fap));
1348 		fap->fa_attr = SMB_FA_DIR;
1349 		fap->fa_ino = 2;
1350 		return 0;
1351 	}
1352 	if (nmlen == 1 && name[0] == '.') {
1353 		error = smbfs_smb_lookup(dnp, NULL, 0, fap, scred);
1354 		return error;
1355 	} else if (nmlen == 2 && name[0] == '.' && name[1] == '.') {
1356 		error = smbfs_smb_lookup(VTOSMB(dnp->n_parent), NULL, 0,
1357 		    fap, scred);
1358 		printf("%s: knows NOTHING about '..'\n", __func__);
1359 		return error;
1360 	}
1361 	error = smbfs_findopen(dnp, name, nmlen,
1362 	    SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, scred, &ctx);
1363 	if (error)
1364 		return error;
1365 	ctx->f_flags |= SMBFS_RDD_FINDSINGLE;
1366 	error = smbfs_findnext(ctx, 1, scred);
1367 	if (error == 0) {
1368 		*fap = ctx->f_attr;
1369 		if (name == NULL)
1370 			fap->fa_ino = dnp->n_ino;
1371 
1372 		/*
1373 		 * Check the returned file name case exactly
1374 		 * matches requested file name. ctx->f_nmlen is
1375 		 * guaranteed to always match nmlen.
1376 		 */
1377 		if (nmlen > 0 && strncmp(name, ctx->f_name, nmlen) != 0)
1378 			error = ENOENT;
1379 	}
1380 	smbfs_findclose(ctx, scred);
1381 	return error;
1382 }
1383 
1384 /*
1385  * This call is used to fetch FID for directories. For normal files,
1386  * SMB_COM_OPEN is used.
1387  */
1388 int
smbfs_smb_ntcreatex(struct smbnode * np,int accmode,struct smb_cred * scred)1389 smbfs_smb_ntcreatex(struct smbnode *np, int accmode,
1390     struct smb_cred *scred)
1391 {
1392 	struct smb_rq *rqp;
1393 	struct smb_share *ssp = np->n_mount->sm_share;
1394 	struct mbchain *mbp;
1395 	struct mdchain *mdp;
1396 	int error;
1397 	u_int8_t wc;
1398 	u_int8_t *nmlen;
1399 	u_int16_t flen;
1400 
1401 	KASSERT(SMBTOV(np)->v_type == VDIR);
1402 
1403 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_NT_CREATE_ANDX, scred, &rqp);
1404 	if (error)
1405 		return error;
1406 	smb_rq_getrequest(rqp, &mbp);
1407 	smb_rq_wstart(rqp);
1408 	mb_put_uint8(mbp, 0xff);	/* Secondary command; 0xFF = None */
1409 	mb_put_uint8(mbp, 0);		/* Reserved (must be 0) */
1410 	mb_put_uint16le(mbp, 0);	/* Off to next cmd WordCount */
1411 	mb_put_uint8(mbp, 0);		/* Reserved (must be 0) */
1412 	nmlen = mb_reserve(mbp, sizeof(u_int16_t));
1413 					/* Length of Name[] in bytes */
1414 	mb_put_uint32le(mbp, SMB_FL_CANONICAL_PATHNAMES);
1415 					/* Flags - Create bit set */
1416 	mb_put_uint32le(mbp, 0);	/* If nonzero, open relative to this */
1417 	mb_put_uint32le(mbp, NT_FILE_LIST_DIRECTORY);	/* Access mask */
1418 	mb_put_uint32le(mbp, 0);	/* Low 32bit */
1419 	mb_put_uint32le(mbp, 0);	/* Hi 32bit */
1420 					/* Initial allocation size */
1421 	mb_put_uint32le(mbp, 0);	/* File attributes */
1422 	mb_put_uint32le(mbp, NT_FILE_SHARE_READ|NT_FILE_SHARE_WRITE);
1423 					/* Type of share access */
1424 	mb_put_uint32le(mbp, NT_OPEN_EXISTING);
1425 					/* Create disposition - just open */
1426 	mb_put_uint32le(mbp, NT_FILE_DIRECTORY_FILE);
1427 					/* Options to use if creating a file */
1428 	mb_put_uint32le(mbp, 0);	/* Security QOS information */
1429 	mb_put_uint8(mbp, 0);		/* Security tracking mode flags */
1430 	smb_rq_wend(rqp);
1431 	smb_rq_bstart(rqp);
1432 
1433 	error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
1434 	if (error)
1435 		return error;
1436 
1437 	/* Windows XP seems to include the final zero. Better do that too. */
1438 	mb_put_uint8(mbp, 0);
1439 
1440 	flen = mbp->mb_count;
1441 	SMBRQ_PUTLE16(nmlen, flen);
1442 
1443 	smb_rq_bend(rqp);
1444 	error = smb_rq_simple(rqp);
1445 	if (error)
1446 		goto bad;
1447 
1448 	smb_rq_getreply(rqp, &mdp);
1449 	md_get_uint8(mdp, &wc);		/* WordCount - check? */
1450 	md_get_uint8(mdp, NULL);	/* AndXCommand */
1451 	md_get_uint8(mdp, NULL);	/* Reserved - must be zero */
1452 	md_get_uint16(mdp, NULL);	/* Offset to next cmd WordCount */
1453 	md_get_uint8(mdp, NULL);	/* Oplock level granted */
1454 	md_get_uint16(mdp, &np->n_fid);	/* FID */
1455 	/* ignore rest */
1456 
1457 bad:
1458 	smb_rq_done(rqp);
1459 	return (error);
1460 }
1461 
1462 /*
1463  * Setup a request for NT DIRECTORY CHANGE NOTIFY.
1464  */
1465 int
smbfs_smb_nt_dirnotify_setup(struct smbnode * dnp,struct smb_rq ** rqpp,struct smb_cred * scred,void (* notifyhook)(void *),void * notifyarg)1466 smbfs_smb_nt_dirnotify_setup(struct smbnode *dnp, struct smb_rq **rqpp, struct smb_cred *scred, void (*notifyhook)(void *), void *notifyarg)
1467 {
1468 	struct smb_rq *rqp;
1469 	struct smb_share *ssp = dnp->n_mount->sm_share;
1470 	struct mbchain *mbp;
1471 	int error;
1472 
1473 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_NT_TRANSACT, scred, &rqp);
1474 	if (error)
1475 		return error;
1476 	smb_rq_getrequest(rqp, &mbp);
1477 	smb_rq_wstart(rqp);
1478 	mb_put_uint8(mbp, 0xff);	/* Max setup words to return */
1479 	mb_put_uint16le(mbp, 0);	/* Flags (according to Samba) */
1480 	mb_put_uint32le(mbp, 0);	/* Total parameter bytes being sent*/
1481 	mb_put_uint32le(mbp, 0);	/* Total data bytes being sent */
1482 	mb_put_uint32le(mbp, 10*1024); /* Max parameter bytes to return */
1483 	mb_put_uint32le(mbp, 0);	/* Max data bytes to return */
1484 	mb_put_uint32le(mbp, 0);	/* Parameter bytes sent this buffer */
1485 	mb_put_uint32le(mbp, 0);	/* Offset (from h. start) to Param */
1486 	mb_put_uint32le(mbp, 0);	/* Data bytes sent this buffer */
1487 	mb_put_uint32le(mbp, 0);	/* Offset (from h. start) to Data */
1488 	mb_put_uint8(mbp, 4);		/* Count of setup words */
1489 	mb_put_uint16le(mbp, SMB_NTTRANS_NOTIFY_CHANGE); /* Trans func code */
1490 
1491 	/* NT TRANSACT NOTIFY CHANGE: Request Change Notification */
1492 	mb_put_uint32le(mbp,
1493 		FILE_NOTIFY_CHANGE_NAME|FILE_NOTIFY_CHANGE_ATTRIBUTES|
1494 		FILE_NOTIFY_CHANGE_SIZE|FILE_NOTIFY_CHANGE_LAST_WRITE|
1495 		FILE_NOTIFY_CHANGE_CREATION);	/* CompletionFilter */
1496 	mb_put_mem(mbp, (void *)&dnp->n_fid, 2, MB_MSYSTEM);	/* FID */
1497 	mb_put_uint8(mbp, 0);		/* WatchTree - Watch all subdirs too */
1498 	mb_put_uint8(mbp, 0);		/* Reserved - must be zero */
1499 	smb_rq_wend(rqp);
1500 	smb_rq_bstart(rqp);
1501 	smb_rq_bend(rqp);
1502 
1503 	/* No timeout */
1504 	rqp->sr_timo = -1;
1505 	smb_rq_setcallback(rqp, notifyhook, notifyarg);
1506 
1507 	error = smb_rq_enqueue(rqp);
1508 	if (!error)
1509 		*rqpp = rqp;
1510 	else
1511 		smb_rq_done(rqp);
1512 
1513 	return (error);
1514 }
1515 
1516 int
smbfs_smb_nt_dirnotify_fetch(struct smb_rq * rqp,int * hint)1517 smbfs_smb_nt_dirnotify_fetch(struct smb_rq *rqp, int *hint)
1518 {
1519 	int error;
1520 	struct mdchain *mdp;
1521 	u_int8_t sc;
1522 	u_int32_t nextentry;
1523 
1524 	error = smb_rq_reply(rqp);
1525 	if (error) {
1526 		/*
1527 		 * If we get EMSGSIZE, there is already too many notifications
1528 		 * available for the directory, and the internal buffer
1529 		 * overflew. Just flag any possible relevant change.
1530 		 */
1531 		if (error == EMSGSIZE) {
1532 			*hint = NOTE_ATTRIB | NOTE_WRITE;
1533 			error = 0;
1534 		}
1535 
1536 		goto bad;
1537 	}
1538 
1539 	smb_rq_getreply(rqp, &mdp);
1540 
1541 	/* Parse reply */
1542 	error = md_get_mem(mdp, NULL, 4 + (8*4), MB_MZERO);	/* skip */
1543 	if (error)
1544 		goto bad;
1545 
1546 	md_get_uint8(mdp, &sc);			/* SetupCount */
1547 	if (sc > 0)
1548 		md_get_mem(mdp, NULL, sc * sizeof(u_int16_t), MB_MZERO);
1549 	md_get_uint16(mdp, NULL);		/* ByteCount */
1550 	md_get_mem(mdp, NULL, 1 + (sc % 2) * 2, MB_MZERO);	/* Pad */
1551 
1552 	/*
1553 	 * The notify data are blocks of
1554 	 *   ULONG nextentry - offset of next entry from start of this one
1555 	 *   ULONG action - type of notification
1556 	 *   ULONG filenamelen - length of filename in bytes
1557 	 *   WCHAR filename[filenamelen/2] - Unicode filename
1558 	 * nexentry == 0 means last notification, filename is in 16bit LE
1559 	 * unicode
1560 	 */
1561 	*hint = 0;
1562 	do {
1563 		u_int32_t action;
1564 #if 0
1565 		u_int32_t fnlen;
1566 		u_int16_t fnc;
1567 #endif
1568 
1569 		md_get_uint32le(mdp, &nextentry);
1570 		md_get_uint32le(mdp, &action);
1571 		if (nextentry)
1572 			md_get_mem(mdp, NULL, nextentry - 2 * 4, MB_MZERO);
1573 #if 0
1574 		md_get_uint32le(mdp, &fnlen);
1575 
1576 		printf("notify: next %u act %u fnlen %u fname '",
1577 			nextentry, action, fnlen);
1578 		for(; fnlen > 0; fnlen -= 2) {
1579 			md_get_uint16le(mdp, &fnc);
1580 			printf("%c", fnc&0xff);
1581 		}
1582 		printf("'\n");
1583 #endif
1584 
1585 		switch(action) {
1586 		case FILE_ACTION_ADDED:
1587 		case FILE_ACTION_REMOVED:
1588 		case FILE_ACTION_RENAMED_OLD_NAME:
1589 		case FILE_ACTION_RENAMED_NEW_NAME:
1590 			*hint |= NOTE_ATTRIB | NOTE_WRITE;
1591 			break;
1592 
1593 		case FILE_ACTION_MODIFIED:
1594 			*hint |= NOTE_ATTRIB;
1595 			break;
1596 		}
1597 	} while(nextentry > 0);
1598 
1599 bad:
1600 	smb_rq_done(rqp);
1601 	return error;
1602 }
1603 
1604 /*
1605  * Cancel previous SMB, with message ID mid. No reply is generated
1606  * to this one (only the previous message returns with error).
1607  */
1608 int
smbfs_smb_ntcancel(struct smb_connobj * layer,u_int16_t mid,struct smb_cred * scred)1609 smbfs_smb_ntcancel(struct smb_connobj *layer, u_int16_t mid, struct smb_cred *scred)
1610 {
1611 	struct smb_rq *rqp;
1612 	struct mbchain *mbp;
1613 	struct mbuf *m;
1614 	u_int8_t *mp;
1615 	int error;
1616 
1617 	error = smb_rq_alloc(layer, SMB_COM_NT_CANCEL, scred, &rqp);
1618 	if (error)
1619 		return (error);
1620 	rqp->sr_flags |= SMBR_NOWAIT;	/* do not wait for reply */
1621 	smb_rq_getrequest(rqp, &mbp);
1622 
1623 	/*
1624 	 * This is nonstandard. We need to rewrite the just written
1625 	 * mid to different one. Access underlying mbuf directly.
1626 	 * We assume mid is the last thing written smb_rq_alloc()
1627 	 * to request buffer.
1628 	 */
1629 	m = mbp->mb_cur;
1630 	mp = mtod(m, u_int8_t *) + m->m_len - 2;
1631 	SMBRQ_PUTLE16(mp, mid);
1632 	rqp->sr_mid = mid;
1633 
1634 	smb_rq_wstart(rqp);
1635 	smb_rq_wend(rqp);
1636 	smb_rq_bstart(rqp);
1637 	smb_rq_bend(rqp);
1638 
1639 	error = (smb_rq_simple(rqp));
1640 
1641 	/* Discard, there is no real reply */
1642 	smb_rq_done(rqp);
1643 
1644 	return (error);
1645 }
1646