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