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