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