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