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