1 /*-
2 * Copyright (c) 2000-2001 Boris Popov
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: releng/10.0/sys/fs/smbfs/smbfs_smb.c 252558 2013-07-03 10:31:45Z davide $
27 */
28 #include <sys/param.h>
29 #include <sys/systm.h>
30 #include <sys/kernel.h>
31 #include <sys/malloc.h>
32 #include <sys/proc.h>
33 #include <sys/lock.h>
34 #include <sys/vnode.h>
35 #include <sys/mbuf.h>
36 #include <sys/mount.h>
37 #include <sys/endian.h>
38
39 #ifdef USE_MD5_HASH
40 #include <sys/md5.h>
41 #endif
42
43 #include <netsmb/smb.h>
44 #include <netsmb/smb_subr.h>
45 #include <netsmb/smb_rq.h>
46 #include <netsmb/smb_conn.h>
47
48 #include <fs/smbfs/smbfs.h>
49 #include <fs/smbfs/smbfs_node.h>
50 #include <fs/smbfs/smbfs_subr.h>
51
52 /*
53 * Lack of inode numbers leads us to the problem of generating them.
54 * Partially this problem can be solved by having a dir/file cache
55 * with inode numbers generated from the incremented by one counter.
56 * However this way will require too much kernel memory, gives all
57 * sorts of locking and consistency problems, not to mentinon counter overflows.
58 * So, I'm decided to use a hash function to generate pseudo random (and unique)
59 * inode numbers.
60 */
61 static long
62 smbfs_getino(struct smbnode *dnp, const char *name, int nmlen)
63 {
64 #ifdef USE_MD5_HASH
65 MD5_CTX md5;
66 u_int32_t state[4];
67 long ino;
68 int i;
69
70 MD5Init(&md5);
71 MD5Update(&md5, name, nmlen);
72 MD5Final((u_char *)state, &md5);
73 for (i = 0, ino = 0; i < 4; i++)
74 ino += state[i];
75 return dnp->n_ino + ino;
76 #endif
77 u_int32_t ino;
78
79 ino = dnp->n_ino + smbfs_hash(name, nmlen);
80 if (ino <= 2)
81 ino += 3;
82 return ino;
83 }
84
85 static int
86 smbfs_smb_lockandx(struct smbnode *np, int op, u_int32_t pid, off_t start, off_t end,
87 struct smb_cred *scred)
88 {
89 struct smb_share *ssp = np->n_mount->sm_share;
90 struct smb_rq *rqp;
91 struct mbchain *mbp;
92 u_char ltype = 0;
93 int error;
94
95 if (op == SMB_LOCK_SHARED)
96 ltype |= SMB_LOCKING_ANDX_SHARED_LOCK;
97
98 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_LOCKING_ANDX, scred, &rqp);
99 if (error)
100 return (error);
101 smb_rq_getrequest(rqp, &mbp);
102 smb_rq_wstart(rqp);
103 mb_put_uint8(mbp, 0xff); /* secondary command */
104 mb_put_uint8(mbp, 0); /* MBZ */
105 mb_put_uint16le(mbp, 0);
106 mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
107 mb_put_uint8(mbp, ltype); /* locktype */
108 mb_put_uint8(mbp, 0); /* oplocklevel - 0 seems is NO_OPLOCK */
109 mb_put_uint32le(mbp, 0); /* timeout - break immediately */
110 mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 1 : 0);
111 mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 0 : 1);
112 smb_rq_wend(rqp);
113 smb_rq_bstart(rqp);
114 mb_put_uint16le(mbp, pid);
115 mb_put_uint32le(mbp, start);
116 mb_put_uint32le(mbp, end - start);
117 smb_rq_bend(rqp);
118 error = smb_rq_simple(rqp);
119 smb_rq_done(rqp);
120 return error;
121 }
122
123 int
124 smbfs_smb_lock(struct smbnode *np, int op, caddr_t id,
125 off_t start, off_t end, struct smb_cred *scred)
126 {
127 struct smb_share *ssp = np->n_mount->sm_share;
128
129 if (SMB_DIALECT(SSTOVC(ssp)) < SMB_DIALECT_LANMAN1_0)
130 /*
131 * TODO: use LOCK_BYTE_RANGE here.
132 */
133 return EINVAL;
134 else
135 return smbfs_smb_lockandx(np, op, (uintptr_t)id, start, end, scred);
136 }
137
138 int
139 smbfs_smb_statfs2(struct smb_share *ssp, struct statfs *sbp,
140 struct smb_cred *scred)
141 {
142 struct smb_t2rq *t2p;
143 struct mbchain *mbp;
144 struct mdchain *mdp;
145 u_int16_t bsize;
146 u_int32_t units, bpu, funits;
147 int error;
148
149 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION,
150 scred, &t2p);
151 if (error)
152 return error;
153 mbp = &t2p->t2_tparam;
154 mb_init(mbp);
155 mb_put_uint16le(mbp, SMB_INFO_ALLOCATION);
156 t2p->t2_maxpcount = 4;
157 t2p->t2_maxdcount = 4 * 4 + 2;
158 error = smb_t2_request(t2p);
159 if (error) {
160 smb_t2_done(t2p);
161 return error;
162 }
163 mdp = &t2p->t2_rdata;
164 md_get_uint32(mdp, NULL); /* fs id */
165 md_get_uint32le(mdp, &bpu);
166 md_get_uint32le(mdp, &units);
167 md_get_uint32le(mdp, &funits);
168 md_get_uint16le(mdp, &bsize);
169 sbp->f_bsize = bpu * bsize; /* fundamental filesystem block size */
170 sbp->f_blocks= units; /* total data blocks in filesystem */
171 sbp->f_bfree = funits; /* free blocks in fs */
172 sbp->f_bavail= funits; /* free blocks avail to non-superuser */
173 sbp->f_files = 0xffff; /* total file nodes in filesystem */
174 sbp->f_ffree = 0xffff; /* free file nodes in fs */
175 smb_t2_done(t2p);
176 return 0;
177 }
178
179 int
180 smbfs_smb_statfs(struct smb_share *ssp, struct statfs *sbp,
181 struct smb_cred *scred)
182 {
183 struct smb_rq *rqp;
184 struct mdchain *mdp;
185 u_int16_t units, bpu, bsize, funits;
186 int error;
187
188 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_QUERY_INFORMATION_DISK,
189 scred, &rqp);
190 if (error)
191 return (error);
192 smb_rq_wstart(rqp);
193 smb_rq_wend(rqp);
194 smb_rq_bstart(rqp);
195 smb_rq_bend(rqp);
196 error = smb_rq_simple(rqp);
197 if (error) {
198 smb_rq_done(rqp);
199 return error;
200 }
201 smb_rq_getreply(rqp, &mdp);
202 md_get_uint16le(mdp, &units);
203 md_get_uint16le(mdp, &bpu);
204 md_get_uint16le(mdp, &bsize);
205 md_get_uint16le(mdp, &funits);
206 sbp->f_bsize = bpu * bsize; /* fundamental filesystem block size */
207 sbp->f_blocks= units; /* total data blocks in filesystem */
208 sbp->f_bfree = funits; /* free blocks in fs */
209 sbp->f_bavail= funits; /* free blocks avail to non-superuser */
210 sbp->f_files = 0xffff; /* total file nodes in filesystem */
211 sbp->f_ffree = 0xffff; /* free file nodes in fs */
212 smb_rq_done(rqp);
213 return 0;
214 }
215
216 static int
217 smbfs_smb_seteof(struct smbnode *np, int64_t newsize, struct smb_cred *scred)
218 {
219 struct smb_t2rq *t2p;
220 struct smb_share *ssp = np->n_mount->sm_share;
221 struct mbchain *mbp;
222 int error;
223
224 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
225 scred, &t2p);
226 if (error)
227 return error;
228 mbp = &t2p->t2_tparam;
229 mb_init(mbp);
230 mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
231 mb_put_uint16le(mbp, SMB_SET_FILE_END_OF_FILE_INFO);
232 mb_put_uint32le(mbp, 0);
233 mbp = &t2p->t2_tdata;
234 mb_init(mbp);
235 mb_put_int64le(mbp, newsize);
236 mb_put_uint32le(mbp, 0); /* padding */
237 mb_put_uint16le(mbp, 0);
238 t2p->t2_maxpcount = 2;
239 t2p->t2_maxdcount = 0;
240 error = smb_t2_request(t2p);
241 smb_t2_done(t2p);
242 return error;
243 }
244
245 static int
246 smb_smb_flush(struct smbnode *np, struct smb_cred *scred)
247 {
248 struct smb_share *ssp = np->n_mount->sm_share;
249 struct smb_rq *rqp;
250 struct mbchain *mbp;
251 int error;
252
253 if ((np->n_flag & NOPEN) == 0 || !SMBTOV(np) ||
254 SMBTOV(np)->v_type != VREG)
255 return 0; /* not a regular open file */
256 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_FLUSH, scred, &rqp);
257 if (error)
258 return (error);
259 smb_rq_getrequest(rqp, &mbp);
260 smb_rq_wstart(rqp);
261 mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
262 smb_rq_wend(rqp);
263 smb_rq_bstart(rqp);
264 smb_rq_bend(rqp);
265 error = smb_rq_simple(rqp);
266 smb_rq_done(rqp);
267 if (!error)
268 np->n_flag &= ~NFLUSHWIRE;
269 return (error);
270 }
271
272 int
273 smbfs_smb_flush(struct smbnode *np, struct smb_cred *scred)
274 {
275 if (np->n_flag & NFLUSHWIRE)
276 return (smb_smb_flush(np, scred));
277 return (0);
278 }
279
280 int
281 smbfs_smb_setfsize(struct smbnode *np, int newsize, struct smb_cred *scred)
282 {
283 struct smb_share *ssp = np->n_mount->sm_share;
284 struct smb_rq *rqp;
285 struct mbchain *mbp;
286 int error;
287
288 if (!smbfs_smb_seteof(np, (int64_t) newsize, scred)) {
289 np->n_flag |= NFLUSHWIRE;
290 return (0);
291 }
292
293 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE, scred, &rqp);
294 if (error)
295 return (error);
296 smb_rq_getrequest(rqp, &mbp);
297 smb_rq_wstart(rqp);
298 mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
299 mb_put_uint16le(mbp, 0);
300 mb_put_uint32le(mbp, newsize);
301 mb_put_uint16le(mbp, 0);
302 smb_rq_wend(rqp);
303 smb_rq_bstart(rqp);
304 mb_put_uint8(mbp, SMB_DT_DATA);
305 mb_put_uint16le(mbp, 0);
306 smb_rq_bend(rqp);
307 error = smb_rq_simple(rqp);
308 smb_rq_done(rqp);
309 return error;
310 }
311
312 int
313 smbfs_smb_query_info(struct smbnode *np, const char *name, int len,
314 struct smbfattr *fap, struct smb_cred *scred)
315 {
316 struct smb_rq *rqp;
317 struct smb_share *ssp = np->n_mount->sm_share;
318 struct mbchain *mbp;
319 struct mdchain *mdp;
320 u_int8_t wc;
321 int error;
322 u_int16_t wattr;
323 u_int32_t lint;
324
325 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_QUERY_INFORMATION, scred,
326 &rqp);
327 if (error)
328 return (error);
329 smb_rq_getrequest(rqp, &mbp);
330 smb_rq_wstart(rqp);
331 smb_rq_wend(rqp);
332 smb_rq_bstart(rqp);
333 mb_put_uint8(mbp, SMB_DT_ASCII);
334 do {
335 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, len);
336 if (error)
337 break;
338 smb_rq_bend(rqp);
339 error = smb_rq_simple(rqp);
340 if (error)
341 break;
342 smb_rq_getreply(rqp, &mdp);
343 if (md_get_uint8(mdp, &wc) != 0 || wc != 10) {
344 error = EBADRPC;
345 break;
346 }
347 md_get_uint16le(mdp, &wattr);
348 fap->fa_attr = wattr;
349 /*
350 * Be careful using the time returned here, as
351 * with FAT on NT4SP6, at least, the time returned is low
352 * 32 bits of 100s of nanoseconds (since 1601) so it rolls
353 * over about every seven minutes!
354 */
355 md_get_uint32le(mdp, &lint); /* specs: secs since 1970 */
356 if (lint) /* avoid bogus zero returns */
357 smb_time_server2local(lint, SSTOVC(ssp)->vc_sopt.sv_tz,
358 &fap->fa_mtime);
359 md_get_uint32le(mdp, &lint);
360 fap->fa_size = lint;
361 } while(0);
362 smb_rq_done(rqp);
363 return error;
364 }
365
366 /*
367 * Set DOS file attributes. mtime should be NULL for dialects above lm10
368 */
369 int
370 smbfs_smb_setpattr(struct smbnode *np, u_int16_t attr, struct timespec *mtime,
371 struct smb_cred *scred)
372 {
373 struct smb_rq *rqp;
374 struct smb_share *ssp = np->n_mount->sm_share;
375 struct mbchain *mbp;
376 u_long time;
377 int error, svtz;
378
379 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_SET_INFORMATION, scred,
380 &rqp);
381 if (error)
382 return (error);
383 svtz = SSTOVC(ssp)->vc_sopt.sv_tz;
384 smb_rq_getrequest(rqp, &mbp);
385 smb_rq_wstart(rqp);
386 mb_put_uint16le(mbp, attr);
387 if (mtime) {
388 smb_time_local2server(mtime, svtz, &time);
389 } else
390 time = 0;
391 mb_put_uint32le(mbp, time); /* mtime */
392 mb_put_mem(mbp, NULL, 5 * 2, MB_MZERO);
393 smb_rq_wend(rqp);
394 smb_rq_bstart(rqp);
395 mb_put_uint8(mbp, SMB_DT_ASCII);
396 do {
397 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
398 if (error)
399 break;
400 mb_put_uint8(mbp, SMB_DT_ASCII);
401 if (SMB_UNICODE_STRINGS(SSTOVC(ssp))) {
402 mb_put_padbyte(mbp);
403 mb_put_uint8(mbp, 0); /* 1st byte of NULL Unicode char */
404 }
405 mb_put_uint8(mbp, 0);
406 smb_rq_bend(rqp);
407 error = smb_rq_simple(rqp);
408 if (error) {
409 SMBERROR("smb_rq_simple(rqp) => error %d\n", error);
410 break;
411 }
412 } while(0);
413 smb_rq_done(rqp);
414 return error;
415 }
416
417 /*
418 * Note, win95 doesn't support this call.
419 */
420 int
421 smbfs_smb_setptime2(struct smbnode *np, struct timespec *mtime,
422 struct timespec *atime, int attr, struct smb_cred *scred)
423 {
424 struct smb_t2rq *t2p;
425 struct smb_share *ssp = np->n_mount->sm_share;
426 struct smb_vc *vcp = SSTOVC(ssp);
427 struct mbchain *mbp;
428 u_int16_t date, time;
429 int error, tzoff;
430
431 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION,
432 scred, &t2p);
433 if (error)
434 return error;
435 mbp = &t2p->t2_tparam;
436 mb_init(mbp);
437 mb_put_uint16le(mbp, SMB_INFO_STANDARD);
438 mb_put_uint32le(mbp, 0); /* MBZ */
439 /* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */
440 error = smbfs_fullpath(mbp, vcp, np, NULL, 0);
441 if (error) {
442 smb_t2_done(t2p);
443 return error;
444 }
445 tzoff = vcp->vc_sopt.sv_tz;
446 mbp = &t2p->t2_tdata;
447 mb_init(mbp);
448 mb_put_uint32le(mbp, 0); /* creation time */
449 if (atime)
450 smb_time_unix2dos(atime, tzoff, &date, &time, NULL);
451 else
452 time = date = 0;
453 mb_put_uint16le(mbp, date);
454 mb_put_uint16le(mbp, time);
455 if (mtime)
456 smb_time_unix2dos(mtime, tzoff, &date, &time, NULL);
457 else
458 time = date = 0;
459 mb_put_uint16le(mbp, date);
460 mb_put_uint16le(mbp, time);
461 mb_put_uint32le(mbp, 0); /* file size */
462 mb_put_uint32le(mbp, 0); /* allocation unit size */
463 mb_put_uint16le(mbp, attr); /* DOS attr */
464 mb_put_uint32le(mbp, 0); /* EA size */
465 t2p->t2_maxpcount = 5 * 2;
466 t2p->t2_maxdcount = vcp->vc_txmax;
467 error = smb_t2_request(t2p);
468 smb_t2_done(t2p);
469 return error;
470 }
471
472 /*
473 * NT level. Specially for win9x
474 */
475 int
476 smbfs_smb_setpattrNT(struct smbnode *np, u_short attr, struct timespec *mtime,
477 struct timespec *atime, struct smb_cred *scred)
478 {
479 struct smb_t2rq *t2p;
480 struct smb_share *ssp = np->n_mount->sm_share;
481 struct smb_vc *vcp = SSTOVC(ssp);
482 struct mbchain *mbp;
483 int64_t tm;
484 int error, tzoff;
485
486 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION,
487 scred, &t2p);
488 if (error)
489 return error;
490 mbp = &t2p->t2_tparam;
491 mb_init(mbp);
492 mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFO);
493 mb_put_uint32le(mbp, 0); /* MBZ */
494 /* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */
495 error = smbfs_fullpath(mbp, vcp, np, NULL, 0);
496 if (error) {
497 smb_t2_done(t2p);
498 return error;
499 }
500 tzoff = vcp->vc_sopt.sv_tz;
501 mbp = &t2p->t2_tdata;
502 mb_init(mbp);
503 mb_put_int64le(mbp, 0); /* creation time */
504 if (atime) {
505 smb_time_local2NT(atime, tzoff, &tm);
506 } else
507 tm = 0;
508 mb_put_int64le(mbp, tm);
509 if (mtime) {
510 smb_time_local2NT(mtime, tzoff, &tm);
511 } else
512 tm = 0;
513 mb_put_int64le(mbp, tm);
514 mb_put_int64le(mbp, tm); /* change time */
515 mb_put_uint32le(mbp, attr); /* attr */
516 t2p->t2_maxpcount = 24;
517 t2p->t2_maxdcount = 56;
518 error = smb_t2_request(t2p);
519 smb_t2_done(t2p);
520 return error;
521 }
522
523 /*
524 * Set file atime and mtime. Doesn't supported by core dialect.
525 */
526 int
527 smbfs_smb_setftime(struct smbnode *np, struct timespec *mtime,
528 struct timespec *atime, struct smb_cred *scred)
529 {
530 struct smb_rq *rqp;
531 struct smb_share *ssp = np->n_mount->sm_share;
532 struct mbchain *mbp;
533 u_int16_t date, time;
534 int error, tzoff;
535
536 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_SET_INFORMATION2, scred,
537 &rqp);
538 if (error)
539 return (error);
540 tzoff = SSTOVC(ssp)->vc_sopt.sv_tz;
541 smb_rq_getrequest(rqp, &mbp);
542 smb_rq_wstart(rqp);
543 mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
544 mb_put_uint32le(mbp, 0); /* creation time */
545
546 if (atime)
547 smb_time_unix2dos(atime, tzoff, &date, &time, NULL);
548 else
549 time = date = 0;
550 mb_put_uint16le(mbp, date);
551 mb_put_uint16le(mbp, time);
552 if (mtime)
553 smb_time_unix2dos(mtime, tzoff, &date, &time, NULL);
554 else
555 time = date = 0;
556 mb_put_uint16le(mbp, date);
557 mb_put_uint16le(mbp, time);
558 smb_rq_wend(rqp);
559 smb_rq_bstart(rqp);
560 smb_rq_bend(rqp);
561 error = smb_rq_simple(rqp);
562 SMBSDEBUG("%d\n", error);
563 smb_rq_done(rqp);
564 return error;
565 }
566
567 /*
568 * Set DOS file attributes.
569 * Looks like this call can be used only if SMB_CAP_NT_SMBS bit is on.
570 */
571 int
572 smbfs_smb_setfattrNT(struct smbnode *np, u_int16_t attr, struct timespec *mtime,
573 struct timespec *atime, struct smb_cred *scred)
574 {
575 struct smb_t2rq *t2p;
576 struct smb_share *ssp = np->n_mount->sm_share;
577 struct mbchain *mbp;
578 int64_t tm;
579 int error, svtz;
580
581 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
582 scred, &t2p);
583 if (error)
584 return error;
585 svtz = SSTOVC(ssp)->vc_sopt.sv_tz;
586 mbp = &t2p->t2_tparam;
587 mb_init(mbp);
588 mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
589 mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFO);
590 mb_put_uint32le(mbp, 0);
591 mbp = &t2p->t2_tdata;
592 mb_init(mbp);
593 mb_put_int64le(mbp, 0); /* creation time */
594 if (atime) {
595 smb_time_local2NT(atime, svtz, &tm);
596 } else
597 tm = 0;
598 mb_put_int64le(mbp, tm);
599 if (mtime) {
600 smb_time_local2NT(mtime, svtz, &tm);
601 } else
602 tm = 0;
603 mb_put_int64le(mbp, tm);
604 mb_put_int64le(mbp, tm); /* change time */
605 mb_put_uint16le(mbp, attr);
606 mb_put_uint32le(mbp, 0); /* padding */
607 mb_put_uint16le(mbp, 0);
608 t2p->t2_maxpcount = 2;
609 t2p->t2_maxdcount = 0;
610 error = smb_t2_request(t2p);
611 smb_t2_done(t2p);
612 return error;
613 }
614
615
616 int
617 smbfs_smb_open(struct smbnode *np, int accmode, struct smb_cred *scred)
618 {
619 struct smb_rq *rqp;
620 struct smb_share *ssp = np->n_mount->sm_share;
621 struct mbchain *mbp;
622 struct mdchain *mdp;
623 u_int8_t wc;
624 u_int16_t fid, wattr, grantedmode;
625 int error;
626
627 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_OPEN, scred, &rqp);
628 if (error)
629 return (error);
630 smb_rq_getrequest(rqp, &mbp);
631 smb_rq_wstart(rqp);
632 mb_put_uint16le(mbp, accmode);
633 mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
634 smb_rq_wend(rqp);
635 smb_rq_bstart(rqp);
636 mb_put_uint8(mbp, SMB_DT_ASCII);
637 do {
638 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
639 if (error)
640 break;
641 smb_rq_bend(rqp);
642 error = smb_rq_simple(rqp);
643 if (error)
644 break;
645 smb_rq_getreply(rqp, &mdp);
646 if (md_get_uint8(mdp, &wc) != 0 || wc != 7) {
647 error = EBADRPC;
648 break;
649 }
650 md_get_uint16(mdp, &fid);
651 md_get_uint16le(mdp, &wattr);
652 md_get_uint32(mdp, NULL); /* mtime */
653 md_get_uint32(mdp, NULL); /* fsize */
654 md_get_uint16le(mdp, &grantedmode);
655 /*
656 * TODO: refresh attributes from this reply
657 */
658 } while(0);
659 smb_rq_done(rqp);
660 if (error)
661 return error;
662 np->n_fid = fid;
663 np->n_rwstate = grantedmode;
664 return 0;
665 }
666
667
668 int
669 smbfs_smb_close(struct smb_share *ssp, u_int16_t fid, struct timespec *mtime,
670 struct smb_cred *scred)
671 {
672 struct smb_rq *rqp;
673 struct mbchain *mbp;
674 u_long time;
675 int error;
676
677 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_CLOSE, scred, &rqp);
678 if (error)
679 return (error);
680 smb_rq_getrequest(rqp, &mbp);
681 smb_rq_wstart(rqp);
682 mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
683 if (mtime) {
684 smb_time_local2server(mtime, SSTOVC(ssp)->vc_sopt.sv_tz, &time);
685 } else
686 time = 0;
687 mb_put_uint32le(mbp, time);
688 smb_rq_wend(rqp);
689 smb_rq_bstart(rqp);
690 smb_rq_bend(rqp);
691 error = smb_rq_simple(rqp);
692 smb_rq_done(rqp);
693 return error;
694 }
695
696 int
697 smbfs_smb_create(struct smbnode *dnp, const char *name, int nmlen,
698 struct smb_cred *scred)
699 {
700 struct smb_rq *rqp;
701 struct smb_share *ssp = dnp->n_mount->sm_share;
702 struct mbchain *mbp;
703 struct mdchain *mdp;
704 struct timespec ctime;
705 u_int8_t wc;
706 u_int16_t fid;
707 u_long tm;
708 int error;
709
710 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_CREATE, scred, &rqp);
711 if (error)
712 return (error);
713 smb_rq_getrequest(rqp, &mbp);
714 smb_rq_wstart(rqp);
715 mb_put_uint16le(mbp, SMB_FA_ARCHIVE); /* attributes */
716 nanotime(&ctime);
717 smb_time_local2server(&ctime, SSTOVC(ssp)->vc_sopt.sv_tz, &tm);
718 mb_put_uint32le(mbp, tm);
719 smb_rq_wend(rqp);
720 smb_rq_bstart(rqp);
721 mb_put_uint8(mbp, SMB_DT_ASCII);
722 error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, nmlen);
723 if (!error) {
724 smb_rq_bend(rqp);
725 error = smb_rq_simple(rqp);
726 if (!error) {
727 smb_rq_getreply(rqp, &mdp);
728 md_get_uint8(mdp, &wc);
729 if (wc == 1)
730 md_get_uint16(mdp, &fid);
731 else
732 error = EBADRPC;
733 }
734 }
735 smb_rq_done(rqp);
736 if (error)
737 return error;
738 smbfs_smb_close(ssp, fid, &ctime, scred);
739 return error;
740 }
741
742 int
743 smbfs_smb_delete(struct smbnode *np, struct smb_cred *scred)
744 {
745 struct smb_rq *rqp;
746 struct smb_share *ssp = np->n_mount->sm_share;
747 struct mbchain *mbp;
748 int error;
749
750 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_DELETE, scred, &rqp);
751 if (error)
752 return (error);
753 smb_rq_getrequest(rqp, &mbp);
754 smb_rq_wstart(rqp);
755 mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
756 smb_rq_wend(rqp);
757 smb_rq_bstart(rqp);
758 mb_put_uint8(mbp, SMB_DT_ASCII);
759 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
760 if (!error) {
761 smb_rq_bend(rqp);
762 error = smb_rq_simple(rqp);
763 }
764 smb_rq_done(rqp);
765 return error;
766 }
767
768 int
769 smbfs_smb_rename(struct smbnode *src, struct smbnode *tdnp,
770 const char *tname, int tnmlen, struct smb_cred *scred)
771 {
772 struct smb_rq *rqp;
773 struct smb_share *ssp = src->n_mount->sm_share;
774 struct mbchain *mbp;
775 int error;
776
777 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_RENAME, scred, &rqp);
778 if (error)
779 return (error);
780 smb_rq_getrequest(rqp, &mbp);
781 smb_rq_wstart(rqp);
782 mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
783 smb_rq_wend(rqp);
784 smb_rq_bstart(rqp);
785 mb_put_uint8(mbp, SMB_DT_ASCII);
786 do {
787 error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0);
788 if (error)
789 break;
790 mb_put_uint8(mbp, SMB_DT_ASCII);
791 error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen);
792 if (error)
793 break;
794 smb_rq_bend(rqp);
795 error = smb_rq_simple(rqp);
796 } while(0);
797 smb_rq_done(rqp);
798 return error;
799 }
800
801 int
802 smbfs_smb_move(struct smbnode *src, struct smbnode *tdnp,
803 const char *tname, int tnmlen, u_int16_t flags, struct smb_cred *scred)
804 {
805 struct smb_rq *rqp;
806 struct smb_share *ssp = src->n_mount->sm_share;
807 struct mbchain *mbp;
808 int error;
809
810 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_MOVE, scred, &rqp);
811 if (error)
812 return (error);
813 smb_rq_getrequest(rqp, &mbp);
814 smb_rq_wstart(rqp);
815 mb_put_uint16le(mbp, SMB_TID_UNKNOWN);
816 mb_put_uint16le(mbp, 0x20); /* delete target file */
817 mb_put_uint16le(mbp, flags);
818 smb_rq_wend(rqp);
819 smb_rq_bstart(rqp);
820 mb_put_uint8(mbp, SMB_DT_ASCII);
821 do {
822 error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0);
823 if (error)
824 break;
825 mb_put_uint8(mbp, SMB_DT_ASCII);
826 error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen);
827 if (error)
828 break;
829 smb_rq_bend(rqp);
830 error = smb_rq_simple(rqp);
831 } while(0);
832 smb_rq_done(rqp);
833 return error;
834 }
835
836 int
837 smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int len,
838 struct smb_cred *scred)
839 {
840 struct smb_rq *rqp;
841 struct smb_share *ssp = dnp->n_mount->sm_share;
842 struct mbchain *mbp;
843 int error;
844
845 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_CREATE_DIRECTORY, scred,
846 &rqp);
847 if (error)
848 return (error);
849 smb_rq_getrequest(rqp, &mbp);
850 smb_rq_wstart(rqp);
851 smb_rq_wend(rqp);
852 smb_rq_bstart(rqp);
853 mb_put_uint8(mbp, SMB_DT_ASCII);
854 error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, len);
855 if (!error) {
856 smb_rq_bend(rqp);
857 error = smb_rq_simple(rqp);
858 }
859 smb_rq_done(rqp);
860 return error;
861 }
862
863 int
864 smbfs_smb_rmdir(struct smbnode *np, struct smb_cred *scred)
865 {
866 struct smb_rq *rqp;
867 struct smb_share *ssp = np->n_mount->sm_share;
868 struct mbchain *mbp;
869 int error;
870
871 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_DELETE_DIRECTORY, scred,
872 &rqp);
873 if (error)
874 return (error);
875 smb_rq_getrequest(rqp, &mbp);
876 smb_rq_wstart(rqp);
877 smb_rq_wend(rqp);
878 smb_rq_bstart(rqp);
879 mb_put_uint8(mbp, SMB_DT_ASCII);
880 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
881 if (!error) {
882 smb_rq_bend(rqp);
883 error = smb_rq_simple(rqp);
884 }
885 smb_rq_done(rqp);
886 return error;
887 }
888
889 static int
890 smbfs_smb_search(struct smbfs_fctx *ctx)
891 {
892 struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
893 struct smb_rq *rqp;
894 struct mbchain *mbp;
895 struct mdchain *mdp;
896 u_int8_t wc, bt;
897 u_int16_t ec, dlen, bc;
898 int maxent, error, iseof = 0;
899
900 maxent = min(ctx->f_left, (vcp->vc_txmax - SMB_HDRLEN - 3) / SMB_DENTRYLEN);
901 if (ctx->f_rq) {
902 smb_rq_done(ctx->f_rq);
903 ctx->f_rq = NULL;
904 }
905 error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_SEARCH, ctx->f_scred, &rqp);
906 if (error)
907 return (error);
908 ctx->f_rq = rqp;
909 smb_rq_getrequest(rqp, &mbp);
910 smb_rq_wstart(rqp);
911 mb_put_uint16le(mbp, maxent); /* max entries to return */
912 mb_put_uint16le(mbp, ctx->f_attrmask);
913 smb_rq_wend(rqp);
914 smb_rq_bstart(rqp);
915 mb_put_uint8(mbp, SMB_DT_ASCII); /* buffer format */
916 if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
917 error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, ctx->f_wclen);
918 if (error)
919 return error;
920 mb_put_uint8(mbp, SMB_DT_VARIABLE);
921 mb_put_uint16le(mbp, 0); /* context length */
922 ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
923 } else {
924 if (SMB_UNICODE_STRINGS(vcp)) {
925 mb_put_padbyte(mbp);
926 mb_put_uint8(mbp, 0);
927 }
928 mb_put_uint8(mbp, 0); /* file name length */
929 mb_put_uint8(mbp, SMB_DT_VARIABLE);
930 mb_put_uint16le(mbp, SMB_SKEYLEN);
931 mb_put_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
932 }
933 smb_rq_bend(rqp);
934 error = smb_rq_simple(rqp);
935 if (error) {
936 if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnofiles) {
937 error = 0;
938 iseof = 1;
939 ctx->f_flags |= SMBFS_RDD_EOF;
940 } else
941 return error;
942 }
943 smb_rq_getreply(rqp, &mdp);
944 md_get_uint8(mdp, &wc);
945 if (wc != 1)
946 return iseof ? ENOENT : EBADRPC;
947 md_get_uint16le(mdp, &ec);
948 if (ec == 0)
949 return ENOENT;
950 ctx->f_ecnt = ec;
951 md_get_uint16le(mdp, &bc);
952 if (bc < 3)
953 return EBADRPC;
954 bc -= 3;
955 md_get_uint8(mdp, &bt);
956 if (bt != SMB_DT_VARIABLE)
957 return EBADRPC;
958 md_get_uint16le(mdp, &dlen);
959 if (dlen != bc || dlen % SMB_DENTRYLEN != 0)
960 return EBADRPC;
961 return 0;
962 }
963
964 static int
965 smbfs_findopenLM1(struct smbfs_fctx *ctx, struct smbnode *dnp,
966 const char *wildcard, int wclen, int attr, struct smb_cred *scred)
967 {
968 ctx->f_attrmask = attr;
969 if (wildcard) {
970 if (wclen == 1 && wildcard[0] == '*') {
971 ctx->f_wildcard = "*.*";
972 ctx->f_wclen = 3;
973 } else {
974 ctx->f_wildcard = wildcard;
975 ctx->f_wclen = wclen;
976 }
977 } else {
978 ctx->f_wildcard = NULL;
979 ctx->f_wclen = 0;
980 }
981 ctx->f_name = ctx->f_fname;
982 return 0;
983 }
984
985 static int
986 smbfs_findnextLM1(struct smbfs_fctx *ctx, int limit)
987 {
988 struct mdchain *mbp;
989 struct smb_rq *rqp;
990 char *cp;
991 u_int8_t battr;
992 u_int16_t date, time;
993 u_int32_t size;
994 int error;
995
996 if (ctx->f_ecnt == 0) {
997 if (ctx->f_flags & SMBFS_RDD_EOF)
998 return ENOENT;
999 ctx->f_left = ctx->f_limit = limit;
1000 error = smbfs_smb_search(ctx);
1001 if (error)
1002 return error;
1003 }
1004 rqp = ctx->f_rq;
1005 smb_rq_getreply(rqp, &mbp);
1006 md_get_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
1007 md_get_uint8(mbp, &battr);
1008 md_get_uint16le(mbp, &time);
1009 md_get_uint16le(mbp, &date);
1010 md_get_uint32le(mbp, &size);
1011 cp = ctx->f_name;
1012 md_get_mem(mbp, cp, sizeof(ctx->f_fname), MB_MSYSTEM);
1013 cp[sizeof(ctx->f_fname) - 1] = 0;
1014 cp += strlen(cp) - 1;
1015 while (*cp == ' ' && cp >= ctx->f_name)
1016 *cp-- = 0;
1017 ctx->f_attr.fa_attr = battr;
1018 smb_dos2unixtime(date, time, 0, rqp->sr_vc->vc_sopt.sv_tz,
1019 &ctx->f_attr.fa_mtime);
1020 ctx->f_attr.fa_size = size;
1021 ctx->f_nmlen = strlen(ctx->f_name);
1022 ctx->f_ecnt--;
1023 ctx->f_left--;
1024 return 0;
1025 }
1026
1027 static int
1028 smbfs_findcloseLM1(struct smbfs_fctx *ctx)
1029 {
1030 if (ctx->f_rq)
1031 smb_rq_done(ctx->f_rq);
1032 return 0;
1033 }
1034
1035 /*
1036 * TRANS2_FIND_FIRST2/NEXT2, used for NT LM12 dialect
1037 */
1038 static int
1039 smbfs_smb_trans2find2(struct smbfs_fctx *ctx)
1040 {
1041 struct smb_t2rq *t2p;
1042 struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
1043 struct mbchain *mbp;
1044 struct mdchain *mdp;
1045 u_int16_t tw, flags;
1046 int error;
1047
1048 if (ctx->f_t2) {
1049 smb_t2_done(ctx->f_t2);
1050 ctx->f_t2 = NULL;
1051 }
1052 ctx->f_flags &= ~SMBFS_RDD_GOTRNAME;
1053 flags = 8 | 2; /* <resume> | <close if EOS> */
1054 if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) {
1055 flags |= 1; /* close search after this request */
1056 ctx->f_flags |= SMBFS_RDD_NOCLOSE;
1057 }
1058 if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
1059 error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_FIRST2,
1060 ctx->f_scred, &t2p);
1061 if (error)
1062 return error;
1063 ctx->f_t2 = t2p;
1064 mbp = &t2p->t2_tparam;
1065 mb_init(mbp);
1066 mb_put_uint16le(mbp, ctx->f_attrmask);
1067 mb_put_uint16le(mbp, ctx->f_limit);
1068 mb_put_uint16le(mbp, flags);
1069 mb_put_uint16le(mbp, ctx->f_infolevel);
1070 mb_put_uint32le(mbp, 0);
1071 error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, ctx->f_wclen);
1072 if (error)
1073 return error;
1074 } else {
1075 error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_NEXT2,
1076 ctx->f_scred, &t2p);
1077 if (error)
1078 return error;
1079 ctx->f_t2 = t2p;
1080 mbp = &t2p->t2_tparam;
1081 mb_init(mbp);
1082 mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM);
1083 mb_put_uint16le(mbp, ctx->f_limit);
1084 mb_put_uint16le(mbp, ctx->f_infolevel);
1085 mb_put_uint32le(mbp, 0); /* resume key */
1086 mb_put_uint16le(mbp, flags);
1087 if (ctx->f_rname)
1088 mb_put_mem(mbp, ctx->f_rname, ctx->f_rnamelen + 1, MB_MSYSTEM);
1089 else
1090 mb_put_uint8(mbp, 0); /* resume file name */
1091 #if 0
1092 struct timeval tv;
1093 tv.tv_sec = 0;
1094 tv.tv_usec = 200 * 1000; /* 200ms */
1095 if (vcp->vc_flags & SMBC_WIN95) {
1096 /*
1097 * some implementations suggests to sleep here
1098 * for 200ms, due to the bug in the Win95.
1099 * I've didn't notice any problem, but put code
1100 * for it.
1101 */
1102 pause("fix95", tvtohz(&tv));
1103 }
1104 #endif
1105 }
1106 t2p->t2_maxpcount = 5 * 2;
1107 t2p->t2_maxdcount = vcp->vc_txmax;
1108 error = smb_t2_request(t2p);
1109 if (error)
1110 return error;
1111 mdp = &t2p->t2_rparam;
1112 if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
1113 if ((error = md_get_uint16(mdp, &ctx->f_Sid)) != 0)
1114 return error;
1115 ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
1116 }
1117 if ((error = md_get_uint16le(mdp, &tw)) != 0)
1118 return error;
1119 ctx->f_ecnt = tw;
1120 if ((error = md_get_uint16le(mdp, &tw)) != 0)
1121 return error;
1122 if (tw)
1123 ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE;
1124 if ((error = md_get_uint16le(mdp, &tw)) != 0)
1125 return error;
1126 if ((error = md_get_uint16le(mdp, &tw)) != 0)
1127 return error;
1128 if (ctx->f_ecnt == 0) {
1129 ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE;
1130 return ENOENT;
1131 }
1132 ctx->f_rnameofs = tw;
1133 mdp = &t2p->t2_rdata;
1134 if (mdp->md_top == NULL) {
1135 printf("bug: ecnt = %d, but data is NULL (please report)\n", ctx->f_ecnt);
1136 return ENOENT;
1137 }
1138 if (mdp->md_top->m_len == 0) {
1139 printf("bug: ecnt = %d, but m_len = 0 and m_next = %p (please report)\n", ctx->f_ecnt,mbp->mb_top->m_next);
1140 return ENOENT;
1141 }
1142 ctx->f_eofs = 0;
1143 return 0;
1144 }
1145
1146 static int
1147 smbfs_smb_findclose2(struct smbfs_fctx *ctx)
1148 {
1149 struct smb_rq *rqp;
1150 struct mbchain *mbp;
1151 int error;
1152
1153 error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_FIND_CLOSE2,
1154 ctx->f_scred, &rqp);
1155 if (error)
1156 return (error);
1157 smb_rq_getrequest(rqp, &mbp);
1158 smb_rq_wstart(rqp);
1159 mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM);
1160 smb_rq_wend(rqp);
1161 smb_rq_bstart(rqp);
1162 smb_rq_bend(rqp);
1163 error = smb_rq_simple(rqp);
1164 smb_rq_done(rqp);
1165 return error;
1166 }
1167
1168 static int
1169 smbfs_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp,
1170 const char *wildcard, int wclen, int attr, struct smb_cred *scred)
1171 {
1172 if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
1173 ctx->f_name = malloc(SMB_MAXFNAMELEN * 2, M_SMBFSDATA, M_WAITOK);
1174 } else
1175 ctx->f_name = malloc(SMB_MAXFNAMELEN, M_SMBFSDATA, M_WAITOK);
1176 ctx->f_infolevel = SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_NTLM0_12 ?
1177 SMB_INFO_STANDARD : SMB_FIND_FILE_DIRECTORY_INFO;
1178 ctx->f_attrmask = attr;
1179 ctx->f_wildcard = wildcard;
1180 ctx->f_wclen = wclen;
1181 return 0;
1182 }
1183
1184 static int
1185 smbfs_findnextLM2(struct smbfs_fctx *ctx, int limit)
1186 {
1187 struct mdchain *mbp;
1188 struct smb_t2rq *t2p;
1189 char *cp;
1190 u_int8_t tb;
1191 u_int16_t date, time, wattr;
1192 u_int32_t size, next, dattr;
1193 int64_t lint;
1194 int error, svtz, cnt, fxsz, nmlen, recsz;
1195
1196 if (ctx->f_ecnt == 0) {
1197 if (ctx->f_flags & SMBFS_RDD_EOF)
1198 return ENOENT;
1199 ctx->f_left = ctx->f_limit = limit;
1200 error = smbfs_smb_trans2find2(ctx);
1201 if (error)
1202 return error;
1203 }
1204 t2p = ctx->f_t2;
1205 mbp = &t2p->t2_rdata;
1206 svtz = SSTOVC(ctx->f_ssp)->vc_sopt.sv_tz;
1207 switch (ctx->f_infolevel) {
1208 case SMB_INFO_STANDARD:
1209 next = 0;
1210 fxsz = 0;
1211 md_get_uint16le(mbp, &date);
1212 md_get_uint16le(mbp, &time); /* creation time */
1213 md_get_uint16le(mbp, &date);
1214 md_get_uint16le(mbp, &time); /* access time */
1215 smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_atime);
1216 md_get_uint16le(mbp, &date);
1217 md_get_uint16le(mbp, &time); /* access time */
1218 smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_mtime);
1219 md_get_uint32le(mbp, &size);
1220 ctx->f_attr.fa_size = size;
1221 md_get_uint32(mbp, NULL); /* allocation size */
1222 md_get_uint16le(mbp, &wattr);
1223 ctx->f_attr.fa_attr = wattr;
1224 md_get_uint8(mbp, &tb);
1225 size = nmlen = tb;
1226 fxsz = 23;
1227 recsz = next = 24 + nmlen; /* docs misses zero byte at end */
1228 break;
1229 case SMB_FIND_FILE_DIRECTORY_INFO:
1230 md_get_uint32le(mbp, &next);
1231 md_get_uint32(mbp, NULL); /* file index */
1232 md_get_int64(mbp, NULL); /* creation time */
1233 md_get_int64le(mbp, &lint);
1234 smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_atime);
1235 md_get_int64le(mbp, &lint);
1236 smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_mtime);
1237 md_get_int64le(mbp, &lint);
1238 smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_ctime);
1239 md_get_int64le(mbp, &lint); /* file size */
1240 ctx->f_attr.fa_size = lint;
1241 md_get_int64(mbp, NULL); /* real size (should use) */
1242 md_get_uint32le(mbp, &dattr); /* EA */
1243 ctx->f_attr.fa_attr = dattr;
1244 md_get_uint32le(mbp, &size); /* name len */
1245 fxsz = 64;
1246 recsz = next ? next : fxsz + size;
1247 break;
1248 default:
1249 SMBERROR("unexpected info level %d\n", ctx->f_infolevel);
1250 return EINVAL;
1251 }
1252 if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
1253 nmlen = min(size, SMB_MAXFNAMELEN * 2);
1254 } else
1255 nmlen = min(size, SMB_MAXFNAMELEN);
1256 cp = ctx->f_name;
1257 error = md_get_mem(mbp, cp, nmlen, MB_MSYSTEM);
1258 if (error)
1259 return error;
1260 if (next) {
1261 cnt = next - nmlen - fxsz;
1262 if (cnt > 0)
1263 md_get_mem(mbp, NULL, cnt, MB_MSYSTEM);
1264 else if (cnt < 0) {
1265 SMBERROR("out of sync\n");
1266 return EBADRPC;
1267 }
1268 }
1269 if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
1270 if (nmlen > 1 && cp[nmlen - 1] == 0 && cp[nmlen - 2] == 0)
1271 nmlen -= 2;
1272 } else
1273 if (nmlen && cp[nmlen - 1] == 0)
1274 nmlen--;
1275 if (nmlen == 0)
1276 return EBADRPC;
1277
1278 next = ctx->f_eofs + recsz;
1279 if (ctx->f_rnameofs && (ctx->f_flags & SMBFS_RDD_GOTRNAME) == 0 &&
1280 (ctx->f_rnameofs >= ctx->f_eofs && ctx->f_rnameofs < next)) {
1281 /*
1282 * Server needs a resume filename.
1283 */
1284 if (ctx->f_rnamelen <= nmlen) {
1285 if (ctx->f_rname)
1286 free(ctx->f_rname, M_SMBFSDATA);
1287 ctx->f_rname = malloc(nmlen + 1, M_SMBFSDATA, M_WAITOK);
1288 ctx->f_rnamelen = nmlen;
1289 }
1290 bcopy(ctx->f_name, ctx->f_rname, nmlen);
1291 ctx->f_rname[nmlen] = 0;
1292 ctx->f_flags |= SMBFS_RDD_GOTRNAME;
1293 }
1294 ctx->f_nmlen = nmlen;
1295 ctx->f_eofs = next;
1296 ctx->f_ecnt--;
1297 ctx->f_left--;
1298 return 0;
1299 }
1300
1301 static int
1302 smbfs_findcloseLM2(struct smbfs_fctx *ctx)
1303 {
1304 if (ctx->f_name)
1305 free(ctx->f_name, M_SMBFSDATA);
1306 if (ctx->f_t2)
1307 smb_t2_done(ctx->f_t2);
1308 if ((ctx->f_flags & SMBFS_RDD_NOCLOSE) == 0)
1309 smbfs_smb_findclose2(ctx);
1310 return 0;
1311 }
1312
1313 int
1314 smbfs_findopen(struct smbnode *dnp, const char *wildcard, int wclen, int attr,
1315 struct smb_cred *scred, struct smbfs_fctx **ctxpp)
1316 {
1317 struct smbfs_fctx *ctx;
1318 int error;
1319
1320 ctx = malloc(sizeof(*ctx), M_SMBFSDATA, M_WAITOK | M_ZERO);
1321 ctx->f_ssp = dnp->n_mount->sm_share;
1322 ctx->f_dnp = dnp;
1323 ctx->f_flags = SMBFS_RDD_FINDFIRST;
1324 ctx->f_scred = scred;
1325 if (SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_LANMAN2_0 ||
1326 (dnp->n_mount->sm_flags & SMBFS_MOUNT_NO_LONG)) {
1327 ctx->f_flags |= SMBFS_RDD_USESEARCH;
1328 error = smbfs_findopenLM1(ctx, dnp, wildcard, wclen, attr, scred);
1329 } else
1330 error = smbfs_findopenLM2(ctx, dnp, wildcard, wclen, attr, scred);
1331 if (error)
1332 smbfs_findclose(ctx, scred);
1333 else
1334 *ctxpp = ctx;
1335 return error;
1336 }
1337
1338 int
1339 smbfs_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scred)
1340 {
1341 int error;
1342
1343 if (limit == 0)
1344 limit = 1000000;
1345 else if (limit > 1)
1346 limit *= 4; /* imperical */
1347 ctx->f_scred = scred;
1348 for (;;) {
1349 if (ctx->f_flags & SMBFS_RDD_USESEARCH) {
1350 error = smbfs_findnextLM1(ctx, limit);
1351 } else
1352 error = smbfs_findnextLM2(ctx, limit);
1353 if (error)
1354 return error;
1355 if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
1356 if ((ctx->f_nmlen == 2 &&
1357 *(u_int16_t *)ctx->f_name == htole16(0x002e)) ||
1358 (ctx->f_nmlen == 4 &&
1359 *(u_int32_t *)ctx->f_name == htole32(0x002e002e)))
1360 continue;
1361 } else
1362 if ((ctx->f_nmlen == 1 && ctx->f_name[0] == '.') ||
1363 (ctx->f_nmlen == 2 && ctx->f_name[0] == '.' &&
1364 ctx->f_name[1] == '.'))
1365 continue;
1366 break;
1367 }
1368 smbfs_fname_tolocal(SSTOVC(ctx->f_ssp), ctx->f_name, &ctx->f_nmlen,
1369 ctx->f_dnp->n_mount->sm_caseopt);
1370 ctx->f_attr.fa_ino = smbfs_getino(ctx->f_dnp, ctx->f_name, ctx->f_nmlen);
1371 return 0;
1372 }
1373
1374 int
1375 smbfs_findclose(struct smbfs_fctx *ctx, struct smb_cred *scred)
1376 {
1377 ctx->f_scred = scred;
1378 if (ctx->f_flags & SMBFS_RDD_USESEARCH) {
1379 smbfs_findcloseLM1(ctx);
1380 } else
1381 smbfs_findcloseLM2(ctx);
1382 if (ctx->f_rname)
1383 free(ctx->f_rname, M_SMBFSDATA);
1384 free(ctx, M_SMBFSDATA);
1385 return 0;
1386 }
1387
1388 int
1389 smbfs_smb_lookup(struct smbnode *dnp, const char *name, int nmlen,
1390 struct smbfattr *fap, struct smb_cred *scred)
1391 {
1392 struct smbfs_fctx *ctx;
1393 int error;
1394
1395 if (dnp == NULL || (dnp->n_ino == 2 && name == NULL)) {
1396 bzero(fap, sizeof(*fap));
1397 fap->fa_attr = SMB_FA_DIR;
1398 fap->fa_ino = 2;
1399 return 0;
1400 }
1401 MPASS(!(nmlen == 2 && name[0] == '.' && name[1] == '.'));
1402 MPASS(!(nmlen == 1 && name[0] == '.'));
1403 ASSERT_VOP_ELOCKED(dnp->n_vnode, "smbfs_smb_lookup");
1404 error = smbfs_findopen(dnp, name, nmlen,
1405 SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, scred, &ctx);
1406 if (error)
1407 return error;
1408 ctx->f_flags |= SMBFS_RDD_FINDSINGLE;
1409 error = smbfs_findnext(ctx, 1, scred);
1410 if (error == 0) {
1411 *fap = ctx->f_attr;
1412 if (name == NULL)
1413 fap->fa_ino = dnp->n_ino;
1414 }
1415 smbfs_findclose(ctx, scred);
1416 return error;
1417 }
Cache object: 6a042ce57c96d476ad132fbc128d0e65
|