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 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_flag & NOPEN) == 0 || !SMBTOV(np) || 367 SMBTOV(np)->v_type != VREG) 368 return 0; /* not a regular open file */ 369 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_FLUSH, scred); 370 if (error) 371 return (error); 372 smb_rq_getrequest(rqp, &mbp); 373 smb_rq_wstart(rqp); 374 mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); 375 smb_rq_wend(rqp); 376 smb_rq_bstart(rqp); 377 smb_rq_bend(rqp); 378 error = smb_rq_simple(rqp); 379 smb_rq_done(rqp); 380 if (!error) 381 np->n_flag &= ~NFLUSHWIRE; 382 return (error); 383 } 384 385 int 386 smbfs_smb_flush(struct smbnode *np, struct smb_cred *scred) 387 { 388 if (np->n_flag & NFLUSHWIRE) 389 return (smb_smb_flush(np, scred)); 390 return (0); 391 } 392 393 int 394 smbfs_smb_setfsize(struct smbnode *np, int newsize, struct smb_cred *scred) 395 { 396 struct smb_share *ssp = np->n_mount->sm_share; 397 struct smb_rq rq, *rqp = &rq; 398 struct mbchain *mbp; 399 int error; 400 401 if (!smbfs_smb_seteof(np, (int64_t) newsize, scred)) { 402 np->n_flag |= NFLUSHWIRE; 403 return (0); 404 } 405 406 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_WRITE, scred); 407 if (error) 408 return error; 409 smb_rq_getrequest(rqp, &mbp); 410 smb_rq_wstart(rqp); 411 mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); 412 mb_put_uint16le(mbp, 0); 413 mb_put_uint32le(mbp, newsize); 414 mb_put_uint16le(mbp, 0); 415 smb_rq_wend(rqp); 416 smb_rq_bstart(rqp); 417 mb_put_uint8(mbp, SMB_DT_DATA); 418 mb_put_uint16le(mbp, 0); 419 smb_rq_bend(rqp); 420 error = smb_rq_simple(rqp); 421 smb_rq_done(rqp); 422 return error; 423 } 424 425 int 426 smbfs_smb_query_info(struct smbnode *np, const char *name, int len, 427 struct smbfattr *fap, struct smb_cred *scred) 428 { 429 struct smb_rq rq, *rqp = &rq; 430 struct smb_share *ssp = np->n_mount->sm_share; 431 struct mbchain *mbp; 432 struct mdchain *mdp; 433 u_int8_t wc; 434 int error; 435 u_int16_t wattr; 436 u_int32_t lint; 437 438 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION, scred); 439 if (error) 440 return error; 441 smb_rq_getrequest(rqp, &mbp); 442 smb_rq_wstart(rqp); 443 smb_rq_wend(rqp); 444 smb_rq_bstart(rqp); 445 mb_put_uint8(mbp, SMB_DT_ASCII); 446 do { 447 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, len); 448 if (error) 449 break; 450 smb_rq_bend(rqp); 451 error = smb_rq_simple(rqp); 452 if (error) 453 break; 454 smb_rq_getreply(rqp, &mdp); 455 if (md_get_uint8(mdp, &wc) != 0 || wc != 10) { 456 error = EBADRPC; 457 break; 458 } 459 md_get_uint16le(mdp, &wattr); 460 fap->fa_attr = wattr; 461 /* 462 * Be careful using the time returned here, as 463 * with FAT on NT4SP6, at least, the time returned is low 464 * 32 bits of 100s of nanoseconds (since 1601) so it rolls 465 * over about every seven minutes! 466 */ 467 md_get_uint32le(mdp, &lint); /* specs: secs since 1970 */ 468 if (lint) /* avoid bogus zero returns */ 469 smb_time_server2local(lint, SSTOVC(ssp)->vc_sopt.sv_tz, 470 &fap->fa_mtime); 471 md_get_uint32le(mdp, &lint); 472 fap->fa_size = lint; 473 } while(0); 474 smb_rq_done(rqp); 475 return error; 476 } 477 478 /* 479 * Set DOS file attributes. mtime should be NULL for dialects above lm10 480 */ 481 int 482 smbfs_smb_setpattr(struct smbnode *np, u_int16_t attr, struct timespec *mtime, 483 struct smb_cred *scred) 484 { 485 struct smb_rq rq, *rqp = &rq; 486 struct smb_share *ssp = np->n_mount->sm_share; 487 struct mbchain *mbp; 488 u_long time; 489 int error, svtz; 490 491 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION, scred); 492 if (error) 493 return error; 494 svtz = SSTOVC(ssp)->vc_sopt.sv_tz; 495 smb_rq_getrequest(rqp, &mbp); 496 smb_rq_wstart(rqp); 497 mb_put_uint16le(mbp, attr); 498 if (mtime) { 499 smb_time_local2server(mtime, svtz, &time); 500 } else 501 time = 0; 502 mb_put_uint32le(mbp, time); /* mtime */ 503 mb_put_mem(mbp, NULL, 5 * 2, MB_MZERO); 504 smb_rq_wend(rqp); 505 smb_rq_bstart(rqp); 506 mb_put_uint8(mbp, SMB_DT_ASCII); 507 do { 508 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0); 509 if (error) 510 break; 511 mb_put_uint8(mbp, SMB_DT_ASCII); 512 mb_put_uint8(mbp, 0); 513 smb_rq_bend(rqp); 514 error = smb_rq_simple(rqp); 515 SMBERROR("%d\n", error); 516 if (error) 517 break; 518 } while(0); 519 smb_rq_done(rqp); 520 return error; 521 } 522 523 /* 524 * Note, win95 doesn't support this call. 525 */ 526 int 527 smbfs_smb_setptime2(struct smbnode *np, struct timespec *mtime, 528 struct timespec *atime, int attr, struct smb_cred *scred) 529 { 530 struct smb_t2rq *t2p; 531 struct smb_share *ssp = np->n_mount->sm_share; 532 struct smb_vc *vcp = SSTOVC(ssp); 533 struct mbchain *mbp; 534 u_int16_t date, time; 535 int error, tzoff; 536 537 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION, 538 scred, &t2p); 539 if (error) 540 return error; 541 mbp = &t2p->t2_tparam; 542 mb_init(mbp); 543 mb_put_uint16le(mbp, SMB_INFO_STANDARD); 544 mb_put_uint32le(mbp, 0); /* MBZ */ 545 /* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */ 546 error = smbfs_fullpath(mbp, vcp, np, NULL, 0); 547 if (error) { 548 smb_t2_done(t2p); 549 return error; 550 } 551 tzoff = vcp->vc_sopt.sv_tz; 552 mbp = &t2p->t2_tdata; 553 mb_init(mbp); 554 mb_put_uint32le(mbp, 0); /* creation time */ 555 if (atime) 556 smb_time_unix2dos(atime, tzoff, &date, &time, NULL); 557 else 558 time = date = 0; 559 mb_put_uint16le(mbp, date); 560 mb_put_uint16le(mbp, time); 561 if (mtime) 562 smb_time_unix2dos(mtime, tzoff, &date, &time, NULL); 563 else 564 time = date = 0; 565 mb_put_uint16le(mbp, date); 566 mb_put_uint16le(mbp, time); 567 mb_put_uint32le(mbp, 0); /* file size */ 568 mb_put_uint32le(mbp, 0); /* allocation unit size */ 569 mb_put_uint16le(mbp, attr); /* DOS attr */ 570 mb_put_uint32le(mbp, 0); /* EA size */ 571 t2p->t2_maxpcount = 5 * 2; 572 t2p->t2_maxdcount = vcp->vc_txmax; 573 error = smb_t2_request(t2p); 574 smb_t2_done(t2p); 575 return error; 576 } 577 578 /* 579 * NT level. Specially for win9x 580 */ 581 int 582 smbfs_smb_setpattrNT(struct smbnode *np, u_short attr, struct timespec *mtime, 583 struct timespec *atime, struct smb_cred *scred) 584 { 585 struct smb_t2rq *t2p; 586 struct smb_share *ssp = np->n_mount->sm_share; 587 struct smb_vc *vcp = SSTOVC(ssp); 588 struct mbchain *mbp; 589 int64_t tm; 590 int error, tzoff; 591 592 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION, 593 scred, &t2p); 594 if (error) 595 return error; 596 mbp = &t2p->t2_tparam; 597 mb_init(mbp); 598 mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFO); 599 mb_put_uint32le(mbp, 0); /* MBZ */ 600 /* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */ 601 error = smbfs_fullpath(mbp, vcp, np, NULL, 0); 602 if (error) { 603 smb_t2_done(t2p); 604 return error; 605 } 606 tzoff = vcp->vc_sopt.sv_tz; 607 mbp = &t2p->t2_tdata; 608 mb_init(mbp); 609 mb_put_int64le(mbp, 0); /* creation time */ 610 if (atime) { 611 smb_time_local2NT(atime, tzoff, &tm); 612 } else 613 tm = 0; 614 mb_put_int64le(mbp, tm); 615 if (mtime) { 616 smb_time_local2NT(mtime, tzoff, &tm); 617 } else 618 tm = 0; 619 mb_put_int64le(mbp, tm); 620 mb_put_int64le(mbp, tm); /* change time */ 621 mb_put_uint32le(mbp, attr); /* attr */ 622 t2p->t2_maxpcount = 24; 623 t2p->t2_maxdcount = 56; 624 error = smb_t2_request(t2p); 625 smb_t2_done(t2p); 626 return error; 627 } 628 629 /* 630 * Set file atime and mtime. Doesn't supported by core dialect. 631 */ 632 int 633 smbfs_smb_setftime(struct smbnode *np, struct timespec *mtime, 634 struct timespec *atime, struct smb_cred *scred) 635 { 636 struct smb_rq rq, *rqp = &rq; 637 struct smb_share *ssp = np->n_mount->sm_share; 638 struct mbchain *mbp; 639 u_int16_t date, time; 640 int error, tzoff; 641 642 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION2, scred); 643 if (error) 644 return error; 645 tzoff = SSTOVC(ssp)->vc_sopt.sv_tz; 646 smb_rq_getrequest(rqp, &mbp); 647 smb_rq_wstart(rqp); 648 mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); 649 mb_put_uint32le(mbp, 0); /* creation time */ 650 651 if (atime) 652 smb_time_unix2dos(atime, tzoff, &date, &time, NULL); 653 else 654 time = date = 0; 655 mb_put_uint16le(mbp, date); 656 mb_put_uint16le(mbp, time); 657 if (mtime) 658 smb_time_unix2dos(mtime, tzoff, &date, &time, NULL); 659 else 660 time = date = 0; 661 mb_put_uint16le(mbp, date); 662 mb_put_uint16le(mbp, time); 663 smb_rq_wend(rqp); 664 smb_rq_bstart(rqp); 665 smb_rq_bend(rqp); 666 error = smb_rq_simple(rqp); 667 SMBSDEBUG("%d\n", error); 668 smb_rq_done(rqp); 669 return error; 670 } 671 672 /* 673 * Set DOS file attributes. 674 * Looks like this call can be used only if CAP_NT_SMBS bit is on. 675 */ 676 int 677 smbfs_smb_setfattrNT(struct smbnode *np, u_int16_t attr, struct timespec *mtime, 678 struct timespec *atime, struct smb_cred *scred) 679 { 680 struct smb_t2rq *t2p; 681 struct smb_share *ssp = np->n_mount->sm_share; 682 struct mbchain *mbp; 683 int64_t tm; 684 int error, svtz; 685 686 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION, 687 scred, &t2p); 688 if (error) 689 return error; 690 svtz = SSTOVC(ssp)->vc_sopt.sv_tz; 691 mbp = &t2p->t2_tparam; 692 mb_init(mbp); 693 mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); 694 mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFO); 695 mb_put_uint32le(mbp, 0); 696 mbp = &t2p->t2_tdata; 697 mb_init(mbp); 698 mb_put_int64le(mbp, 0); /* creation time */ 699 if (atime) { 700 smb_time_local2NT(atime, svtz, &tm); 701 } else 702 tm = 0; 703 mb_put_int64le(mbp, tm); 704 if (mtime) { 705 smb_time_local2NT(mtime, svtz, &tm); 706 } else 707 tm = 0; 708 mb_put_int64le(mbp, tm); 709 mb_put_int64le(mbp, tm); /* change time */ 710 mb_put_uint16le(mbp, attr); 711 mb_put_uint32le(mbp, 0); /* padding */ 712 mb_put_uint16le(mbp, 0); 713 t2p->t2_maxpcount = 2; 714 t2p->t2_maxdcount = 0; 715 error = smb_t2_request(t2p); 716 smb_t2_done(t2p); 717 return error; 718 } 719 720 721 int 722 smbfs_smb_open(struct smbnode *np, int accmode, struct smb_cred *scred) 723 { 724 struct smb_rq rq, *rqp = &rq; 725 struct smb_share *ssp = np->n_mount->sm_share; 726 struct mbchain *mbp; 727 struct mdchain *mdp; 728 u_int8_t wc; 729 u_int16_t fid, wattr, grantedmode; 730 int error; 731 732 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_OPEN, scred); 733 if (error) 734 return error; 735 smb_rq_getrequest(rqp, &mbp); 736 smb_rq_wstart(rqp); 737 mb_put_uint16le(mbp, accmode); 738 mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN); 739 smb_rq_wend(rqp); 740 smb_rq_bstart(rqp); 741 mb_put_uint8(mbp, SMB_DT_ASCII); 742 do { 743 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0); 744 if (error) 745 break; 746 smb_rq_bend(rqp); 747 error = smb_rq_simple(rqp); 748 if (error) 749 break; 750 smb_rq_getreply(rqp, &mdp); 751 if (md_get_uint8(mdp, &wc) != 0 || wc != 7) { 752 error = EBADRPC; 753 break; 754 } 755 md_get_uint16(mdp, &fid); 756 md_get_uint16le(mdp, &wattr); 757 md_get_uint32(mdp, NULL); /* mtime */ 758 md_get_uint32(mdp, NULL); /* fsize */ 759 md_get_uint16le(mdp, &grantedmode); 760 /* 761 * TODO: refresh attributes from this reply 762 */ 763 } while(0); 764 smb_rq_done(rqp); 765 if (error) 766 return error; 767 np->n_fid = fid; 768 np->n_rwstate = grantedmode; 769 return 0; 770 } 771 772 773 int 774 smbfs_smb_close(struct smb_share *ssp, u_int16_t fid, struct timespec *mtime, 775 struct smb_cred *scred) 776 { 777 struct smb_rq rq, *rqp = &rq; 778 struct mbchain *mbp; 779 u_long time; 780 int error; 781 782 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CLOSE, scred); 783 if (error) 784 return error; 785 smb_rq_getrequest(rqp, &mbp); 786 smb_rq_wstart(rqp); 787 mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM); 788 if (mtime) { 789 smb_time_local2server(mtime, SSTOVC(ssp)->vc_sopt.sv_tz, &time); 790 } else 791 time = 0; 792 mb_put_uint32le(mbp, time); 793 smb_rq_wend(rqp); 794 smb_rq_bstart(rqp); 795 smb_rq_bend(rqp); 796 error = smb_rq_simple(rqp); 797 smb_rq_done(rqp); 798 return error; 799 } 800 801 int 802 smbfs_smb_create(struct smbnode *dnp, const char *name, int nmlen, 803 struct smb_cred *scred) 804 { 805 struct smb_rq rq, *rqp = &rq; 806 struct smb_share *ssp = dnp->n_mount->sm_share; 807 struct mbchain *mbp; 808 struct mdchain *mdp; 809 struct timespec ctime; 810 u_int8_t wc; 811 u_int16_t fid; 812 u_long tm; 813 int error; 814 815 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE, scred); 816 if (error) 817 return error; 818 smb_rq_getrequest(rqp, &mbp); 819 smb_rq_wstart(rqp); 820 mb_put_uint16le(mbp, SMB_FA_ARCHIVE); /* attributes */ 821 nanotime(&ctime); 822 smb_time_local2server(&ctime, SSTOVC(ssp)->vc_sopt.sv_tz, &tm); 823 mb_put_uint32le(mbp, tm); 824 smb_rq_wend(rqp); 825 smb_rq_bstart(rqp); 826 mb_put_uint8(mbp, SMB_DT_ASCII); 827 error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, nmlen); 828 if (!error) { 829 smb_rq_bend(rqp); 830 error = smb_rq_simple(rqp); 831 if (!error) { 832 smb_rq_getreply(rqp, &mdp); 833 md_get_uint8(mdp, &wc); 834 if (wc == 1) 835 md_get_uint16(mdp, &fid); 836 else 837 error = EBADRPC; 838 } 839 } 840 smb_rq_done(rqp); 841 if (error) 842 return error; 843 smbfs_smb_close(ssp, fid, &ctime, scred); 844 return error; 845 } 846 847 int 848 smbfs_smb_delete(struct smbnode *np, struct smb_cred *scred) 849 { 850 struct smb_rq rq, *rqp = &rq; 851 struct smb_share *ssp = np->n_mount->sm_share; 852 struct mbchain *mbp; 853 int error; 854 855 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE, scred); 856 if (error) 857 return error; 858 smb_rq_getrequest(rqp, &mbp); 859 smb_rq_wstart(rqp); 860 mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN); 861 smb_rq_wend(rqp); 862 smb_rq_bstart(rqp); 863 mb_put_uint8(mbp, SMB_DT_ASCII); 864 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0); 865 if (!error) { 866 smb_rq_bend(rqp); 867 error = smb_rq_simple(rqp); 868 } 869 smb_rq_done(rqp); 870 return error; 871 } 872 873 int 874 smbfs_smb_rename(struct smbnode *src, struct smbnode *tdnp, 875 const char *tname, int tnmlen, struct smb_cred *scred) 876 { 877 struct smb_rq rq, *rqp = &rq; 878 struct smb_share *ssp = src->n_mount->sm_share; 879 struct mbchain *mbp; 880 int error; 881 882 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_RENAME, scred); 883 if (error) 884 return error; 885 smb_rq_getrequest(rqp, &mbp); 886 smb_rq_wstart(rqp); 887 mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN); 888 smb_rq_wend(rqp); 889 smb_rq_bstart(rqp); 890 mb_put_uint8(mbp, SMB_DT_ASCII); 891 do { 892 error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0); 893 if (error) 894 break; 895 mb_put_uint8(mbp, SMB_DT_ASCII); 896 error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen); 897 if (error) 898 break; 899 smb_rq_bend(rqp); 900 error = smb_rq_simple(rqp); 901 } while(0); 902 smb_rq_done(rqp); 903 return error; 904 } 905 906 int 907 smbfs_smb_move(struct smbnode *src, struct smbnode *tdnp, 908 const char *tname, int tnmlen, u_int16_t flags, struct smb_cred *scred) 909 { 910 struct smb_rq rq, *rqp = &rq; 911 struct smb_share *ssp = src->n_mount->sm_share; 912 struct mbchain *mbp; 913 int error; 914 915 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_MOVE, scred); 916 if (error) 917 return error; 918 smb_rq_getrequest(rqp, &mbp); 919 smb_rq_wstart(rqp); 920 mb_put_uint16le(mbp, SMB_TID_UNKNOWN); 921 mb_put_uint16le(mbp, 0x20); /* delete target file */ 922 mb_put_uint16le(mbp, flags); 923 smb_rq_wend(rqp); 924 smb_rq_bstart(rqp); 925 mb_put_uint8(mbp, SMB_DT_ASCII); 926 do { 927 error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0); 928 if (error) 929 break; 930 mb_put_uint8(mbp, SMB_DT_ASCII); 931 error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen); 932 if (error) 933 break; 934 smb_rq_bend(rqp); 935 error = smb_rq_simple(rqp); 936 } while(0); 937 smb_rq_done(rqp); 938 return error; 939 } 940 941 int 942 smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int len, 943 struct smb_cred *scred) 944 { 945 struct smb_rq rq, *rqp = &rq; 946 struct smb_share *ssp = dnp->n_mount->sm_share; 947 struct mbchain *mbp; 948 int error; 949 950 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE_DIRECTORY, scred); 951 if (error) 952 return error; 953 smb_rq_getrequest(rqp, &mbp); 954 smb_rq_wstart(rqp); 955 smb_rq_wend(rqp); 956 smb_rq_bstart(rqp); 957 mb_put_uint8(mbp, SMB_DT_ASCII); 958 error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, len); 959 if (!error) { 960 smb_rq_bend(rqp); 961 error = smb_rq_simple(rqp); 962 } 963 smb_rq_done(rqp); 964 return error; 965 } 966 967 int 968 smbfs_smb_rmdir(struct smbnode *np, struct smb_cred *scred) 969 { 970 struct smb_rq rq, *rqp = &rq; 971 struct smb_share *ssp = np->n_mount->sm_share; 972 struct mbchain *mbp; 973 int error; 974 975 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE_DIRECTORY, scred); 976 if (error) 977 return error; 978 smb_rq_getrequest(rqp, &mbp); 979 smb_rq_wstart(rqp); 980 smb_rq_wend(rqp); 981 smb_rq_bstart(rqp); 982 mb_put_uint8(mbp, SMB_DT_ASCII); 983 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0); 984 if (!error) { 985 smb_rq_bend(rqp); 986 error = smb_rq_simple(rqp); 987 } 988 smb_rq_done(rqp); 989 return error; 990 } 991 992 static int 993 smbfs_smb_search(struct smbfs_fctx *ctx) 994 { 995 struct smb_vc *vcp = SSTOVC(ctx->f_ssp); 996 struct smb_rq *rqp; 997 struct mbchain *mbp; 998 struct mdchain *mdp; 999 u_int8_t wc, bt; 1000 u_int16_t ec, dlen, bc; 1001 int maxent, error, iseof = 0; 1002 1003 maxent = min(ctx->f_left, (vcp->vc_txmax - SMB_HDRLEN - 3) / SMB_DENTRYLEN); 1004 if (ctx->f_rq) { 1005 smb_rq_done(ctx->f_rq); 1006 ctx->f_rq = NULL; 1007 } 1008 error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_SEARCH, ctx->f_scred, &rqp); 1009 if (error) 1010 return error; 1011 ctx->f_rq = rqp; 1012 smb_rq_getrequest(rqp, &mbp); 1013 smb_rq_wstart(rqp); 1014 mb_put_uint16le(mbp, maxent); /* max entries to return */ 1015 mb_put_uint16le(mbp, ctx->f_attrmask); 1016 smb_rq_wend(rqp); 1017 smb_rq_bstart(rqp); 1018 mb_put_uint8(mbp, SMB_DT_ASCII); /* buffer format */ 1019 if (ctx->f_flags & SMBFS_RDD_FINDFIRST) { 1020 error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, ctx->f_wclen); 1021 if (error) 1022 return error; 1023 mb_put_uint8(mbp, SMB_DT_VARIABLE); 1024 mb_put_uint16le(mbp, 0); /* context length */ 1025 ctx->f_flags &= ~SMBFS_RDD_FINDFIRST; 1026 } else { 1027 mb_put_uint8(mbp, 0); /* file name length */ 1028 mb_put_uint8(mbp, SMB_DT_VARIABLE); 1029 mb_put_uint16le(mbp, SMB_SKEYLEN); 1030 mb_put_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM); 1031 } 1032 smb_rq_bend(rqp); 1033 error = smb_rq_simple(rqp); 1034 if (error) { 1035 if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnofiles) { 1036 error = 0; 1037 iseof = 1; 1038 ctx->f_flags |= SMBFS_RDD_EOF; 1039 } else 1040 return error; 1041 } 1042 smb_rq_getreply(rqp, &mdp); 1043 md_get_uint8(mdp, &wc); 1044 if (wc != 1) 1045 return iseof ? ENOENT : EBADRPC; 1046 md_get_uint16le(mdp, &ec); 1047 if (ec == 0) 1048 return ENOENT; 1049 ctx->f_ecnt = ec; 1050 md_get_uint16le(mdp, &bc); 1051 if (bc < 3) 1052 return EBADRPC; 1053 bc -= 3; 1054 md_get_uint8(mdp, &bt); 1055 if (bt != SMB_DT_VARIABLE) 1056 return EBADRPC; 1057 md_get_uint16le(mdp, &dlen); 1058 if (dlen != bc || dlen % SMB_DENTRYLEN != 0) 1059 return EBADRPC; 1060 return 0; 1061 } 1062 1063 static int 1064 smbfs_findopenLM1(struct smbfs_fctx *ctx, struct smbnode *dnp, 1065 const char *wildcard, int wclen, int attr, struct smb_cred *scred) 1066 { 1067 ctx->f_attrmask = attr; 1068 if (wildcard) { 1069 if (wclen == 1 && wildcard[0] == '*') { 1070 ctx->f_wildcard = "*.*"; 1071 ctx->f_wclen = 3; 1072 } else { 1073 ctx->f_wildcard = wildcard; 1074 ctx->f_wclen = wclen; 1075 } 1076 } else { 1077 ctx->f_wildcard = NULL; 1078 ctx->f_wclen = 0; 1079 } 1080 ctx->f_name = ctx->f_fname; 1081 return 0; 1082 } 1083 1084 static int 1085 smbfs_findnextLM1(struct smbfs_fctx *ctx, int limit) 1086 { 1087 struct mdchain *mbp; 1088 struct smb_rq *rqp; 1089 char *cp; 1090 u_int8_t battr; 1091 u_int16_t date, time; 1092 u_int32_t size; 1093 int error; 1094 1095 if (ctx->f_ecnt == 0) { 1096 if (ctx->f_flags & SMBFS_RDD_EOF) 1097 return ENOENT; 1098 ctx->f_left = ctx->f_limit = limit; 1099 error = smbfs_smb_search(ctx); 1100 if (error) 1101 return error; 1102 } 1103 rqp = ctx->f_rq; 1104 smb_rq_getreply(rqp, &mbp); 1105 md_get_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM); 1106 md_get_uint8(mbp, &battr); 1107 md_get_uint16le(mbp, &time); 1108 md_get_uint16le(mbp, &date); 1109 md_get_uint32le(mbp, &size); 1110 cp = ctx->f_name; 1111 md_get_mem(mbp, cp, sizeof(ctx->f_fname), MB_MSYSTEM); 1112 cp[sizeof(ctx->f_fname) - 1] = 0; 1113 cp += strlen(cp) - 1; 1114 while (*cp == ' ' && cp >= ctx->f_name) 1115 *cp-- = 0; 1116 ctx->f_attr.fa_attr = battr; 1117 smb_dos2unixtime(date, time, 0, rqp->sr_vc->vc_sopt.sv_tz, 1118 &ctx->f_attr.fa_mtime); 1119 ctx->f_attr.fa_size = size; 1120 ctx->f_nmlen = strlen(ctx->f_name); 1121 ctx->f_ecnt--; 1122 ctx->f_left--; 1123 return 0; 1124 } 1125 1126 static int 1127 smbfs_findcloseLM1(struct smbfs_fctx *ctx) 1128 { 1129 if (ctx->f_rq) 1130 smb_rq_done(ctx->f_rq); 1131 return 0; 1132 } 1133 1134 /* 1135 * TRANS2_FIND_FIRST2/NEXT2, used for NT LM12 dialect 1136 */ 1137 static int 1138 smbfs_smb_trans2find2(struct smbfs_fctx *ctx) 1139 { 1140 struct smb_t2rq *t2p; 1141 struct smb_vc *vcp = SSTOVC(ctx->f_ssp); 1142 struct mbchain *mbp; 1143 struct mdchain *mdp; 1144 u_int16_t tw, flags; 1145 int error; 1146 1147 if (ctx->f_t2) { 1148 smb_t2_done(ctx->f_t2); 1149 ctx->f_t2 = NULL; 1150 } 1151 ctx->f_flags &= ~SMBFS_RDD_GOTRNAME; 1152 flags = 8 | 2; /* <resume> | <close if EOS> */ 1153 if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) { 1154 flags |= 1; /* close search after this request */ 1155 ctx->f_flags |= SMBFS_RDD_NOCLOSE; 1156 } 1157 if (ctx->f_flags & SMBFS_RDD_FINDFIRST) { 1158 error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_FIRST2, 1159 ctx->f_scred, &t2p); 1160 if (error) 1161 return error; 1162 ctx->f_t2 = t2p; 1163 mbp = &t2p->t2_tparam; 1164 mb_init(mbp); 1165 mb_put_uint16le(mbp, ctx->f_attrmask); 1166 mb_put_uint16le(mbp, ctx->f_limit); 1167 mb_put_uint16le(mbp, flags); 1168 mb_put_uint16le(mbp, ctx->f_infolevel); 1169 mb_put_uint32le(mbp, 0); 1170 error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, ctx->f_wclen); 1171 if (error) 1172 return error; 1173 } else { 1174 error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_NEXT2, 1175 ctx->f_scred, &t2p); 1176 if (error) 1177 return error; 1178 ctx->f_t2 = t2p; 1179 mbp = &t2p->t2_tparam; 1180 mb_init(mbp); 1181 mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM); 1182 mb_put_uint16le(mbp, ctx->f_limit); 1183 mb_put_uint16le(mbp, ctx->f_infolevel); 1184 mb_put_uint32le(mbp, 0); /* resume key */ 1185 mb_put_uint16le(mbp, flags); 1186 if (ctx->f_rname) 1187 mb_put_mem(mbp, ctx->f_rname, strlen(ctx->f_rname) + 1, MB_MSYSTEM); 1188 else 1189 mb_put_uint8(mbp, 0); /* resume file name */ 1190 #if 0 1191 struct timeval tv; 1192 tv.tv_sec = 0; 1193 tv.tv_usec = 200 * 1000; /* 200ms */ 1194 if (vcp->vc_flags & SMBC_WIN95) { 1195 /* 1196 * some implementations suggests to sleep here 1197 * for 200ms, due to the bug in the Win95. 1198 * I've didn't notice any problem, but put code 1199 * for it. 1200 */ 1201 tsleep(&flags, PVFS, "fix95", tvtohz(&tv)); 1202 } 1203 #endif 1204 } 1205 t2p->t2_maxpcount = 5 * 2; 1206 t2p->t2_maxdcount = vcp->vc_txmax; 1207 error = smb_t2_request(t2p); 1208 if (error) 1209 return error; 1210 mdp = &t2p->t2_rparam; 1211 if (ctx->f_flags & SMBFS_RDD_FINDFIRST) { 1212 if ((error = md_get_uint16(mdp, &ctx->f_Sid)) != 0) 1213 return error; 1214 ctx->f_flags &= ~SMBFS_RDD_FINDFIRST; 1215 } 1216 if ((error = md_get_uint16le(mdp, &tw)) != 0) 1217 return error; 1218 ctx->f_ecnt = tw; 1219 if ((error = md_get_uint16le(mdp, &tw)) != 0) 1220 return error; 1221 if (tw) 1222 ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE; 1223 if ((error = md_get_uint16le(mdp, &tw)) != 0) 1224 return error; 1225 if ((error = md_get_uint16le(mdp, &tw)) != 0) 1226 return error; 1227 if (ctx->f_ecnt == 0) { 1228 ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE; 1229 return ENOENT; 1230 } 1231 ctx->f_rnameofs = tw; 1232 mdp = &t2p->t2_rdata; 1233 if (mdp->md_top == NULL) { 1234 printf("bug: ecnt = %d, but data is NULL (please report)\n", ctx->f_ecnt); 1235 return ENOENT; 1236 } 1237 if (mdp->md_top->m_len == 0) { 1238 printf("bug: ecnt = %d, but m_len = 0 and m_next = %p (please report)\n", ctx->f_ecnt,mbp->mb_top->m_next); 1239 return ENOENT; 1240 } 1241 ctx->f_eofs = 0; 1242 return 0; 1243 } 1244 1245 static int 1246 smbfs_smb_findclose2(struct smbfs_fctx *ctx) 1247 { 1248 struct smb_rq rq, *rqp = &rq; 1249 struct mbchain *mbp; 1250 int error; 1251 1252 error = smb_rq_init(rqp, SSTOCP(ctx->f_ssp), SMB_COM_FIND_CLOSE2, ctx->f_scred); 1253 if (error) 1254 return error; 1255 smb_rq_getrequest(rqp, &mbp); 1256 smb_rq_wstart(rqp); 1257 mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM); 1258 smb_rq_wend(rqp); 1259 smb_rq_bstart(rqp); 1260 smb_rq_bend(rqp); 1261 error = smb_rq_simple(rqp); 1262 smb_rq_done(rqp); 1263 return error; 1264 } 1265 1266 static int 1267 smbfs_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp, 1268 const char *wildcard, int wclen, int attr, struct smb_cred *scred) 1269 { 1270 ctx->f_name = malloc(SMB_MAXFNAMELEN, M_SMBFSDATA, M_WAITOK); 1271 if (ctx->f_name == NULL) 1272 return ENOMEM; 1273 ctx->f_infolevel = SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_NTLM0_12 ? 1274 SMB_INFO_STANDARD : SMB_FIND_FILE_DIRECTORY_INFO; 1275 ctx->f_attrmask = attr; 1276 ctx->f_wildcard = wildcard; 1277 ctx->f_wclen = wclen; 1278 return 0; 1279 } 1280 1281 static int 1282 smbfs_findnextLM2(struct smbfs_fctx *ctx, int limit) 1283 { 1284 struct mdchain *mbp; 1285 struct smb_t2rq *t2p; 1286 char *cp; 1287 u_int8_t tb; 1288 u_int16_t date, time, wattr; 1289 u_int32_t size, next, dattr; 1290 int64_t lint; 1291 int error, svtz, cnt, fxsz, nmlen, recsz; 1292 1293 if (ctx->f_ecnt == 0) { 1294 if (ctx->f_flags & SMBFS_RDD_EOF) 1295 return ENOENT; 1296 ctx->f_left = ctx->f_limit = limit; 1297 error = smbfs_smb_trans2find2(ctx); 1298 if (error) 1299 return error; 1300 } 1301 t2p = ctx->f_t2; 1302 mbp = &t2p->t2_rdata; 1303 svtz = SSTOVC(ctx->f_ssp)->vc_sopt.sv_tz; 1304 switch (ctx->f_infolevel) { 1305 case SMB_INFO_STANDARD: 1306 next = 0; 1307 fxsz = 0; 1308 md_get_uint16le(mbp, &date); 1309 md_get_uint16le(mbp, &time); /* creation time */ 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_atime); 1313 md_get_uint16le(mbp, &date); 1314 md_get_uint16le(mbp, &time); /* access time */ 1315 smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_mtime); 1316 md_get_uint32le(mbp, &size); 1317 ctx->f_attr.fa_size = size; 1318 md_get_uint32(mbp, NULL); /* allocation size */ 1319 md_get_uint16le(mbp, &wattr); 1320 ctx->f_attr.fa_attr = wattr; 1321 md_get_uint8(mbp, &tb); 1322 size = nmlen = tb; 1323 fxsz = 23; 1324 recsz = next = 24 + nmlen; /* docs misses zero byte at end */ 1325 break; 1326 case SMB_FIND_FILE_DIRECTORY_INFO: 1327 md_get_uint32le(mbp, &next); 1328 md_get_uint32(mbp, NULL); /* file index */ 1329 md_get_int64(mbp, NULL); /* creation time */ 1330 md_get_int64le(mbp, &lint); 1331 smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_atime); 1332 md_get_int64le(mbp, &lint); 1333 smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_mtime); 1334 md_get_int64le(mbp, &lint); 1335 smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_ctime); 1336 md_get_int64le(mbp, &lint); /* file size */ 1337 ctx->f_attr.fa_size = lint; 1338 md_get_int64(mbp, NULL); /* real size (should use) */ 1339 md_get_uint32le(mbp, &dattr); /* EA */ 1340 ctx->f_attr.fa_attr = dattr; 1341 md_get_uint32le(mbp, &size); /* name len */ 1342 fxsz = 64; 1343 recsz = next ? next : fxsz + size; 1344 break; 1345 default: 1346 SMBERROR("unexpected info level %d\n", ctx->f_infolevel); 1347 return EINVAL; 1348 } 1349 nmlen = min(size, SMB_MAXFNAMELEN); 1350 cp = ctx->f_name; 1351 error = md_get_mem(mbp, cp, nmlen, MB_MSYSTEM); 1352 if (error) 1353 return error; 1354 if (next) { 1355 cnt = next - nmlen - fxsz; 1356 if (cnt > 0) 1357 md_get_mem(mbp, NULL, cnt, MB_MSYSTEM); 1358 else if (cnt < 0) { 1359 SMBERROR("out of sync\n"); 1360 return EBADRPC; 1361 } 1362 } 1363 if (nmlen && cp[nmlen - 1] == 0) 1364 nmlen--; 1365 if (nmlen == 0) 1366 return EBADRPC; 1367 1368 next = ctx->f_eofs + recsz; 1369 if (ctx->f_rnameofs && (ctx->f_flags & SMBFS_RDD_GOTRNAME) == 0 && 1370 (ctx->f_rnameofs >= ctx->f_eofs && ctx->f_rnameofs < next)) { 1371 /* 1372 * Server needs a resume filename. 1373 */ 1374 if (ctx->f_rnamelen <= nmlen) { 1375 if (ctx->f_rname) 1376 free(ctx->f_rname, M_SMBFSDATA); 1377 ctx->f_rname = malloc(nmlen + 1, M_SMBFSDATA, M_WAITOK); 1378 ctx->f_rnamelen = nmlen; 1379 } 1380 bcopy(ctx->f_name, ctx->f_rname, nmlen); 1381 ctx->f_rname[nmlen] = 0; 1382 ctx->f_flags |= SMBFS_RDD_GOTRNAME; 1383 } 1384 ctx->f_nmlen = nmlen; 1385 ctx->f_eofs = next; 1386 ctx->f_ecnt--; 1387 ctx->f_left--; 1388 return 0; 1389 } 1390 1391 static int 1392 smbfs_findcloseLM2(struct smbfs_fctx *ctx) 1393 { 1394 if (ctx->f_name) 1395 free(ctx->f_name, M_SMBFSDATA); 1396 if (ctx->f_t2) 1397 smb_t2_done(ctx->f_t2); 1398 if ((ctx->f_flags & SMBFS_RDD_NOCLOSE) == 0) 1399 smbfs_smb_findclose2(ctx); 1400 return 0; 1401 } 1402 1403 int 1404 smbfs_findopen(struct smbnode *dnp, const char *wildcard, int wclen, int attr, 1405 struct smb_cred *scred, struct smbfs_fctx **ctxpp) 1406 { 1407 struct smbfs_fctx *ctx; 1408 int error; 1409 1410 ctx = malloc(sizeof(*ctx), M_SMBFSDATA, M_WAITOK); 1411 if (ctx == NULL) 1412 return ENOMEM; 1413 bzero(ctx, sizeof(*ctx)); 1414 ctx->f_ssp = dnp->n_mount->sm_share; 1415 ctx->f_dnp = dnp; 1416 ctx->f_flags = SMBFS_RDD_FINDFIRST; 1417 ctx->f_scred = scred; 1418 if (SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_LANMAN2_0 || 1419 (dnp->n_mount->sm_flags & SMBFS_MOUNT_NO_LONG)) { 1420 ctx->f_flags |= SMBFS_RDD_USESEARCH; 1421 error = smbfs_findopenLM1(ctx, dnp, wildcard, wclen, attr, scred); 1422 } else 1423 error = smbfs_findopenLM2(ctx, dnp, wildcard, wclen, attr, scred); 1424 if (error) 1425 smbfs_findclose(ctx, scred); 1426 else 1427 *ctxpp = ctx; 1428 return error; 1429 } 1430 1431 int 1432 smbfs_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scred) 1433 { 1434 int error; 1435 1436 if (limit == 0) 1437 limit = 1000000; 1438 else if (limit > 1) 1439 limit *= 4; /* imperical */ 1440 ctx->f_scred = scred; 1441 for (;;) { 1442 if (ctx->f_flags & SMBFS_RDD_USESEARCH) { 1443 error = smbfs_findnextLM1(ctx, limit); 1444 } else 1445 error = smbfs_findnextLM2(ctx, limit); 1446 if (error) 1447 return error; 1448 if ((ctx->f_nmlen == 1 && ctx->f_name[0] == '.') || 1449 (ctx->f_nmlen == 2 && ctx->f_name[0] == '.' && 1450 ctx->f_name[1] == '.')) 1451 continue; 1452 break; 1453 } 1454 smbfs_fname_tolocal(SSTOVC(ctx->f_ssp), ctx->f_name, &ctx->f_nmlen, 1455 ctx->f_dnp->n_mount->sm_caseopt); 1456 ctx->f_attr.fa_ino = smbfs_getino(ctx->f_dnp, ctx->f_name, ctx->f_nmlen); 1457 return 0; 1458 } 1459 1460 int 1461 smbfs_findclose(struct smbfs_fctx *ctx, struct smb_cred *scred) 1462 { 1463 ctx->f_scred = scred; 1464 if (ctx->f_flags & SMBFS_RDD_USESEARCH) { 1465 smbfs_findcloseLM1(ctx); 1466 } else 1467 smbfs_findcloseLM2(ctx); 1468 if (ctx->f_rname) 1469 free(ctx->f_rname, M_SMBFSDATA); 1470 free(ctx, M_SMBFSDATA); 1471 return 0; 1472 } 1473 1474 int 1475 smbfs_smb_lookup(struct smbnode *dnp, const char *name, int nmlen, 1476 struct smbfattr *fap, struct smb_cred *scred) 1477 { 1478 struct smbfs_fctx *ctx; 1479 int error; 1480 1481 if (dnp == NULL || (dnp->n_ino == 2 && name == NULL)) { 1482 bzero(fap, sizeof(*fap)); 1483 fap->fa_attr = SMB_FA_DIR; 1484 fap->fa_ino = 2; 1485 return 0; 1486 } 1487 if (nmlen == 1 && name[0] == '.') { 1488 error = smbfs_smb_lookup(dnp, NULL, 0, fap, scred); 1489 return error; 1490 } else if (nmlen == 2 && name[0] == '.' && name[1] == '.') { 1491 error = smbfs_smb_lookup(VTOSMB(dnp->n_parent), NULL, 0, fap, 1492 scred); 1493 printf("%s: knows NOTHING about '..'\n", __func__); 1494 return error; 1495 } 1496 error = smbfs_findopen(dnp, name, nmlen, 1497 SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, scred, &ctx); 1498 if (error) 1499 return error; 1500 ctx->f_flags |= SMBFS_RDD_FINDSINGLE; 1501 error = smbfs_findnext(ctx, 1, scred); 1502 if (error == 0) { 1503 *fap = ctx->f_attr; 1504 if (name == NULL) 1505 fap->fa_ino = dnp->n_ino; 1506 } 1507 smbfs_findclose(ctx, scred); 1508 return error; 1509 } 1510