1/* 2 * Copyright (c) 2011 - 2012 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24#include <sys/smb_apple.h> 25#include <sys/syslog.h> 26 27#include <sys/msfscc.h> 28#include <netsmb/smb.h> 29#include <netsmb/smb_2.h> 30#include <netsmb/smb_rq.h> 31#include <netsmb/smb_rq_2.h> 32#include <netsmb/smb_conn.h> 33#include <netsmb/smb_conn_2.h> 34 35#include <smbfs/smbfs.h> 36#include <smbfs/smbfs_node.h> 37#include <smbfs/smbfs_subr.h> 38#include <smbfs/smbfs_subr_2.h> 39#include <smbfs/smbfs_notify_change.h> 40#include <smbclient/ntstatus.h> 41#include <netsmb/smb_converter.h> 42 43 44static int 45smb2fs_smb_copyfile_mac(struct smb_share *share, struct smbnode *src_np, 46 struct smbnode *tdnp, const char *tnamep, size_t tname_len, 47 vfs_context_t context); 48static int 49smb2fs_smb_delete(struct smb_share *share, struct smbnode *np, 50 const char *namep, size_t name_len, int xattr, 51 vfs_context_t context); 52 53static uint32_t 54smb2fs_smb_fillchunk_arr(struct smb2_copychunk_chunk *chunk_arr, 55 uint32_t chunk_arr_size, 56 uint64_t total_len, uint32_t max_chunk_len, 57 uint64_t src_offset, uint64_t trg_offset, 58 uint32_t *chunk_count_out, uint64_t *total_len_out); 59 60static int 61smb2fs_smb_listxattrs(struct smb_share *share, struct smbnode *np, char **xattrlist, 62 size_t *xattrlist_len, vfs_context_t context); 63int 64smb2fs_smb_ntcreatex(struct smb_share *share, struct smbnode *np, 65 const char *namep, size_t in_nmlen, 66 const char *strm_namep, size_t in_strm_nmlen, 67 uint32_t desired_access, enum vtype vnode_type, 68 uint32_t share_access, uint32_t disposition, 69 uint64_t create_flags, 70 SMBFID *fidp, struct smbfattr *fap, 71 struct smb_rq **compound_rqp, struct smb2_create_rq **in_createp, 72 void *create_contextp, vfs_context_t context); 73static int 74smb2fs_smb_parse_ntcreatex(struct smb_share *share, struct smbnode *np, 75 struct smb2_create_rq *createp, 76 SMBFID *fidp, struct smbfattr *fap, 77 vfs_context_t context); 78static int 79smb2fs_smb_qstreaminfo(struct smb_share *share, struct smbnode *np, 80 const char *namep, size_t name_len, 81 const char *stream_namep, 82 uio_t uio, size_t *sizep, 83 uint64_t *stream_sizep, uint64_t *stream_alloc_sizep, 84 uint32_t *stream_flagsp, uint32_t *max_accessp, 85 vfs_context_t context); 86static int 87smb2fs_smb_request_resume_key(struct smb_share *share, SMBFID fid, u_char *resume_key, 88 vfs_context_t context); 89 90static int 91smb2fs_smb_set_eof(struct smb_share *share, SMBFID fid, uint64_t newsize, 92 vfs_context_t context); 93 94/* 95 * Note: The _smbfs_smb_ in the function name indicates that these functions 96 * are called from the smbfs kext and set up the structs necessary to call the 97 * _smb_ functions. Then copy the results back out to smbfs. 98 * 99 * 100 * SMB1 implementation remains in original files 101 * 102 * Implementations listed in alphabetical order 103 * 1) SMB2 implementation listed first, 104 * 2) SMB1/SMB2 generic implementation next 105 * 106 */ 107 108/* 109 * Compound Request Chain notes: 110 * 1) A compound req is identified by rqp->sr_next_rqp != NULL 111 * 2) The first rqp in the chain has the response data for ALL the 112 * responses. Its header data has already been parsed out and saved in 113 * the first rqp. Subsequent headers will have to be manually parsed out. 114 * 3) When parsing the response chain, even if an earlier response gets an 115 * error, continuing trying to parse the rest of the replies to get the 116 * credits granted in the response header. 117 * 4) If the first response got an error, only print that error message and 118 * skip printing any more errors for the rest of the responses in the chain. 119 */ 120 121int 122smb2fs_smb_cmpd_create(struct smb_share *share, struct smbnode *np, 123 const char *namep, size_t name_len, 124 const char *strm_namep, size_t strm_name_len, 125 uint32_t desired_access, enum vtype vnode_type, 126 uint32_t share_access, uint32_t disposition, 127 uint64_t create_flags, uint32_t *ntstatus, 128 SMBFID *fidp, struct smbfattr *fap, 129 void *create_contextp, vfs_context_t context) 130{ 131 int error, tmp_error; 132 struct smb2_create_rq *createp = NULL; 133 struct smb2_query_info_rq *queryp = NULL; 134 struct smb2_close_rq *closep = NULL; 135 struct smb_rq *create_rqp = NULL; 136 struct smb_rq *query_rqp = NULL; 137 struct smb_rq *close_rqp = NULL; 138 struct mdchain *mdp; 139 size_t next_cmd_offset = 0; 140 uint32_t need_delete_fid = 0; 141 SMBFID fid = 0; 142 int add_query = 0; 143 int add_close = 0; 144 uint64_t inode_number = 0; 145 uint32_t inode_number_len; 146 147 /* 148 * This function can do Create/Close, Create/Query, or Create/Query/Close 149 * If SMB2_CREATE_DO_CREATE is set in create_flags, then the Query is 150 * added to get the file ID. If fidp is NULL, then the Close is added. 151 * 152 * ntstatus is needed for DFS code. smb_usr_check_dir needs to return the 153 * ntstatus up to isReferralPathNotCovered() in user space. 154 */ 155 156 if ((create_flags & SMB2_CREATE_DO_CREATE) && 157 (SSTOVC(share)->vc_misc_flags & SMBV_HAS_FILEIDS)) { 158 /* Need the file id, so add a query into the compound request */ 159 add_query = 1; 160 } 161 162 if (fidp == NULL) { 163 /* If fidp is null, add the close into the compound request */ 164 add_close = 1; 165 } 166 167 if ((add_query == 0) && (add_close == 0)) { 168 /* Just doing a simple create */ 169 error = smb2fs_smb_ntcreatex(share, np, 170 namep, name_len, 171 strm_namep, strm_name_len, 172 desired_access, vnode_type, 173 share_access, disposition, 174 create_flags, 175 fidp, fap, 176 NULL, NULL, 177 create_contextp, context); 178 return error; 179 } 180 181 if (add_query) { 182 SMB_MALLOC(queryp, 183 struct smb2_query_info_rq *, 184 sizeof(struct smb2_query_info_rq), 185 M_SMBTEMP, 186 M_WAITOK | M_ZERO); 187 if (queryp == NULL) { 188 SMBERROR("SMB_MALLOC failed\n"); 189 error = ENOMEM; 190 goto bad; 191 } 192 } 193 194resend: 195 /* 196 * Build the Create call 197 */ 198 error = smb2fs_smb_ntcreatex(share, np, 199 namep, name_len, 200 strm_namep, strm_name_len, 201 desired_access, vnode_type, 202 share_access, disposition, 203 create_flags, 204 &fid, fap, 205 &create_rqp, &createp, 206 create_contextp, context); 207 if (error) { 208 SMBERROR("smb2fs_smb_ntcreatex failed %d\n", error); 209 goto bad; 210 } 211 212 /* Update Create hdr */ 213 error = smb2_rq_update_cmpd_hdr(create_rqp, SMB2_CMPD_FIRST); 214 if (error) { 215 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 216 goto bad; 217 } 218 219 fid = 0xffffffffffffffff; /* fid is -1 for compound requests */ 220 221 if (add_query) { 222 /* 223 * Build the Query Info request (to get File ID) 224 */ 225 inode_number_len = (uint32_t) sizeof(inode_number); 226 227 queryp->info_type = SMB2_0_INFO_FILE; 228 queryp->file_info_class = FileInternalInformation; 229 queryp->add_info = 0; 230 queryp->flags = 0; 231 queryp->output_buffer_len = inode_number_len; 232 queryp->output_buffer = (uint8_t *) &inode_number; 233 queryp->input_buffer_len = 0; 234 queryp->input_buffer = NULL; 235 queryp->ret_buffer_len = 0; 236 queryp->fid = fid; 237 238 error = smb2_smb_query_info(share, queryp, &query_rqp, context); 239 if (error) { 240 SMBERROR("smb2_smb_query_info failed %d\n", error); 241 goto bad; 242 } 243 244 /* Update Query hdr */ 245 if (add_close) { 246 error = smb2_rq_update_cmpd_hdr(query_rqp, SMB2_CMPD_MIDDLE); 247 } 248 else { 249 error = smb2_rq_update_cmpd_hdr(query_rqp, SMB2_CMPD_LAST); 250 } 251 if (error) { 252 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 253 goto bad; 254 } 255 256 /* Chain Query Info to the Create */ 257 create_rqp->sr_next_rqp = query_rqp; 258 } 259 260 if (add_close) { 261 /* 262 * Build the Close request 263 */ 264 error = smb2_smb_close_fid(share, fid, &close_rqp, &closep, context); 265 if (error) { 266 SMBERROR("smb2_smb_close_fid failed %d\n", error); 267 goto bad; 268 } 269 270 /* Update Close hdr */ 271 error = smb2_rq_update_cmpd_hdr(close_rqp, SMB2_CMPD_LAST); 272 if (error) { 273 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 274 goto bad; 275 } 276 277 if (add_query) { 278 /* Chain Close to the Query */ 279 query_rqp->sr_next_rqp = close_rqp; 280 } 281 else { 282 /* Chain Close to the Create */ 283 create_rqp->sr_next_rqp = close_rqp; 284 } 285 } 286 287 /* 288 * Send the compound request of Create/Query/Close 289 */ 290 error = smb_rq_simple(create_rqp); 291 292 if ((error) && (create_rqp->sr_flags & SMBR_RECONNECTED)) { 293 /* Rebuild and try sending again */ 294 smb_rq_done(create_rqp); 295 create_rqp = NULL; 296 297 if (query_rqp != NULL) { 298 smb_rq_done(query_rqp); 299 query_rqp = NULL; 300 } 301 302 if (close_rqp != NULL) { 303 smb_rq_done(close_rqp); 304 close_rqp = NULL; 305 } 306 307 SMB_FREE(createp, M_SMBTEMP); 308 createp = NULL; 309 310 if (closep != NULL) { 311 SMB_FREE(closep, M_SMBTEMP); 312 closep = NULL; 313 } 314 315 goto resend; 316 } 317 318 createp->ret_ntstatus = create_rqp->sr_ntstatus; 319 if (ntstatus) { 320 /* Return NT Status error if they want it */ 321 *ntstatus = createp->ret_ntstatus; 322 } 323 324 /* Get pointer to response data */ 325 smb_rq_getreply(create_rqp, &mdp); 326 327 if (error) { 328 /* Create failed, try parsing the Query */ 329 if (error != ENOENT) { 330 SMBDEBUG("smb_rq_simple failed %d id %lld\n", 331 error, create_rqp->sr_messageid); 332 } 333 goto parse_query; 334 } 335 336 /* 337 * Parse the Create response. 338 */ 339 error = smb2_smb_parse_create(share, mdp, createp); 340 if (error) { 341 /* Create parsing failed, try parsing the Query */ 342 SMBERROR("smb2_smb_parse_create failed %d id %lld\n", 343 error, create_rqp->sr_messageid); 344 goto parse_query; 345 } 346 347 /* At this point, fid has been entered into fid table */ 348 need_delete_fid = 1; 349 350 /* 351 * Fill in fap and possibly update vnode's meta data caches 352 */ 353 error = smb2fs_smb_parse_ntcreatex(share, np, createp, 354 fidp, fap, context); 355 if (error) { 356 /* Updating meta data cache failed, try parsing the Close */ 357 SMBERROR("smb2fs_smb_parse_ntcreatex failed %d id %lld\n", 358 error, create_rqp->sr_messageid); 359 } 360 361parse_query: 362 if (query_rqp != NULL) { 363 /* Consume any pad bytes */ 364 tmp_error = smb2_rq_next_command(create_rqp, &next_cmd_offset, mdp); 365 if (tmp_error) { 366 /* Failed to find next command, so can't parse rest of the responses */ 367 SMBERROR("create smb2_rq_next_command failed %d id %lld\n", 368 tmp_error, create_rqp->sr_messageid); 369 error = error ? error : tmp_error; 370 goto bad; 371 } 372 373 /* 374 * Parse Query Info SMB2 header 375 */ 376 tmp_error = smb2_rq_parse_header(query_rqp, &mdp); 377 queryp->ret_ntstatus = query_rqp->sr_ntstatus; 378 if (tmp_error) { 379 /* Query Info got an error, try parsing the Close */ 380 if (!error) { 381 SMBDEBUG("query smb2_rq_parse_header failed %d, id %lld\n", 382 tmp_error, query_rqp->sr_messageid); 383 error = tmp_error; 384 } 385 goto parse_close; 386 } 387 388 /* Parse the Query Info response */ 389 tmp_error = smb2_smb_parse_query_info(mdp, queryp); 390 if (tmp_error) { 391 /* Query Info parsing got an error, try parsing the Close */ 392 if (!error) { 393 if (tmp_error != ENOATTR) { 394 SMBERROR("smb2_smb_parse_query_info failed %d id %lld\n", 395 tmp_error, query_rqp->sr_messageid); 396 } 397 error = tmp_error; 398 } 399 goto parse_close; 400 } 401 else { 402 /* Query worked, so get the inode number */ 403 if (fap) { 404 fap->fa_ino = inode_number; 405 smb2fs_smb_file_id_check(share, fap->fa_ino, NULL, 0); 406 } 407 } 408 } 409 410parse_close: 411 if (close_rqp != NULL) { 412 /* Update closep fid so it gets freed from FID table */ 413 closep->fid = createp->ret_fid; 414 415 /* Consume any pad bytes */ 416 tmp_error = smb2_rq_next_command(query_rqp != NULL ? query_rqp : create_rqp, 417 &next_cmd_offset, mdp); 418 if (tmp_error) { 419 /* Failed to find next command, so can't parse rest of the responses */ 420 SMBERROR("create smb2_rq_next_command failed %d id %lld\n", 421 tmp_error, create_rqp->sr_messageid); 422 error = error ? error : tmp_error; 423 goto bad; 424 } 425 426 /* 427 * Parse Close SMB2 header 428 */ 429 tmp_error = smb2_rq_parse_header(close_rqp, &mdp); 430 closep->ret_ntstatus = close_rqp->sr_ntstatus; 431 if (tmp_error) { 432 if (!error) { 433 SMBDEBUG("close smb2_rq_parse_header failed %d id %lld\n", 434 tmp_error, close_rqp->sr_messageid); 435 error = tmp_error; 436 437 if (ntstatus) { 438 /* Return NT Status error if they want it */ 439 *ntstatus = closep->ret_ntstatus; 440 } 441 } 442 goto bad; 443 } 444 445 /* Parse the Close response */ 446 tmp_error = smb2_smb_parse_close(mdp, closep); 447 if (tmp_error) { 448 if (!error) { 449 SMBERROR("smb2_smb_parse_close failed %d id %lld\n", 450 tmp_error, close_rqp->sr_messageid); 451 error = tmp_error; 452 } 453 goto bad; 454 } 455 456 /* At this point, fid has been removed from fid table */ 457 need_delete_fid = 0; 458 } 459 else { 460 /* Not doing a close, so leave it open */ 461 need_delete_fid = 0; 462 } 463 464bad: 465 if (need_delete_fid == 1) { 466 /* 467 * Close failed but the Create worked and was successfully parsed. 468 * Try issuing the Close request again. 469 */ 470 tmp_error = smb2_smb_close_fid(share, createp->ret_fid, 471 NULL, NULL, context); 472 if (tmp_error) { 473 SMBERROR("Second close failed %d\n", tmp_error); 474 } 475 } 476 477 if (create_rqp != NULL) { 478 smb_rq_done(create_rqp); 479 } 480 if (query_rqp != NULL) { 481 smb_rq_done(query_rqp); 482 } 483 if (close_rqp != NULL) { 484 smb_rq_done(close_rqp); 485 } 486 487 if (createp != NULL) { 488 SMB_FREE(createp, M_SMBTEMP); 489 } 490 if (queryp != NULL) { 491 SMB_FREE(queryp, M_SMBTEMP); 492 } 493 if (closep != NULL) { 494 SMB_FREE(closep, M_SMBTEMP); 495 } 496 497 return error; 498} 499 500static int 501smb2fs_smb_cmpd_create_read(struct smb_share *share, struct smbnode *dnp, 502 const char *namep, size_t name_len, 503 const char *snamep, size_t sname_len, 504 uint32_t desired_access, uio_t uio, 505 size_t *sizep, uint32_t *max_accessp, 506 SMBFID *fidp, struct timespec *mtime, 507 vfs_context_t context) 508{ 509 int error, tmp_error; 510 uint32_t disposition; 511 uint32_t share_access; 512 SMBFID fid = 0; 513 struct smbfattr *fap = NULL; 514 struct smb2_create_rq *createp = NULL; 515 struct smb2_rw_rq *readp = NULL; 516 struct smb2_close_rq *closep = NULL; 517 struct smb_rq *create_rqp = NULL; 518 struct smb_rq *read_rqp = NULL; 519 struct smb_rq *close_rqp = NULL; 520 struct mdchain *mdp; 521 size_t next_cmd_offset = 0; 522 user_ssize_t len, resid = 0; 523 user_ssize_t rresid = 0; 524 uint64_t create_flags = SMB2_CREATE_GET_MAX_ACCESS; 525 uint32_t need_delete_fid = 0; 526 int add_close = 0; 527 528 /* 529 * This function can do Create/Read or Create/Read/Close 530 * If fidp is NULL, then the Close is added. 531 */ 532 533 /* 534 * (1) This is used when dealing with readdirattr for Finder Info 535 * It has a parent dnp, child of namep and stream name of snamep. 536 * (2) This is used for dealing with Finder Info which is an xattr 537 * (ie stream) and assumes the read data will all fit in one read request 538 */ 539 540 if (fidp == NULL) { 541 /* If fidp is null, add the close into the compound request */ 542 add_close = 1; 543 } 544 else { 545 *fidp = 0; /* indicates create failed */ 546 } 547 548 SMB_MALLOC(fap, 549 struct smbfattr *, 550 sizeof(struct smbfattr), 551 M_SMBTEMP, 552 M_WAITOK | M_ZERO); 553 if (fap == NULL) { 554 SMBERROR("SMB_MALLOC failed\n"); 555 error = ENOMEM; 556 goto bad; 557 } 558 559 SMB_MALLOC(readp, 560 struct smb2_rw_rq *, 561 sizeof(struct smb2_rw_rq), 562 M_SMBTEMP, 563 M_WAITOK | M_ZERO); 564 if (readp == NULL) { 565 SMBERROR("SMB_MALLOC failed\n"); 566 error = ENOMEM; 567 goto bad; 568 } 569 570 /* 571 * Set up for the Create call 572 */ 573 if (snamep) { 574 create_flags |= SMB2_CREATE_IS_NAMED_STREAM; 575 } 576 577 if (desired_access & SMB2_FILE_WRITE_DATA) { 578 share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_DELETE; 579 disposition = FILE_OPEN_IF; 580 } 581 else { 582 share_access = NTCREATEX_SHARE_ACCESS_ALL; 583 disposition = FILE_OPEN; 584 } 585 586resend: 587 /* 588 * Build the Create call 589 */ 590 error = smb2fs_smb_ntcreatex(share, dnp, 591 namep, name_len, 592 snamep, sname_len, 593 desired_access, VREG, 594 share_access, disposition, 595 create_flags, 596 &fid, fap, 597 &create_rqp, &createp, 598 NULL, context); 599 if (error) { 600 SMBERROR("smb2fs_smb_ntcreatex failed %d\n", error); 601 goto bad; 602 } 603 604 /* Update Create hdr */ 605 error = smb2_rq_update_cmpd_hdr(create_rqp, SMB2_CMPD_FIRST); 606 if (error) { 607 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 608 goto bad; 609 } 610 611 /* 612 * Build the Read request 613 */ 614 readp->flags = 0; 615 readp->remaining = 0; 616 readp->write_flags = 0; 617 fid = 0xffffffffffffffff; /* fid is -1 for compound requests */ 618 readp->fid = fid; 619 readp->auio = uio; 620 621 /* assume we can read it all in one request */ 622 len = uio_resid(readp->auio); 623 624 error = smb2_smb_read_one(share, readp, &len, &resid, &read_rqp, context); 625 if (error) { 626 SMBERROR("smb2_smb_read_one failed %d\n", error); 627 goto bad; 628 } 629 630 /* Update Read hdr */ 631 if (add_close) { 632 error = smb2_rq_update_cmpd_hdr(read_rqp, SMB2_CMPD_MIDDLE); 633 } 634 else { 635 error = smb2_rq_update_cmpd_hdr(read_rqp, SMB2_CMPD_LAST); 636 } 637 if (error) { 638 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 639 goto bad; 640 } 641 642 /* Chain Read to the Create */ 643 create_rqp->sr_next_rqp = read_rqp; 644 645 if (add_close) { 646 /* 647 * Build the Close request 648 */ 649 error = smb2_smb_close_fid(share, fid, &close_rqp, &closep, context); 650 if (error) { 651 SMBERROR("smb2_smb_close_fid failed %d\n", error); 652 goto bad; 653 } 654 655 /* Update Close hdr */ 656 error = smb2_rq_update_cmpd_hdr(close_rqp, SMB2_CMPD_LAST); 657 if (error) { 658 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 659 goto bad; 660 } 661 662 /* Chain Close to the Read */ 663 read_rqp->sr_next_rqp = close_rqp; 664 } 665 666 /* 667 * Send the compound request of Create/Read/Close 668 */ 669 error = smb_rq_simple(create_rqp); 670 671 if ((error) && (create_rqp->sr_flags & SMBR_RECONNECTED)) { 672 /* Rebuild and try sending again */ 673 smb_rq_done(create_rqp); 674 create_rqp = NULL; 675 676 smb_rq_done(read_rqp); 677 read_rqp = NULL; 678 679 if (close_rqp != NULL) { 680 smb_rq_done(close_rqp); 681 close_rqp = NULL; 682 } 683 684 SMB_FREE(createp, M_SMBTEMP); 685 createp = NULL; 686 687 if (closep != NULL) { 688 SMB_FREE(closep, M_SMBTEMP); 689 closep = NULL; 690 } 691 692 goto resend; 693 } 694 695 createp->ret_ntstatus = create_rqp->sr_ntstatus; 696 697 /* Get pointer to response data */ 698 smb_rq_getreply(create_rqp, &mdp); 699 700 if (error) { 701 /* Create failed, try parsing the Read */ 702 if (error != ENOENT) { 703 SMBDEBUG("smb_rq_simple failed %d id %lld\n", 704 error, create_rqp->sr_messageid); 705 } 706 707 if (fidp) { 708 *fidp = 0; /* indicate Create failed */ 709 } 710 goto parse_read; 711 } 712 713 /* 714 * Parse the Create response. 715 */ 716 error = smb2_smb_parse_create(share, mdp, createp); 717 if (error) { 718 /* Create parsing failed, try parsing the Read */ 719 SMBERROR("smb2_smb_parse_create failed %d id %lld\n", 720 error, create_rqp->sr_messageid); 721 722 if (fidp) { 723 *fidp = 0; /* indicate Create failed */ 724 } 725 goto parse_read; 726 } 727 728 /* At this point, fid has been entered into fid table */ 729 need_delete_fid = 1; 730 731 /* 732 * Fill in fap and possibly update vnode's meta data caches 733 */ 734 error = smb2fs_smb_parse_ntcreatex(share, dnp, createp, 735 fidp, fap, context); 736 if (error) { 737 /* Updating meta data cache failed, try parsing the Read */ 738 SMBERROR("smb2fs_smb_parse_ntcreatex failed %d id %lld\n", 739 error, create_rqp->sr_messageid); 740 } 741 else { 742 /* Return max access if they want it */ 743 if (max_accessp) { 744 DBG_ASSERT(fap->fa_valid_mask & FA_MAX_ACCESS_VALID) 745 *max_accessp = fap->fa_max_access; 746 } 747 if (mtime) { 748 *mtime = fap->fa_mtime; 749 } 750 } 751 752parse_read: 753 /* Consume any pad bytes */ 754 tmp_error = smb2_rq_next_command(create_rqp, &next_cmd_offset, mdp); 755 if (tmp_error) { 756 /* Failed to find next command, so can't parse rest of the responses */ 757 SMBERROR("create smb2_rq_next_command failed %d id %lld\n", 758 tmp_error, create_rqp->sr_messageid); 759 error = error ? error : tmp_error; 760 goto bad; 761 } 762 763 /* 764 * Parse Read SMB2 header 765 */ 766 tmp_error = smb2_rq_parse_header(read_rqp, &mdp); 767 readp->ret_ntstatus = read_rqp->sr_ntstatus; 768 769 if (tmp_error == ENODATA) { 770 /* 771 * Ignore EOF and leave error alone as it could contain an error from 772 * the create, but skip trying to parse the read data 773 */ 774 goto parse_close; 775 } 776 777 if (tmp_error) { 778 /* Read got an error, try parsing the Close */ 779 if (!error) { 780 SMBDEBUG("read smb2_rq_parse_header failed %d, id %lld\n", 781 tmp_error, read_rqp->sr_messageid); 782 error = tmp_error; 783 } 784 goto parse_close; 785 } 786 787 /* Parse the Read response */ 788 tmp_error = smb2_smb_parse_read_one(mdp, &rresid, readp); 789 if (tmp_error) { 790 /* Read parsing got an error, try parsing the Close */ 791 if (!error) { 792 SMBERROR("smb2_smb_parse_read_one failed %d id %lld\n", 793 tmp_error, read_rqp->sr_messageid); 794 error = tmp_error; 795 } 796 goto parse_close; 797 } 798 799 if (sizep) { 800 /* 801 * *sizep contains the logical size of the stream 802 * The calling routines can only handle size_t 803 */ 804 *sizep = fap->fa_size; 805 } 806 807parse_close: 808 if (close_rqp != NULL) { 809 /* Update closep fid so it gets freed from FID table */ 810 closep->fid = createp->ret_fid; 811 812 /* Consume any pad bytes */ 813 tmp_error = smb2_rq_next_command(read_rqp, &next_cmd_offset, mdp); 814 if (tmp_error) { 815 /* Failed to find next command, so can't parse rest of the responses */ 816 SMBERROR("read smb2_rq_next_command failed %d id %lld\n", 817 tmp_error, read_rqp->sr_messageid); 818 error = error ? error : tmp_error; 819 goto bad; 820 } 821 822 /* 823 * Parse Close SMB2 header 824 */ 825 tmp_error = smb2_rq_parse_header(close_rqp, &mdp); 826 closep->ret_ntstatus = close_rqp->sr_ntstatus; 827 if (tmp_error) { 828 if (!error) { 829 SMBDEBUG("close smb2_rq_parse_header failed %d id %lld\n", 830 tmp_error, close_rqp->sr_messageid); 831 error = tmp_error; 832 } 833 goto bad; 834 } 835 836 /* Parse the Close response */ 837 tmp_error = smb2_smb_parse_close(mdp, closep); 838 if (tmp_error) { 839 if (!error) { 840 SMBERROR("smb2_smb_parse_close failed %d id %lld\n", 841 tmp_error, close_rqp->sr_messageid); 842 error = tmp_error; 843 } 844 goto bad; 845 } 846 847 /* At this point, fid has been removed from fid table */ 848 need_delete_fid = 0; 849 } 850 else { 851 /* Not doing a close, so leave it open */ 852 need_delete_fid = 0; 853 } 854 855bad: 856 if (need_delete_fid == 1) { 857 /* 858 * Close failed but the Create worked and was successfully parsed. 859 * Try issuing the Close request again. 860 */ 861 tmp_error = smb2_smb_close_fid(share, createp->ret_fid, 862 NULL, NULL, context); 863 if (tmp_error) { 864 SMBERROR("Second close failed %d\n", tmp_error); 865 } 866 } 867 868 if (create_rqp != NULL) { 869 smb_rq_done(create_rqp); 870 } 871 if (read_rqp != NULL) { 872 smb_rq_done(read_rqp); 873 } 874 if (close_rqp != NULL) { 875 smb_rq_done(close_rqp); 876 } 877 878 if (createp != NULL) { 879 SMB_FREE(createp, M_SMBTEMP); 880 } 881 if (readp != NULL) { 882 SMB_FREE(readp, M_SMBTEMP); 883 } 884 if (closep != NULL) { 885 SMB_FREE(closep, M_SMBTEMP); 886 } 887 888 if (fap != NULL) { 889 SMB_FREE(fap, M_SMBTEMP); 890 } 891 892 return error; 893} 894 895int smbfs_smb_cmpd_create_read_close(struct smb_share *share, struct smbnode *dnp, 896 const char *namep, size_t name_len, 897 const char *snamep, size_t sname_len, 898 uio_t uio, size_t *sizep, 899 uint32_t *max_accessp, 900 vfs_context_t context) 901{ 902 int error; 903 SMBFID fid = 0; 904 905 /* 906 * This is only used when dealing with readdirattr for Finder Info 907 */ 908 909 if (SSTOVC(share)->vc_flags & SMBV_SMB2) { 910 /* Do a Create/Read/Close */ 911 error = smb2fs_smb_cmpd_create_read(share, dnp, 912 namep, name_len, 913 snamep, sname_len, 914 SMB2_FILE_READ_DATA, uio, 915 sizep, max_accessp, 916 NULL, NULL, 917 context); 918 } 919 else { 920 error = smb1fs_smb_open_read(share, dnp, 921 namep, name_len, 922 snamep, sname_len, 923 &fid, uio, sizep, 924 max_accessp, 925 context); 926 if (fid) { 927 (void)smbfs_smb_close(share, fid, context); 928 } 929 } 930 931 return error; 932} 933 934static int 935smb2fs_smb_cmpd_query(struct smb_share *share, struct smbnode *create_np, 936 const char *create_namep, size_t create_name_len, 937 uint32_t create_xattr, uint32_t create_desired_access, 938 uint8_t query_info_type, uint8_t query_file_info_class, 939 uint32_t query_add_info, uint32_t *max_accessp, 940 uint32_t *query_output_buffer_len, uint8_t *query_output_buffer, 941 vfs_context_t context) 942{ 943 int error, tmp_error; 944 SMBFID fid = 0; 945 struct smbfattr *fap = NULL; 946 struct smb2_create_rq *createp = NULL; 947 struct smb2_query_info_rq *queryp = NULL; 948 struct smb2_close_rq *closep = NULL; 949 struct smb_rq *create_rqp = NULL; 950 struct smb_rq *query_rqp = NULL; 951 struct smb_rq *close_rqp = NULL; 952 struct mdchain *mdp; 953 size_t next_cmd_offset = 0; 954 uint32_t need_delete_fid = 0; 955 uint32_t share_access = NTCREATEX_SHARE_ACCESS_ALL; 956 uint64_t create_flags = create_xattr ? SMB2_CREATE_IS_NAMED_STREAM : 0; 957 char *file_namep = NULL, *stream_namep = NULL; 958 size_t file_name_len = 0, stream_name_len = 0; 959 int add_submount_path = 0; 960 961 /* 962 * Note: Be careful as 963 * (1) share->ss_mount can be null 964 * (2) create_np can be null 965 */ 966 967 SMB_MALLOC(fap, 968 struct smbfattr *, 969 sizeof(struct smbfattr), 970 M_SMBTEMP, 971 M_WAITOK | M_ZERO); 972 if (fap == NULL) { 973 SMBERROR("SMB_MALLOC failed\n"); 974 error = ENOMEM; 975 goto bad; 976 } 977 978 SMB_MALLOC(queryp, 979 struct smb2_query_info_rq *, 980 sizeof(struct smb2_query_info_rq), 981 M_SMBTEMP, 982 M_WAITOK | M_ZERO); 983 if (queryp == NULL) { 984 SMBERROR("SMB_MALLOC failed\n"); 985 error = ENOMEM; 986 goto bad; 987 } 988 989 if ((create_np == NULL) && (create_namep != NULL) && 990 ((query_file_info_class == FileFsAttributeInformation) || 991 (query_file_info_class == FileFsSizeInformation))) { 992 /* 993 * Must be during mount time which means we do not have the root 994 * vnode yet, but we do have a submount path. Submount path is 995 * inside the create_namep and already in network form. 996 */ 997 add_submount_path = 1; 998 } 999 1000resend: 1001 /* 1002 * Build the Create call 1003 */ 1004 create_flags |= SMB2_CREATE_GET_MAX_ACCESS; 1005 1006 if (add_submount_path == 1) { 1007 create_flags |= SMB2_CREATE_NAME_IS_PATH; 1008 } 1009 1010 /* Should we check to see if the server is OS X based? */ 1011 if (!(SSTOVC(share)->vc_misc_flags & (SMBV_OSX_SERVER | SMBV_OTHER_SERVER))) { 1012 if ((create_np != NULL) && 1013 (create_namep == NULL) && 1014 (create_xattr == 0) && 1015 (create_np->n_ino == create_np->n_mount->sm_root_ino)) { 1016 SMBDEBUG("Checking for OS X server \n"); 1017 create_flags |= SMB2_CREATE_AAPL_QUERY; 1018 } 1019 } 1020 1021 if (!(create_flags & SMB2_CREATE_IS_NAMED_STREAM)) { 1022 file_namep = (char *) create_namep; 1023 file_name_len = create_name_len; 1024 } 1025 else { 1026 /* create_namep is actually the stream name */ 1027 stream_namep = (char *) create_namep; 1028 stream_name_len = create_name_len; 1029 } 1030 1031 error = smb2fs_smb_ntcreatex(share, create_np, 1032 file_namep, file_name_len, 1033 stream_namep, stream_name_len, 1034 create_desired_access, VREG, 1035 share_access, FILE_OPEN, 1036 create_flags, 1037 &fid, fap, 1038 &create_rqp, &createp, 1039 NULL, context); 1040 if (error) { 1041 SMBERROR("smb2fs_smb_ntcreatex failed %d\n", error); 1042 goto bad; 1043 } 1044 1045 if (add_submount_path == 1) { 1046 /* Clear DFS Operation flag that got set */ 1047 *create_rqp->sr_flagsp &= ~(htolel(SMB2_FLAGS_DFS_OPERATIONS)); 1048 } 1049 1050 /* Update Create hdr */ 1051 error = smb2_rq_update_cmpd_hdr(create_rqp, SMB2_CMPD_FIRST); 1052 if (error) { 1053 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 1054 goto bad; 1055 } 1056 1057 /* 1058 * Build the Query Info request 1059 */ 1060 queryp->info_type = query_info_type; 1061 queryp->file_info_class = query_file_info_class; 1062 queryp->add_info = query_add_info; 1063 queryp->flags = 0; 1064 queryp->output_buffer_len = *query_output_buffer_len; 1065 queryp->output_buffer = query_output_buffer; 1066 queryp->input_buffer_len = 0; 1067 queryp->input_buffer = NULL; 1068 queryp->ret_buffer_len = 0; 1069 fid = 0xffffffffffffffff; /* fid is -1 for compound requests */ 1070 queryp->fid = fid; 1071 1072 error = smb2_smb_query_info(share, queryp, &query_rqp, context); 1073 if (error) { 1074 SMBERROR("smb2_smb_query_info failed %d\n", error); 1075 goto bad; 1076 } 1077 1078 /* Update Query hdr */ 1079 error = smb2_rq_update_cmpd_hdr(query_rqp, SMB2_CMPD_MIDDLE); 1080 if (error) { 1081 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 1082 goto bad; 1083 } 1084 1085 /* Chain Query Info to the Create */ 1086 create_rqp->sr_next_rqp = query_rqp; 1087 1088 /* 1089 * Build the Close request 1090 */ 1091 error = smb2_smb_close_fid(share, fid, &close_rqp, &closep, context); 1092 if (error) { 1093 SMBERROR("smb2_smb_close_fid failed %d\n", error); 1094 goto bad; 1095 } 1096 1097 /* Update Close hdr */ 1098 error = smb2_rq_update_cmpd_hdr(close_rqp, SMB2_CMPD_LAST); 1099 if (error) { 1100 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 1101 goto bad; 1102 } 1103 1104 /* Chain Close to the Query Info */ 1105 query_rqp->sr_next_rqp = close_rqp; 1106 1107 /* 1108 * Send the compound request of Create/Query/Close 1109 */ 1110 error = smb_rq_simple(create_rqp); 1111 1112 if ((error) && (create_rqp->sr_flags & SMBR_RECONNECTED)) { 1113 /* Rebuild and try sending again */ 1114 smb_rq_done(create_rqp); 1115 create_rqp = NULL; 1116 1117 smb_rq_done(query_rqp); 1118 query_rqp = NULL; 1119 1120 smb_rq_done(close_rqp); 1121 close_rqp = NULL; 1122 1123 SMB_FREE(createp, M_SMBTEMP); 1124 createp = NULL; 1125 1126 SMB_FREE(closep, M_SMBTEMP); 1127 closep = NULL; 1128 1129 goto resend; 1130 } 1131 1132 createp->ret_ntstatus = create_rqp->sr_ntstatus; 1133 1134 /* Get pointer to response data */ 1135 smb_rq_getreply(create_rqp, &mdp); 1136 1137 if (error) { 1138 /* Create failed, try parsing the Query Info */ 1139 if ((error != ENOENT) && (error != EACCES)) { 1140 SMBDEBUG("smb_rq_simple failed %d id %lld\n", 1141 error, create_rqp->sr_messageid); 1142 } 1143 1144 /* 1145 * Some servers return an error with the AAPL Create context instead 1146 * of just ignoring the context like it says in the MS-SMB doc. 1147 * Obviously must be a non OS X Server. 1148 */ 1149 if (createp->flags & SMB2_CREATE_AAPL_QUERY) { 1150 SMBDEBUG("Found a NON OS X server\n"); 1151 SSTOVC(share)->vc_misc_flags |= SMBV_OTHER_SERVER; 1152 } 1153 1154 goto parse_query; 1155 } 1156 1157 /* 1158 * Parse the Create response. 1159 */ 1160 error = smb2_smb_parse_create(share, mdp, createp); 1161 if (error) { 1162 /* Create parsing failed, try parsing the Query Info */ 1163 SMBERROR("smb2_smb_parse_create failed %d id %lld\n", 1164 error, create_rqp->sr_messageid); 1165 goto parse_query; 1166 } 1167 1168 /* At this point, fid has been entered into fid table */ 1169 need_delete_fid = 1; 1170 1171 /* 1172 * Fill in fap and possibly update vnode's meta data caches 1173 */ 1174 error = smb2fs_smb_parse_ntcreatex(share, create_np, createp, 1175 &fid, fap, context); 1176 if (error) { 1177 /* Updating meta data cache failed, try parsing the Query Info */ 1178 SMBERROR("smb2fs_smb_parse_ntcreatex failed %d id %lld\n", 1179 error, create_rqp->sr_messageid); 1180 } 1181 else { 1182 /* Return max access if they want it */ 1183 if (max_accessp) { 1184 DBG_ASSERT(fap->fa_valid_mask & FA_MAX_ACCESS_VALID) 1185 *max_accessp = fap->fa_max_access; 1186 } 1187 } 1188 1189parse_query: 1190 /* Consume any pad bytes */ 1191 tmp_error = smb2_rq_next_command(create_rqp, &next_cmd_offset, mdp); 1192 if (tmp_error) { 1193 /* Failed to find next command, so can't parse rest of the responses */ 1194 SMBERROR("create smb2_rq_next_command failed %d id %lld\n", 1195 tmp_error, create_rqp->sr_messageid); 1196 error = error ? error : tmp_error; 1197 goto bad; 1198 } 1199 1200 /* 1201 * Parse Query Info SMB2 header 1202 */ 1203 tmp_error = smb2_rq_parse_header(query_rqp, &mdp); 1204 queryp->ret_ntstatus = query_rqp->sr_ntstatus; 1205 if (tmp_error) { 1206 /* Query Info got an error, try parsing the Close */ 1207 if (!error) { 1208 SMBDEBUG("query smb2_rq_parse_header failed %d, id %lld\n", 1209 tmp_error, query_rqp->sr_messageid); 1210 error = tmp_error; 1211 } 1212 goto parse_close; 1213 } 1214 1215 /* Parse the Query Info response */ 1216 tmp_error = smb2_smb_parse_query_info(mdp, queryp); 1217 if (tmp_error) { 1218 /* Query Info parsing got an error, try parsing the Close */ 1219 if (!error) { 1220 if (tmp_error != ENOATTR) { 1221 SMBERROR("smb2_smb_parse_query_info failed %d id %lld\n", 1222 tmp_error, query_rqp->sr_messageid); 1223 } 1224 error = tmp_error; 1225 } 1226 goto parse_close; 1227 } 1228 else { 1229 *query_output_buffer_len = queryp->ret_buffer_len; 1230 } 1231 1232parse_close: 1233 /* Update closep fid so it gets freed from FID table */ 1234 closep->fid = createp->ret_fid; 1235 1236 /* Consume any pad bytes */ 1237 tmp_error = smb2_rq_next_command(query_rqp, &next_cmd_offset, mdp); 1238 if (tmp_error) { 1239 /* Failed to find next command, so can't parse rest of the responses */ 1240 SMBERROR("query smb2_rq_next_command failed %d\n", tmp_error); 1241 error = error ? error : tmp_error; 1242 goto bad; 1243 } 1244 1245 /* 1246 * Parse Close SMB2 header 1247 */ 1248 tmp_error = smb2_rq_parse_header(close_rqp, &mdp); 1249 closep->ret_ntstatus = close_rqp->sr_ntstatus; 1250 if (tmp_error) { 1251 /* Close got an error */ 1252 if (!error) { 1253 SMBDEBUG("close smb2_rq_parse_header failed %d id %lld\n", 1254 tmp_error, close_rqp->sr_messageid); 1255 error = tmp_error; 1256 } 1257 goto bad; 1258 } 1259 1260 /* Parse the Close response */ 1261 tmp_error = smb2_smb_parse_close(mdp, closep); 1262 if (tmp_error) { 1263 /* Close parsing got an error */ 1264 if (!error) { 1265 SMBERROR("smb2_smb_parse_close failed %d id %lld\n", 1266 tmp_error, close_rqp->sr_messageid); 1267 error = tmp_error; 1268 } 1269 goto bad; 1270 } 1271 1272 /* At this point, fid has been removed from fid table */ 1273 need_delete_fid = 0; 1274 1275bad: 1276 if (need_delete_fid == 1) { 1277 /* 1278 * Close failed but the Create worked and was successfully parsed. 1279 * Try issuing the Close request again. 1280 */ 1281 tmp_error = smb2_smb_close_fid(share, createp->ret_fid, 1282 NULL, NULL, context); 1283 if (tmp_error) { 1284 SMBERROR("Second close failed %d\n", tmp_error); 1285 } 1286 } 1287 1288 if (create_rqp != NULL) { 1289 smb_rq_done(create_rqp); 1290 } 1291 if (query_rqp != NULL) { 1292 smb_rq_done(query_rqp); 1293 } 1294 if (close_rqp != NULL) { 1295 smb_rq_done(close_rqp); 1296 } 1297 1298 if (createp != NULL) { 1299 SMB_FREE(createp, M_SMBTEMP); 1300 } 1301 if (queryp != NULL) { 1302 SMB_FREE(queryp, M_SMBTEMP); 1303 } 1304 if (closep != NULL) { 1305 SMB_FREE(closep, M_SMBTEMP); 1306 } 1307 1308 if (fap != NULL) { 1309 SMB_FREE(fap, M_SMBTEMP); 1310 } 1311 1312 return error; 1313} 1314 1315static int 1316smb2fs_smb_cmpd_query_dir(struct smbfs_fctx *ctx, 1317 struct smb2_query_dir_rq *queryp, 1318 vfs_context_t context) 1319{ 1320 int error, tmp_error; 1321 struct mdchain *mdp; 1322 size_t next_cmd_offset = 0; 1323 struct smb_rq *create_rqp = NULL; 1324 struct smb_rq *query_rqp = NULL; 1325 struct smb2_create_rq *createp = NULL; 1326 struct smbnode *create_np; 1327 uint32_t desired_access = SMB2_FILE_READ_ATTRIBUTES | SMB2_FILE_LIST_DIRECTORY | SMB2_SYNCHRONIZE; 1328 uint32_t share_access = NTCREATEX_SHARE_ACCESS_ALL; 1329 uint64_t create_flags = 0; 1330 uint32_t n_name_locked = 0; 1331 1332 /* 1333 * SMB2 searches do not want any paths (ie no '\') in the search 1334 * pattern so we have to open the actual dir that we are going to 1335 * search. 1336 * 1337 * Get the FID for the dir we are going to search 1338 */ 1339 if (ctx->f_lookupName == NULL) { 1340 /* 1341 * No name, open the parent of dnp, search pattern will 1342 * be dnp->n_name 1343 */ 1344 1345 /* 1346 * We hold f_dnp->n_name_rwlock while we are referencing the parent 1347 * to prevent a race with smbfs_ClearChildren(), which could happen in 1348 * a forced unmount scenario. See <rdar://problem/11824956>. 1349 */ 1350 lck_rw_lock_shared(&ctx->f_dnp->n_name_rwlock); 1351 n_name_locked = 1; 1352 if (ctx->f_dnp->n_parent == NULL) { 1353 SMBERROR("Looking for dnp->n_name, but f_dnp->n_parent is NULL\n"); 1354 error = ENOENT; 1355 goto bad; 1356 } 1357 create_np = ctx->f_dnp->n_parent; 1358 } 1359 else { 1360 /* 1361 * Have a name, so just open dnp and search pattern will 1362 * be ctx->f_lookupName 1363 */ 1364 create_np = ctx->f_dnp; 1365 } 1366 1367resend: 1368 /* 1369 * Build the Create call 1370 */ 1371 1372 /* fid is -1 for compound requests */ 1373 ctx->f_create_fid = 0xffffffffffffffff; 1374 1375 error = smb2fs_smb_ntcreatex(ctx->f_share, create_np, 1376 NULL, 0, 1377 NULL, 0, 1378 desired_access, VDIR, 1379 share_access, FILE_OPEN, 1380 create_flags, 1381 &ctx->f_create_fid, NULL, 1382 &create_rqp, &createp, 1383 NULL, context); 1384 if (error) { 1385 SMBERROR("smb2fs_smb_ntcreatex failed %d\n", error); 1386 goto bad; 1387 } 1388 1389 /* Update Create hdr */ 1390 error = smb2_rq_update_cmpd_hdr(create_rqp, SMB2_CMPD_FIRST); 1391 if (error) { 1392 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 1393 goto bad; 1394 } 1395 1396 /* Create the Query Dir */ 1397 error = smb2_smb_query_dir(ctx->f_share, queryp, &query_rqp, context); 1398 if (error) { 1399 SMBERROR("smb2_smb_query_dir failed %d\n", error); 1400 goto bad; 1401 } 1402 1403 /* Update Query Hdr */ 1404 error = smb2_rq_update_cmpd_hdr(query_rqp, SMB2_CMPD_LAST); 1405 if (error) { 1406 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 1407 goto bad; 1408 } 1409 1410 /* Chain Query Dir to the Create */ 1411 create_rqp->sr_next_rqp = query_rqp; 1412 1413 /* 1414 * Send the compound request of Create/Query Dir 1415 */ 1416 error = smb_rq_simple(create_rqp); 1417 1418 if ((error) && (create_rqp->sr_flags & SMBR_RECONNECTED)) { 1419 /* Rebuild and try sending again */ 1420 smb_rq_done(create_rqp); 1421 create_rqp = NULL; 1422 1423 smb_rq_done(query_rqp); 1424 query_rqp = NULL; 1425 1426 SMB_FREE(createp, M_SMBTEMP); 1427 createp = NULL; 1428 1429 goto resend; 1430 } 1431 1432 createp->ret_ntstatus = create_rqp->sr_ntstatus; 1433 1434 /* Get pointer to response data */ 1435 smb_rq_getreply(create_rqp, &mdp); 1436 1437 if (error) { 1438 /* Create failed, try parsing the Query Dir */ 1439 if (error != ENOENT) { 1440 SMBDEBUG("smb_rq_simple failed %d id %lld\n", 1441 error, create_rqp->sr_messageid); 1442 } 1443 goto parse_query; 1444 } 1445 1446 /* 1447 * Parse the Create response. 1448 */ 1449 error = smb2_smb_parse_create(ctx->f_share, mdp, createp); 1450 if (error) { 1451 /* Create parsing failed, try parsing the Query Dir */ 1452 SMBERROR("smb2_smb_parse_create failed %d id %lld\n", 1453 error, create_rqp->sr_messageid); 1454 goto parse_query; 1455 } 1456 1457 /* 1458 * No need to call smb2fs_smb_parse_ntcreatex since this is Query Dir and 1459 * the only vnode we have is the parent dir being searched. 1460 */ 1461 1462 /* At this point, the dir was successfully opened */ 1463 ctx->f_need_close = TRUE; 1464 ctx->f_create_fid = createp->ret_fid; 1465 1466parse_query: 1467 /* Consume any pad bytes */ 1468 tmp_error = smb2_rq_next_command(create_rqp, &next_cmd_offset, mdp); 1469 if (tmp_error) { 1470 /* Failed to find next command, so can't parse rest of the responses */ 1471 SMBERROR("create smb2_rq_next_command failed %d id %lld\n", 1472 tmp_error, create_rqp->sr_messageid); 1473 error = error ? error : tmp_error; 1474 goto bad; 1475 } 1476 1477 /* 1478 * Parse Query Dir SMB2 header 1479 */ 1480 tmp_error = smb2_rq_parse_header(query_rqp, &mdp); 1481 queryp->ret_ntstatus = query_rqp->sr_ntstatus; 1482 if (tmp_error) { 1483 /* Query Dir got an error */ 1484 if (!error) { 1485 if (tmp_error != ENOENT) { 1486 SMBDEBUG("query smb2_rq_parse_header failed %d, id %lld\n", 1487 tmp_error, query_rqp->sr_messageid); 1488 } 1489 error = tmp_error; 1490 } 1491 goto bad; 1492 } 1493 1494 /* Parse the Query Dir response */ 1495 tmp_error = smb2_smb_parse_query_dir(mdp, queryp); 1496 if (tmp_error) { 1497 /* Query Dir parsing got an error */ 1498 if (!error) { 1499 SMBERROR("smb2_smb_parse_query_dir failed %d id %lld\n", 1500 tmp_error, query_rqp->sr_messageid); 1501 error = tmp_error; 1502 } 1503 goto bad; 1504 } 1505 1506bad: 1507 ctx->f_create_rqp = create_rqp; /* save rqp so it can be freed later */ 1508 ctx->f_query_rqp = query_rqp; /* save rqp so it can be freed later */ 1509 1510 if (createp != NULL) { 1511 SMB_FREE(createp, M_SMBTEMP); 1512 } 1513 1514 if (n_name_locked) { 1515 lck_rw_unlock_shared(&ctx->f_dnp->n_name_rwlock); 1516 } 1517 1518 return error; 1519} 1520 1521int 1522smb2fs_smb_cmpd_query_dir_one(struct smb_share *share, struct smbnode *np, 1523 const char *query_namep, size_t query_name_len, 1524 struct smbfattr *fap, char **namep, size_t *name_lenp, 1525 vfs_context_t context) 1526{ 1527 int error, tmp_error; 1528 uint16_t info_level; 1529 uint8_t info_class, flags; 1530 SMBFID fid = 0; 1531 struct smb2_create_rq *createp = NULL; 1532 struct smb2_query_dir_rq *queryp = NULL; 1533 struct smb2_close_rq *closep = NULL; 1534 struct smb_rq *create_rqp = NULL; 1535 struct smb_rq *query_rqp = NULL; 1536 struct smb_rq *close_rqp = NULL; 1537 struct mdchain *mdp; 1538 size_t next_cmd_offset = 0; 1539 uint32_t need_delete_fid = 0; 1540 uint32_t desired_access = SMB2_FILE_READ_ATTRIBUTES | SMB2_FILE_LIST_DIRECTORY | SMB2_SYNCHRONIZE; 1541 uint32_t share_access = NTCREATEX_SHARE_ACCESS_ALL; 1542 uint64_t create_flags = 0; 1543 char *network_name = NULL; 1544 uint32_t network_name_len = 0; 1545 char *local_name = NULL; 1546 size_t local_name_len = 0; 1547 size_t max_network_name_buffer_size = 0; 1548 struct smbmount *smp; 1549 uint32_t n_name_locked = 0; 1550 1551 smp = np->n_mount; 1552 if ((np->n_ino == smp->sm_root_ino) && (query_namep == NULL)) { 1553 /* 1554 * For the root vnode, we just need limited info, so a Create/Close 1555 * will work. Cant do a Create/Query Dir/Close on the root vnode since 1556 * we have no parent to do the Create on. 1557 */ 1558 fap->fa_ino = smp->sm_root_ino; /* default value */ 1559 1560 /* Add SMB2_CREATE_DO_CREATE to get the root vnode'd File ID */ 1561 create_flags = SMB2_CREATE_GET_MAX_ACCESS | SMB2_CREATE_DO_CREATE; 1562 1563 error = smb2fs_smb_cmpd_create(share, np, 1564 NULL, 0, 1565 NULL, 0, 1566 SMB2_FILE_READ_ATTRIBUTES | SMB2_SYNCHRONIZE, VDIR, 1567 NTCREATEX_SHARE_ACCESS_ALL, FILE_OPEN, 1568 create_flags, NULL, 1569 NULL, fap, 1570 NULL, context); 1571 if (!error) { 1572 fap->fa_attr = SMB_EFA_DIRECTORY; 1573 fap->fa_vtype = VDIR; 1574 } 1575 1576 return (error); 1577 } 1578 1579 /* 1580 * Unicode requires 4 * max file name len, codepage requires 3 * max file 1581 * name, so lets just always use the unicode size. 1582 */ 1583 max_network_name_buffer_size = share->ss_maxfilenamelen * 4; 1584 SMB_MALLOC(network_name, char *, max_network_name_buffer_size, M_TEMP, 1585 M_WAITOK | M_ZERO); 1586 if (network_name == NULL) { 1587 SMBERROR("network_name malloc failed\n"); 1588 error = ENOMEM; 1589 goto bad; 1590 } 1591 1592 fid = 0xffffffffffffffff; /* fid is -1 for compound requests */ 1593 1594 info_level = SMB_FIND_BOTH_DIRECTORY_INFO; 1595 1596 /* 1597 * Set up for the Query Dir call 1598 */ 1599 SMB_MALLOC(queryp, 1600 struct smb2_query_dir_rq *, 1601 sizeof(struct smb2_query_dir_rq), 1602 M_SMBTEMP, 1603 M_WAITOK | M_ZERO); 1604 if (queryp == NULL) { 1605 SMBERROR("SMB_MALLOC failed\n"); 1606 error = ENOMEM; 1607 goto bad; 1608 } 1609 1610 /* Just want first search entry returned and start from beginning */ 1611 flags = SMB2_RETURN_SINGLE_ENTRY | SMB2_RESTART_SCANS; 1612 1613 switch (info_level) { 1614 case SMB_FIND_FULL_DIRECTORY_INFO: 1615 /* For SMB2.x, get the file/dir IDs too but no short names */ 1616 info_class = FileIdFullDirectoryInformation; 1617 break; 1618 1619 case SMB_FIND_BOTH_DIRECTORY_INFO: 1620 /* For SMB2.x, get the file/dir IDs too */ 1621 info_class = FileIdBothDirectoryInformation; 1622 break; 1623 1624 default: 1625 SMBERROR("invalid infolevel %d", info_level); 1626 error = EINVAL; 1627 goto bad; 1628 } 1629 1630 queryp->file_info_class = info_class; 1631 queryp->flags = flags; 1632 queryp->file_index = 0; /* no FileIndex from prev search */ 1633 queryp->fid = fid; 1634 queryp->output_buffer_len = 64 * 1024; /* 64K should be large enough */ 1635 1636 /* 1637 * Not a wildcard, so use UTF_SFM_CONVERSIONS 1638 */ 1639 queryp->name_flags = UTF_SFM_CONVERSIONS; 1640 1641 if (query_namep != NULL) { 1642 /* We have a dnp and a name to search for in that dir */ 1643 queryp->dnp = np; 1644 queryp->namep = (char*) query_namep; 1645 queryp->name_len = (uint32_t) query_name_len; 1646 } 1647 else { 1648 /* We are looking for np, so use np->n_parent and np->n_name */ 1649 1650 /* 1651 * We hold np->n_name_rwlock while we are referencing the parent 1652 * to prevent a race with smbfs_ClearChildren(), which could happen in 1653 * a forced unmount scenario. See <rdar://problem/11824956>. 1654 */ 1655 lck_rw_lock_shared(&np->n_name_rwlock); 1656 queryp->dnp = np->n_parent; 1657 n_name_locked = 1; 1658 1659 if (queryp->dnp == NULL) { 1660 /* This could happen during a forced unmount */ 1661 SMBERROR("Looking for np, but np->n_parent is NULL\n"); 1662 error = ENOENT; 1663 goto bad; 1664 1665 } 1666 1667 queryp->namep = (char*) np->n_name; 1668 queryp->name_len = (uint32_t) np->n_nmlen; 1669 } 1670 1671resend: 1672 /* 1673 * Build the Create call 1674 */ 1675 DBG_ASSERT (vnode_vtype(queryp->dnp->n_vnode) == VDIR); 1676 error = smb2fs_smb_ntcreatex(share, queryp->dnp, 1677 NULL, 0, 1678 NULL, 0, 1679 desired_access, VDIR, 1680 share_access, FILE_OPEN, 1681 create_flags, 1682 &fid, NULL, 1683 &create_rqp, &createp, 1684 NULL, context); 1685 if (error) { 1686 SMBERROR("smb2fs_smb_ntcreatex failed %d\n", error); 1687 goto bad; 1688 } 1689 1690 /* Update Create hdr */ 1691 error = smb2_rq_update_cmpd_hdr(create_rqp, SMB2_CMPD_FIRST); 1692 if (error) { 1693 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 1694 goto bad; 1695 } 1696 1697 /* 1698 * Build the Query Dir request 1699 */ 1700 error = smb2_smb_query_dir(share, queryp, &query_rqp, context); 1701 if (error) { 1702 SMBERROR("smb2_smb_query_dir failed %d\n", error); 1703 goto bad; 1704 } 1705 1706 /* Update Query Hdr */ 1707 error = smb2_rq_update_cmpd_hdr(query_rqp, SMB2_CMPD_MIDDLE); 1708 if (error) { 1709 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 1710 goto bad; 1711 } 1712 1713 /* Chain Query Dir to the Create */ 1714 create_rqp->sr_next_rqp = query_rqp; 1715 1716 /* 1717 * Build the Close request 1718 */ 1719 error = smb2_smb_close_fid(share, fid, &close_rqp, &closep, context); 1720 if (error) { 1721 SMBERROR("smb2_smb_close_fid failed %d\n", error); 1722 goto bad; 1723 } 1724 1725 /* Update Close hdr */ 1726 error = smb2_rq_update_cmpd_hdr(close_rqp, SMB2_CMPD_LAST); 1727 if (error) { 1728 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 1729 goto bad; 1730 } 1731 1732 /* Chain Close to the Query Info */ 1733 query_rqp->sr_next_rqp = close_rqp; 1734 1735 /* 1736 * Send the compound request of Create/QueryDir/Close 1737 */ 1738 error = smb_rq_simple(create_rqp); 1739 1740 if ((error) && (create_rqp->sr_flags & SMBR_RECONNECTED)) { 1741 /* Rebuild and try sending again */ 1742 smb_rq_done(create_rqp); 1743 create_rqp = NULL; 1744 1745 smb_rq_done(query_rqp); 1746 query_rqp = NULL; 1747 1748 smb_rq_done(close_rqp); 1749 close_rqp = NULL; 1750 1751 SMB_FREE(createp, M_SMBTEMP); 1752 createp = NULL; 1753 1754 SMB_FREE(closep, M_SMBTEMP); 1755 closep = NULL; 1756 1757 goto resend; 1758 } 1759 1760 createp->ret_ntstatus = create_rqp->sr_ntstatus; 1761 1762 /* Get pointer to response data */ 1763 smb_rq_getreply(create_rqp, &mdp); 1764 1765 if (error) { 1766 /* Create failed, try parsing the Query Dir */ 1767 if ((error != ENOENT) && (error != EACCES)) { 1768 SMBDEBUG("smb_rq_simple failed %d id %lld\n", 1769 error, create_rqp->sr_messageid); 1770 } 1771 goto parse_query; 1772 } 1773 1774 /* 1775 * Parse the Create response. 1776 */ 1777 error = smb2_smb_parse_create(share, mdp, createp); 1778 if (error) { 1779 /* Create parsing failed, try parsing the Query Dir */ 1780 SMBERROR("smb2_smb_parse_create failed %d id %lld\n", 1781 error, create_rqp->sr_messageid); 1782 goto parse_query; 1783 } 1784 1785 /* At this point, fid has been entered into fid table */ 1786 need_delete_fid = 1; 1787 1788 /* 1789 * No need to call smb2fs_smb_parse_ntcreatex since this is Query Dir and 1790 * the only vnode we have is the parent dir being searched. 1791 */ 1792 1793parse_query: 1794 /* Consume any pad bytes */ 1795 tmp_error = smb2_rq_next_command(create_rqp, &next_cmd_offset, mdp); 1796 if (tmp_error) { 1797 /* Failed to find next command, so can't parse rest of the responses */ 1798 SMBERROR("create smb2_rq_next_command failed %d id %lld\n", 1799 tmp_error, create_rqp->sr_messageid); 1800 error = error ? error : tmp_error; 1801 goto bad; 1802 } 1803 1804 /* 1805 * Parse Query Dir SMB2 header 1806 */ 1807 tmp_error = smb2_rq_parse_header(query_rqp, &mdp); 1808 queryp->ret_ntstatus = query_rqp->sr_ntstatus; 1809 if (tmp_error) { 1810 /* Query Dir got an error */ 1811 if (!error) { 1812 if (tmp_error != ENOENT) { 1813 SMBDEBUG("query smb2_rq_parse_header failed %d, id %lld\n", 1814 tmp_error, query_rqp->sr_messageid); 1815 } 1816 error = tmp_error; 1817 } 1818 goto parse_close; 1819 } 1820 1821 /* Parse the Query Dir response */ 1822 tmp_error = smb2_smb_parse_query_dir(mdp, queryp); 1823 if (tmp_error) { 1824 /* Query Dir parsing got an error */ 1825 if (!error) { 1826 SMBERROR("smb2_smb_parse_query_dir failed %d id %lld\n", 1827 tmp_error, query_rqp->sr_messageid); 1828 error = tmp_error; 1829 } 1830 goto parse_close; 1831 } 1832 1833 /* 1834 * Parse the only entry out of the output buffer 1835 */ 1836 switch (queryp->file_info_class) { 1837 case FileIdFullDirectoryInformation: 1838 case FileIdBothDirectoryInformation: 1839 /* Call the parsing function */ 1840 tmp_error = smb2_smb_parse_query_dir_both_dir_info(share, mdp, 1841 info_level, 1842 NULL, fap, 1843 network_name, &network_name_len, 1844 max_network_name_buffer_size); 1845 if (tmp_error) { 1846 /* Query Dir parsing got an error */ 1847 if (!error) { 1848 SMBERROR("smb2_smb_parse_query_dir_both_dir_info failed %d id %lld\n", 1849 tmp_error, query_rqp->sr_messageid); 1850 error = tmp_error; 1851 } 1852 goto parse_close; 1853 } 1854 1855 /* 1856 * Convert network name to a malloc'd local name and return 1857 * that name 1858 */ 1859 local_name_len = network_name_len; 1860 local_name = smbfs_ntwrkname_tolocal(network_name, &local_name_len, 1861 SMB_UNICODE_STRINGS(SSTOVC(share))); 1862 1863 if (!(SSTOVC(share)->vc_misc_flags & SMBV_HAS_FILEIDS)) { 1864 /* Server does not support File IDs */ 1865 fap->fa_ino = smbfs_getino(np, local_name, local_name_len); 1866 } 1867 1868 /* Return the malloc'd name from the server */ 1869 if (namep) { 1870 *namep = local_name; 1871 local_name = NULL; 1872 } 1873 1874 if (name_lenp) { 1875 *name_lenp = local_name_len; 1876 } 1877 1878 break; 1879 1880 default: 1881 if (!error) { 1882 SMBERROR("unexpected info level %d\n", queryp->file_info_class); 1883 error = EINVAL; 1884 } 1885 goto parse_close; 1886 } 1887 1888parse_close: 1889 /* Update closep fid so it gets freed from FID table */ 1890 closep->fid = createp->ret_fid; 1891 1892 /* Consume any pad bytes */ 1893 tmp_error = smb2_rq_next_command(query_rqp, &next_cmd_offset, mdp); 1894 if (tmp_error) { 1895 /* Failed to find next command, so can't parse rest of the responses */ 1896 SMBERROR("query smb2_rq_next_command failed %d\n", tmp_error); 1897 error = error ? error : tmp_error; 1898 goto bad; 1899 } 1900 1901 /* 1902 * Parse Close SMB2 header 1903 */ 1904 tmp_error = smb2_rq_parse_header(close_rqp, &mdp); 1905 closep->ret_ntstatus = close_rqp->sr_ntstatus; 1906 if (tmp_error) { 1907 /* Close got an error */ 1908 if (!error) { 1909 SMBDEBUG("close smb2_rq_parse_header failed %d id %lld\n", 1910 tmp_error, close_rqp->sr_messageid); 1911 error = tmp_error; 1912 } 1913 goto bad; 1914 } 1915 1916 /* Parse the Close response */ 1917 tmp_error = smb2_smb_parse_close(mdp, closep); 1918 if (tmp_error) { 1919 /* Close parsing got an error */ 1920 if (!error) { 1921 SMBERROR("smb2_smb_parse_close failed %d id %lld\n", 1922 tmp_error, close_rqp->sr_messageid); 1923 error = tmp_error; 1924 } 1925 goto bad; 1926 } 1927 1928 /* At this point, fid has been removed from fid table */ 1929 need_delete_fid = 0; 1930 1931bad: 1932 if (need_delete_fid == 1) { 1933 /* 1934 * Close failed but the Create worked and was successfully parsed. 1935 * Try issuing the Close request again. 1936 */ 1937 tmp_error = smb2_smb_close_fid(share, createp->ret_fid, 1938 NULL, NULL, context); 1939 if (tmp_error) { 1940 SMBERROR("Second close failed %d\n", tmp_error); 1941 } 1942 } 1943 1944 if (n_name_locked) { 1945 lck_rw_unlock_shared(&np->n_name_rwlock); 1946 } 1947 1948 if (create_rqp != NULL) { 1949 smb_rq_done(create_rqp); 1950 } 1951 if (query_rqp != NULL) { 1952 smb_rq_done(query_rqp); 1953 } 1954 if (close_rqp != NULL) { 1955 smb_rq_done(close_rqp); 1956 } 1957 1958 if (createp != NULL) { 1959 SMB_FREE(createp, M_SMBTEMP); 1960 } 1961 if (queryp != NULL) { 1962 SMB_FREE(queryp, M_SMBTEMP); 1963 } 1964 if (closep != NULL) { 1965 SMB_FREE(closep, M_SMBTEMP); 1966 } 1967 1968 if (network_name != NULL) { 1969 SMB_FREE(network_name, M_SMBTEMP); 1970 } 1971 if (local_name != NULL) { 1972 SMB_FREE(local_name, M_SMBTEMP); 1973 } 1974 1975 return error; 1976} 1977 1978static int 1979smb2fs_smb_cmpd_reparse_point_get(struct smb_share *share, 1980 struct smbnode *create_np, 1981 struct uio *ioctl_uiop, 1982 vfs_context_t context) 1983{ 1984 int error, tmp_error; 1985 SMBFID fid = 0; 1986 struct smbfattr *fap = NULL; 1987 struct smb2_create_rq *createp = NULL; 1988 struct smb2_ioctl_rq *ioctlp = NULL; 1989 struct smb2_close_rq *closep = NULL; 1990 struct smb_rq *create_rqp = NULL; 1991 struct smb_rq *ioctl_rqp = NULL; 1992 struct smb_rq *close_rqp = NULL; 1993 struct mdchain *mdp; 1994 size_t next_cmd_offset = 0; 1995 uint32_t need_delete_fid = 0; 1996 uint32_t create_desired_access = SMB2_FILE_READ_DATA | 1997 SMB2_FILE_READ_ATTRIBUTES; 1998 uint32_t share_access = NTCREATEX_SHARE_ACCESS_ALL; 1999 uint64_t create_flags = SMB2_CREATE_GET_MAX_ACCESS; 2000 2001 SMB_MALLOC(fap, 2002 struct smbfattr *, 2003 sizeof(struct smbfattr), 2004 M_SMBTEMP, 2005 M_WAITOK | M_ZERO); 2006 if (fap == NULL) { 2007 SMBERROR("SMB_MALLOC failed\n"); 2008 error = ENOMEM; 2009 goto bad; 2010 } 2011 2012 SMB_MALLOC(ioctlp, 2013 struct smb2_ioctl_rq *, 2014 sizeof(struct smb2_ioctl_rq), 2015 M_SMBTEMP, 2016 M_WAITOK | M_ZERO); 2017 if (ioctlp == NULL) { 2018 SMBERROR("SMB_MALLOC failed\n"); 2019 error = ENOMEM; 2020 goto bad; 2021 } 2022 2023resend: 2024 /* 2025 * Build the Create call 2026 */ 2027 error = smb2fs_smb_ntcreatex(share, create_np, 2028 NULL, 0, 2029 NULL, 0, 2030 create_desired_access, VREG, 2031 share_access, FILE_OPEN, 2032 create_flags, 2033 &fid, NULL, 2034 &create_rqp, &createp, 2035 NULL, context); 2036 if (error) { 2037 SMBERROR("smb2fs_smb_ntcreatex failed %d\n", error); 2038 goto bad; 2039 } 2040 2041 /* Update Create hdr */ 2042 error = smb2_rq_update_cmpd_hdr(create_rqp, SMB2_CMPD_FIRST); 2043 if (error) { 2044 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 2045 goto bad; 2046 } 2047 2048 /* 2049 * Build the IOCTL request 2050 */ 2051 ioctlp->share = share; 2052 ioctlp->ctl_code = FSCTL_GET_REPARSE_POINT; 2053 fid = 0xffffffffffffffff; /* fid is -1 for compound requests */ 2054 ioctlp->fid = fid; 2055 2056 ioctlp->snd_input_len = 0; 2057 ioctlp->snd_output_len = 0; 2058 ioctlp->rcv_input_len = 0; 2059 /* reparse points should not need more than 16K of data */ 2060 ioctlp->rcv_output_len = 16 * 1024; 2061 2062 error = smb2_smb_ioctl(share, ioctlp, &ioctl_rqp, context); 2063 if (error) { 2064 SMBERROR("smb2_smb_ioctl failed %d\n", error); 2065 goto bad; 2066 } 2067 2068 /* Update IOCTL hdr */ 2069 error = smb2_rq_update_cmpd_hdr(ioctl_rqp, SMB2_CMPD_MIDDLE); 2070 if (error) { 2071 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 2072 goto bad; 2073 } 2074 2075 /* Chain IOCTL to the Create */ 2076 create_rqp->sr_next_rqp = ioctl_rqp; 2077 2078 /* 2079 * Build the Close request 2080 */ 2081 error = smb2_smb_close_fid(share, fid, &close_rqp, &closep, context); 2082 if (error) { 2083 SMBERROR("smb2_smb_close_fid failed %d\n", error); 2084 goto bad; 2085 } 2086 2087 /* Update Close hdr */ 2088 error = smb2_rq_update_cmpd_hdr(close_rqp, SMB2_CMPD_LAST); 2089 if (error) { 2090 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 2091 goto bad; 2092 } 2093 2094 /* Chain Close to the IOCTL */ 2095 ioctl_rqp->sr_next_rqp = close_rqp; 2096 2097 /* 2098 * Send the compound request of Create/IOCTL/Close 2099 */ 2100 error = smb_rq_simple(create_rqp); 2101 2102 if ((error) && (create_rqp->sr_flags & SMBR_RECONNECTED)) { 2103 /* Rebuild and try sending again */ 2104 smb_rq_done(create_rqp); 2105 create_rqp = NULL; 2106 2107 smb_rq_done(ioctl_rqp); 2108 ioctl_rqp = NULL; 2109 2110 smb_rq_done(close_rqp); 2111 close_rqp = NULL; 2112 2113 SMB_FREE(createp, M_SMBTEMP); 2114 createp = NULL; 2115 2116 SMB_FREE(closep, M_SMBTEMP); 2117 closep = NULL; 2118 2119 goto resend; 2120 } 2121 2122 createp->ret_ntstatus = create_rqp->sr_ntstatus; 2123 2124 /* Get pointer to response data */ 2125 smb_rq_getreply(create_rqp, &mdp); 2126 2127 if (error) { 2128 /* Create failed, try parsing the IOCTL */ 2129 SMBDEBUG("smb_rq_simple failed %d id %lld\n", 2130 error, create_rqp->sr_messageid); 2131 goto parse_ioctl; 2132 } 2133 2134 /* 2135 * Parse the Create response. 2136 */ 2137 error = smb2_smb_parse_create(share, mdp, createp); 2138 if (error) { 2139 /* Create parsing failed, try parsing the IOCTL */ 2140 SMBERROR("smb2_smb_parse_create failed %d id %lld\n", 2141 error, create_rqp->sr_messageid); 2142 goto parse_ioctl; 2143 } 2144 2145 /* At this point, fid has been entered into fid table */ 2146 need_delete_fid = 1; 2147 2148 /* 2149 * Fill in fap and possibly update vnode's meta data caches 2150 */ 2151 error = smb2fs_smb_parse_ntcreatex(share, create_np, createp, 2152 &fid, fap, context); 2153 if (error) { 2154 /* Updating meta data cache failed, try parsing the Ioctl */ 2155 SMBERROR("smb2fs_smb_parse_ntcreatex failed %d id %lld\n", 2156 error, create_rqp->sr_messageid); 2157 } 2158 2159parse_ioctl: 2160 /* Consume any pad bytes */ 2161 tmp_error = smb2_rq_next_command(create_rqp, &next_cmd_offset, mdp); 2162 if (tmp_error) { 2163 /* Failed to find next command, so can't parse rest of the responses */ 2164 SMBERROR("create smb2_rq_next_command failed %d id %lld\n", 2165 tmp_error, create_rqp->sr_messageid); 2166 goto bad; 2167 } 2168 2169 /* 2170 * Parse IOCTL SMB2 header 2171 */ 2172 tmp_error = smb2_rq_parse_header(ioctl_rqp, &mdp); 2173 ioctlp->ret_ntstatus = ioctl_rqp->sr_ntstatus; 2174 if (tmp_error) { 2175 /* IOCTL got an error, try parsing the Close */ 2176 if (!error) { 2177 SMBDEBUG("ioctl smb2_rq_parse_header failed %d, id %lld\n", 2178 tmp_error, ioctl_rqp->sr_messageid); 2179 error = tmp_error; 2180 } 2181 goto parse_close; 2182 } 2183 2184 /* Parse the IOCTL response */ 2185 tmp_error = smb2_smb_parse_ioctl(mdp, ioctlp); 2186 if (tmp_error) { 2187 /* IOCTL parsing got an error, try parsing the Close */ 2188 if (!error) { 2189 SMBERROR("smb2_smb_parse_ioctl failed %d id %lld\n", 2190 tmp_error, ioctl_rqp->sr_messageid); 2191 error = tmp_error; 2192 } 2193 goto parse_close; 2194 } 2195 2196 /* 2197 * At this point, we know the IOCTL worked. 2198 * The IOCTL will return the path in rcv_output_buffer and rcv_output_len 2199 * Update the create_np with the symlink info. 2200 * smbfs_update_symlink_cache will deal with any null pointers 2201 */ 2202 smbfs_update_symlink_cache(create_np, (char *) ioctlp->rcv_output_buffer, 2203 ioctlp->rcv_output_len); 2204 tmp_error = uiomove((char *) ioctlp->rcv_output_buffer, 2205 (int) ioctlp->rcv_output_len, 2206 ioctl_uiop); 2207 if (tmp_error) { 2208 /* uiomove failed */ 2209 if (!error) { 2210 SMBERROR("uiomove failed %d id %lld\n", 2211 tmp_error, ioctl_rqp->sr_messageid); 2212 error = tmp_error; 2213 } 2214 goto parse_close; 2215 } 2216 2217parse_close: 2218 /* Update closep fid so it gets freed from FID table */ 2219 closep->fid = createp->ret_fid; 2220 2221 /* Consume any pad bytes */ 2222 tmp_error = smb2_rq_next_command(ioctl_rqp, &next_cmd_offset, mdp); 2223 if (tmp_error) { 2224 /* Failed to find next command, so can't parse rest of the responses */ 2225 SMBERROR("ioctl smb2_rq_next_command failed %d\n", tmp_error); 2226 error = error ? error : tmp_error; 2227 goto bad; 2228 } 2229 2230 /* 2231 * Parse Close SMB2 header 2232 */ 2233 tmp_error = smb2_rq_parse_header(close_rqp, &mdp); 2234 closep->ret_ntstatus = close_rqp->sr_ntstatus; 2235 if (tmp_error) { 2236 if (!error) { 2237 SMBDEBUG("close smb2_rq_parse_header failed %d id %lld\n", 2238 tmp_error, close_rqp->sr_messageid); 2239 error = tmp_error; 2240 } 2241 goto bad; 2242 } 2243 2244 /* Parse the Close response */ 2245 tmp_error = smb2_smb_parse_close(mdp, closep); 2246 if (tmp_error) { 2247 if (!error) { 2248 SMBERROR("smb2_smb_parse_close failed %d id %lld\n", 2249 tmp_error, close_rqp->sr_messageid); 2250 error = tmp_error; 2251 } 2252 goto bad; 2253 } 2254 2255 /* At this point, fid has been removed from fid table */ 2256 need_delete_fid = 0; 2257 2258bad: 2259 if (need_delete_fid == 1) { 2260 /* 2261 * Close failed but the Create worked and was successfully parsed. 2262 * Try issuing the Close request again. 2263 */ 2264 tmp_error = smb2_smb_close_fid(share, createp->ret_fid, 2265 NULL, NULL, context); 2266 if (tmp_error) { 2267 SMBERROR("Second close failed %d\n", tmp_error); 2268 } 2269 } 2270 2271 if (create_rqp != NULL) { 2272 smb_rq_done(create_rqp); 2273 } 2274 if (ioctl_rqp != NULL) { 2275 smb_rq_done(ioctl_rqp); 2276 } 2277 if (close_rqp != NULL) { 2278 smb_rq_done(close_rqp); 2279 } 2280 2281 if (createp != NULL) { 2282 SMB_FREE(createp, M_SMBTEMP); 2283 } 2284 if (ioctlp != NULL) { 2285 SMB_FREE(ioctlp, M_SMBTEMP); 2286 } 2287 if (closep != NULL) { 2288 SMB_FREE(closep, M_SMBTEMP); 2289 } 2290 2291 if (fap != NULL) { 2292 SMB_FREE(fap, M_SMBTEMP); 2293 } 2294 2295 return error; 2296} 2297 2298static int 2299smb2fs_smb_cmpd_reparse_point_set(struct smb_share *share, struct smbnode *create_np, 2300 const char *namep, size_t name_len, 2301 char *targetp, size_t target_len, 2302 struct smbfattr *fap, vfs_context_t context) 2303{ 2304 int error, tmp_error; 2305 int ioctl_error= EINVAL; /* assume IOCTL failed */ 2306 SMBFID fid = 0; 2307 struct smb2_create_rq *createp = NULL; 2308 struct smb2_query_info_rq *queryp = NULL; 2309 struct smb2_ioctl_rq *ioctlp = NULL; 2310 struct smb2_close_rq *closep = NULL; 2311 struct smb_rq *create_rqp = NULL; 2312 struct smb_rq *query_rqp = NULL; 2313 struct smb_rq *ioctl_rqp = NULL; 2314 struct smb_rq *close_rqp = NULL; 2315 struct mdchain *mdp; 2316 size_t next_cmd_offset = 0; 2317 uint32_t need_delete_fid = 0, create_worked = 0; 2318 uint32_t create_desired_access = SMB2_FILE_WRITE_DATA | 2319 SMB2_FILE_WRITE_ATTRIBUTES | 2320 SMB2_DELETE; 2321 uint32_t share_access = NTCREATEX_SHARE_ACCESS_ALL; 2322 uint64_t create_flags = SMB2_CREATE_DO_CREATE | SMB2_CREATE_GET_MAX_ACCESS; 2323 size_t path_len; 2324 char *pathp = NULL; 2325 struct smbmount *smp = create_np->n_mount; 2326 int add_query = 0; 2327 uint64_t inode_number = 0; 2328 uint32_t inode_number_len; 2329 2330 if (fap == NULL) { 2331 /* This should never happen */ 2332 SMBERROR("fap is NULL \n"); 2333 error = EINVAL; 2334 goto bad; 2335 } 2336 2337 /* 2338 * This function can do Create/Query/Ioctl/Close, or Create/Ioctl/Close 2339 * If File IDs are supported, then the Query is added to get the file ID. 2340 */ 2341 2342 if (SSTOVC(share)->vc_misc_flags & SMBV_HAS_FILEIDS) { 2343 /* Need the file id, so add a query into the compound request */ 2344 add_query = 1; 2345 } 2346 2347 /* Convert target to a network style path */ 2348 path_len = (target_len * 2) + 2; /* Start with the max possible size */ 2349 SMB_MALLOC(pathp, char *, path_len, M_TEMP, M_WAITOK | M_ZERO); 2350 if (pathp == NULL) { 2351 error = ENOMEM; 2352 goto bad; 2353 } 2354 2355 error = smb_convert_path_to_network(targetp, target_len, pathp, &path_len, 2356 '\\', SMB_UTF_SFM_CONVERSIONS, 2357 SMB_UNICODE_STRINGS(SSTOVC(share))); 2358 if (error) { 2359 goto bad; 2360 } 2361 2362 if (add_query) { 2363 SMB_MALLOC(queryp, 2364 struct smb2_query_info_rq *, 2365 sizeof(struct smb2_query_info_rq), 2366 M_SMBTEMP, 2367 M_WAITOK | M_ZERO); 2368 if (queryp == NULL) { 2369 SMBERROR("SMB_MALLOC failed\n"); 2370 error = ENOMEM; 2371 goto bad; 2372 } 2373 } 2374 2375 SMB_MALLOC(ioctlp, 2376 struct smb2_ioctl_rq *, 2377 sizeof(struct smb2_ioctl_rq), 2378 M_SMBTEMP, 2379 M_WAITOK | M_ZERO); 2380 if (ioctlp == NULL) { 2381 SMBERROR("SMB_MALLOC failed\n"); 2382 error = ENOMEM; 2383 goto bad; 2384 } 2385 2386resend: 2387 /* 2388 * Build the Create call 2389 */ 2390 error = smb2fs_smb_ntcreatex(share, create_np, 2391 namep, name_len, 2392 NULL, 0, 2393 create_desired_access, VLNK, 2394 share_access, FILE_CREATE, 2395 create_flags, 2396 &fid, fap, 2397 &create_rqp, &createp, 2398 NULL, context); 2399 if (error) { 2400 SMBERROR("smb2fs_smb_ntcreatex failed %d\n", error); 2401 goto bad; 2402 } 2403 2404 /* Update Create hdr */ 2405 error = smb2_rq_update_cmpd_hdr(create_rqp, SMB2_CMPD_FIRST); 2406 if (error) { 2407 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 2408 goto bad; 2409 } 2410 2411 fid = 0xffffffffffffffff; /* fid is -1 for compound requests */ 2412 2413 if (add_query) { 2414 /* 2415 * Build the Query Info request (to get File ID) 2416 */ 2417 inode_number_len = (uint32_t) sizeof(inode_number); 2418 2419 queryp->info_type = SMB2_0_INFO_FILE; 2420 queryp->file_info_class = FileInternalInformation; 2421 queryp->add_info = 0; 2422 queryp->flags = 0; 2423 queryp->output_buffer_len = inode_number_len; 2424 queryp->output_buffer = (uint8_t *) &inode_number; 2425 queryp->input_buffer_len = 0; 2426 queryp->input_buffer = NULL; 2427 queryp->ret_buffer_len = 0; 2428 queryp->fid = fid; 2429 2430 error = smb2_smb_query_info(share, queryp, &query_rqp, context); 2431 if (error) { 2432 SMBERROR("smb2_smb_query_info failed %d\n", error); 2433 goto bad; 2434 } 2435 2436 /* Update Query hdr */ 2437 error = smb2_rq_update_cmpd_hdr(query_rqp, SMB2_CMPD_MIDDLE); 2438 if (error) { 2439 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 2440 goto bad; 2441 } 2442 2443 /* Chain Query Info to the Create */ 2444 create_rqp->sr_next_rqp = query_rqp; 2445 } 2446 2447 /* 2448 * Build the IOCTL request 2449 * path and path len is passed in via snd_input_buffer and snd_input_len 2450 */ 2451 ioctlp->share = share; 2452 ioctlp->ctl_code = FSCTL_SET_REPARSE_POINT; 2453 ioctlp->fid = fid; 2454 2455 ioctlp->snd_input_len = (uint32_t) path_len; 2456 ioctlp->snd_output_len = 0; 2457 ioctlp->rcv_input_len = 0; 2458 ioctlp->rcv_output_len = 0; 2459 ioctlp->snd_input_buffer = (uint8_t *) pathp; 2460 2461 error = smb2_smb_ioctl(share, ioctlp, &ioctl_rqp, context); 2462 if (error) { 2463 SMBERROR("smb2_smb_ioctl failed %d\n", error); 2464 goto bad; 2465 } 2466 2467 /* Update IOCTL hdr */ 2468 error = smb2_rq_update_cmpd_hdr(ioctl_rqp, SMB2_CMPD_MIDDLE); 2469 if (error) { 2470 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 2471 goto bad; 2472 } 2473 2474 if (add_query) { 2475 /* Chain IOCTL to the Query */ 2476 query_rqp->sr_next_rqp = ioctl_rqp; 2477 } 2478 else { 2479 /* Chain IOCTL to the Create */ 2480 create_rqp->sr_next_rqp = ioctl_rqp; 2481 } 2482 2483 /* 2484 * Build the Close request 2485 */ 2486 error = smb2_smb_close_fid(share, fid, &close_rqp, &closep, context); 2487 if (error) { 2488 SMBERROR("smb2_smb_close_fid failed %d\n", error); 2489 goto bad; 2490 } 2491 2492 /* Update Close hdr */ 2493 error = smb2_rq_update_cmpd_hdr(close_rqp, SMB2_CMPD_LAST); 2494 if (error) { 2495 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 2496 goto bad; 2497 } 2498 2499 /* Chain Close to the IOCTL */ 2500 ioctl_rqp->sr_next_rqp = close_rqp; 2501 2502 /* 2503 * Send the compound request of Create/IOCTL/Close 2504 */ 2505 error = smb_rq_simple(create_rqp); 2506 2507 if ((error) && (create_rqp->sr_flags & SMBR_RECONNECTED)) { 2508 /* Rebuild and try sending again */ 2509 smb_rq_done(create_rqp); 2510 create_rqp = NULL; 2511 2512 if (query_rqp) { 2513 smb_rq_done(query_rqp); 2514 query_rqp = NULL; 2515 } 2516 2517 smb_rq_done(ioctl_rqp); 2518 ioctl_rqp = NULL; 2519 2520 smb_rq_done(close_rqp); 2521 close_rqp = NULL; 2522 2523 SMB_FREE(createp, M_SMBTEMP); 2524 createp = NULL; 2525 2526 SMB_FREE(closep, M_SMBTEMP); 2527 closep = NULL; 2528 2529 goto resend; 2530 } 2531 2532 createp->ret_ntstatus = create_rqp->sr_ntstatus; 2533 2534 /* Get pointer to response data */ 2535 smb_rq_getreply(create_rqp, &mdp); 2536 2537 if (error) { 2538 /* Create failed, try parsing the IOCTL */ 2539 SMBDEBUG("smb_rq_simple failed %d id %lld\n", 2540 error, create_rqp->sr_messageid); 2541 goto parse_query; 2542 } 2543 2544 /* 2545 * Parse the Create response. 2546 */ 2547 error = smb2_smb_parse_create(share, mdp, createp); 2548 if (error) { 2549 /* Create parsing failed, try parsing the IOCTL */ 2550 SMBERROR("smb2_smb_parse_create failed %d id %lld\n", 2551 error, create_rqp->sr_messageid); 2552 goto parse_query; 2553 } 2554 2555 /* At this point, fid has been entered into fid table */ 2556 need_delete_fid = 1; 2557 create_worked = 1; 2558 2559 /* 2560 * Fill in fap and possibly update vnode's meta data caches 2561 */ 2562 error = smb2fs_smb_parse_ntcreatex(share, create_np, createp, 2563 &fid, fap, context); 2564 if (error) { 2565 /* Updating meta data cache failed, try parsing the IOCTL */ 2566 SMBERROR("smb2fs_smb_parse_ntcreatex failed %d id %lld\n", 2567 error, create_rqp->sr_messageid); 2568 } 2569 2570parse_query: 2571 if (query_rqp != NULL) { 2572 /* Consume any pad bytes */ 2573 tmp_error = smb2_rq_next_command(create_rqp, &next_cmd_offset, mdp); 2574 if (tmp_error) { 2575 /* Failed to find next command, so can't parse rest of the responses */ 2576 SMBERROR("create smb2_rq_next_command failed %d id %lld\n", 2577 tmp_error, create_rqp->sr_messageid); 2578 error = error ? error : tmp_error; 2579 goto bad; 2580 } 2581 2582 /* 2583 * Parse Query Info SMB2 header 2584 */ 2585 tmp_error = smb2_rq_parse_header(query_rqp, &mdp); 2586 queryp->ret_ntstatus = query_rqp->sr_ntstatus; 2587 if (tmp_error) { 2588 /* Query Info got an error, try parsing the Close */ 2589 if (!error) { 2590 SMBDEBUG("query smb2_rq_parse_header failed %d, id %lld\n", 2591 tmp_error, query_rqp->sr_messageid); 2592 error = tmp_error; 2593 } 2594 goto parse_ioctl; 2595 } 2596 2597 /* Parse the Query Info response */ 2598 tmp_error = smb2_smb_parse_query_info(mdp, queryp); 2599 if (tmp_error) { 2600 /* Query Info parsing got an error, try parsing the Close */ 2601 if (!error) { 2602 if (tmp_error != ENOATTR) { 2603 SMBERROR("smb2_smb_parse_query_info failed %d id %lld\n", 2604 tmp_error, query_rqp->sr_messageid); 2605 } 2606 error = tmp_error; 2607 } 2608 goto parse_ioctl; 2609 } 2610 else { 2611 /* Query worked, so get the inode number */ 2612 if (fap) { 2613 fap->fa_ino = inode_number; 2614 smb2fs_smb_file_id_check(share, fap->fa_ino, NULL, 0); 2615 } 2616 } 2617 } 2618 2619parse_ioctl: 2620 /* Consume any pad bytes */ 2621 tmp_error = smb2_rq_next_command(query_rqp != NULL ? query_rqp : create_rqp, 2622 &next_cmd_offset, mdp); 2623 if (tmp_error) { 2624 /* Failed to find next command, so can't parse rest of the responses */ 2625 SMBERROR("create smb2_rq_next_command failed %d id %lld\n", 2626 tmp_error, create_rqp->sr_messageid); 2627 goto bad; 2628 } 2629 2630 /* 2631 * Parse IOCTL SMB2 header 2632 */ 2633 tmp_error = smb2_rq_parse_header(ioctl_rqp, &mdp); 2634 ioctlp->ret_ntstatus = ioctl_rqp->sr_ntstatus; 2635 ioctl_error = tmp_error; 2636 if (tmp_error) { 2637 /* IOCTL got an error, try parsing the Close */ 2638 if (!error) { 2639 SMBDEBUG("ioctl smb2_rq_parse_header failed %d, id %lld\n", 2640 tmp_error, ioctl_rqp->sr_messageid); 2641 error = tmp_error; 2642 } 2643 goto parse_close; 2644 } 2645 2646 /* Parse the IOCTL response */ 2647 tmp_error = smb2_smb_parse_ioctl(mdp, ioctlp); 2648 if (tmp_error) { 2649 /* IOCTL parsing got an error, try parsing the Close */ 2650 if (!error) { 2651 SMBERROR("smb2_smb_parse_ioctl failed %d id %lld\n", 2652 tmp_error, ioctl_rqp->sr_messageid); 2653 error = tmp_error; 2654 } 2655 goto parse_close; 2656 } 2657 2658parse_close: 2659 /* Update closep fid so it gets freed from FID table */ 2660 closep->fid = createp->ret_fid; 2661 2662 /* Consume any pad bytes */ 2663 tmp_error = smb2_rq_next_command(ioctl_rqp, &next_cmd_offset, mdp); 2664 if (tmp_error) { 2665 /* Failed to find next command, so can't parse rest of the responses */ 2666 SMBERROR("ioctl smb2_rq_next_command failed %d\n", tmp_error); 2667 error = error ? error : tmp_error; 2668 goto bad; 2669 } 2670 2671 /* 2672 * Parse Close SMB2 header 2673 */ 2674 tmp_error = smb2_rq_parse_header(close_rqp, &mdp); 2675 closep->ret_ntstatus = close_rqp->sr_ntstatus; 2676 if (tmp_error) { 2677 if (!error) { 2678 SMBDEBUG("close smb2_rq_parse_header failed %d id %lld\n", 2679 tmp_error, close_rqp->sr_messageid); 2680 error = tmp_error; 2681 } 2682 goto bad; 2683 } 2684 2685 /* Parse the Close response */ 2686 tmp_error = smb2_smb_parse_close(mdp, closep); 2687 if (tmp_error) { 2688 if (!error) { 2689 SMBERROR("smb2_smb_parse_close failed %d id %lld\n", 2690 tmp_error, close_rqp->sr_messageid); 2691 error = tmp_error; 2692 } 2693 goto bad; 2694 } 2695 2696 /* At this point, fid has been removed from fid table */ 2697 need_delete_fid = 0; 2698 2699bad: 2700 if (need_delete_fid == 1) { 2701 /* 2702 * Close failed but the Create worked and was successfully parsed. 2703 * Try issuing the Close request again. 2704 */ 2705 tmp_error = smb2_smb_close_fid(share, createp->ret_fid, 2706 NULL, NULL, context); 2707 if (tmp_error) { 2708 SMBERROR("Second close failed %d\n", tmp_error); 2709 } 2710 } 2711 2712 /* Only check for IOCTL errors if the create worked */ 2713 if (create_worked == 1) { 2714 if (ioctl_error) { 2715 SMBDEBUG("smb2_smb_ioctl failed %d ntstatus %d\n", 2716 ioctl_error, ioctlp->ret_ntstatus); 2717 2718 /* Failed to create the symlink, remove the file */ 2719 (void) smb2fs_smb_delete(share, create_np, namep, name_len, 0, context); 2720 } 2721 else { 2722 /* IOCTL worked, reset any other fap information */ 2723 fap->fa_size = target_len; 2724 /* FSCTL_SET_REPARSE_POINT succeeded, so mark it as a reparse point */ 2725 fap->fa_attr |= SMB_EFA_REPARSE_POINT; 2726 fap->fa_valid_mask |= FA_REPARSE_TAG_VALID; 2727 fap->fa_reparse_tag = IO_REPARSE_TAG_SYMLINK; 2728 fap->fa_valid_mask |= FA_VTYPE_VALID; 2729 fap->fa_vtype = VLNK; 2730 } 2731 2732 /* 2733 * Windows systems requires special user access to create a reparse symlinks. 2734 * They default to only allow administrator symlink create access. This can 2735 * be changed on the server, but we are going to run into this issue. So if 2736 * we get an access error on the fsctl then we assume this user doesn't have 2737 * create symlink rights and we need to fallback to the old Conrad/Steve 2738 * symlinks. Since the create worked, we know the user has access to the file 2739 * system, they just don't have create symlink rights. We never fallback if 2740 * the server is running darwin. 2741 */ 2742 if ((ioctl_error) && !(UNIX_SERVER(SSTOVC(share)))) { 2743 /* 2744 * <14281932> Could be NetApp server not supporting reparse 2745 * points and returning STATUS_INVALID_DEVICE_REQUEST. 2746 */ 2747 if ((ioctl_error == EACCES) || 2748 (ioctlp->ret_ntstatus == STATUS_INVALID_DEVICE_REQUEST)) { 2749 smp->sm_flags &= ~MNT_SUPPORTS_REPARSE_SYMLINKS; 2750 2751 error = smbfs_smb_create_windows_symlink(share, create_np, 2752 namep, name_len, 2753 targetp, target_len, 2754 fap, context); 2755 if (!error) { 2756 SMBDEBUG("smbfs_smb_create_windows_symlink failed %d\n", error); 2757 } 2758 } 2759 } 2760 } 2761 2762 if (create_rqp != NULL) { 2763 smb_rq_done(create_rqp); 2764 } 2765 if (query_rqp != NULL) { 2766 smb_rq_done(query_rqp); 2767 } 2768 if (ioctl_rqp != NULL) { 2769 smb_rq_done(ioctl_rqp); 2770 } 2771 if (close_rqp != NULL) { 2772 smb_rq_done(close_rqp); 2773 } 2774 2775 if (createp != NULL) { 2776 SMB_FREE(createp, M_SMBTEMP); 2777 } 2778 if (queryp != NULL) { 2779 SMB_FREE(queryp, M_SMBTEMP); 2780 } 2781 if (ioctlp != NULL) { 2782 SMB_FREE(ioctlp, M_SMBTEMP); 2783 } 2784 if (closep != NULL) { 2785 SMB_FREE(closep, M_SMBTEMP); 2786 } 2787 2788 if (pathp != NULL) { 2789 SMB_FREE(pathp, M_TEMP); 2790 } 2791 2792 return error; 2793} 2794 2795int 2796smb2fs_smb_cmpd_resolve_id(struct smb_share *share, struct smbnode *np, 2797 uint64_t ino, uint32_t *resolve_errorp, char **pathp, 2798 vfs_context_t context) 2799{ 2800 int error, tmp_error; 2801 struct smbfattr *fap = NULL; 2802 struct smb2_create_rq *createp = NULL; 2803 struct smb2_close_rq *closep = NULL; 2804 struct smb_rq *create_rqp = NULL; 2805 struct smb_rq *close_rqp = NULL; 2806 struct mdchain *mdp; 2807 size_t next_cmd_offset = 0; 2808 uint32_t need_delete_fid = 0; 2809 SMBFID fid = 0; 2810 struct smb2_create_ctx_resolve_id resolve_id; 2811 2812 SMB_MALLOC(fap, 2813 struct smbfattr *, 2814 sizeof(struct smbfattr), 2815 M_SMBTEMP, 2816 M_WAITOK | M_ZERO); 2817 if (fap == NULL) { 2818 SMBERROR("SMB_MALLOC failed\n"); 2819 error = ENOMEM; 2820 goto bad; 2821 } 2822 2823 /* Fill in Resolve ID context */ 2824 resolve_id.file_id = ino; 2825 resolve_id.ret_errorp = resolve_errorp; 2826 resolve_id.ret_pathp = pathp; 2827 2828resend: 2829 /* 2830 * Build the Create call 2831 */ 2832 error = smb2fs_smb_ntcreatex(share, np, 2833 NULL, 0, 2834 NULL, 0, 2835 SMB2_FILE_READ_ATTRIBUTES | SMB2_SYNCHRONIZE, VDIR, 2836 NTCREATEX_SHARE_ACCESS_ALL, FILE_OPEN, 2837 SMB2_CREATE_AAPL_RESOLVE_ID, 2838 &fid, fap, 2839 &create_rqp, &createp, 2840 &resolve_id, context); 2841 if (error) { 2842 SMBERROR("smb2fs_smb_ntcreatex failed %d\n", error); 2843 goto bad; 2844 } 2845 2846 /* Update Create hdr */ 2847 error = smb2_rq_update_cmpd_hdr(create_rqp, SMB2_CMPD_FIRST); 2848 if (error) { 2849 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 2850 goto bad; 2851 } 2852 2853 fid = 0xffffffffffffffff; /* fid is -1 for compound requests */ 2854 2855 /* 2856 * Build the Close request 2857 */ 2858 error = smb2_smb_close_fid(share, fid, &close_rqp, &closep, context); 2859 if (error) { 2860 SMBERROR("smb2_smb_close_fid failed %d\n", error); 2861 goto bad; 2862 } 2863 2864 /* Update Close hdr */ 2865 error = smb2_rq_update_cmpd_hdr(close_rqp, SMB2_CMPD_LAST); 2866 if (error) { 2867 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 2868 goto bad; 2869 } 2870 2871 /* Chain Close to the Create */ 2872 create_rqp->sr_next_rqp = close_rqp; 2873 2874 /* 2875 * Send the compound request of Create/Close 2876 */ 2877 error = smb_rq_simple(create_rqp); 2878 2879 if ((error) && (create_rqp->sr_flags & SMBR_RECONNECTED)) { 2880 /* Rebuild and try sending again */ 2881 smb_rq_done(create_rqp); 2882 create_rqp = NULL; 2883 2884 smb_rq_done(close_rqp); 2885 close_rqp = NULL; 2886 2887 SMB_FREE(createp, M_SMBTEMP); 2888 createp = NULL; 2889 2890 SMB_FREE(closep, M_SMBTEMP); 2891 closep = NULL; 2892 2893 goto resend; 2894 } 2895 2896 createp->ret_ntstatus = create_rqp->sr_ntstatus; 2897 2898 /* Get pointer to response data */ 2899 smb_rq_getreply(create_rqp, &mdp); 2900 2901 if (error) { 2902 /* Create failed, try parsing the Close */ 2903 if (error != ENOENT) { 2904 SMBDEBUG("smb_rq_simple failed %d id %lld\n", 2905 error, create_rqp->sr_messageid); 2906 } 2907 goto parse_close; 2908 } 2909 2910 /* 2911 * Parse the Create response. 2912 */ 2913 error = smb2_smb_parse_create(share, mdp, createp); 2914 if (error) { 2915 /* Create parsing failed, try parsing the Close */ 2916 SMBERROR("smb2_smb_parse_create failed %d id %lld\n", 2917 error, create_rqp->sr_messageid); 2918 goto parse_close; 2919 } 2920 2921 /* At this point, fid has been entered into fid table */ 2922 need_delete_fid = 1; 2923 2924parse_close: 2925 /* Update closep fid so it gets freed from FID table */ 2926 closep->fid = createp->ret_fid; 2927 2928 /* Consume any pad bytes */ 2929 tmp_error = smb2_rq_next_command(create_rqp, &next_cmd_offset, mdp); 2930 if (tmp_error) { 2931 /* Failed to find next command, so can't parse rest of the responses */ 2932 SMBERROR("create smb2_rq_next_command failed %d id %lld\n", 2933 tmp_error, create_rqp->sr_messageid); 2934 error = error ? error : tmp_error; 2935 goto bad; 2936 } 2937 2938 /* 2939 * Parse Close SMB2 header 2940 */ 2941 tmp_error = smb2_rq_parse_header(close_rqp, &mdp); 2942 closep->ret_ntstatus = close_rqp->sr_ntstatus; 2943 if (tmp_error) { 2944 if (!error) { 2945 SMBDEBUG("close smb2_rq_parse_header failed %d id %lld\n", 2946 tmp_error, close_rqp->sr_messageid); 2947 error = tmp_error; 2948 } 2949 goto bad; 2950 } 2951 2952 /* Parse the Close response */ 2953 tmp_error = smb2_smb_parse_close(mdp, closep); 2954 if (tmp_error) { 2955 if (!error) { 2956 SMBERROR("smb2_smb_parse_close failed %d id %lld\n", 2957 tmp_error, close_rqp->sr_messageid); 2958 error = tmp_error; 2959 } 2960 goto bad; 2961 } 2962 2963 /* At this point, fid has been removed from fid table */ 2964 need_delete_fid = 0; 2965 2966bad: 2967 if (need_delete_fid == 1) { 2968 /* 2969 * Close failed but the Create worked and was successfully parsed. 2970 * Try issuing the Close request again. 2971 */ 2972 tmp_error = smb2_smb_close_fid(share, createp->ret_fid, 2973 NULL, NULL, context); 2974 if (tmp_error) { 2975 SMBERROR("Second close failed %d\n", tmp_error); 2976 } 2977 } 2978 2979 if (create_rqp != NULL) { 2980 smb_rq_done(create_rqp); 2981 } 2982 if (close_rqp != NULL) { 2983 smb_rq_done(close_rqp); 2984 } 2985 2986 if (createp != NULL) { 2987 SMB_FREE(createp, M_SMBTEMP); 2988 } 2989 if (closep != NULL) { 2990 SMB_FREE(closep, M_SMBTEMP); 2991 } 2992 2993 if (fap != NULL) { 2994 SMB_FREE(fap, M_SMBTEMP); 2995 } 2996 2997 return error; 2998} 2999 3000static int 3001smb2fs_smb_cmpd_set_info(struct smb_share *share, struct smbnode *create_np, 3002 const char *create_namep, size_t create_name_len, 3003 uint32_t create_xattr, uint32_t create_desired_access, 3004 uint8_t setinfo_info_type, uint8_t setinfo_file_info_class, 3005 uint32_t setinfo_add_info, 3006 uint32_t setinfo_input_buffer_len, uint8_t *setinfo_input_buffer, 3007 uint32_t *setinfo_ntstatus, 3008 vfs_context_t context) 3009{ 3010#pragma unused(setinfo_input_buffer_len) 3011 int error, tmp_error; 3012 SMBFID fid = 0; 3013 struct smbfattr *fap = NULL; 3014 struct smb2_create_rq *createp = NULL; 3015 struct smb2_set_info_rq *infop = NULL; 3016 struct smb2_close_rq *closep = NULL; 3017 struct smb_rq *create_rqp = NULL; 3018 struct smb_rq *setinfo_rqp = NULL; 3019 struct smb_rq *close_rqp = NULL; 3020 struct mdchain *mdp; 3021 size_t next_cmd_offset = 0; 3022 uint32_t need_delete_fid = 0; 3023 uint32_t share_access = NTCREATEX_SHARE_ACCESS_ALL; 3024 uint64_t create_flags = create_xattr ? SMB2_CREATE_IS_NAMED_STREAM : 0; 3025 char *file_namep = NULL, *stream_namep = NULL; 3026 size_t file_name_len = 0, stream_name_len = 0; 3027 3028 if ((setinfo_info_type == SMB2_0_INFO_FILE) && 3029 (setinfo_file_info_class == FileDispositionInformation)) { 3030 /* 3031 * <17346821> Must be a Delete. Set share_access to 3032 * NTCREATEX_SHARE_ACCESS_NONE so that we can attempt to delete the 3033 * item right now. 3034 */ 3035 share_access = NTCREATEX_SHARE_ACCESS_NONE; 3036 } 3037 3038 *setinfo_ntstatus = 0; 3039 3040 SMB_MALLOC(fap, 3041 struct smbfattr *, 3042 sizeof(struct smbfattr), 3043 M_SMBTEMP, 3044 M_WAITOK | M_ZERO); 3045 if (fap == NULL) { 3046 SMBERROR("SMB_MALLOC failed\n"); 3047 error = ENOMEM; 3048 goto bad; 3049 } 3050 3051 SMB_MALLOC(infop, 3052 struct smb2_set_info_rq *, 3053 sizeof(struct smb2_set_info_rq), 3054 M_SMBTEMP, 3055 M_WAITOK | M_ZERO); 3056 if (infop == NULL) { 3057 SMBERROR("SMB_MALLOC failed\n"); 3058 error = ENOMEM; 3059 goto bad; 3060 } 3061 3062resend: 3063 /* 3064 * Build the Create call 3065 */ 3066 create_flags |= SMB2_CREATE_GET_MAX_ACCESS; 3067 3068 if (!(create_flags & SMB2_CREATE_IS_NAMED_STREAM)) { 3069 file_namep = (char *) create_namep; 3070 file_name_len = create_name_len; 3071 } 3072 else { 3073 /* create_namep is actually the stream name */ 3074 stream_namep = (char *) create_namep; 3075 stream_name_len = create_name_len; 3076 } 3077 3078 error = smb2fs_smb_ntcreatex(share, create_np, 3079 file_namep, file_name_len, 3080 stream_namep, stream_name_len, 3081 create_desired_access, VREG, 3082 share_access, FILE_OPEN, 3083 create_flags, 3084 &fid, fap, 3085 &create_rqp, &createp, 3086 NULL, context); 3087 3088 if (error) { 3089 SMBERROR("smb2fs_smb_ntcreatex failed %d\n", error); 3090 goto bad; 3091 } 3092 3093 /* Update Create hdr */ 3094 error = smb2_rq_update_cmpd_hdr(create_rqp, SMB2_CMPD_FIRST); 3095 if (error) { 3096 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 3097 goto bad; 3098 } 3099 3100 /* 3101 * Build the Set Info request 3102 */ 3103 infop->info_type = setinfo_info_type; 3104 infop->file_info_class = setinfo_file_info_class; 3105 infop->add_info = setinfo_add_info; 3106 fid = 0xffffffffffffffff; /* fid is -1 for compound requests */ 3107 infop->fid = fid; 3108 infop->input_buffer = setinfo_input_buffer; 3109 3110 error = smb2_smb_set_info(share, infop, &setinfo_rqp, context); 3111 if (error) { 3112 SMBERROR("smb2_smb_set_info failed %d\n", error); 3113 goto bad; 3114 } 3115 3116 /* Update Set Info hdr */ 3117 error = smb2_rq_update_cmpd_hdr(setinfo_rqp, SMB2_CMPD_MIDDLE); 3118 if (error) { 3119 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 3120 goto bad; 3121 } 3122 3123 /* Chain Set Info to the Create */ 3124 create_rqp->sr_next_rqp = setinfo_rqp; 3125 3126 /* 3127 * Build the Close request 3128 */ 3129 error = smb2_smb_close_fid(share, fid, &close_rqp, &closep, context); 3130 if (error) { 3131 SMBERROR("smb2_smb_close_fid failed %d\n", error); 3132 goto bad; 3133 } 3134 3135 /* Update Close hdr */ 3136 error = smb2_rq_update_cmpd_hdr(close_rqp, SMB2_CMPD_LAST); 3137 if (error) { 3138 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 3139 goto bad; 3140 } 3141 3142 /* Chain Close to the Query Info */ 3143 setinfo_rqp->sr_next_rqp = close_rqp; 3144 3145 /* 3146 * Send the compound request of Create/SetInfo/Close 3147 */ 3148 error = smb_rq_simple(create_rqp); 3149 3150 if ((error) && (create_rqp->sr_flags & SMBR_RECONNECTED)) { 3151 /* Rebuild and try sending again */ 3152 smb_rq_done(create_rqp); 3153 create_rqp = NULL; 3154 3155 smb_rq_done(setinfo_rqp); 3156 setinfo_rqp = NULL; 3157 3158 smb_rq_done(close_rqp); 3159 close_rqp = NULL; 3160 3161 SMB_FREE(createp, M_SMBTEMP); 3162 createp = NULL; 3163 3164 SMB_FREE(closep, M_SMBTEMP); 3165 closep = NULL; 3166 3167 goto resend; 3168 } 3169 3170 createp->ret_ntstatus = create_rqp->sr_ntstatus; 3171 3172 /* Get pointer to response data */ 3173 smb_rq_getreply(create_rqp, &mdp); 3174 3175 if (error) { 3176 /* Create failed, try parsing the Set Info */ 3177 if (error != ENOENT) { 3178 SMBDEBUG("smb_rq_simple failed %d id %lld\n", 3179 error, create_rqp->sr_messageid); 3180 } 3181 goto parse_setinfo; 3182 } 3183 3184 /* 3185 * Parse the Create response. 3186 */ 3187 error = smb2_smb_parse_create(share, mdp, createp); 3188 if (error) { 3189 /* Create parsing failed, try parsing the Set Info */ 3190 SMBERROR("smb2_smb_parse_create failed %d id %lld\n", 3191 error, create_rqp->sr_messageid); 3192 goto parse_setinfo; 3193 } 3194 3195 /* At this point, fid has been entered into fid table */ 3196 need_delete_fid = 1; 3197 3198 /* 3199 * Fill in fap and possibly update vnode's meta data caches 3200 */ 3201 error = smb2fs_smb_parse_ntcreatex(share, create_np, createp, 3202 &fid, fap, context); 3203 if (error) { 3204 /* Updating meta data cache failed, try parsing the IOCTL */ 3205 SMBERROR("smb2fs_smb_parse_ntcreatex failed %d id %lld\n", 3206 error, create_rqp->sr_messageid); 3207 } 3208 3209parse_setinfo: 3210 /* Consume any pad bytes */ 3211 tmp_error = smb2_rq_next_command(create_rqp, &next_cmd_offset, mdp); 3212 if (tmp_error) { 3213 /* Failed to find next command, so can't parse rest of the responses */ 3214 SMBERROR("create smb2_rq_next_command failed %d id %lld\n", 3215 tmp_error, create_rqp->sr_messageid); 3216 goto bad; 3217 } 3218 3219 /* 3220 * Parse Set Info SMB2 header 3221 */ 3222 tmp_error = smb2_rq_parse_header(setinfo_rqp, &mdp); 3223 infop->ret_ntstatus = setinfo_rqp->sr_ntstatus; 3224 *setinfo_ntstatus = setinfo_rqp->sr_ntstatus; 3225 if (tmp_error) { 3226 /* Set Info got an error, try parsing the Close */ 3227 if (!error) { 3228 if ((tmp_error != EACCES) && (tmp_error != ENOTEMPTY)) { 3229 SMBDEBUG("setinfo smb2_rq_parse_header failed %d, id %lld\n", 3230 tmp_error, setinfo_rqp->sr_messageid); 3231 } 3232 error = tmp_error; 3233 } 3234 goto parse_close; 3235 } 3236 3237 /* Parse the Set Info response */ 3238 tmp_error = smb2_smb_parse_set_info(mdp, infop); 3239 if (tmp_error) { 3240 /* Query Info parsing got an error, try parsing the Close */ 3241 if (!error) { 3242 if (tmp_error != EACCES) { 3243 SMBERROR("smb2_smb_parse_set_info failed %d id %lld\n", 3244 tmp_error, setinfo_rqp->sr_messageid); 3245 } 3246 error = tmp_error; 3247 } 3248 goto parse_close; 3249 } 3250 3251parse_close: 3252 /* Update closep fid so it gets freed from FID table */ 3253 closep->fid = createp->ret_fid; 3254 3255 /* Consume any pad bytes */ 3256 tmp_error = smb2_rq_next_command(setinfo_rqp, &next_cmd_offset, mdp); 3257 if (tmp_error) { 3258 /* Failed to find next command, so can't parse rest of the responses */ 3259 SMBERROR("setinfo smb2_rq_next_command failed %d\n", tmp_error); 3260 error = error ? error : tmp_error; 3261 goto bad; 3262 } 3263 3264 /* 3265 * Parse Close SMB2 header 3266 */ 3267 tmp_error = smb2_rq_parse_header(close_rqp, &mdp); 3268 closep->ret_ntstatus = close_rqp->sr_ntstatus; 3269 if (tmp_error) { 3270 if (!error) { 3271 SMBDEBUG("close smb2_rq_parse_header failed %d id %lld\n", 3272 tmp_error, close_rqp->sr_messageid); 3273 error = tmp_error; 3274 } 3275 goto bad; 3276 } 3277 3278 /* Parse the Close response */ 3279 tmp_error = smb2_smb_parse_close(mdp, closep); 3280 if (tmp_error) { 3281 if (!error) { 3282 SMBERROR("smb2_smb_parse_close failed %d id %lld\n", 3283 tmp_error, close_rqp->sr_messageid); 3284 error = tmp_error; 3285 } 3286 goto bad; 3287 } 3288 3289 /* At this point, fid has been removed from fid table */ 3290 need_delete_fid = 0; 3291 3292bad: 3293 if (need_delete_fid == 1) { 3294 /* 3295 * Close failed but the Create worked and was successfully parsed. 3296 * Try issuing the Close request again. 3297 */ 3298 tmp_error = smb2_smb_close_fid(share, createp->ret_fid, 3299 NULL, NULL, context); 3300 if (tmp_error) { 3301 SMBERROR("Second close failed %d\n", tmp_error); 3302 } 3303 } 3304 3305 if (create_rqp != NULL) { 3306 smb_rq_done(create_rqp); 3307 } 3308 if (setinfo_rqp != NULL) { 3309 smb_rq_done(setinfo_rqp); 3310 } 3311 if (close_rqp != NULL) { 3312 smb_rq_done(close_rqp); 3313 } 3314 3315 if (createp != NULL) { 3316 SMB_FREE(createp, M_SMBTEMP); 3317 } 3318 if (infop != NULL) { 3319 SMB_FREE(infop, M_SMBTEMP); 3320 } 3321 if (closep != NULL) { 3322 SMB_FREE(closep, M_SMBTEMP); 3323 } 3324 3325 if (fap != NULL) { 3326 SMB_FREE(fap, M_SMBTEMP); 3327 } 3328 3329 return error; 3330} 3331 3332int 3333smb2fs_smb_change_notify(struct smb_share *share, uint32_t output_buffer_len, 3334 uint32_t completion_filter, 3335 void *fn_callback, void *fn_callback_args, 3336 vfs_context_t context) 3337{ 3338 int error; 3339 struct watch_item *watch_item = fn_callback_args; 3340 struct smb2_change_notify_rq *changep = NULL; 3341 uint32_t flags = 0; 3342 3343 SMB_MALLOC(changep, 3344 struct smb2_change_notify_rq *, 3345 sizeof(struct smb2_change_notify_rq), 3346 M_SMBTEMP, 3347 M_WAITOK | M_ZERO); 3348 if (changep == NULL) { 3349 SMBERROR("SMB_MALLOC failed\n"); 3350 error = ENOMEM; 3351 goto bad; 3352 } 3353 3354 /* 3355 * Set up for the Change Notify call 3356 */ 3357 if (watch_item->watchTree) { 3358 flags |= SMB2_WATCH_TREE; 3359 } 3360 changep->flags = flags; 3361 if (watch_item->isServerMsg) { 3362 /* special FID to let server know this is a 3363 * Mac-to-Mac srvmsg notify 3364 */ 3365 changep->fid = 0xffffffffffffffff; 3366 } else { 3367 changep->fid = watch_item->np->d_fid; 3368 } 3369 changep->output_buffer_len = output_buffer_len; 3370 changep->filter = completion_filter; 3371 changep->fn_callback = fn_callback; 3372 changep->fn_callback_args = fn_callback_args; 3373 3374 /* 3375 * Do the Change Notify call 3376 * Save the rqp into watch_item->rqp 3377 */ 3378 error = smb2_smb_change_notify(share, changep, &watch_item->rqp, context); 3379 if (error) { 3380 SMBERROR("smb2_smb_change_notify failed %d\n", error); 3381 goto bad; 3382 } 3383 3384bad: 3385 if (changep != NULL) { 3386 SMB_FREE(changep, M_SMBTEMP); 3387 } 3388 3389 return error; 3390} 3391 3392int 3393smbfs_smb_close(struct smb_share *share, SMBFID fid, vfs_context_t context) 3394{ 3395 int error; 3396 3397 if (SSTOVC(share)->vc_flags & SMBV_SMB2) { 3398 error = smb2_smb_close_fid(share, fid, NULL, NULL, context); 3399 } 3400 else { 3401 error = smb1fs_smb_close(share, fid, context); 3402 } 3403 3404 /* 3405 * ENOTCONN isn't interesting - if the connection is closed, 3406 * so are all our FIDs - and ENXIO is also not interesting, 3407 * as it means a forced unmount was done. 3408 * 3409 * EBADF means the fid is no longer good. Reconnect will make this happen. 3410 * Should we check to see if the open was broken on the reconnect or does it 3411 * really matter? 3412 * 3413 * Don't clog up the system log with warnings about those failures 3414 * on closes. 3415 */ 3416 if ((error == ENOTCONN) || (error == ENXIO) || (error == EBADF)) { 3417 error = 0; 3418 } 3419 3420 return error; 3421} 3422 3423/* 3424 * This routine is used for both Mac-to-Mac and Mac-to-Windows copyfile 3425 * operations. For Mac-to-Mac, the FSCTL_SRV_COPYCHUNK ioctl is sent with 3426 * a chunk count of zero, because the server uses copyfile(3) and doesn't need 3427 * a list of chunks from the client. To specify Mac-to-Mac semantics, the 3428 * mac_to_mac parameter should be set to TRUE. 3429 */ 3430static int 3431smb2fs_smb_copychunks(struct smb_share *share, SMBFID src_fid, 3432 SMBFID targ_fid, uint64_t src_file_len, 3433 int mac_to_mac, vfs_context_t context) 3434{ 3435 struct smb2_ioctl_rq *ioctlp = NULL; 3436 struct smb2_copychunk *copychunk_hdr; 3437 struct smb2_copychunk_chunk *copychunk_element; 3438 struct smb2_copychunk_result *copychunk_result; 3439 char *sendbuf = NULL; 3440 uint32_t sendbuf_len, src_offset, chunk_count; 3441 uint32_t max_chunk_len, retry; 3442 uint64_t remaining_len, this_len; 3443 u_char resume_key[SMB2_RESUME_KEY_LEN]; 3444 int error = 0; 3445 3446 /* Allocate a copychunk header with an array of chunk elements */ 3447 sendbuf_len = sizeof(struct smb2_copychunk) + 3448 (sizeof(struct smb2_copychunk_chunk) * SMB2_COPYCHUNK_ARR_SIZE); 3449 3450 /* setup a send buffer for the copychunk headers */ 3451 SMB_MALLOC(sendbuf, 3452 char *, 3453 sendbuf_len, 3454 M_SMBTEMP, 3455 M_WAITOK | M_ZERO); 3456 if (sendbuf == NULL) { 3457 SMBERROR("SMB_MALLOC failed\n"); 3458 error = ENOMEM; 3459 goto out; 3460 } 3461 3462 /* Begin by getting a resume key from the source */ 3463 error = smb2fs_smb_request_resume_key(share, src_fid, resume_key, context); 3464 3465 if (error) { 3466 SMBERROR("Failed to get resume key, error: %d\n", error); 3467 goto out; 3468 } 3469 3470 /* 3471 * Build the IOCTL request 3472 */ 3473 SMB_MALLOC(ioctlp, 3474 struct smb2_ioctl_rq *, 3475 sizeof(struct smb2_ioctl_rq), 3476 M_SMBTEMP, 3477 M_WAITOK | M_ZERO); 3478 if (ioctlp == NULL) { 3479 SMBERROR("SMB_MALLOC failed\n"); 3480 error = ENOMEM; 3481 goto out; 3482 } 3483 3484 /* We will initialize ioctlp->snd_input_len later */ 3485 ioctlp->share = share; 3486 ioctlp->ctl_code = FSCTL_SRV_COPYCHUNK; 3487 ioctlp->fid = targ_fid; 3488 ioctlp->snd_input_buffer = (uint8_t *)sendbuf; 3489 ioctlp->rcv_output_len = sizeof(struct smb2_copychunk_result); 3490 3491 copychunk_hdr = (struct smb2_copychunk *)sendbuf; 3492 3493 /* setup copy chunk hdr */ 3494 memcpy(copychunk_hdr->source_key, resume_key, SMB2_RESUME_KEY_LEN); 3495 copychunk_hdr->reserved = 0; 3496 3497 if (mac_to_mac == TRUE) { 3498 /* Mac-to-Mac case */ 3499 3500 /* Just a header, no chunks */ 3501 ioctlp->snd_input_len = sizeof(struct smb2_copychunk); 3502 3503 copychunk_hdr->chunk_count = 0; 3504 3505 error = smb2_smb_ioctl(share, ioctlp, NULL, context); 3506 3507 if (error) { 3508 SMBDEBUG("smb2_smb_ioctl error: %d\n", error); 3509 goto out; 3510 } 3511 3512 /* sanity check */ 3513 if (ioctlp->rcv_output_len < sizeof(struct smb2_copychunk_result)) { 3514 /* big problem, response too small, nothing we can do */ 3515 SMBERROR("rcv_output_buffer too small, expected: %lu, got: %u\n", 3516 sizeof(struct smb2_copychunk_result), ioctlp->rcv_output_len); 3517 error = EINVAL; 3518 goto out; 3519 } 3520 3521 // Check results 3522 if (ioctlp->ret_ntstatus != STATUS_SUCCESS) { 3523 SMBDEBUG("copychunk result: nt_stat: 0x%0x\n", ioctlp->ret_ntstatus); 3524 3525 /* map the nt_status to an errno */ 3526 error = smb_ntstatus_to_errno(ioctlp->ret_ntstatus); 3527 goto out; 3528 } 3529 } else { 3530 /* Non Mac-to-Mac case */ 3531 3532 retry = 0; 3533 copychunk_element = (struct smb2_copychunk_chunk *)(sendbuf + sizeof(struct smb2_copychunk)); 3534 max_chunk_len = SMB2_COPYCHUNK_MAX_CHUNK_LEN; 3535 3536again: 3537 remaining_len = src_file_len; 3538 src_offset = 0; 3539 while (remaining_len) { 3540 3541 /* Fillup the chunk array */ 3542 error = smb2fs_smb_fillchunk_arr(copychunk_element, 3543 SMB2_COPYCHUNK_ARR_SIZE, 3544 remaining_len, max_chunk_len, 3545 src_offset, src_offset, 3546 &chunk_count, &this_len); 3547 if (error) { 3548 goto out; 3549 } 3550 3551 remaining_len -= this_len; 3552 src_offset += this_len; 3553 copychunk_hdr->chunk_count = chunk_count; 3554 3555 /* snd_input_len depends on how many chunks we're sending */ 3556 ioctlp->snd_input_len = sizeof(struct smb2_copychunk) + 3557 (sizeof(struct smb2_copychunk_chunk) * chunk_count); 3558 3559 error = smb2_smb_ioctl(share, ioctlp, NULL, context); 3560 3561 if (error) { 3562 SMBDEBUG("smb2_smb_ioctl error: %d, remain: %llu, max_chunk: %u, count: %u, this_len: %llu\n", 3563 error, remaining_len, max_chunk_len, chunk_count, this_len); 3564 3565 if (ioctlp->ret_ntstatus != STATUS_INVALID_PARAMETER) { 3566 goto out; 3567 } 3568 } 3569 3570 /* sanity check */ 3571 if ( (ioctlp->rcv_output_len < sizeof(struct smb2_copychunk_result)) || 3572 (ioctlp->rcv_output_buffer == NULL) ) { 3573 /* big problem, response too small, nothing we can do */ 3574 SMBERROR("rcv_output_buffer too small, expected: %lu, got: %u\n", 3575 sizeof(struct smb2_copychunk_result), ioctlp->rcv_output_len); 3576 error = EINVAL; 3577 goto out; 3578 } 3579 3580 // Check results 3581 copychunk_result = (struct smb2_copychunk_result *)ioctlp->rcv_output_buffer; 3582 3583 if (ioctlp->ret_ntstatus == STATUS_INVALID_PARAMETER && !retry) { 3584 /* 3585 * Exceeded server's maximum chunk length. We will try 3586 * once more using the server's value, which is 3587 * returned by the server in chunk_bytes_written. 3588 * See <rdar://problem/14750992>. 3589 */ 3590 3591 if (copychunk_result->chunk_bytes_written < max_chunk_len) { 3592 max_chunk_len = copychunk_result->chunk_bytes_written; 3593 retry = 1; 3594 3595 SMB_FREE(ioctlp->rcv_output_buffer, M_SMBTEMP); 3596 goto again; 3597 } 3598 } 3599 3600 if (ioctlp->ret_ntstatus != STATUS_SUCCESS) { 3601 SMBDEBUG("smb2_smb_ioctl result: nt_stat: 0x%0x\n", ioctlp->ret_ntstatus); 3602 3603 /* map the nt_status to an errno */ 3604 error = smb_ntstatus_to_errno(ioctlp->ret_ntstatus); 3605 goto out; 3606 } 3607 3608 if (copychunk_result->chunks_written != copychunk_hdr->chunk_count) { 3609 SMBERROR("copychunk error: chunks_written: %u, expected: %u\n", 3610 copychunk_result->chunks_written, copychunk_hdr->chunk_count); 3611 error = EIO; 3612 goto out; 3613 } 3614 3615 if (copychunk_result->total_bytes_written != this_len) { 3616 SMBERROR("copychunk error: total_bytes_written: %u, expected: %llu\n", 3617 copychunk_result->total_bytes_written, this_len); 3618 error = EIO; 3619 goto out; 3620 } 3621 3622 SMB_FREE(ioctlp->rcv_output_buffer, M_SMBTEMP); 3623 } 3624 } 3625out: 3626 // clean house 3627 if (sendbuf != NULL) { 3628 SMB_FREE(sendbuf, M_SMBTEMP); 3629 } 3630 3631 if (ioctlp != NULL) { 3632 if (ioctlp->rcv_output_buffer != NULL) { 3633 SMB_FREE(ioctlp->rcv_output_buffer, M_SMBTEMP); 3634 } 3635 3636 SMB_FREE(ioctlp, M_SMBTEMP); 3637 } 3638 3639 return (error); 3640} 3641 3642int 3643smb2fs_smb_copyfile(struct smb_share *share, struct smbnode *src_np, 3644 struct smbnode *tdnp, const char *tnamep, 3645 size_t tname_len, vfs_context_t context) 3646{ 3647 struct smbfattr *sfap = NULL, *tfap = NULL; 3648 char *xattr_list = NULL, *xattrp = NULL; 3649 SMBFID src_fid = 0, targ_fid = 0, src_xattr_fid = 0, targ_xattr_fid = 0; 3650 size_t xattrlist_len = 0, remaining_len = 0, this_len; 3651 uint32_t desired_access, share_access, disp; 3652 boolean_t src_is_open = FALSE, targ_is_open = FALSE; 3653 boolean_t srcxattr_is_open = FALSE, targxattr_is_open = FALSE; 3654 uint64_t create_flags, src_file_len; 3655 struct timespec mtime; 3656 int error = 0; 3657 uint32_t ntstatus = 0; 3658 3659 if ((SSTOVC(share)->vc_misc_flags & SMBV_OSX_SERVER) && 3660 (SSTOVC(share)->vc_server_caps & kAAPL_SUPPORTS_OSX_COPYFILE)) { 3661 /* Mac-to-Mac copyfile */ 3662 return smb2fs_smb_copyfile_mac(share, src_np, 3663 tdnp, tnamep, 3664 tname_len, context); 3665 } 3666 3667 /* We'll need a couple of fattrs */ 3668 SMB_MALLOC(sfap, 3669 struct smbfattr *, 3670 sizeof(struct smbfattr), 3671 M_SMBTEMP, 3672 M_WAITOK | M_ZERO); 3673 if (sfap == NULL) { 3674 SMBERROR("SMB_MALLOC failed, sfap\n"); 3675 error = ENOMEM; 3676 goto out; 3677 } 3678 3679 SMB_MALLOC(tfap, 3680 struct smbfattr *, 3681 sizeof(struct smbfattr), 3682 M_SMBTEMP, 3683 M_WAITOK | M_ZERO); 3684 if (tfap == NULL) { 3685 SMBERROR("SMB_MALLOC failed, tfap\n"); 3686 error = ENOMEM; 3687 goto out; 3688 } 3689 3690 /*******************************/ 3691 /* Get list of src file xattrs */ 3692 /*******************************/ 3693 if (share->ss_attributes & FILE_NAMED_STREAMS) { 3694 error = smb2fs_smb_listxattrs(share, src_np, &xattr_list, 3695 &xattrlist_len, context); 3696 if (error) { 3697 SMBDEBUG("listxattrs failed, error: %d\n", error); 3698 goto out; 3699 } 3700 } 3701 3702 /********************/ 3703 /* Open source file */ 3704 /********************/ 3705 desired_access = SMB2_FILE_READ_DATA | SMB2_FILE_READ_ATTRIBUTES | SMB2_FILE_READ_EA; 3706 share_access = NTCREATEX_SHARE_ACCESS_READ; 3707 disp = FILE_OPEN; 3708 create_flags = 0; 3709 3710 error = smb2fs_smb_ntcreatex(share, src_np, 3711 NULL, 0, 3712 NULL, 0, 3713 desired_access, VREG, 3714 share_access, disp, 3715 create_flags, 3716 &src_fid, sfap, 3717 NULL, NULL, 3718 NULL, context); 3719 3720 if (error) { 3721 SMBDEBUG("smb2fs_smb_ntcreatex failed (src file) %d\n", error); 3722 goto out; 3723 } 3724 3725 src_is_open = TRUE; 3726 src_file_len = sfap->fa_size; 3727 3728 /***************************/ 3729 /* Open/Create target file */ 3730 /***************************/ 3731 desired_access = SMB2_FILE_READ_DATA | SMB2_FILE_WRITE_DATA | SMB2_FILE_APPEND_DATA | 3732 SMB2_FILE_READ_ATTRIBUTES | SMB2_FILE_WRITE_ATTRIBUTES | SMB2_FILE_WRITE_EA; 3733 disp = FILE_OVERWRITE_IF; 3734 create_flags = SMB2_CREATE_DO_CREATE; 3735 share_access = 0; /* No Access */ 3736 3737 /* Do a Create */ 3738 error = smb2fs_smb_cmpd_create(share, tdnp, 3739 tnamep, tname_len, 3740 NULL, 0, 3741 desired_access, VREG, 3742 share_access, disp, 3743 create_flags, &ntstatus, 3744 &targ_fid, tfap, 3745 NULL, context); 3746 3747 if (error) { 3748 SMBDEBUG("smb2fs_smb_ntcreatex failed (targ file) %d\n", error); 3749 goto out; 3750 } 3751 3752 targ_is_open = TRUE; 3753 3754 /*************************************/ 3755 /* Now initiate the server-side copy */ 3756 /*************************************/ 3757 error = smb2fs_smb_copychunks(share, src_fid, 3758 targ_fid, src_file_len, 3759 FALSE, context); 3760 3761 if (error) { 3762 SMBDEBUG("smb2fs_smb_copychunks failed (file data) %d\n", error); 3763 goto out; 3764 } 3765 3766 /********************************/ 3767 /* Set metadata of target file. */ 3768 /********************************/ 3769 3770 /* Set EOF of target file */ 3771 error = smb2fs_smb_set_eof(share, targ_fid, src_file_len, context); 3772 if (error) { 3773 SMBDEBUG("failed setting target eof, error: %d\n", error); 3774 goto out; 3775 } 3776 3777 /* 3778 * Set LastWriteTime timestamp of target file. 3779 * 3780 * Note: Windows clients will also set LastChangeTime here, 3781 * but we don't allow anyone to set the change time. 3782 */ 3783 nanotime(&mtime); 3784 error = smbfs_smb_setfattrNT(share, 0, targ_fid, NULL, &mtime, NULL, context); 3785 if (error) { 3786 SMBDEBUG("failed setting mtime: %d\n", error); 3787 goto out; 3788 } 3789 3790 /*********************************/ 3791 /* Close source and target files */ 3792 /*********************************/ 3793 smb2_smb_close_fid(share, src_fid, NULL, NULL, context); 3794 smb2_smb_close_fid(share, targ_fid, NULL, NULL, context); 3795 src_is_open = FALSE; 3796 targ_is_open = FALSE; 3797 3798 /*******************************/ 3799 /* Copy named streams (if any) */ 3800 /*******************************/ 3801 xattrp = xattr_list; 3802 remaining_len = xattrlist_len; 3803 while (remaining_len) { 3804 this_len = strnlen(xattrp, xattrlist_len); 3805 3806 /********************************************/ 3807 /* Open src_xattr, Open/Create target xattr */ 3808 /********************************************/ 3809 desired_access = SMB2_FILE_READ_DATA | SMB2_FILE_READ_ATTRIBUTES | SMB2_FILE_READ_EA; 3810 share_access = NTCREATEX_SHARE_ACCESS_READ; 3811 disp = FILE_OPEN; 3812 create_flags = SMB2_CREATE_IS_NAMED_STREAM; 3813 3814 error = smb2fs_smb_ntcreatex(share, src_np, 3815 NULL, 0, 3816 xattrp, this_len, 3817 desired_access, VREG, 3818 share_access, disp, 3819 create_flags, 3820 &src_xattr_fid, sfap, 3821 NULL, NULL, 3822 NULL, context); 3823 if (error) { 3824 SMBDEBUG("smb2fs_smb_ntcreatex failed (src xattr), error: %d\n", error); 3825 goto out; 3826 } 3827 3828 srcxattr_is_open = TRUE; 3829 src_file_len = sfap->fa_size; 3830 3831 /* Open/Create target file xattr */ 3832 desired_access = SMB2_FILE_READ_DATA | SMB2_FILE_WRITE_DATA | SMB2_FILE_APPEND_DATA | 3833 SMB2_FILE_READ_ATTRIBUTES | SMB2_FILE_WRITE_ATTRIBUTES | SMB2_FILE_WRITE_EA; 3834 disp = FILE_OVERWRITE_IF; 3835 create_flags = SMB2_CREATE_IS_NAMED_STREAM | SMB2_CREATE_DO_CREATE; 3836 share_access = 0; /* No Access */ 3837 3838 /* Do a Create */ 3839 error = smb2fs_smb_cmpd_create(share, tdnp, 3840 tnamep, tname_len, 3841 xattrp, this_len, 3842 desired_access, VREG, 3843 share_access, disp, 3844 create_flags, &ntstatus, 3845 &targ_xattr_fid, tfap, 3846 NULL, context); 3847 3848 if (error) { 3849 SMBDEBUG("smb2fs_smb_ntcreatex failed (targ xattr), error: %d\n", error); 3850 goto out; 3851 } 3852 3853 targxattr_is_open = TRUE; 3854 3855 /*************************************/ 3856 /* Now initiate the server-side copy */ 3857 /*************************************/ 3858 error = smb2fs_smb_copychunks(share, src_xattr_fid, 3859 targ_xattr_fid, src_file_len, 3860 FALSE, context); 3861 3862 if (error) { 3863 SMBDEBUG("smb2fs_smb_copychunks failed (xattr), error: %d\n", error); 3864 goto out; 3865 } 3866 3867 /*********************************/ 3868 /* Set metadata of target xattr. */ 3869 /*********************************/ 3870 3871 /* Set EOF */ 3872 error = smb2fs_smb_set_eof(share, targ_xattr_fid, src_file_len, context); 3873 if (error) { 3874 SMBDEBUG("failed setting target xattr eof, error: %d\n", error); 3875 goto out; 3876 } 3877 3878 /* 3879 * Set LastWriteTime timestamp of target file. 3880 * 3881 * Note: Windows clients will also set LastChangeTime here, 3882 * but we don't allow anyone to set the change time. 3883 */ 3884 nanotime(&mtime); 3885 error = smbfs_smb_setfattrNT(share, 0, targ_xattr_fid, NULL, &mtime, NULL, context); 3886 if (error) { 3887 SMBDEBUG("failed setting xattr mtime: %d\n", error); 3888 goto out; 3889 } 3890 3891 /**********************************/ 3892 /* Close source and target xattrs */ 3893 /**********************************/ 3894 smb2_smb_close_fid(share, src_xattr_fid, NULL, NULL, context); 3895 smb2_smb_close_fid(share, targ_xattr_fid, NULL, NULL, context); 3896 srcxattr_is_open = FALSE; 3897 targxattr_is_open = FALSE; 3898 3899 /* Skip over terminating NULL, advance to next xattr name */ 3900 this_len += 1; 3901 remaining_len -= this_len; 3902 if (xattrlist_len) { 3903 xattrp += this_len; 3904 } 3905 } 3906 3907out: 3908 /* Clean house */ 3909 if (src_is_open == TRUE) { 3910 smb2_smb_close_fid(share, src_fid, NULL, NULL, context); 3911 } 3912 3913 if (srcxattr_is_open == TRUE) { 3914 smb2_smb_close_fid(share, src_xattr_fid, NULL, NULL, context); 3915 } 3916 3917 if (targ_is_open == TRUE) { 3918 smb2_smb_close_fid(share, targ_fid, NULL, NULL, context); 3919 } 3920 3921 if (targxattr_is_open == TRUE) { 3922 smb2_smb_close_fid(share, targ_xattr_fid, NULL, NULL, context); 3923 } 3924 3925 if (xattr_list != NULL) { 3926 SMB_FREE(xattr_list, M_SMBTEMP); 3927 } 3928 3929 if (sfap != NULL) { 3930 SMB_FREE(sfap, M_SMBTEMP); 3931 } 3932 3933 if (tfap != NULL) { 3934 SMB_FREE(tfap, M_SMBTEMP); 3935 } 3936 3937 return error; 3938} 3939 3940static int 3941smb2fs_smb_copyfile_mac(struct smb_share *share, struct smbnode *src_np, 3942 struct smbnode *tdnp, const char *tnamep, size_t tname_len, 3943 vfs_context_t context) 3944{ 3945 struct smbfattr *sfap = NULL, *tfap = NULL; 3946 SMBFID src_fid = 0, targ_fid = 0; 3947 uint32_t desired_access, share_access, disp; 3948 boolean_t src_is_open = FALSE, targ_is_open = FALSE; 3949 uint64_t create_flags; 3950 int error = 0; 3951 uint32_t ntstatus = 0; 3952 3953 /* We'll need a couple of fattrs */ 3954 SMB_MALLOC(sfap, 3955 struct smbfattr *, 3956 sizeof(struct smbfattr), 3957 M_SMBTEMP, 3958 M_WAITOK | M_ZERO); 3959 if (sfap == NULL) { 3960 SMBERROR("SMB_MALLOC failed, sfap\n"); 3961 error = ENOMEM; 3962 goto out; 3963 } 3964 3965 SMB_MALLOC(tfap, 3966 struct smbfattr *, 3967 sizeof(struct smbfattr), 3968 M_SMBTEMP, 3969 M_WAITOK | M_ZERO); 3970 if (tfap == NULL) { 3971 SMBERROR("SMB_MALLOC failed, tfap\n"); 3972 error = ENOMEM; 3973 goto out; 3974 } 3975 3976 /*********************************************/ 3977 /* Open source file, Open/Create target file */ 3978 /*********************************************/ 3979 desired_access = SMB2_FILE_READ_DATA | SMB2_FILE_READ_ATTRIBUTES | SMB2_FILE_READ_EA; 3980 share_access = NTCREATEX_SHARE_ACCESS_READ; 3981 disp = FILE_OPEN; 3982 create_flags = 0; 3983 3984 error = smb2fs_smb_ntcreatex(share, src_np, 3985 NULL, 0, 3986 NULL, 0, 3987 desired_access, VREG, 3988 share_access, disp, 3989 create_flags, 3990 &src_fid, sfap, 3991 NULL, NULL, 3992 NULL, context); 3993 3994 if (error) { 3995 SMBDEBUG("smb2fs_smb_ntcreatex failed (src file) %d\n", error); 3996 goto out; 3997 } 3998 3999 src_is_open = TRUE; 4000 4001 /***************************/ 4002 /* Open/Create target file */ 4003 /***************************/ 4004 desired_access = SMB2_FILE_READ_DATA | SMB2_FILE_WRITE_DATA | SMB2_FILE_APPEND_DATA | 4005 SMB2_FILE_READ_ATTRIBUTES | SMB2_FILE_WRITE_ATTRIBUTES | SMB2_FILE_WRITE_EA; 4006 disp = FILE_OVERWRITE_IF; 4007 create_flags = SMB2_CREATE_DO_CREATE; 4008 share_access = 0; /* No Access */ 4009 4010 /* Do a Create */ 4011 error = smb2fs_smb_cmpd_create(share, tdnp, 4012 tnamep, tname_len, 4013 NULL, 0, 4014 desired_access, VREG, 4015 share_access, disp, 4016 create_flags, &ntstatus, 4017 &targ_fid, tfap, 4018 NULL, context); 4019 4020 if (error) { 4021 SMBDEBUG("smb2fs_smb_ntcreatex failed (targ file) %d\n", error); 4022 goto out; 4023 } 4024 4025 targ_is_open = TRUE; 4026 4027 /*************************************/ 4028 /* Now initiate the server-side copy */ 4029 /*************************************/ 4030 error = smb2fs_smb_copychunks(share, src_fid, 4031 targ_fid, 0, 4032 TRUE, context); 4033 4034 if (error) { 4035 SMBDEBUG("smb2fs_smb_copychunks_mac failed (file data) %d\n", error); 4036 goto out; 4037 } 4038 4039 /*********************************/ 4040 /* Close source and target files */ 4041 /*********************************/ 4042 smb2_smb_close_fid(share, src_fid, NULL, NULL, context); 4043 smb2_smb_close_fid(share, targ_fid, NULL, NULL, context); 4044 src_is_open = FALSE; 4045 targ_is_open = FALSE; 4046 4047out: 4048 /* Clean house */ 4049 if (src_is_open == TRUE) { 4050 smb2_smb_close_fid(share, src_fid, NULL, NULL, context); 4051 } 4052 4053 if (targ_is_open == TRUE) { 4054 smb2_smb_close_fid(share, targ_fid, NULL, NULL, context); 4055 } 4056 4057 if (sfap != NULL) { 4058 SMB_FREE(sfap, M_SMBTEMP); 4059 } 4060 4061 if (tfap != NULL) { 4062 SMB_FREE(tfap, M_SMBTEMP); 4063 } 4064 4065 return error; 4066} 4067 4068int 4069smbfs_smb_create_reparse_symlink(struct smb_share *share, struct smbnode *dnp, 4070 const char *namep, size_t name_len, 4071 char *targetp, size_t target_len, 4072 struct smbfattr *fap, vfs_context_t context) 4073{ 4074 int error; 4075 4076 if (SSTOVC(share)->vc_flags & SMBV_SMB2) { 4077 error = smb2fs_smb_cmpd_reparse_point_set(share, dnp, 4078 namep, name_len, 4079 targetp, target_len, 4080 fap, context); 4081 } 4082 else { 4083 error = smb1fs_smb_create_reparse_symlink(share, dnp, 4084 namep, name_len, 4085 targetp, target_len, 4086 fap, context); 4087 } 4088 4089 return error; 4090 4091} 4092 4093static int 4094smb2fs_smb_delete(struct smb_share *share, struct smbnode *np, 4095 const char *namep, size_t name_len, int xattr, 4096 vfs_context_t context) 4097{ 4098 int error; 4099 uint32_t setinfo_ntstatus; 4100 uint8_t delete_byte = 1; 4101 4102 /* 4103 * Looking at Win <-> Win with SMB2, delete is handled by opening the file 4104 * with Delete and "Read Attributes", then a Set Info is done to set 4105 * "Delete on close", then a Close is sent. 4106 */ 4107 4108 /* 4109 * Do the Compound Create/SetInfo/Close call 4110 */ 4111 error = smb2fs_smb_cmpd_set_info(share, np, 4112 namep, name_len, 4113 xattr, SMB2_FILE_READ_ATTRIBUTES | SMB2_STD_ACCESS_DELETE | SMB2_SYNCHRONIZE, 4114 SMB2_0_INFO_FILE, FileDispositionInformation, 4115 0, 4116 sizeof (delete_byte), (uint8_t *) &delete_byte, 4117 &setinfo_ntstatus, 4118 context); 4119 if (error) { 4120 if (error != ENOTEMPTY) { 4121 SMBDEBUG("smb2fs_smb_cmpd_set_info failed %d\n", error); 4122 } 4123 goto bad; 4124 } 4125 4126bad: 4127 return error; 4128} 4129 4130/* 4131 * The calling routine must hold a reference on the share 4132 */ 4133int 4134smbfs_smb_delete(struct smb_share *share, struct smbnode *np, 4135 const char *name, size_t nmlen, int xattr, 4136 vfs_context_t context) 4137{ 4138 int error; 4139 4140 if (SSTOVC(share)->vc_flags & SMBV_SMB2) { 4141 error = smb2fs_smb_delete (share, np, name, nmlen, xattr, context); 4142 } 4143 else { 4144 error = smb1fs_smb_delete (share, np, name, nmlen, xattr, context); 4145 } 4146 4147 return error; 4148} 4149 4150static uint32_t 4151smb2fs_smb_fillchunk_arr(struct smb2_copychunk_chunk *chunk_arr, 4152 uint32_t chunk_arr_size, 4153 uint64_t total_len, uint32_t max_chunk_len, 4154 uint64_t src_offset, uint64_t trg_offset, 4155 uint32_t *chunk_count_out, uint64_t *total_len_out) 4156{ 4157 uint64_t len_remaining = total_len; 4158 uint64_t total_chunk_len, src_off, trg_off; 4159 uint32_t i, chunk_count, this_chunk_len; 4160 4161 src_off = src_offset; 4162 trg_off = trg_offset; 4163 4164 chunk_count = 0; 4165 total_chunk_len = 0; 4166 for (i = 0; i < chunk_arr_size; i++) { 4167 if (!len_remaining) { 4168 // all done 4169 break; 4170 } 4171 4172 if (len_remaining > max_chunk_len) { 4173 this_chunk_len = max_chunk_len; 4174 } 4175 else { 4176 /* Cast is fine, here */ 4177 this_chunk_len = (uint32_t)len_remaining; 4178 } 4179 4180 chunk_arr[i].length = this_chunk_len; 4181 chunk_arr[i].reserved = 0; 4182 chunk_arr[i].source_offset = src_off; 4183 chunk_arr[i].target_offset = trg_off; 4184 4185 total_chunk_len += this_chunk_len; 4186 len_remaining -= this_chunk_len; 4187 chunk_count++; 4188 src_off += this_chunk_len; 4189 trg_off += this_chunk_len; 4190 } 4191 4192 *chunk_count_out = chunk_count; 4193 *total_len_out = total_chunk_len; 4194 return (0); 4195} 4196 4197int 4198smbfs_smb_findclose(struct smbfs_fctx *ctx, vfs_context_t context) 4199{ 4200 int error; 4201 4202 if (SSTOVC(ctx->f_share)->vc_flags & SMBV_SMB2) { 4203 if (ctx->f_create_rqp) { 4204 smb_rq_done(ctx->f_create_rqp); 4205 ctx->f_create_rqp = NULL; 4206 } 4207 if (ctx->f_query_rqp) { 4208 smb_rq_done(ctx->f_query_rqp); 4209 ctx->f_query_rqp = NULL; 4210 } 4211 4212 /* Close Create FID if we need to */ 4213 if (ctx->f_need_close == TRUE) { 4214 error = smb2_smb_close_fid(ctx->f_share, ctx->f_create_fid, 4215 NULL, NULL, context); 4216 if (error) { 4217 SMBDEBUG("smb2_smb_close_fid failed %d\n", error); 4218 } 4219 ctx->f_need_close = FALSE; 4220 } 4221 4222 /* We are done with the share release our reference */ 4223 smb_share_rele(ctx->f_share, context); 4224 4225 if (ctx->f_LocalName) { 4226 SMB_FREE(ctx->f_LocalName, M_SMBFSDATA); 4227 } 4228 4229 if (ctx->f_NetworkNameBuffer) { 4230 SMB_FREE(ctx->f_NetworkNameBuffer, M_SMBFSDATA); 4231 } 4232 4233 if (ctx->f_rname) { 4234 SMB_FREE(ctx->f_rname, M_SMBFSDATA); 4235 } 4236 4237 SMB_FREE(ctx, M_SMBFSDATA); 4238 return 0; 4239 } 4240 else { 4241 error = smb1fs_smb_findclose(ctx, context); 4242 return (error); 4243 } 4244 4245} 4246 4247static int 4248smb2fs_smb_findnext(struct smbfs_fctx *ctx, vfs_context_t context) 4249{ 4250 struct timespec ts; 4251 int error = EINVAL; 4252 struct mdchain *mdp; 4253 struct smb2_query_dir_rq *queryp = NULL; 4254 uint8_t info_class, flags; 4255 uint32_t file_index; 4256 int attempts = 0; 4257 4258 SMB_MALLOC(queryp, 4259 struct smb2_query_dir_rq *, 4260 sizeof(struct smb2_query_dir_rq), 4261 M_SMBTEMP, 4262 M_WAITOK | M_ZERO); 4263 if (queryp == NULL) { 4264 SMBERROR("SMB_MALLOC failed\n"); 4265 error = ENOMEM; 4266 goto bad; 4267 } 4268 4269 if (ctx->f_output_buf_len == 0) { 4270 /* 4271 * if no more output buffer bytes to parse, then we have finished 4272 * parsing out all the entries from this search. 4273 */ 4274 if (ctx->f_flags & SMBFS_RDD_EOF) { 4275 error = ENOENT; 4276 goto bad; 4277 } 4278 4279 nanouptime(&ts); 4280 4281 /* free any previous search requests */ 4282 if (ctx->f_create_rqp) { 4283 smb_rq_done(ctx->f_create_rqp); 4284 ctx->f_create_rqp = NULL; 4285 } 4286 if (ctx->f_query_rqp) { 4287 smb_rq_done(ctx->f_query_rqp); 4288 ctx->f_query_rqp = NULL; 4289 } 4290 4291 /* Clear resume file name */ 4292 ctx->f_flags &= ~SMBFS_RDD_GOTRNAME; 4293 4294 /* Is the dir already open? */ 4295 if (ctx->f_need_close == FALSE) { 4296 /* 4297 * Dir needs to be opened first so do a Create/Query Dir 4298 * fid is -1 for compound requests 4299 */ 4300 ctx->f_create_fid = 0xffffffffffffffff; 4301 } 4302 4303 /* 4304 * Set up for the Query Dir call 4305 */ 4306 4307 /* If not a wildcard search, then want first search entry returned */ 4308 flags = 0; 4309 if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) { 4310 flags |= SMB2_RETURN_SINGLE_ENTRY; 4311 } 4312 4313 if (ctx->f_flags & SMBFS_RDD_FINDFIRST) { 4314 /* Because this is first search, set some flags */ 4315 flags |= SMB2_RESTART_SCANS; /* start search from beginning */ 4316 file_index = 0; /* no FileIndex from prev search */ 4317 } 4318 else { 4319 flags |= SMB2_INDEX_SPECIFIED; /* search begining at FileIndex */ 4320 file_index = ctx->f_resume_file_index; 4321 } 4322 4323 switch (ctx->f_infolevel) { 4324 case SMB_FIND_FULL_DIRECTORY_INFO: 4325 /* For SMB2.x, get the file/dir IDs too but no short names */ 4326 info_class = FileIdFullDirectoryInformation; 4327 break; 4328 4329 case SMB_FIND_BOTH_DIRECTORY_INFO: 4330 /* For SMB2.x, get the file/dir IDs too */ 4331 info_class = FileIdBothDirectoryInformation; 4332 break; 4333 4334 default: 4335 SMBERROR("invalid infolevel %d", ctx->f_infolevel); 4336 error = EINVAL; 4337 goto bad; 4338 } 4339 4340again: 4341 queryp->file_info_class = info_class; 4342 queryp->flags = flags; 4343 queryp->file_index = file_index; 4344 queryp->fid = ctx->f_create_fid; 4345 4346 /* handle servers that dislike large output buffer lens */ 4347 if (SSTOVC(ctx->f_share)->vc_misc_flags & SMBV_64K_QUERY_DIR) { 4348 queryp->output_buffer_len = kSMB_64K; 4349 } 4350 else { 4351 queryp->output_buffer_len = SSTOVC(ctx->f_share)->vc_txmax; 4352 } 4353 4354 /* 4355 * Copy in whether to use UTF_SFM_CONVERSIONS or not 4356 * Seems like if NOT a wildcard, then use UTF_SFM_CONVERSIONS 4357 */ 4358 queryp->name_flags = ctx->f_sfm_conversion; 4359 4360 queryp->dnp = ctx->f_dnp; 4361 queryp->namep = (char*) ctx->f_lookupName; 4362 queryp->name_len = (uint32_t) ctx->f_lookupNameLen; 4363 4364 if (ctx->f_need_close == FALSE) { 4365 /* Build and send a Create/Query dir */ 4366 error = smb2fs_smb_cmpd_query_dir(ctx, queryp, context); 4367 } 4368 else { 4369 /* Just send a single Query Dir */ 4370 error = smb2_smb_query_dir(ctx->f_share, queryp, NULL, context); 4371 4372 /* save f_query_rqp so it can be freed later */ 4373 ctx->f_query_rqp = queryp->ret_rqp; 4374 } 4375 4376 if (error) { 4377 if (error == ENOENT) { 4378 ctx->f_flags |= SMBFS_RDD_EOF; 4379 } 4380 4381 /* handle servers that dislike large output buffer lens */ 4382 if ((error == EINVAL) && 4383 (queryp->ret_ntstatus == STATUS_INVALID_PARAMETER) && 4384 !((SSTOVC(ctx->f_share)->vc_misc_flags) & SMBV_64K_QUERY_DIR) && 4385 (attempts == 0)) { 4386 SMBWARNING("SMB 2.x server cant handle large OutputBufferLength in Query_Dir. Reducing to 64Kb.\n"); 4387 SSTOVC(ctx->f_share)->vc_misc_flags |= SMBV_64K_QUERY_DIR; 4388 attempts += 1; 4389 4390 if (ctx->f_create_rqp) { 4391 smb_rq_done(ctx->f_create_rqp); 4392 ctx->f_create_rqp = NULL; 4393 } 4394 if (ctx->f_query_rqp) { 4395 smb_rq_done(ctx->f_query_rqp); 4396 ctx->f_query_rqp = NULL; 4397 } 4398 goto again; 4399 } 4400 4401 goto bad; 4402 } 4403 4404 ctx->f_output_buf_len = queryp->ret_buffer_len; 4405 4406 if (ctx->f_flags & SMBFS_RDD_FINDFIRST) { 4407 /* next find will be a Find Next */ 4408 ctx->f_flags &= ~SMBFS_RDD_FINDFIRST; 4409 } 4410 4411 ctx->f_eofs = 0; 4412 ctx->f_attr.fa_reqtime = ts; 4413 } 4414 4415 /* 4416 * Either we did a new search and we are parsing the first entry out or 4417 * we are just parsing more names out of a previous search. 4418 */ 4419 ctx->f_NetworkNameLen = 0; 4420 4421 /* at this point, mdp is pointing to output buffer */ 4422 if (ctx->f_create_rqp != NULL) { 4423 /* 4424 * <14227703> Check to see if server is using non compound replies. 4425 * If SMB2_RESPONSE is set in queyr_rqp, then server is not using 4426 * compound replies and thusreply is in the query_rqp 4427 */ 4428 if (!(ctx->f_query_rqp->sr_extflags & SMB2_RESPONSE)) { 4429 /* Did a compound request so data is in create_rqp */ 4430 smb_rq_getreply(ctx->f_create_rqp, &mdp); 4431 } 4432 else { 4433 /* Server does not support compound replies */ 4434 smb_rq_getreply(ctx->f_query_rqp, &mdp); 4435 } 4436 } 4437 else { 4438 /* Only a Query Dir, so data is in query_rqp */ 4439 smb_rq_getreply(ctx->f_query_rqp, &mdp); 4440 } 4441 4442 /* 4443 * Parse one entry out of the output buffer and store results into ctx 4444 */ 4445 switch (ctx->f_infolevel) { 4446 case SMB_FIND_FULL_DIRECTORY_INFO: 4447 case SMB_FIND_BOTH_DIRECTORY_INFO: 4448 /* Call the parsing function */ 4449 error = smb2_smb_parse_query_dir_both_dir_info(ctx->f_share, mdp, 4450 ctx->f_infolevel, 4451 ctx, &ctx->f_attr, 4452 ctx->f_NetworkNameBuffer, &ctx->f_NetworkNameLen, 4453 ctx->f_MaxNetworkNameBufferSize); 4454 if (error) { 4455 goto bad; 4456 } 4457 break; 4458 default: 4459 SMBERROR("unexpected info level %d\n", ctx->f_infolevel); 4460 return EINVAL; 4461 } 4462 4463bad: 4464 if (queryp != NULL) { 4465 SMB_FREE(queryp, M_SMBTEMP); 4466 } 4467 4468 return error; 4469} 4470 4471int 4472smbfs_smb_findnext(struct smbfs_fctx *ctx, vfs_context_t context) 4473{ 4474 struct smb_vc *vcp = SSTOVC(ctx->f_share); 4475 int error; 4476 4477 if (vcp->vc_flags & SMBV_SMB2) { 4478 error = smb2fs_smb_findnext(ctx, context); 4479 } 4480 else { 4481 error = smb1fs_smb_findnext(ctx, context); 4482 } 4483 4484 return error; 4485} 4486 4487/* 4488 * This routine will send a flush across the wire to the server. This is an expensive 4489 * operation that should only be done when the user request it. 4490 * 4491 * The calling routine must hold a reference on the share 4492 * 4493 */ 4494int 4495smbfs_smb_flush(struct smb_share *share, SMBFID fid, vfs_context_t context) 4496{ 4497 int error; 4498 4499 if (SSTOVC(share)->vc_flags & SMBV_SMB2) { 4500 error = smb2_smb_flush(share, fid, context); 4501 } 4502 else { 4503 error = smb1fs_smb_flush(share, fid, context); 4504 } 4505 return error; 4506} 4507 4508static int 4509smb2fs_smb_listxattrs(struct smb_share *share, struct smbnode *np, char **xattrlist, 4510 size_t *xattrlist_len, vfs_context_t context) 4511{ 4512 uio_t xuio = NULL; 4513 size_t xattr_len = 0; 4514 char *xattrb = NULL; 4515 uint32_t flags = 0, max_access = 0; 4516 int error = 0; 4517 4518 /* Only pass stream_buf_sizep, so we can determine the size of the list */ 4519 error = smb2fs_smb_qstreaminfo(share, np, 4520 NULL, 0, 4521 NULL, 4522 NULL, &xattr_len, 4523 NULL, NULL, 4524 &flags, &max_access, 4525 context); 4526 if (error) { 4527 if (error !=ENOATTR) { 4528 SMBERROR("qstreaminfo error: %d\n", error); 4529 goto out; 4530 } 4531 error = 0; 4532 } 4533 4534 if (!xattr_len) { 4535 /* np does not have any xattrs */ 4536 goto out; 4537 } 4538 4539 /* Setup a uio and buffer for the xattr list */ 4540 SMB_MALLOC(xattrb, 4541 char *, 4542 xattr_len, 4543 M_SMBTEMP, 4544 M_WAITOK | M_ZERO); 4545 if (xattrb == NULL) { 4546 SMBERROR("SMB_MALLOC failed\n"); 4547 error = ENOMEM; 4548 goto out; 4549 } 4550 4551 xuio = uio_create(1, 0, UIO_SYSSPACE, UIO_READ); 4552 if (xuio == NULL) { 4553 SMBERROR("uio_create failed\n"); 4554 error = ENOMEM; 4555 goto out; 4556 } 4557 4558 error = uio_addiov(xuio, xattrb, xattr_len); 4559 4560 if (error) { 4561 SMBERROR("uio_addiov failed, error: %d", error); 4562 goto out; 4563 } 4564 4565 uio_setoffset(xuio, 0); 4566 4567 /* Only pass a uio and stream_buf_sizep, to get the entire list of xattrs */ 4568 flags = SMB_NO_TRANSLATE_NAMES; /* Do not translate AFP_Resource & AFP_AfpInfo */ 4569 error = smb2fs_smb_qstreaminfo(share, np, 4570 NULL, 0, 4571 NULL, 4572 xuio, &xattr_len, 4573 NULL, NULL, 4574 &flags, &max_access, 4575 context); 4576 4577 if (error) { 4578 SMBDEBUG("qstream failed, error: %d", error); 4579 goto out; 4580 } 4581 4582 /* Return the results */ 4583 *xattrlist = xattrb; 4584 *xattrlist_len = xattr_len; 4585 4586 /* Clean up */ 4587 uio_free(xuio); 4588 4589 return (0); 4590 4591out: 4592 if (xuio != NULL) { 4593 uio_free(xuio); 4594 } 4595 if (xattrb != NULL) { 4596 SMB_FREE(xattrb, M_SMBTEMP); 4597 } 4598 4599 *xattrlist = NULL; 4600 *xattrlist_len = 0; 4601 4602 return (error); 4603} 4604 4605int 4606smbfs_smb_lock(struct smb_share *share, int op, SMBFID fid, uint32_t pid, 4607 off_t start, uint64_t len, uint32_t timo, vfs_context_t context) 4608{ 4609 int error; 4610 4611 if (SSTOVC(share)->vc_flags & SMBV_SMB2) { 4612 error = smb2_smb_lock(share, op, fid, start, len, context); 4613 } 4614 else { 4615 error = smb1fs_smb_lock(share, op, fid, pid, start, len, timo, context); 4616 } 4617 return error; 4618} 4619 4620static int 4621smb2fs_smb_markfordelete(struct smb_share *share, SMBFID fid, vfs_context_t context) 4622{ 4623 int error; 4624 struct smb2_set_info_rq *infop = NULL; 4625 uint8_t delete_byte = 1; 4626 4627 SMB_MALLOC(infop, 4628 struct smb2_set_info_rq *, 4629 sizeof(struct smb2_set_info_rq), 4630 M_SMBTEMP, 4631 M_WAITOK | M_ZERO); 4632 if (infop == NULL) { 4633 SMBERROR("SMB_MALLOC failed\n"); 4634 error = ENOMEM; 4635 goto bad; 4636 } 4637 4638 /* 4639 * Set up for the Set Info call 4640 */ 4641 infop->info_type = SMB2_0_INFO_FILE; 4642 infop->file_info_class = FileDispositionInformation; 4643 infop->add_info = 0; 4644 infop->fid = fid; 4645 infop->input_buffer = (uint8_t *) &delete_byte; 4646 4647 error = smb2_smb_set_info(share, infop, NULL, context); 4648 if (error) { 4649 SMBDEBUG("smb2_smb_set_info failed %d ntstatus %d\n", 4650 error, 4651 infop->ret_ntstatus); 4652 goto bad; 4653 } 4654 4655bad: 4656 if (infop != NULL) { 4657 SMB_FREE(infop, M_SMBTEMP); 4658 } 4659 4660 return error; 4661} 4662 4663/* 4664 * smbfs_smb_markfordelete 4665 * 4666 * We have an open file that they want to delete. This call will tell the 4667 * server to delete the file when the last close happens. Currenly we know that 4668 * XP, Windows 2000 and Windows 2003 support this call. SAMBA does support the 4669 * call, but currently has a bug that prevents it from working. 4670 * 4671 * The calling routine must hold a reference on the share 4672 * 4673 */ 4674int 4675smbfs_smb_markfordelete(struct smb_share *share, SMBFID fid, vfs_context_t context) 4676{ 4677 int error; 4678 4679 if (SSTOVC(share)->vc_flags & SMBV_SMB2) { 4680 error = smb2fs_smb_markfordelete(share, fid, context); 4681 } 4682 else { 4683 error = smb1fs_smb_markfordelete(share, fid, context); 4684 } 4685 return error; 4686} 4687 4688int 4689smb2fs_smb_ntcreatex(struct smb_share *share, struct smbnode *np, 4690 const char *namep, size_t in_nmlen, 4691 const char *strm_namep, size_t in_strm_nmlen, 4692 uint32_t desired_access, enum vtype vnode_type, 4693 uint32_t share_access, uint32_t disposition, 4694 uint64_t create_flags, 4695 SMBFID *fidp, struct smbfattr *fap, 4696 struct smb_rq **compound_rqp, struct smb2_create_rq **in_createp, 4697 void *create_contextp, vfs_context_t context) 4698{ 4699 uint32_t create_options, file_attributes; 4700 int error; 4701 size_t name_len = in_nmlen; 4702 size_t strm_name_len = in_strm_nmlen; 4703 /* Don't change the input name length, we need it for making the ino number */ 4704 struct smb2_create_rq *createp = NULL; 4705 uint32_t impersonation_level = SMB2_IMPERSONATION_IMPERSONATION; 4706 uint8_t oplock_level = SMB2_OPLOCK_LEVEL_NONE; 4707 4708 /* 4709 * smb2fs_smb_ntcreatex() has various ways it can be called 4710 * 1) np - open item (np) 4711 * 2) np, namep - open the child (namep) in parent dir (np) 4712 * 3) np, strm_namep - open named stream (strm_namep) of item (np) 4713 * 4) np, namep, strm_namep - open named stream of (strm_namep) of 4714 * child (namep) in parent dir (np) 4715 */ 4716 4717 if (fap) { 4718 bzero(fap, sizeof(*fap)); 4719 nanouptime(&fap->fa_reqtime); 4720 } 4721 4722 SMB_MALLOC(createp, 4723 struct smb2_create_rq *, 4724 sizeof(struct smb2_create_rq), 4725 M_SMBTEMP, 4726 M_WAITOK | M_ZERO); 4727 if (createp == NULL) { 4728 SMBERROR("SMB_MALLOC failed\n"); 4729 error = ENOMEM; 4730 goto bad; 4731 } 4732 4733 /* determine file attributes */ 4734 if (vnode_type == VDIR) { 4735 file_attributes = SMB_EFA_DIRECTORY; 4736 } 4737 else { 4738 file_attributes = SMB_EFA_NORMAL; 4739 } 4740 if ((disposition != FILE_OPEN) && 4741 (!(create_flags & SMB2_CREATE_IS_NAMED_STREAM))) { 4742 if (file_attributes == SMB_EFA_NORMAL) { 4743 file_attributes |= SMB_EFA_ARCHIVE; 4744 } 4745 if ((namep) && (*namep == '.')) { 4746 file_attributes |= SMB_EFA_HIDDEN; 4747 } 4748 } 4749 4750 /* determine create options */ 4751 create_options = 0; 4752 if (disposition != FILE_OPEN) { 4753 if (vnode_type == VDIR) { 4754 create_options |= NTCREATEX_OPTIONS_DIRECTORY; 4755 /* (other create options currently not useful) */ 4756 } 4757 } 4758 /* 4759 * The server supports reparse points and its a symlink so open the item 4760 * with a reparse point bit set and bypass normal reparse point processing 4761 * for the file. 4762 */ 4763 if ((share->ss_attributes & FILE_SUPPORTS_REPARSE_POINTS) && 4764 (np && (np->n_vnode) && vnode_islnk(np->n_vnode))) { 4765 create_options |= NTCREATEX_OPTIONS_OPEN_REPARSE_POINT; 4766 4767 if (np && (np->n_dosattr & SMB_EFA_OFFLINE)) { 4768 /* 4769 * File has been moved to offline storage, do not open with a 4770 * reparse point in this case. See <rdar://problem/10836961>. 4771 */ 4772 create_options &= ~NTCREATEX_OPTIONS_OPEN_REPARSE_POINT; 4773 } 4774 } 4775 4776 /* start wth the passed in flag settings */ 4777 createp->flags |= create_flags; 4778 4779 /* Do they want to open the resource fork? */ 4780 if ((np) && (np->n_vnode) && 4781 (vnode_isnamedstream(np->n_vnode)) && 4782 (!strm_namep) && (!(create_flags & SMB2_CREATE_IS_NAMED_STREAM))) { 4783 strm_namep = (const char *) np->n_sname; 4784 strm_name_len = np->n_snmlen; 4785 createp->flags |= SMB2_CREATE_IS_NAMED_STREAM; 4786 } 4787 4788 if (create_flags & SMB2_CREATE_DUR_HANDLE_RECONNECT) { 4789 impersonation_level = 0; 4790 file_attributes = 0; 4791 create_options = 0; 4792 createp->create_contextp = create_contextp; 4793 oplock_level = SMB2_OPLOCK_LEVEL_LEASE; 4794 } 4795 else { 4796 if (create_flags & SMB2_CREATE_DUR_HANDLE) { 4797 createp->create_contextp = create_contextp; 4798 oplock_level = SMB2_OPLOCK_LEVEL_LEASE; 4799 } 4800 } 4801 4802 if (create_flags & SMB2_CREATE_AAPL_RESOLVE_ID) { 4803 createp->create_contextp = create_contextp; 4804 } 4805 4806 /* 4807 * Set up for the Create call 4808 */ 4809 createp->oplock_level = oplock_level; 4810 createp->impersonate_level = impersonation_level; 4811 4812 createp->desired_access = desired_access; 4813 if (create_flags & SMB2_CREATE_GET_MAX_ACCESS) { 4814 /* since getting max access, make sure SMB2_FILE_READ_ATTRIBUTES set */ 4815 createp->desired_access |= SMB2_FILE_READ_ATTRIBUTES; 4816 } 4817 createp->file_attributes = file_attributes; 4818 createp->share_access = share_access; 4819 createp->disposition = disposition; 4820 createp->create_options = create_options; 4821 createp->name_len = (uint32_t) name_len; 4822 createp->namep = (char *) namep; 4823 createp->strm_name_len = (uint32_t) strm_name_len; 4824 createp->strm_namep = (char *) strm_namep; 4825 createp->dnp = np; 4826 4827 /* 4828 * Do the Create call 4829 */ 4830 error = smb2_smb_create(share, createp, compound_rqp, context); 4831 if (error) { 4832 if ((error != ENOENT) && (error != EEXIST) && (error != EBUSY)) { 4833 SMBDEBUG("smb2_smb_create failed %d ntstatus 0x%x\n", 4834 error, 4835 createp->ret_ntstatus); 4836 } 4837 goto bad; 4838 } 4839 4840 /* Building a compound requests */ 4841 if (in_createp != NULL) { 4842 *in_createp = createp; 4843 return (0); 4844 } 4845 4846 if (fidp) { 4847 *fidp = createp->ret_fid; 4848 } 4849 4850 /* 4851 * Fill in fap and possibly update vnode's meta data caches 4852 */ 4853 error = smb2fs_smb_parse_ntcreatex(share, np, createp, 4854 fidp, fap, context); 4855bad: 4856 if (createp != NULL) { 4857 SMB_FREE(createp, M_SMBTEMP); 4858 } 4859 4860 return error; 4861} 4862 4863/* 4864 * Modern create/open of file or directory. 4865 * 4866 * If disp is FILE_OPEN then this is an open attempt, and: 4867 * If xattr then name is the stream to be opened at np, 4868 * Else np should be opened. 4869 * ...we won't touch *fidp, 4870 * Else this is a creation attempt, and: 4871 * If xattr then name is the stream to create at np, 4872 * Else name is the thing to create under directory np. 4873 * ...we will return *fidp, 4874 * 4875 * The calling routine must hold a reference on the share 4876 * 4877 * Either pass in np which is the file/dir to open OR 4878 * pass in dnp and a name 4879 * 4880 */ 4881int 4882smbfs_smb_ntcreatex(struct smb_share *share, struct smbnode *np, 4883 uint32_t rights, uint32_t shareMode, enum vtype vt, 4884 SMBFID *fidp, const char *name, size_t in_nmlen, 4885 uint32_t disp, int xattr, struct smbfattr *fap, 4886 int do_create, struct smb2_durable_handle *dur_handlep, vfs_context_t context) 4887{ 4888 int error; 4889 uint64_t create_flags = 0; 4890 char *file_namep = NULL, *stream_namep = NULL; 4891 size_t file_name_len = 0, stream_name_len = 0; 4892 4893 if (SSTOVC(share)->vc_flags & SMBV_SMB2) { 4894 create_flags = SMB2_CREATE_GET_MAX_ACCESS; /* Always set want_max_access */ 4895 4896 if (do_create) 4897 create_flags |= SMB2_CREATE_DO_CREATE; 4898 4899 if (dur_handlep) { 4900 if (dur_handlep->flags & SMB2_DURABLE_HANDLE_RECONNECT) { 4901 create_flags = SMB2_CREATE_DUR_HANDLE_RECONNECT; 4902 } 4903 else { 4904 if (dur_handlep->flags & SMB2_DURABLE_HANDLE_REQUEST) { 4905 create_flags = SMB2_CREATE_DUR_HANDLE; 4906 } 4907 } 4908 } 4909 4910 if (!xattr) { 4911 file_namep = (char *) name; 4912 file_name_len = in_nmlen; 4913 } 4914 else { 4915 /* name is actually the stream name */ 4916 create_flags |= SMB2_CREATE_IS_NAMED_STREAM; 4917 4918 stream_namep = (char *) name; 4919 stream_name_len = in_nmlen; 4920 } 4921 4922 error = smb2fs_smb_cmpd_create(share, np, 4923 file_namep, file_name_len, 4924 stream_namep, stream_name_len, 4925 rights, vt, 4926 shareMode, disp, 4927 create_flags, NULL, 4928 fidp, fap, 4929 dur_handlep, context); 4930 } 4931 else { 4932 error = smb1fs_smb_ntcreatex(share, np, rights, shareMode, vt, fidp, 4933 name, in_nmlen, disp, xattr, fap, 4934 do_create, context); 4935 } 4936 4937 return error; 4938} 4939 4940/* 4941 * This routine chains the open and read into one message. This routine is used 4942 * only for reading data out of a stream. If we decided to use it for something 4943 * else then we will need to make some changes. 4944 * 4945 * The calling routine must hold a reference on the share 4946 * 4947 */ 4948int 4949smbfs_smb_openread(struct smb_share *share, struct smbnode *np, SMBFID *fidp, 4950 uint32_t desired_access, uio_t uio, size_t *sizep, const char *stream_namep, 4951 struct timespec *mtimep, vfs_context_t context) 4952{ 4953 int error; 4954 size_t stream_name_len = strnlen(stream_namep, 4955 share->ss_maxfilenamelen + 1); 4956 uint32_t max_access; 4957 4958 /* This is only used when dealing with xattr calls */ 4959 4960 if (SSTOVC(share)->vc_flags & SMBV_SMB2) { 4961 /* Do a Create/Read and skip the close */ 4962 error = smb2fs_smb_cmpd_create_read(share, np, 4963 NULL, 0, 4964 stream_namep, stream_name_len, 4965 desired_access, uio, 4966 sizep, &max_access, 4967 fidp, mtimep, 4968 context); 4969 } 4970 else { 4971 error = smb1fs_smb_openread(share, np, fidp, desired_access, uio, sizep, 4972 stream_namep, mtimep, context); 4973 } 4974 4975 return error; 4976} 4977 4978static int 4979smb2fs_smb_parse_ntcreatex(struct smb_share *share, struct smbnode *np, 4980 struct smb2_create_rq *createp, 4981 SMBFID *fidp, struct smbfattr *fap, 4982 vfs_context_t context) 4983{ 4984 /* 4985 * smb2fs_smb_ntcreatex() has various ways it can be called 4986 * (1) np - open item (np) 4987 * (2) np, namep - open the child (namep) in parent dir (np) 4988 * (3) np, strm_namep - open named stream (strm_namep) of item (np) 4989 * (4) np, namep, strm_namep - open named stream of (strm_namep) of 4990 * child (namep) in parent dir (np) 4991 * 4992 * If there is a namep, then do not update the vnode np as that will 4993 * be the parent vnode. 4994 */ 4995 4996 DBG_ASSERT(fap != NULL); 4997 4998 /* 4999 * Copy results out into fap 5000 */ 5001 fap->fa_created_disp = createp->ret_create_action; 5002 smb_time_NT2local(createp->ret_create_time, &fap->fa_crtime); 5003 smb_time_NT2local(createp->ret_access_time, &fap->fa_atime); 5004 smb_time_NT2local(createp->ret_write_time, &fap->fa_mtime); 5005 smb_time_NT2local(createp->ret_change_time, &fap->fa_chtime); 5006 5007 /* 5008 * Because of the Steve/Conrad Symlinks we can never be completely 5009 * sure that we have the correct vnode type if its a file. For 5010 * directories we always know the correct information. 5011 */ 5012 fap->fa_attr = createp->ret_attributes; 5013 if (fap->fa_attr & SMB_EFA_DIRECTORY) { 5014 fap->fa_valid_mask |= FA_VTYPE_VALID; 5015 } 5016 fap->fa_vtype = (fap->fa_attr & SMB_EFA_DIRECTORY) ? VDIR : VREG; 5017 5018 fap->fa_data_alloc = createp->ret_alloc_size; 5019 fap->fa_size = createp->ret_eof; 5020 5021 if (createp->flags & SMB2_CREATE_GET_MAX_ACCESS) { 5022 fap->fa_max_access = createp->ret_max_access; 5023 fap->fa_valid_mask |= FA_MAX_ACCESS_VALID; 5024 5025 /* Special case the root vnode */ 5026 if (createp->namep == NULL) { 5027 /* Must be (1) or (3) and could be the root vnode */ 5028 if ((np) && (np->n_vnode) && (vnode_isvroot(np->n_vnode))) { 5029 /* 5030 * its the root folder, if no Execute, but share grants 5031 * Execute then grant Execute to root folder 5032 */ 5033 if ((!(np->maxAccessRights & SMB2_FILE_EXECUTE)) && 5034 (share->maxAccessRights & SMB2_FILE_EXECUTE)) { 5035 fap->fa_max_access |= SMB2_FILE_EXECUTE; 5036 } 5037 5038 /* 5039 * its the root, if no ReadAttr, but share grants 5040 * ReadAttr then grant ReadAttr to root 5041 */ 5042 if ((!(np->maxAccessRights & SMB2_FILE_READ_ATTRIBUTES)) && 5043 (share->maxAccessRights & SMB2_FILE_READ_ATTRIBUTES)) { 5044 fap->fa_max_access |= SMB2_FILE_READ_ATTRIBUTES; 5045 } 5046 } 5047 } 5048 } 5049 5050 if (fidp) { 5051 *fidp = createp->ret_fid; 5052 } 5053 5054 /* 5055 * If not a directory, check if node needs to be reopened, 5056 * if so, then don't update anything at this point. 5057 * See <rdar://problem/11366143>. 5058 */ 5059 if ((np) && (np->n_vnode) && !(vnode_isdir(np->n_vnode))) { 5060 lck_mtx_lock(&np->f_openStateLock); 5061 if (np->f_openState & kInReopen) { 5062 lck_mtx_unlock(&np->f_openStateLock); 5063 goto done; 5064 } 5065 lck_mtx_unlock(&np->f_openStateLock); 5066 } 5067 5068 if (createp->flags & SMB2_CREATE_IS_NAMED_STREAM) { 5069 /* 5070 * Must be (3) or (4). 5071 * If an EA or Stream then we are done. We dont update that main 5072 * data vnode with information from a stream. Possibly we could since 5073 * the data should be valid... 5074 */ 5075 goto done; 5076 } 5077 5078 if ((np) && (createp->flags & SMB2_CREATE_DO_CREATE)) { 5079 if (!(SSTOVC(share)->vc_misc_flags & SMBV_HAS_FILEIDS)) { 5080 /* 5081 * File server does not support File IDs 5082 */ 5083 5084 /* 5085 * Must be (2). We are creating the item so create the ino number. 5086 * Since its a create, it must be the data fork and thus 5087 * createp->name_len is the same as the orig in_nmlen. 5088 */ 5089 5090 /* This is a create so better have a name, but root does not have a name */ 5091 fap->fa_ino = smbfs_getino(np, createp->namep, createp->name_len); 5092 goto done; 5093 } 5094 } 5095 5096 if (createp->namep) { 5097 /* 5098 * SMB2_CREATE_DO_CREATE is not set, but still have a name, so 5099 * must be (2) 5100 */ 5101 goto done; 5102 } 5103 5104 /* If this is a SYMLINK, then n_vnode could be set to NULL */ 5105 if ((np) && (np->n_vnode == NULL)) { 5106 goto done; 5107 } 5108 5109 /* 5110 * At this point, it must be (1). 5111 * We have all the meta data attributes so update the cache. If the 5112 * calling routine is setting an attribute it should not change the 5113 * smb node value until after the open has completed. NOTE: The old 5114 * code would only update the cache if the mtime, attributes and size 5115 * haven't changed. 5116 */ 5117 if (np) { 5118 smbfs_attr_cacheenter(share, np->n_vnode, fap, TRUE, context); 5119 } 5120 5121done: 5122 return 0; 5123} 5124 5125static int 5126smb2fs_smb_qfsattr(struct smbmount *smp, 5127 struct FILE_FS_ATTRIBUTE_INFORMATION *fs_attrs, 5128 vfs_context_t context) 5129{ 5130 struct smb_share *share = smp->sm_share; 5131 int error; 5132 uint32_t output_buffer_len; 5133 5134 output_buffer_len = sizeof(struct FILE_FS_ATTRIBUTE_INFORMATION); 5135 output_buffer_len += PATH_MAX; 5136 5137 /* 5138 * Do the Compound Create/Query Info/Close call 5139 * Query results are passed back in *fs_attrs 5140 * 5141 * Have to pass in submount path if it exists because we have no root vnode, 5142 * and smbmount and smb_share may not be fully set up yet. 5143 */ 5144 error = smb2fs_smb_cmpd_query(share, NULL, 5145 (smp->sm_args.path_len == 0 ? NULL : smp->sm_args.path), 5146 smp->sm_args.path_len, 5147 0, SMB2_FILE_READ_ATTRIBUTES | SMB2_SYNCHRONIZE, 5148 SMB2_0_INFO_FILESYSTEM, FileFsAttributeInformation, 5149 0, NULL, 5150 &output_buffer_len, (uint8_t *) fs_attrs, 5151 context); 5152 5153 return error; 5154} 5155 5156/* 5157 * Since the first thing we do is set the default values there is no longer 5158 * any reason to return an error for this routine. Some servers may not support 5159 * this call. We should not fail the mount just because they do not support this 5160 * call. 5161 * 5162 * The calling routine must hold a reference on the share 5163 * 5164 */ 5165void 5166smbfs_smb_qfsattr(struct smbmount *smp, vfs_context_t context) 5167{ 5168 struct smb_share *share = smp->sm_share; 5169 struct smb_vc *vcp = SSTOVC(share); 5170 struct FILE_FS_ATTRIBUTE_INFORMATION fs_attrs; 5171 int error; 5172 size_t fs_nmlen; /* The sized malloced for fs_name */ 5173 char *fsname = NULL; 5174 5175 /* Start with the default values */ 5176 share->ss_fstype = SMB_FS_FAT; /* default to FAT File System */ 5177 share->ss_attributes = 0; 5178 share->ss_maxfilenamelen = 255; 5179 5180 bzero(&fs_attrs, sizeof(fs_attrs)); 5181 5182 if (vcp->vc_flags & SMBV_SMB2) { 5183 error = smb2fs_smb_qfsattr(smp, &fs_attrs, context); 5184 } 5185 else { 5186 /* 5187 * Goal is to leave the SMB1 code unchanged as much as possible 5188 * to minimize the risk. That is why there is duplicate code here 5189 * for the SMB2 path and also in SMB1 code path. 5190 */ 5191 smb1fs_qfsattr(share, context); 5192 return; 5193 } 5194 5195 if (error) { 5196 /* This is a very bad server */ 5197 SMBWARNING("Server returned a bad SMB_QFS_ATTRIBUTE_INFO message\n"); 5198 /* Don't believe them when they say they are unix */ 5199 SSTOVC(share)->vc_sopt.sv_caps &= ~SMB_CAP_UNIX; 5200 return; 5201 } 5202 5203 share->ss_attributes = fs_attrs.file_system_attrs; 5204 share->ss_maxfilenamelen = fs_attrs.max_component_name_len; 5205 5206 if (!SMB_UNICODE_STRINGS(SSTOVC(share))) { 5207 SMBERROR("Unicode must be supported\n"); 5208 goto done; 5209 } 5210 5211 /* If have a file system name, determine what it is */ 5212 if (fs_attrs.file_system_namep != NULL) { 5213 /* Convert Unicode string */ 5214 fs_nmlen = fs_attrs.file_system_name_len; 5215 fsname = smbfs_ntwrkname_tolocal(fs_attrs.file_system_namep, 5216 &fs_nmlen, 5217 SMB_UNICODE_STRINGS(SSTOVC(share))); 5218 if (fsname == NULL) { 5219 SMBERROR("fs_attr name failed to convert\n"); 5220 goto done; /* Should never happen, but just to be safe */ 5221 } 5222 5223 fs_nmlen += 1; /* Include the null byte for the compare */ 5224 5225 /* 5226 * Let's start keeping track of the file system type. Most 5227 * things we need to do differently really depend on the 5228 * file system type. As an example we know that FAT file systems 5229 * do not update the modify time on directories. 5230 */ 5231 if (strncmp(fsname, "FAT", fs_nmlen) == 0) 5232 share->ss_fstype = SMB_FS_FAT; 5233 else if (strncmp(fsname, "FAT12", fs_nmlen) == 0) 5234 share->ss_fstype = SMB_FS_FAT; 5235 else if (strncmp(fsname, "FAT16", fs_nmlen) == 0) 5236 share->ss_fstype = SMB_FS_FAT; 5237 else if (strncmp(fsname, "FAT32", fs_nmlen) == 0) 5238 share->ss_fstype = SMB_FS_FAT; 5239 else if (strncmp(fsname, "CDFS", fs_nmlen) == 0) 5240 share->ss_fstype = SMB_FS_CDFS; 5241 else if (strncmp(fsname, "UDF", fs_nmlen) == 0) 5242 share->ss_fstype = SMB_FS_UDF; 5243 else if (strncmp(fsname, "NTFS", fs_nmlen) == 0) 5244 share->ss_fstype = SMB_FS_NTFS_UNKNOWN; /* Could be lying */ 5245 5246 SMBWARNING("%s/%s type '%s', attr 0x%x, maxfilename %d\n", 5247 SSTOVC(share)->vc_srvname, share->ss_name, fsname, 5248 share->ss_attributes, share->ss_maxfilenamelen); 5249 5250 /* 5251 * NT4 will not return the FILE_NAMED_STREAMS bit in the ss_attributes 5252 * even though they support streams. So if its a NT4 server and a 5253 * NTFS file format then turn on the streams flag. 5254 */ 5255 if ((SSTOVC(share)->vc_flags & SMBV_NT4) && 5256 (share->ss_fstype & SMB_FS_NTFS_UNKNOWN)) { 5257 share->ss_attributes |= FILE_NAMED_STREAMS; 5258 } 5259 /* 5260 * The server says they support streams and they say they are NTFS. So mark 5261 * the subtype as NTFS. Remember a lot of non Windows servers pretend 5262 * their NTFS so they can support ACLs, but they aren't really because they have 5263 * no stream support. This allows us to tell the difference. 5264 */ 5265 if ((share->ss_fstype == SMB_FS_NTFS_UNKNOWN) && 5266 (share->ss_attributes & FILE_NAMED_STREAMS)) { 5267 share->ss_fstype = SMB_FS_NTFS; /* Real NTFS Volume */ 5268 } 5269 else if ((share->ss_fstype == SMB_FS_NTFS_UNKNOWN) && 5270 (UNIX_SERVER(SSTOVC(share)))) { 5271 share->ss_fstype = SMB_FS_NTFS_UNIX; 5272 /* UNIX system lying about being NTFS */ 5273 } 5274 5275 /* 5276 * Note: If this is an OS X SMB2 server, smbfs_mount() will 5277 * set share->ss_fstype() to SMB_FS_MAC_OS_X. We cannot do 5278 * that here because at this point we haven't yet queried the 5279 * server for AAPL create context support. 5280 */ 5281 } 5282 5283done: 5284 if (fs_attrs.file_system_namep != NULL) { 5285 SMB_FREE(fs_attrs.file_system_namep, M_SMBFSDATA); 5286 } 5287 if (fsname != NULL) { 5288 SMB_FREE(fsname, M_SMBSTR); 5289 } 5290} 5291 5292static int 5293smb2fs_smb_qpathinfo(struct smb_share *share, struct smbnode *np, 5294 struct smbfattr *fap, short infolevel, 5295 const char **namep, size_t *name_lenp, 5296 vfs_context_t context) 5297{ 5298 struct FILE_ALL_INFORMATION *all_infop = NULL; 5299 int error = EINVAL; 5300 const char *name = (namep ? *namep : NULL); 5301 size_t name_len = (name_lenp ? *name_lenp : 0); 5302 uint32_t output_buffer_len; 5303 5304 SMB_MALLOC(all_infop, 5305 struct FILE_ALL_INFORMATION *, 5306 sizeof(struct FILE_ALL_INFORMATION), 5307 M_SMBTEMP, 5308 M_WAITOK | M_ZERO); 5309 if (all_infop == NULL) { 5310 SMBERROR("SMB_MALLOC failed\n"); 5311 error = ENOMEM; 5312 goto bad; 5313 } 5314 5315 /* 5316 * Set up for the Query Info call 5317 */ 5318 switch (infolevel) { 5319 case SMB_QFILEINFO_ALL_INFO: 5320 all_infop->share = share; 5321 all_infop->np = np; 5322 all_infop->fap = fap; 5323 all_infop->namep = namep; 5324 all_infop->name_lenp = name_lenp; 5325 break; 5326 5327 default: 5328 SMBERROR("Unimplemented infolevel %d\n", infolevel); 5329 goto bad; 5330 break; 5331 } 5332 5333 output_buffer_len = SMB2_FILE_ALL_INFO_LEN; 5334 5335 /* 5336 * Do the Compound Create/SetInfo/Close call 5337 * Query results are passed back in *fap 5338 */ 5339 error = smb2fs_smb_cmpd_query(share, np, 5340 name, name_len, 5341 0, SMB2_FILE_READ_ATTRIBUTES | SMB2_SYNCHRONIZE, 5342 SMB2_0_INFO_FILE, FileAllInformation, 5343 0, NULL, 5344 &output_buffer_len, (uint8_t *) all_infop, 5345 context); 5346 5347bad: 5348 if (all_infop != NULL) { 5349 SMB_FREE(all_infop, M_SMBTEMP); 5350 } 5351 5352 return error; 5353} 5354 5355/* 5356 * The calling routine must hold a reference on the share 5357 */ 5358int 5359smbfs_smb_qpathinfo(struct smb_share *share, struct smbnode *np, 5360 struct smbfattr *fap, short infolevel, const char **namep, 5361 size_t *nmlenp, vfs_context_t context) 5362{ 5363 struct smb_vc *vcp = SSTOVC(share); 5364 int error; 5365 5366 if (vcp->vc_flags & SMBV_SMB2) { 5367 error = smb2fs_smb_qpathinfo(share, 5368 np, 5369 fap, 5370 infolevel, 5371 namep, 5372 nmlenp, 5373 context); 5374 } 5375 else { 5376 error = smb1fs_smb_qpathinfo(share, 5377 np, 5378 fap, 5379 infolevel, 5380 namep, 5381 nmlenp, 5382 context); 5383 } 5384 5385 return error; 5386} 5387 5388/* 5389 * When calling this routine be very careful when passing the arguments. 5390 * Depending on the arguments different actions will be taken with this routine. 5391 * 5392 * The calling routine must hold a reference on the share 5393 * 5394 */ 5395static int 5396smb2fs_smb_qstreaminfo(struct smb_share *share, struct smbnode *np, 5397 const char *namep, size_t name_len, 5398 const char *stream_namep, 5399 uio_t uio, size_t *sizep, 5400 uint64_t *stream_sizep, uint64_t *stream_alloc_sizep, 5401 uint32_t *stream_flagsp, uint32_t *max_accessp, 5402 vfs_context_t context) 5403{ 5404 /* 5405 * Two usage cases: 5406 * 1) Given np and namep == NULL. Query the path of np 5407 * 2) Given np and namep (must be readdirattr). Query PARENT np and 5408 * child namep. In this case, do not update vnode np as that is the parent. 5409 * 5410 * In both cases, Query for a list of streams and if streams are found, 5411 * see if they match stream_namep that was passed in. 5412 */ 5413 struct FILE_STREAM_INFORMATION *stream_infop = NULL; 5414 int error; 5415 int attempts = 0; 5416 uint32_t output_buffer_len; 5417 5418 if (namep == NULL) { 5419 /* Not readdirattr case */ 5420 if ((np->n_fstatus & kNO_SUBSTREAMS) || 5421 (np->n_dosattr & SMB_EFA_REPARSE_POINT)) { 5422 error = ENOATTR; 5423 goto bad; 5424 } 5425 } 5426 5427 if (sizep) { 5428 *sizep = 0; 5429 } 5430 5431 SMB_MALLOC(stream_infop, 5432 struct FILE_STREAM_INFORMATION *, 5433 sizeof(struct FILE_STREAM_INFORMATION), 5434 M_SMBTEMP, 5435 M_WAITOK | M_ZERO); 5436 if (stream_infop == NULL) { 5437 SMBERROR("SMB_MALLOC failed\n"); 5438 error = ENOMEM; 5439 goto bad; 5440 } 5441 5442again: 5443 /* 5444 * Set up for the Query Info call 5445 * 5446 * We have two typical usages for this call 5447 * 1) listxattr - uio and/or stream_buf_sizep 5448 * a) if uio and stream_buf_sizep, then return all xattrs If stream_flagsp has 5449 * SMB_NO_TRANSLATE_NAMES set, then AFP_Resource & AFP_AfpInfo are not translated 5450 * to extended attribute names. 5451 * b) if only stream_buf_sizep, then they are just trying to determine size 5452 * of a buffer sufficiently large enough to hold all the xattr names 5453 * 2) Checking for existence of a specific stream 5454 * a) If stream_namep and stream_sizep/stream_alloc_sizep, then look for 5455 * that specific stream and if found, return its logical and alloc sizes 5456 * b) If only stream_namep, just check for existence of that specific stream 5457 */ 5458 stream_infop->share = share; 5459 stream_infop->np = np; 5460 stream_infop->namep = namep; 5461 stream_infop->name_len = name_len; 5462 stream_infop->uio = uio; 5463 stream_infop->stream_buf_sizep = sizep; 5464 stream_infop->stream_namep = stream_namep; 5465 stream_infop->stream_sizep = stream_sizep; 5466 stream_infop->stream_alloc_sizep = stream_alloc_sizep; 5467 stream_infop->stream_flagsp = stream_flagsp; 5468 5469 /* handle servers that dislike large output buffer lens */ 5470 if (SSTOVC(share)->vc_misc_flags & SMBV_64K_QUERY_INFO) { 5471 output_buffer_len = kSMB_64K; 5472 } 5473 else { 5474 output_buffer_len = SSTOVC(share)->vc_txmax; 5475 } 5476 5477 /* 5478 * Do the Compound Create/QueryInfo/Close call 5479 * Query results are passed back in uio 5480 */ 5481 error = smb2fs_smb_cmpd_query(share, np, 5482 namep, name_len, 5483 0, SMB2_FILE_READ_ATTRIBUTES | SMB2_SYNCHRONIZE, 5484 SMB2_0_INFO_FILE, FileStreamInformation, 5485 0, max_accessp, 5486 &output_buffer_len, (uint8_t *) stream_infop, 5487 context); 5488 5489 if (error) { 5490 if ((error != ENOATTR) && (error != EINVAL) && 5491 (error != EACCES) && (error != ENOENT)) { 5492 SMBDEBUG("smb2fs_smb_cmpd_query failed %d\n", error); 5493 } 5494 5495 /* handle servers that dislike large output buffer lens */ 5496 if ((error == EINVAL) && (attempts == 0)) { 5497 SMBWARNING("SMB 2.x server cant handle large OutputBufferLength in Query_Info. Reducing to 64Kb.\n"); 5498 SSTOVC(share)->vc_misc_flags |= SMBV_64K_QUERY_INFO; 5499 attempts += 1; 5500 goto again; 5501 } 5502 goto bad; 5503 } 5504 5505bad: 5506 if (stream_infop != NULL) { 5507 SMB_FREE(stream_infop, M_SMBTEMP); 5508 } 5509 5510 return error; 5511} 5512 5513/* 5514 * When calling this routine be very careful when passing the arguments. 5515 * Depending on the arguments different actions will be taken with this routine. 5516 * 5517 * The calling routine must hold a reference on the share 5518 * 5519 */ 5520int 5521smbfs_smb_qstreaminfo(struct smb_share *share, struct smbnode *np, 5522 const char *namep, size_t name_len, 5523 const char *stream_namep, 5524 uio_t uio, size_t *sizep, 5525 uint64_t *strm_sizep, uint64_t *strm_alloc_sizep, 5526 uint32_t *stream_flags, uint32_t *max_accessp, 5527 vfs_context_t context) 5528{ 5529 struct smb_vc *vcp = SSTOVC(share); 5530 int error; 5531 5532 if (vcp->vc_flags & SMBV_SMB2) { 5533 error = smb2fs_smb_qstreaminfo(share, np, 5534 namep, name_len, 5535 stream_namep, 5536 uio, sizep, 5537 strm_sizep, strm_alloc_sizep, 5538 stream_flags, max_accessp, 5539 context); 5540 } 5541 else { 5542 error = smb1fs_smb_qstreaminfo(share, np, 5543 namep, name_len, 5544 stream_namep, 5545 uio, sizep, 5546 strm_sizep, strm_alloc_sizep, 5547 stream_flags, 5548 context); 5549 } 5550 5551 return error; 5552 5553} 5554 5555/* 5556 * We should replace it with something more modern. See <rdar://problem/7595213>. 5557 * This routine is only used to test the existence of an item or to get its 5558 * DOS attributes when changing the status of the HIDDEN bit. 5559 * 5560 * The calling routine must hold a reference on the share 5561 * 5562 */ 5563int 5564smbfs_smb_query_info(struct smb_share *share, struct smbnode *dnp, 5565 const char *in_name, size_t len, uint32_t *attr, 5566 vfs_context_t context) 5567{ 5568 struct smb_vc *vcp = SSTOVC(share); 5569 const char *name = in_name; 5570 size_t name_len = len; 5571 struct smbfattr *fap = NULL; 5572 int error; 5573 5574 if (vcp->vc_flags & SMBV_SMB2) { 5575 SMB_MALLOC(fap, 5576 struct smbfattr *, 5577 sizeof(struct smbfattr), 5578 M_SMBTEMP, 5579 M_WAITOK | M_ZERO); 5580 if (fap == NULL) { 5581 SMBERROR("SMB_MALLOC failed\n"); 5582 error = ENOMEM; 5583 goto out; 5584 } 5585 5586 if (vcp->vc_misc_flags & SMBV_NO_QUERYINFO) { 5587 /* Use Query Dir instead of Query Info, but only if SMB 2/3 */ 5588 error = smb2fs_smb_cmpd_query_dir_one(share, dnp, 5589 name, name_len, 5590 fap, (char **) &name, &name_len, 5591 context); 5592 } 5593 else { 5594 error = smb2fs_smb_qpathinfo(share, 5595 dnp, 5596 fap, 5597 SMB_QFILEINFO_ALL_INFO, 5598 &name, 5599 &name_len, 5600 context); 5601 } 5602 5603 if (error) { 5604 goto out; 5605 } 5606 5607 /* return attributes if they want them */ 5608 if (attr != NULL) { 5609 *attr = fap->fa_attr; 5610 } 5611 5612 /* if got returned a new name, free it since we do not need it */ 5613 if (name != in_name) { 5614 SMB_FREE(name, M_SMBNODENAME); 5615 } 5616 } 5617 else { 5618 error = smb1fs_smb_query_info(share, 5619 dnp, 5620 name, 5621 len, 5622 attr, 5623 context); 5624 } 5625 5626out: 5627 if (fap != NULL) { 5628 SMB_FREE(fap, M_SMBTEMP); 5629 } 5630 5631 return error; 5632} 5633 5634static int 5635smb2fs_smb_rename(struct smb_share *share, struct smbnode *src, 5636 struct smbnode *tdnp, const char *tnamep, size_t tname_len, 5637 vfs_context_t context) 5638{ 5639 int error; 5640 uint32_t setinfo_ntstatus; 5641 struct smb2_set_info_file_rename_info *renamep = NULL; 5642 5643 /* 5644 * Looking at Win <-> Win with SMB2, rename/move is handled by opening the 5645 * file with Delete and "Read Attributes", then a Set Info is done to move 5646 * or rename the file. Finally a Close is sent. 5647 */ 5648 5649 SMB_MALLOC(renamep, 5650 struct smb2_set_info_file_rename_info *, 5651 sizeof(struct smb2_set_info_file_rename_info), 5652 M_SMBTEMP, 5653 M_WAITOK | M_ZERO); 5654 if (renamep == NULL) { 5655 SMBERROR("SMB_MALLOC failed\n"); 5656 error = ENOMEM; 5657 goto bad; 5658 } 5659 5660 /* 5661 * Set up for the Set Info call 5662 */ 5663 renamep->replace_if_exists = 0; 5664 renamep->tname_len = (uint32_t) tname_len; 5665 renamep->tdnp = tdnp; 5666 renamep->tnamep = (char*) tnamep; 5667 5668 /* 5669 * Do the Compound Create/SetInfo/Close call 5670 * Delete access will allow us to rename an open file 5671 */ 5672 error = smb2fs_smb_cmpd_set_info(share, src, 5673 NULL, 0, 5674 0, SMB2_FILE_READ_ATTRIBUTES | SMB2_STD_ACCESS_DELETE | SMB2_SYNCHRONIZE, 5675 SMB2_0_INFO_FILE, FileRenameInformation, 5676 0, 5677 sizeof (*renamep), (uint8_t *) renamep, 5678 &setinfo_ntstatus, 5679 context); 5680 if (error) { 5681 if (error != EACCES) { 5682 SMBDEBUG("smb2fs_smb_cmpd_set_info failed %d\n", error); 5683 } 5684 goto bad; 5685 } 5686 5687bad: 5688 if (renamep != NULL) { 5689 SMB_FREE(renamep, M_SMBTEMP); 5690 } 5691 5692 return error; 5693} 5694 5695/* 5696 * The calling routine must hold a reference on the share 5697 */ 5698int 5699smbfs_smb_rename(struct smb_share *share, struct smbnode *src, 5700 struct smbnode *tdnp, const char *tname, size_t tnmlen, 5701 vfs_context_t context) 5702{ 5703 int error; 5704 5705 if (SSTOVC(share)->vc_flags & SMBV_SMB2) { 5706 error = smb2fs_smb_rename(share, src, tdnp, tname, tnmlen, context); 5707 } 5708 else { 5709 error = smb1fs_smb_rename(share, src, tdnp, tname, tnmlen, context); 5710 } 5711 5712 return error; 5713} 5714 5715int 5716smbfs_smb_reparse_read_symlink(struct smb_share *share, struct smbnode *np, 5717 struct uio *uiop, vfs_context_t context) 5718{ 5719 int error; 5720 5721 if (SSTOVC(share)->vc_flags & SMBV_SMB2) { 5722 error = smb2fs_smb_cmpd_reparse_point_get(share, np, uiop, context); 5723 } 5724 else { 5725 error = smb1fs_smb_reparse_read_symlink(share, np, uiop, context); 5726 } 5727 5728 return error; 5729 5730} 5731 5732static int 5733smb2fs_smb_request_resume_key(struct smb_share *share, SMBFID fid, u_char *resume_key, 5734 vfs_context_t context) 5735{ 5736 struct smb2_ioctl_rq *ioctlp = NULL; 5737 int error = 0; 5738 5739 /* 5740 * Build the IOCTL request 5741 */ 5742 SMB_MALLOC(ioctlp, 5743 struct smb2_ioctl_rq *, 5744 sizeof(struct smb2_ioctl_rq), 5745 M_SMBTEMP, 5746 M_WAITOK | M_ZERO); 5747 if (ioctlp == NULL) { 5748 SMBERROR("SMB_MALLOC failed\n"); 5749 error = ENOMEM; 5750 goto bad; 5751 } 5752 5753 ioctlp->share = share; 5754 ioctlp->ctl_code = FSCTL_SRV_REQUEST_RESUME_KEY; 5755 ioctlp->fid = fid; 5756 5757 ioctlp->snd_input_len = 0; 5758 ioctlp->snd_output_len = 0; 5759 ioctlp->rcv_input_len = 0; 5760 ioctlp->rcv_output_len = 0x20; 5761 5762 error = smb2_smb_ioctl(share, ioctlp, NULL, context); 5763 5764 if (!error) { 5765 memcpy(resume_key, ioctlp->rcv_output_buffer, SMB2_RESUME_KEY_LEN); 5766 SMB_FREE(ioctlp->rcv_output_buffer, M_TEMP); 5767 } 5768 5769bad: 5770 if (ioctlp != NULL) { 5771 SMB_FREE(ioctlp, M_SMBTEMP); 5772 } 5773 5774 return (error); 5775} 5776 5777/* 5778 * The calling routine must hold a reference on the share 5779 */ 5780int 5781smbfs_smb_rmdir(struct smb_share *share, struct smbnode *np, 5782 vfs_context_t context) 5783{ 5784 int error; 5785 5786 if (SSTOVC(share)->vc_flags & SMBV_SMB2) { 5787 error = smb2fs_smb_delete (share, np, NULL, 0, 0, context); 5788 } 5789 else { 5790 error = smb1fs_smb_rmdir (share, np, context); 5791 } 5792 5793 return error; 5794} 5795 5796int 5797smb2fs_smb_security_get(struct smb_share *share, struct smbnode *np, 5798 uint32_t desired_access, uint32_t security_attrs, 5799 struct ntsecdesc **resp, uint32_t *resp_len, 5800 vfs_context_t context) 5801{ 5802 int error; 5803 5804 /* 5805 * Do the Compound Create/QueryInfo/Close call 5806 */ 5807 error = smb2fs_smb_cmpd_query(share, np, 5808 NULL, 0, 5809 0, desired_access, 5810 SMB2_0_INFO_SECURITY, 0, 5811 security_attrs, NULL, 5812 resp_len, (uint8_t *) resp, 5813 context); 5814 if (error) { 5815 SMBDEBUG("smb2fs_smb_cmpd_query failed %d\n", error); 5816 } 5817 5818 return error; 5819} 5820 5821int 5822smb2fs_smb_security_set(struct smb_share *share, struct smbnode *np, 5823 uint32_t desired_access, 5824 uint32_t security_attrs, uint16_t control_flags, 5825 struct ntsid *owner, struct ntsid *group, 5826 struct ntacl *sacl, struct ntacl *dacl, 5827 vfs_context_t context) 5828{ 5829 int error; 5830 uint32_t setinfo_ntstatus; 5831 struct smb2_set_info_security sec_info; 5832 5833 /* 5834 * Set up for the Set Info call 5835 */ 5836 sec_info.security_attrs = security_attrs; 5837 sec_info.control_flags = control_flags; 5838 sec_info.owner = owner; 5839 sec_info.group = group; 5840 sec_info.sacl = sacl; 5841 sec_info.dacl = dacl; 5842 5843 /* 5844 * Do the Compound Create/SetInfo/Close call 5845 */ 5846 error = smb2fs_smb_cmpd_set_info(share, np, 5847 NULL, 0, 5848 0, desired_access, 5849 SMB2_0_INFO_SECURITY, 0, 5850 security_attrs, 5851 sizeof (sec_info), (uint8_t *) &sec_info, 5852 &setinfo_ntstatus, 5853 context); 5854 if (error) { 5855 SMBDEBUG("smb2fs_smb_cmpd_set_info failed %d, ntstatus 0x%x\n", 5856 error, setinfo_ntstatus); 5857 5858 if (setinfo_ntstatus == STATUS_INVALID_SID) { 5859 /* 5860 * If the server returns STATUS_INVALID_SID, then just pretend 5861 * that we set the security info even though it "failed". 5862 * See <rdar://problem/10852453>. 5863 */ 5864 error = 0; 5865 } 5866 } 5867 5868 return error; 5869} 5870 5871int 5872smbfs_smb_setsec(struct smb_share *share, struct smbnode *np, 5873 uint32_t desired_access, SMBFID fid, 5874 uint32_t selector, uint16_t control_flags, 5875 struct ntsid *owner, struct ntsid *group, 5876 struct ntacl *sacl, struct ntacl *dacl, 5877 vfs_context_t context) 5878{ 5879 int error; 5880 5881 if (SSTOVC(share)->vc_flags & SMBV_SMB2) { 5882 error = smb2fs_smb_security_set(share, np, desired_access, 5883 selector, control_flags, 5884 owner, group, 5885 sacl, dacl, 5886 context); 5887 } 5888 else { 5889 error = smb1fs_setsec(share, fid, selector, control_flags, 5890 owner, group, sacl, dacl, context); 5891 } 5892 5893 return (error); 5894} 5895 5896static int 5897smb2fs_smb_set_allocation(struct smb_share *share, SMBFID fid, 5898 uint64_t new_size, vfs_context_t context) 5899{ 5900 int error; 5901 struct smb2_set_info_rq *infop = NULL; 5902 5903 SMB_MALLOC(infop, 5904 struct smb2_set_info_rq *, 5905 sizeof(struct smb2_set_info_rq), 5906 M_SMBTEMP, 5907 M_WAITOK | M_ZERO); 5908 if (infop == NULL) { 5909 SMBERROR("SMB_MALLOC failed\n"); 5910 error = ENOMEM; 5911 goto bad; 5912 } 5913 5914 /* 5915 * Set up for the Set Info call 5916 */ 5917 infop->info_type = SMB2_0_INFO_FILE; 5918 infop->file_info_class = FileAllocationInformation; 5919 infop->add_info = 0; 5920 infop->fid = fid; 5921 infop->input_buffer = (uint8_t *) &new_size; 5922 5923 error = smb2_smb_set_info(share, infop, NULL, context); 5924 if (error) { 5925 SMBDEBUG("smb2_smb_set_info failed %d ntstatus %d\n", 5926 error, 5927 infop->ret_ntstatus); 5928 goto bad; 5929 } 5930 5931bad: 5932 if (infop != NULL) { 5933 SMB_FREE(infop, M_SMBTEMP); 5934 } 5935 5936 return error; 5937} 5938 5939/* 5940 * This routine will send an allocation across the wire to the server. 5941 * 5942 * The calling routine must hold a reference on the share 5943 * 5944 */ 5945int 5946smbfs_smb_set_allocation(struct smb_share *share, SMBFID fid, uint64_t new_size, 5947 vfs_context_t context) 5948{ 5949 int error; 5950 5951 if (SSTOVC(share)->vc_flags & SMBV_SMB2) { 5952 error = smb2fs_smb_set_allocation(share, fid, new_size, context); 5953 } 5954 else { 5955 error = smb1fs_set_allocation(share, fid, new_size, context); 5956 } 5957 return error; 5958} 5959 5960static int 5961smb2fs_smb_set_eof(struct smb_share *share, SMBFID fid, uint64_t newsize, 5962 vfs_context_t context) 5963{ 5964 int error; 5965 struct smb2_set_info_rq *infop = NULL; 5966 5967 SMB_MALLOC(infop, 5968 struct smb2_set_info_rq *, 5969 sizeof(struct smb2_set_info_rq), 5970 M_SMBTEMP, 5971 M_WAITOK | M_ZERO); 5972 if (infop == NULL) { 5973 SMBERROR("SMB_MALLOC failed\n"); 5974 error = ENOMEM; 5975 goto bad; 5976 } 5977 5978 /* 5979 * Set up for the Set Info call 5980 */ 5981 infop->info_type = SMB2_0_INFO_FILE; 5982 infop->file_info_class = FileEndOfFileInformation; 5983 infop->add_info = 0; 5984 infop->fid = fid; 5985 infop->input_buffer = (uint8_t *) &newsize; 5986 5987 /* 5988 * Do the Set Info call 5989 */ 5990 error = smb2_smb_set_info(share, infop, NULL, context); 5991 if (error) { 5992 SMBDEBUG("smb2_smb_set_info failed %d ntstatus %d\n", 5993 error, 5994 infop->ret_ntstatus); 5995 goto bad; 5996 } 5997 5998bad: 5999 if (infop != NULL) { 6000 SMB_FREE(infop, M_SMBTEMP); 6001 } 6002 6003 return error; 6004} 6005 6006/* 6007 * This routine will send a seteof across the wire to the server. 6008 * 6009 * The calling routine must hold a reference on the share 6010 * 6011 */ 6012int 6013smbfs_smb_seteof(struct smb_share *share, SMBFID fid, uint64_t newsize, 6014 vfs_context_t context) 6015{ 6016 int error; 6017 6018 if (SSTOVC(share)->vc_flags & SMBV_SMB2) { 6019 error = smb2fs_smb_set_eof(share, fid, newsize, context); 6020 } 6021 else { 6022 error = smb1fs_seteof(share, fid, newsize, context); 6023 } 6024 return error; 6025} 6026 6027static int 6028smb2fs_smb_set_file_basic_info(struct smb_share *share, 6029 struct smb2_set_info_file_basic_info **infopp, 6030 struct timespec *crtime, struct timespec *atime, 6031 struct timespec *mtime, uint32_t file_attrs) 6032{ 6033 uint64_t tm; 6034 6035 SMB_MALLOC(*infopp, 6036 struct smb2_set_info_file_basic_info *, 6037 sizeof(struct smb2_set_info_file_basic_info), 6038 M_SMBTEMP, 6039 M_WAITOK | M_ZERO); 6040 if (*infopp == NULL) { 6041 SMBERROR("SMB_MALLOC failed\n"); 6042 return (ENOMEM); 6043 } 6044 6045 /* 6046 * Set Creation time 6047 */ 6048 tm = 0; 6049 if (crtime) { 6050 smb_time_local2NT(crtime, &tm, (share->ss_fstype == SMB_FS_FAT)); 6051 (*infopp)->create_time = tm; 6052 } 6053 6054 /* Set last access time */ 6055 tm = 0; 6056 if (atime) { 6057 smb_time_local2NT(atime, &tm, (share->ss_fstype == SMB_FS_FAT)); 6058 (*infopp)->access_time = tm; 6059 } 6060 6061 /* Set last write time */ 6062 tm = 0; 6063 if (mtime) { 6064 smb_time_local2NT(mtime, &tm, (share->ss_fstype == SMB_FS_FAT)); 6065 (*infopp)->write_time = tm; 6066 } 6067 6068 /* We never allow anyone to set the change time */ 6069 6070 /* set file attributes */ 6071 (*infopp)->attributes = file_attrs; 6072 6073 return (0); 6074} 6075 6076static int 6077smb2fs_smb_setfattrNT(struct smb_share *share, uint32_t attr, SMBFID fid, 6078 struct timespec *crtime, struct timespec *mtime, 6079 struct timespec *atime, vfs_context_t context) 6080{ 6081 int error; 6082 struct smb2_set_info_rq *infop = NULL; 6083 struct smb2_set_info_file_basic_info *basic_infop = NULL; 6084 6085 /* Allocate and fill out the file basic info */ 6086 error = smb2fs_smb_set_file_basic_info(share, &basic_infop, 6087 crtime, atime, mtime, attr); 6088 if (error) { 6089 SMBDEBUG("smb2fs_smb_set_file_basic_info failed %d\n", error); 6090 goto bad; 6091 } 6092 6093 SMB_MALLOC(infop, 6094 struct smb2_set_info_rq *, 6095 sizeof(struct smb2_set_info_rq), 6096 M_SMBTEMP, 6097 M_WAITOK | M_ZERO); 6098 if (infop == NULL) { 6099 SMBERROR("SMB_MALLOC failed\n"); 6100 error = ENOMEM; 6101 goto bad; 6102 } 6103 6104 /* 6105 * Set up for the Set Info call 6106 */ 6107 infop->info_type = SMB2_0_INFO_FILE; 6108 infop->file_info_class = FileBasicInformation; 6109 infop->add_info = 0; 6110 infop->fid = fid; 6111 infop->input_buffer = (uint8_t *) basic_infop; 6112 6113 /* 6114 * Do the Set Info call 6115 */ 6116 error = smb2_smb_set_info(share, infop, NULL, context); 6117 if (error) { 6118 SMBDEBUG("smb2_smb_set_info failed %d ntstatus %d\n", 6119 error, 6120 infop->ret_ntstatus); 6121 goto bad; 6122 } 6123 6124bad: 6125 if (infop != NULL) { 6126 SMB_FREE(infop, M_SMBTEMP); 6127 } 6128 6129 if (basic_infop != NULL) { 6130 SMB_FREE(basic_infop, M_SMBTEMP); 6131 } 6132 6133 return error; 6134} 6135 6136/* 6137 * Same as smbfs_smb_setpattrNT except with a file handle. Note once we remove 6138 * Windows 98 support we can remove passing the node into this routine. 6139 * 6140 * The calling routine must hold a reference on the share 6141 * 6142 */ 6143int 6144smbfs_smb_setfattrNT(struct smb_share *share, uint32_t attr, SMBFID fid, 6145 struct timespec *crtime, struct timespec *mtime, 6146 struct timespec *atime, vfs_context_t context) 6147{ 6148 int error; 6149 6150 if (SSTOVC(share)->vc_flags & SMBV_SMB2) { 6151 error = smb2fs_smb_setfattrNT(share, attr, fid, crtime, mtime, atime, 6152 context); 6153 } 6154 else { 6155 error = smb1fs_smb_setfattrNT(share, attr, fid, crtime, mtime, atime, 6156 context); 6157 } 6158 return error; 6159} 6160 6161/* 6162 * Set DOS file attributes, may want to replace with a more modern call 6163 * 6164 * The calling routine must hold a reference on the share 6165 * 6166 */ 6167int 6168smbfs_smb_setpattr(struct smb_share *share, struct smbnode *np, 6169 const char *namep, size_t name_len, 6170 uint16_t attr, vfs_context_t context) 6171{ 6172 int error; 6173 6174 if (SSTOVC(share)->vc_flags & SMBV_SMB2) { 6175 error = smb2fs_smb_setpattrNT(share, np, 6176 namep, name_len, 6177 attr, NULL, 6178 NULL, NULL, 6179 context); 6180 } 6181 else { 6182 error = smb1fs_smb_setpattr(share, np, 6183 namep, name_len, 6184 attr, context); 6185 } 6186 return error; 6187} 6188 6189int 6190smb2fs_smb_setpattrNT(struct smb_share *share, struct smbnode *np, 6191 const char *namep, size_t name_len, 6192 uint32_t attr, struct timespec *crtime, 6193 struct timespec *mtime, struct timespec *atime, 6194 vfs_context_t context) 6195{ 6196 int error; 6197 uint32_t setinfo_ntstatus; 6198 struct smb2_set_info_file_basic_info *basic_infop = NULL; 6199 6200 /* Allocate and fill out the file basic info */ 6201 error = smb2fs_smb_set_file_basic_info(share, &basic_infop, 6202 crtime, atime, mtime, attr); 6203 if (error) { 6204 SMBDEBUG("smb2fs_smb_set_file_basic_info failed %d\n", error); 6205 goto bad; 6206 } 6207 6208 /* 6209 * Do the Compound Create/SetInfo/Close call 6210 */ 6211 error = smb2fs_smb_cmpd_set_info(share, np, 6212 namep, name_len, 6213 0, SMB2_FILE_WRITE_ATTRIBUTES | SMB2_SYNCHRONIZE, 6214 SMB2_0_INFO_FILE, FileBasicInformation, 6215 0, 6216 sizeof (*basic_infop), (uint8_t *) basic_infop, 6217 &setinfo_ntstatus, 6218 context); 6219 if (error) { 6220 SMBDEBUG("smb2fs_smb_cmpd_set_info failed %d\n", error); 6221 goto bad; 6222 } 6223 6224bad: 6225 if (basic_infop != NULL) { 6226 SMB_FREE(basic_infop, M_SMBTEMP); 6227 } 6228 6229 return error; 6230} 6231 6232/* 6233 * BASIC_INFO works with Samba, but Win2K servers say it is an invalid information 6234 * level on a SET_PATH_INFO. Note Win2K does support *BASIC_INFO on a SET_FILE_INFO, 6235 * and they support the equivalent *BASIC_INFORMATION on SET_PATH_INFO. Go figure. 6236 * 6237 * The calling routine must hold a reference on the share 6238 * 6239 */ 6240int 6241smbfs_smb_setpattrNT(struct smb_share *share, struct smbnode *np, 6242 const char *namep, size_t name_len, 6243 uint32_t attr, struct timespec *crtime, 6244 struct timespec *mtime, struct timespec *atime, 6245 vfs_context_t context) 6246{ 6247 int error; 6248 6249 if (SSTOVC(share)->vc_flags & SMBV_SMB2) { 6250 error = smb2fs_smb_setpattrNT(share, np, 6251 namep, name_len, 6252 attr, crtime, 6253 mtime, atime, 6254 context); 6255 } 6256 else { 6257 error = smb1fs_smb_setpattrNT(share, np, attr, crtime, mtime, atime, 6258 context); 6259 } 6260 return error; 6261} 6262 6263static int 6264smb2fs_smb_statfs(struct smbmount *smp, 6265 struct FILE_FS_SIZE_INFORMATION *fs_size, 6266 vfs_context_t context) 6267{ 6268 struct smb_share *share = smp->sm_share; 6269 int error; 6270 uint32_t output_buffer_len; 6271 6272 output_buffer_len = sizeof(struct FILE_FS_SIZE_INFORMATION); 6273 6274 /* 6275 * Do the Compound Create/GetInfo/Close call 6276 * Query results are passed back in *fs_size 6277 * 6278 * Have to pass in submount path if it exists because we have no root vnode, 6279 * and smbmount and smb_share may not be fully set up yet. 6280 */ 6281 error = smb2fs_smb_cmpd_query(share, NULL, 6282 (smp->sm_args.path_len == 0 ? NULL : smp->sm_args.path), 6283 smp->sm_args.path_len, 6284 0, SMB2_FILE_READ_ATTRIBUTES | SMB2_SYNCHRONIZE, 6285 SMB2_0_INFO_FILESYSTEM, FileFsSizeInformation, 6286 0, NULL, 6287 &output_buffer_len, (uint8_t *) fs_size, 6288 context); 6289 6290 return error; 6291} 6292 6293/* 6294 * The calling routine must hold a reference on the share 6295 */ 6296int 6297smbfs_smb_statfs(struct smbmount *smp, struct vfsstatfs *sbp, 6298 vfs_context_t context) 6299{ 6300 struct smb_share *share = smp->sm_share; 6301 struct smb_vc *vcp = SSTOVC(share); 6302 struct FILE_FS_SIZE_INFORMATION fs_size; 6303 int error; 6304 uint64_t s, t, f; 6305 size_t xmax; 6306 6307 bzero(&fs_size, sizeof(fs_size)); 6308 6309 if (vcp->vc_flags & SMBV_SMB2) { 6310 error = smb2fs_smb_statfs(smp, &fs_size, context); 6311 } 6312 else { 6313 /* 6314 * Goal is to leave the SMB1 code unchanged as much as possible 6315 * to minimize the risk. That is why there is duplicate code here 6316 * for the SMB2 path and also in SMB1 code path. 6317 */ 6318 error = smb1fs_statfs(share, sbp, context); 6319 return (error); 6320 } 6321 6322 if (error) { 6323 return error; 6324 } 6325 6326 t = fs_size.total_alloc_units; 6327 f = fs_size.avail_alloc_units; 6328 s = fs_size.bytes_per_sector; 6329 s *= fs_size.sectors_per_alloc_unit; 6330 /* 6331 * Don't allow over-large blocksizes as they determine 6332 * Finder List-view size granularities. On the other 6333 * hand, we mustn't let the block count overflow the 6334 * 31 bits available. 6335 */ 6336 while (s > 16 * 1024) { 6337 if (t > LONG_MAX) 6338 break; 6339 s /= 2; 6340 t *= 2; 6341 f *= 2; 6342 } 6343 while (t > LONG_MAX) { 6344 t /= 2; 6345 f /= 2; 6346 s *= 2; 6347 } 6348 sbp->f_bsize = (uint32_t)s; /* fundamental file system block size */ 6349 sbp->f_blocks= t; /* total data blocks in file system */ 6350 sbp->f_bfree = f; /* free blocks in fs */ 6351 sbp->f_bavail= f; /* free blocks avail to non-superuser */ 6352 sbp->f_files = (-1); /* total file nodes in file system */ 6353 sbp->f_ffree = (-1); /* free file nodes in fs */ 6354 6355 /* 6356 * Done with the network stuff, now get the iosize. This code was moved from 6357 * smbfs_vfs_getattr to here 6358 * 6359 * The min size of f_iosize is 1 MB and the max is SMB_IOMAX. 6360 * 6361 * We used to report back a multiple of the max io size supported by the 6362 * server and then read/write that amount in synchronous calls (SMB 1 still 6363 * does this). Now, we just let the applications decide how large and how 6364 * many IO blocks they want to give us. Finder will scale up to 8 MB IO 6365 * blocks depending on the transfer times for each block. UBC will give us 6366 * multiple blocks of f_iosize depending on their internal logic. UBC gets 6367 * the f_iosize from us because we call vfs_setioattr(). 6368 */ 6369 xmax = max(SSTOVC(share)->vc_rxmax, SSTOVC(share)->vc_wxmax); 6370 6371 /* 6372 * <Is this still needed???> 6373 * Now we want to make sure it will land on both a PAGE_SIZE boundary and a 6374 * smb xfer size boundary. So first mod the xfer size by the page size, then 6375 * subtract that from page size. This will give us the extra amount that 6376 * will be needed to get it on a page boundary. Now divide the page size by 6377 * this amount. This will give us the number of xmax it will take to make 6378 * f_iosize land on a page size and xfer boundary. 6379 */ 6380 xmax = (PAGE_SIZE / (PAGE_SIZE - (xmax % PAGE_SIZE))) * xmax; 6381 6382 if (xmax < SMB_IOMIN) { 6383 xmax = SMB_IOMIN; 6384 } 6385 6386 if (xmax > SMB_IOMAX) 6387 sbp->f_iosize = SMB_IOMAX; 6388 else 6389 sbp->f_iosize = xmax; 6390 6391 return error; 6392} 6393 6394