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