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