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