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