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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 | |