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