1 // SPDX-License-Identifier: LGPL-2.1 2 /* 3 * 4 * Copyright (C) International Business Machines Corp., 2002, 2011 5 * Etersoft, 2012 6 * Author(s): Pavel Shilovsky (pshilovsky@samba.org), 7 * Steve French (sfrench@us.ibm.com) 8 * 9 */ 10 #include <linux/fs.h> 11 #include <linux/stat.h> 12 #include <linux/slab.h> 13 #include <linux/pagemap.h> 14 #include <asm/div64.h> 15 #include "cifsfs.h" 16 #include "cifspdu.h" 17 #include "cifsglob.h" 18 #include "cifsproto.h" 19 #include "cifs_debug.h" 20 #include "cifs_fs_sb.h" 21 #include "cifs_unicode.h" 22 #include "fscache.h" 23 #include "smb2glob.h" 24 #include "smb2pdu.h" 25 #include "smb2proto.h" 26 #include "cached_dir.h" 27 #include "smb2status.h" 28 29 static inline __u32 file_create_options(struct dentry *dentry) 30 { 31 struct cifsInodeInfo *ci; 32 33 if (dentry) { 34 ci = CIFS_I(d_inode(dentry)); 35 if (ci->cifsAttrs & ATTR_REPARSE) 36 return OPEN_REPARSE_POINT; 37 } 38 return 0; 39 } 40 41 /* 42 * note: If cfile is passed, the reference to it is dropped here. 43 * So make sure that you do not reuse cfile after return from this func. 44 * 45 * If passing @out_iov and @out_buftype, ensure to make them both large enough 46 * (>= 3) to hold all compounded responses. Caller is also responsible for 47 * freeing them up with free_rsp_buf(). 48 */ 49 static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, 50 struct cifs_sb_info *cifs_sb, const char *full_path, 51 __u32 desired_access, __u32 create_disposition, 52 __u32 create_options, umode_t mode, struct kvec *in_iov, 53 int *cmds, int num_cmds, struct cifsFileInfo *cfile, 54 __u8 **extbuf, size_t *extbuflen, 55 struct kvec *out_iov, int *out_buftype) 56 { 57 struct smb2_compound_vars *vars = NULL; 58 struct kvec *rsp_iov; 59 struct smb_rqst *rqst; 60 int rc; 61 __le16 *utf16_path = NULL; 62 __u8 oplock = SMB2_OPLOCK_LEVEL_NONE; 63 struct cifs_fid fid; 64 struct cifs_ses *ses = tcon->ses; 65 struct TCP_Server_Info *server; 66 int num_rqst = 0, i; 67 int resp_buftype[MAX_COMPOUND]; 68 struct smb2_query_info_rsp *qi_rsp = NULL; 69 struct cifs_open_info_data *idata; 70 int flags = 0; 71 __u8 delete_pending[8] = {1, 0, 0, 0, 0, 0, 0, 0}; 72 unsigned int size[2]; 73 void *data[2]; 74 int len; 75 76 vars = kzalloc(sizeof(*vars), GFP_ATOMIC); 77 if (vars == NULL) 78 return -ENOMEM; 79 rqst = &vars->rqst[0]; 80 rsp_iov = &vars->rsp_iov[0]; 81 82 server = cifs_pick_channel(ses); 83 84 if (smb3_encryption_required(tcon)) 85 flags |= CIFS_TRANSFORM_REQ; 86 87 for (i = 0; i < ARRAY_SIZE(resp_buftype); i++) 88 resp_buftype[i] = CIFS_NO_BUFFER; 89 90 /* We already have a handle so we can skip the open */ 91 if (cfile) 92 goto after_open; 93 94 /* Open */ 95 utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb); 96 if (!utf16_path) { 97 rc = -ENOMEM; 98 goto finished; 99 } 100 101 vars->oparms = (struct cifs_open_parms) { 102 .tcon = tcon, 103 .path = full_path, 104 .desired_access = desired_access, 105 .disposition = create_disposition, 106 .create_options = cifs_create_options(cifs_sb, create_options), 107 .fid = &fid, 108 .mode = mode, 109 .cifs_sb = cifs_sb, 110 }; 111 112 rqst[num_rqst].rq_iov = &vars->open_iov[0]; 113 rqst[num_rqst].rq_nvec = SMB2_CREATE_IOV_SIZE; 114 rc = SMB2_open_init(tcon, server, 115 &rqst[num_rqst], &oplock, &vars->oparms, 116 utf16_path); 117 kfree(utf16_path); 118 if (rc) 119 goto finished; 120 121 smb2_set_next_command(tcon, &rqst[num_rqst]); 122 after_open: 123 num_rqst++; 124 rc = 0; 125 126 for (i = 0; i < num_cmds; i++) { 127 /* Operation */ 128 switch (cmds[i]) { 129 case SMB2_OP_QUERY_INFO: 130 rqst[num_rqst].rq_iov = &vars->qi_iov; 131 rqst[num_rqst].rq_nvec = 1; 132 133 if (cfile) { 134 rc = SMB2_query_info_init(tcon, server, 135 &rqst[num_rqst], 136 cfile->fid.persistent_fid, 137 cfile->fid.volatile_fid, 138 FILE_ALL_INFORMATION, 139 SMB2_O_INFO_FILE, 0, 140 sizeof(struct smb2_file_all_info) + 141 PATH_MAX * 2, 0, NULL); 142 } else { 143 rc = SMB2_query_info_init(tcon, server, 144 &rqst[num_rqst], 145 COMPOUND_FID, 146 COMPOUND_FID, 147 FILE_ALL_INFORMATION, 148 SMB2_O_INFO_FILE, 0, 149 sizeof(struct smb2_file_all_info) + 150 PATH_MAX * 2, 0, NULL); 151 if (!rc) { 152 smb2_set_next_command(tcon, &rqst[num_rqst]); 153 smb2_set_related(&rqst[num_rqst]); 154 } 155 } 156 157 if (rc) 158 goto finished; 159 num_rqst++; 160 trace_smb3_query_info_compound_enter(xid, ses->Suid, 161 tcon->tid, full_path); 162 break; 163 case SMB2_OP_POSIX_QUERY_INFO: 164 rqst[num_rqst].rq_iov = &vars->qi_iov; 165 rqst[num_rqst].rq_nvec = 1; 166 167 if (cfile) { 168 /* TBD: fix following to allow for longer SIDs */ 169 rc = SMB2_query_info_init(tcon, server, 170 &rqst[num_rqst], 171 cfile->fid.persistent_fid, 172 cfile->fid.volatile_fid, 173 SMB_FIND_FILE_POSIX_INFO, 174 SMB2_O_INFO_FILE, 0, 175 sizeof(struct smb311_posix_qinfo *) + 176 (PATH_MAX * 2) + 177 (sizeof(struct cifs_sid) * 2), 0, NULL); 178 } else { 179 rc = SMB2_query_info_init(tcon, server, 180 &rqst[num_rqst], 181 COMPOUND_FID, 182 COMPOUND_FID, 183 SMB_FIND_FILE_POSIX_INFO, 184 SMB2_O_INFO_FILE, 0, 185 sizeof(struct smb311_posix_qinfo *) + 186 (PATH_MAX * 2) + 187 (sizeof(struct cifs_sid) * 2), 0, NULL); 188 if (!rc) { 189 smb2_set_next_command(tcon, &rqst[num_rqst]); 190 smb2_set_related(&rqst[num_rqst]); 191 } 192 } 193 194 if (rc) 195 goto finished; 196 num_rqst++; 197 trace_smb3_posix_query_info_compound_enter(xid, ses->Suid, 198 tcon->tid, full_path); 199 break; 200 case SMB2_OP_DELETE: 201 trace_smb3_delete_enter(xid, ses->Suid, tcon->tid, full_path); 202 break; 203 case SMB2_OP_MKDIR: 204 /* 205 * Directories are created through parameters in the 206 * SMB2_open() call. 207 */ 208 trace_smb3_mkdir_enter(xid, ses->Suid, tcon->tid, full_path); 209 break; 210 case SMB2_OP_RMDIR: 211 rqst[num_rqst].rq_iov = &vars->si_iov[0]; 212 rqst[num_rqst].rq_nvec = 1; 213 214 size[0] = 1; /* sizeof __u8 See MS-FSCC section 2.4.11 */ 215 data[0] = &delete_pending[0]; 216 217 rc = SMB2_set_info_init(tcon, server, 218 &rqst[num_rqst], COMPOUND_FID, 219 COMPOUND_FID, current->tgid, 220 FILE_DISPOSITION_INFORMATION, 221 SMB2_O_INFO_FILE, 0, data, size); 222 if (rc) 223 goto finished; 224 smb2_set_next_command(tcon, &rqst[num_rqst]); 225 smb2_set_related(&rqst[num_rqst++]); 226 trace_smb3_rmdir_enter(xid, ses->Suid, tcon->tid, full_path); 227 break; 228 case SMB2_OP_SET_EOF: 229 rqst[num_rqst].rq_iov = &vars->si_iov[0]; 230 rqst[num_rqst].rq_nvec = 1; 231 232 size[0] = in_iov[i].iov_len; 233 data[0] = in_iov[i].iov_base; 234 235 if (cfile) { 236 rc = SMB2_set_info_init(tcon, server, 237 &rqst[num_rqst], 238 cfile->fid.persistent_fid, 239 cfile->fid.volatile_fid, 240 current->tgid, 241 FILE_END_OF_FILE_INFORMATION, 242 SMB2_O_INFO_FILE, 0, 243 data, size); 244 } else { 245 rc = SMB2_set_info_init(tcon, server, 246 &rqst[num_rqst], 247 COMPOUND_FID, 248 COMPOUND_FID, 249 current->tgid, 250 FILE_END_OF_FILE_INFORMATION, 251 SMB2_O_INFO_FILE, 0, 252 data, size); 253 if (!rc) { 254 smb2_set_next_command(tcon, &rqst[num_rqst]); 255 smb2_set_related(&rqst[num_rqst]); 256 } 257 } 258 if (rc) 259 goto finished; 260 num_rqst++; 261 trace_smb3_set_eof_enter(xid, ses->Suid, tcon->tid, full_path); 262 break; 263 case SMB2_OP_SET_INFO: 264 rqst[num_rqst].rq_iov = &vars->si_iov[0]; 265 rqst[num_rqst].rq_nvec = 1; 266 267 size[0] = in_iov[i].iov_len; 268 data[0] = in_iov[i].iov_base; 269 270 if (cfile) { 271 rc = SMB2_set_info_init(tcon, server, 272 &rqst[num_rqst], 273 cfile->fid.persistent_fid, 274 cfile->fid.volatile_fid, current->tgid, 275 FILE_BASIC_INFORMATION, 276 SMB2_O_INFO_FILE, 0, data, size); 277 } else { 278 rc = SMB2_set_info_init(tcon, server, 279 &rqst[num_rqst], 280 COMPOUND_FID, 281 COMPOUND_FID, current->tgid, 282 FILE_BASIC_INFORMATION, 283 SMB2_O_INFO_FILE, 0, data, size); 284 if (!rc) { 285 smb2_set_next_command(tcon, &rqst[num_rqst]); 286 smb2_set_related(&rqst[num_rqst]); 287 } 288 } 289 290 if (rc) 291 goto finished; 292 num_rqst++; 293 trace_smb3_set_info_compound_enter(xid, ses->Suid, 294 tcon->tid, full_path); 295 break; 296 case SMB2_OP_RENAME: 297 rqst[num_rqst].rq_iov = &vars->si_iov[0]; 298 rqst[num_rqst].rq_nvec = 2; 299 300 len = in_iov[i].iov_len; 301 302 vars->rename_info.ReplaceIfExists = 1; 303 vars->rename_info.RootDirectory = 0; 304 vars->rename_info.FileNameLength = cpu_to_le32(len); 305 306 size[0] = sizeof(struct smb2_file_rename_info); 307 data[0] = &vars->rename_info; 308 309 size[1] = len + 2 /* null */; 310 data[1] = in_iov[i].iov_base; 311 312 if (cfile) { 313 rc = SMB2_set_info_init(tcon, server, 314 &rqst[num_rqst], 315 cfile->fid.persistent_fid, 316 cfile->fid.volatile_fid, 317 current->tgid, FILE_RENAME_INFORMATION, 318 SMB2_O_INFO_FILE, 0, data, size); 319 } else { 320 rc = SMB2_set_info_init(tcon, server, 321 &rqst[num_rqst], 322 COMPOUND_FID, COMPOUND_FID, 323 current->tgid, FILE_RENAME_INFORMATION, 324 SMB2_O_INFO_FILE, 0, data, size); 325 if (!rc) { 326 smb2_set_next_command(tcon, &rqst[num_rqst]); 327 smb2_set_related(&rqst[num_rqst]); 328 } 329 } 330 if (rc) 331 goto finished; 332 num_rqst++; 333 trace_smb3_rename_enter(xid, ses->Suid, tcon->tid, full_path); 334 break; 335 case SMB2_OP_HARDLINK: 336 rqst[num_rqst].rq_iov = &vars->si_iov[0]; 337 rqst[num_rqst].rq_nvec = 2; 338 339 len = in_iov[i].iov_len; 340 341 vars->link_info.ReplaceIfExists = 0; 342 vars->link_info.RootDirectory = 0; 343 vars->link_info.FileNameLength = cpu_to_le32(len); 344 345 size[0] = sizeof(struct smb2_file_link_info); 346 data[0] = &vars->link_info; 347 348 size[1] = len + 2 /* null */; 349 data[1] = in_iov[i].iov_base; 350 351 rc = SMB2_set_info_init(tcon, server, 352 &rqst[num_rqst], COMPOUND_FID, 353 COMPOUND_FID, current->tgid, 354 FILE_LINK_INFORMATION, 355 SMB2_O_INFO_FILE, 0, data, size); 356 if (rc) 357 goto finished; 358 smb2_set_next_command(tcon, &rqst[num_rqst]); 359 smb2_set_related(&rqst[num_rqst++]); 360 trace_smb3_hardlink_enter(xid, ses->Suid, tcon->tid, full_path); 361 break; 362 default: 363 cifs_dbg(VFS, "Invalid command\n"); 364 rc = -EINVAL; 365 } 366 } 367 if (rc) 368 goto finished; 369 370 /* We already have a handle so we can skip the close */ 371 if (cfile) 372 goto after_close; 373 /* Close */ 374 flags |= CIFS_CP_CREATE_CLOSE_OP; 375 rqst[num_rqst].rq_iov = &vars->close_iov; 376 rqst[num_rqst].rq_nvec = 1; 377 rc = SMB2_close_init(tcon, server, 378 &rqst[num_rqst], COMPOUND_FID, 379 COMPOUND_FID, false); 380 smb2_set_related(&rqst[num_rqst]); 381 if (rc) 382 goto finished; 383 after_close: 384 num_rqst++; 385 386 if (cfile) { 387 rc = compound_send_recv(xid, ses, server, 388 flags, num_rqst - 2, 389 &rqst[1], &resp_buftype[1], 390 &rsp_iov[1]); 391 } else 392 rc = compound_send_recv(xid, ses, server, 393 flags, num_rqst, 394 rqst, resp_buftype, 395 rsp_iov); 396 397 finished: 398 num_rqst = 0; 399 SMB2_open_free(&rqst[num_rqst++]); 400 if (rc == -EREMCHG) { 401 pr_warn_once("server share %s deleted\n", tcon->tree_name); 402 tcon->need_reconnect = true; 403 } 404 405 for (i = 0; i < num_cmds; i++) { 406 switch (cmds[i]) { 407 case SMB2_OP_QUERY_INFO: 408 idata = in_iov[i].iov_base; 409 if (rc == 0 && cfile && cfile->symlink_target) { 410 idata->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL); 411 if (!idata->symlink_target) 412 rc = -ENOMEM; 413 } 414 if (rc == 0) { 415 qi_rsp = (struct smb2_query_info_rsp *) 416 rsp_iov[i + 1].iov_base; 417 rc = smb2_validate_and_copy_iov( 418 le16_to_cpu(qi_rsp->OutputBufferOffset), 419 le32_to_cpu(qi_rsp->OutputBufferLength), 420 &rsp_iov[i + 1], sizeof(idata->fi), (char *)&idata->fi); 421 } 422 SMB2_query_info_free(&rqst[num_rqst++]); 423 if (rc) 424 trace_smb3_query_info_compound_err(xid, ses->Suid, 425 tcon->tid, rc); 426 else 427 trace_smb3_query_info_compound_done(xid, ses->Suid, 428 tcon->tid); 429 break; 430 case SMB2_OP_POSIX_QUERY_INFO: 431 idata = in_iov[i].iov_base; 432 if (rc == 0 && cfile && cfile->symlink_target) { 433 idata->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL); 434 if (!idata->symlink_target) 435 rc = -ENOMEM; 436 } 437 if (rc == 0) { 438 qi_rsp = (struct smb2_query_info_rsp *) 439 rsp_iov[i + 1].iov_base; 440 rc = smb2_validate_and_copy_iov( 441 le16_to_cpu(qi_rsp->OutputBufferOffset), 442 le32_to_cpu(qi_rsp->OutputBufferLength), 443 &rsp_iov[i + 1], sizeof(idata->posix_fi) /* add SIDs */, 444 (char *)&idata->posix_fi); 445 } 446 if (rc == 0) { 447 unsigned int length = le32_to_cpu(qi_rsp->OutputBufferLength); 448 449 if (length > sizeof(idata->posix_fi)) { 450 char *base = (char *)rsp_iov[i + 1].iov_base + 451 le16_to_cpu(qi_rsp->OutputBufferOffset) + 452 sizeof(idata->posix_fi); 453 *extbuflen = length - sizeof(idata->posix_fi); 454 *extbuf = kmemdup(base, *extbuflen, GFP_KERNEL); 455 if (!*extbuf) 456 rc = -ENOMEM; 457 } else { 458 rc = -EINVAL; 459 } 460 } 461 SMB2_query_info_free(&rqst[num_rqst++]); 462 if (rc) 463 trace_smb3_posix_query_info_compound_err(xid, ses->Suid, 464 tcon->tid, rc); 465 else 466 trace_smb3_posix_query_info_compound_done(xid, ses->Suid, 467 tcon->tid); 468 break; 469 case SMB2_OP_DELETE: 470 if (rc) 471 trace_smb3_delete_err(xid, ses->Suid, tcon->tid, rc); 472 else 473 trace_smb3_delete_done(xid, ses->Suid, tcon->tid); 474 break; 475 case SMB2_OP_MKDIR: 476 if (rc) 477 trace_smb3_mkdir_err(xid, ses->Suid, tcon->tid, rc); 478 else 479 trace_smb3_mkdir_done(xid, ses->Suid, tcon->tid); 480 break; 481 case SMB2_OP_HARDLINK: 482 if (rc) 483 trace_smb3_hardlink_err(xid, ses->Suid, tcon->tid, rc); 484 else 485 trace_smb3_hardlink_done(xid, ses->Suid, tcon->tid); 486 SMB2_set_info_free(&rqst[num_rqst++]); 487 break; 488 case SMB2_OP_RENAME: 489 if (rc) 490 trace_smb3_rename_err(xid, ses->Suid, tcon->tid, rc); 491 else 492 trace_smb3_rename_done(xid, ses->Suid, tcon->tid); 493 SMB2_set_info_free(&rqst[num_rqst++]); 494 break; 495 case SMB2_OP_RMDIR: 496 if (rc) 497 trace_smb3_rmdir_err(xid, ses->Suid, tcon->tid, rc); 498 else 499 trace_smb3_rmdir_done(xid, ses->Suid, tcon->tid); 500 SMB2_set_info_free(&rqst[num_rqst++]); 501 break; 502 case SMB2_OP_SET_EOF: 503 if (rc) 504 trace_smb3_set_eof_err(xid, ses->Suid, tcon->tid, rc); 505 else 506 trace_smb3_set_eof_done(xid, ses->Suid, tcon->tid); 507 SMB2_set_info_free(&rqst[num_rqst++]); 508 break; 509 case SMB2_OP_SET_INFO: 510 if (rc) 511 trace_smb3_set_info_compound_err(xid, ses->Suid, 512 tcon->tid, rc); 513 else 514 trace_smb3_set_info_compound_done(xid, ses->Suid, 515 tcon->tid); 516 SMB2_set_info_free(&rqst[num_rqst++]); 517 break; 518 } 519 } 520 SMB2_close_free(&rqst[num_rqst]); 521 522 if (cfile) 523 cifsFileInfo_put(cfile); 524 525 num_cmds += 2; 526 if (out_iov && out_buftype) { 527 memcpy(out_iov, rsp_iov, num_cmds * sizeof(*out_iov)); 528 memcpy(out_buftype, resp_buftype, 529 num_cmds * sizeof(*out_buftype)); 530 } else { 531 for (i = 0; i < num_cmds; i++) 532 free_rsp_buf(resp_buftype[i], rsp_iov[i].iov_base); 533 } 534 kfree(vars); 535 return rc; 536 } 537 538 static int parse_create_response(struct cifs_open_info_data *data, 539 struct cifs_sb_info *cifs_sb, 540 const struct kvec *iov) 541 { 542 struct smb2_create_rsp *rsp = iov->iov_base; 543 bool reparse_point = false; 544 u32 tag = 0; 545 int rc = 0; 546 547 switch (rsp->hdr.Status) { 548 case STATUS_IO_REPARSE_TAG_NOT_HANDLED: 549 reparse_point = true; 550 break; 551 case STATUS_STOPPED_ON_SYMLINK: 552 rc = smb2_parse_symlink_response(cifs_sb, iov, 553 &data->symlink_target); 554 if (rc) 555 return rc; 556 tag = IO_REPARSE_TAG_SYMLINK; 557 reparse_point = true; 558 break; 559 case STATUS_SUCCESS: 560 reparse_point = !!(rsp->Flags & SMB2_CREATE_FLAG_REPARSEPOINT); 561 break; 562 } 563 data->reparse_point = reparse_point; 564 data->reparse.tag = tag; 565 return rc; 566 } 567 568 int smb2_query_path_info(const unsigned int xid, 569 struct cifs_tcon *tcon, 570 struct cifs_sb_info *cifs_sb, 571 const char *full_path, 572 struct cifs_open_info_data *data) 573 { 574 __u32 create_options = 0; 575 struct cifsFileInfo *cfile; 576 struct cached_fid *cfid = NULL; 577 struct smb2_hdr *hdr; 578 struct kvec in_iov, out_iov[3] = {}; 579 int out_buftype[3] = {}; 580 bool islink; 581 int cmd = SMB2_OP_QUERY_INFO; 582 int rc, rc2; 583 584 data->adjust_tz = false; 585 data->reparse_point = false; 586 587 if (strcmp(full_path, "")) 588 rc = -ENOENT; 589 else 590 rc = open_cached_dir(xid, tcon, full_path, cifs_sb, false, &cfid); 591 /* If it is a root and its handle is cached then use it */ 592 if (!rc) { 593 if (cfid->file_all_info_is_valid) { 594 memcpy(&data->fi, &cfid->file_all_info, sizeof(data->fi)); 595 } else { 596 rc = SMB2_query_info(xid, tcon, cfid->fid.persistent_fid, 597 cfid->fid.volatile_fid, &data->fi); 598 } 599 close_cached_dir(cfid); 600 return rc; 601 } 602 603 in_iov.iov_base = data; 604 in_iov.iov_len = sizeof(*data); 605 606 cifs_get_readable_path(tcon, full_path, &cfile); 607 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, 608 FILE_READ_ATTRIBUTES, FILE_OPEN, 609 create_options, ACL_NO_MODE, &in_iov, 610 &cmd, 1, cfile, NULL, NULL, out_iov, out_buftype); 611 hdr = out_iov[0].iov_base; 612 /* 613 * If first iov is unset, then SMB session was dropped or we've got a 614 * cached open file (@cfile). 615 */ 616 if (!hdr || out_buftype[0] == CIFS_NO_BUFFER) 617 goto out; 618 619 switch (rc) { 620 case 0: 621 case -EOPNOTSUPP: 622 rc = parse_create_response(data, cifs_sb, &out_iov[0]); 623 if (rc || !data->reparse_point) 624 goto out; 625 626 create_options |= OPEN_REPARSE_POINT; 627 /* Failed on a symbolic link - query a reparse point info */ 628 cifs_get_readable_path(tcon, full_path, &cfile); 629 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, 630 FILE_READ_ATTRIBUTES, FILE_OPEN, 631 create_options, ACL_NO_MODE, &in_iov, 632 &cmd, 1, cfile, NULL, NULL, NULL, NULL); 633 break; 634 case -EREMOTE: 635 break; 636 default: 637 if (hdr->Status != STATUS_OBJECT_NAME_INVALID) 638 break; 639 rc2 = cifs_inval_name_dfs_link_error(xid, tcon, cifs_sb, 640 full_path, &islink); 641 if (rc2) { 642 rc = rc2; 643 goto out; 644 } 645 if (islink) 646 rc = -EREMOTE; 647 } 648 649 out: 650 free_rsp_buf(out_buftype[0], out_iov[0].iov_base); 651 free_rsp_buf(out_buftype[1], out_iov[1].iov_base); 652 free_rsp_buf(out_buftype[2], out_iov[2].iov_base); 653 return rc; 654 } 655 656 int smb311_posix_query_path_info(const unsigned int xid, 657 struct cifs_tcon *tcon, 658 struct cifs_sb_info *cifs_sb, 659 const char *full_path, 660 struct cifs_open_info_data *data, 661 struct cifs_sid *owner, 662 struct cifs_sid *group) 663 { 664 int rc; 665 __u32 create_options = 0; 666 struct cifsFileInfo *cfile; 667 struct kvec in_iov, out_iov[3] = {}; 668 int out_buftype[3] = {}; 669 __u8 *sidsbuf = NULL; 670 __u8 *sidsbuf_end = NULL; 671 size_t sidsbuflen = 0; 672 size_t owner_len, group_len; 673 int cmd = SMB2_OP_POSIX_QUERY_INFO; 674 675 data->adjust_tz = false; 676 data->reparse_point = false; 677 678 /* 679 * BB TODO: Add support for using the cached root handle. 680 * Create SMB2_query_posix_info worker function to do non-compounded query 681 * when we already have an open file handle for this. For now this is fast enough 682 * (always using the compounded version). 683 */ 684 in_iov.iov_base = data; 685 in_iov.iov_len = sizeof(*data); 686 687 cifs_get_readable_path(tcon, full_path, &cfile); 688 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, 689 FILE_READ_ATTRIBUTES, FILE_OPEN, 690 create_options, ACL_NO_MODE, &in_iov, &cmd, 1, 691 cfile, &sidsbuf, &sidsbuflen, out_iov, out_buftype); 692 /* 693 * If first iov is unset, then SMB session was dropped or we've got a 694 * cached open file (@cfile). 695 */ 696 if (!out_iov[0].iov_base || out_buftype[0] == CIFS_NO_BUFFER) 697 goto out; 698 699 switch (rc) { 700 case 0: 701 case -EOPNOTSUPP: 702 /* BB TODO: When support for special files added to Samba re-verify this path */ 703 rc = parse_create_response(data, cifs_sb, &out_iov[0]); 704 if (rc || !data->reparse_point) 705 goto out; 706 707 create_options |= OPEN_REPARSE_POINT; 708 /* Failed on a symbolic link - query a reparse point info */ 709 cifs_get_readable_path(tcon, full_path, &cfile); 710 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, 711 FILE_READ_ATTRIBUTES, FILE_OPEN, 712 create_options, ACL_NO_MODE, &in_iov, &cmd, 1, 713 cfile, &sidsbuf, &sidsbuflen, NULL, NULL); 714 break; 715 } 716 717 out: 718 if (rc == 0) { 719 sidsbuf_end = sidsbuf + sidsbuflen; 720 721 owner_len = posix_info_sid_size(sidsbuf, sidsbuf_end); 722 if (owner_len == -1) { 723 rc = -EINVAL; 724 goto out; 725 } 726 memcpy(owner, sidsbuf, owner_len); 727 728 group_len = posix_info_sid_size( 729 sidsbuf + owner_len, sidsbuf_end); 730 if (group_len == -1) { 731 rc = -EINVAL; 732 goto out; 733 } 734 memcpy(group, sidsbuf + owner_len, group_len); 735 } 736 737 kfree(sidsbuf); 738 free_rsp_buf(out_buftype[0], out_iov[0].iov_base); 739 free_rsp_buf(out_buftype[1], out_iov[1].iov_base); 740 free_rsp_buf(out_buftype[2], out_iov[2].iov_base); 741 return rc; 742 } 743 744 int 745 smb2_mkdir(const unsigned int xid, struct inode *parent_inode, umode_t mode, 746 struct cifs_tcon *tcon, const char *name, 747 struct cifs_sb_info *cifs_sb) 748 { 749 return smb2_compound_op(xid, tcon, cifs_sb, name, 750 FILE_WRITE_ATTRIBUTES, FILE_CREATE, 751 CREATE_NOT_FILE, mode, NULL, 752 &(int){SMB2_OP_MKDIR}, 1, 753 NULL, NULL, NULL, NULL, NULL); 754 } 755 756 void 757 smb2_mkdir_setinfo(struct inode *inode, const char *name, 758 struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon, 759 const unsigned int xid) 760 { 761 FILE_BASIC_INFO data = {}; 762 struct cifsInodeInfo *cifs_i; 763 struct cifsFileInfo *cfile; 764 struct kvec in_iov; 765 u32 dosattrs; 766 int tmprc; 767 768 in_iov.iov_base = &data; 769 in_iov.iov_len = sizeof(data); 770 cifs_i = CIFS_I(inode); 771 dosattrs = cifs_i->cifsAttrs | ATTR_READONLY; 772 data.Attributes = cpu_to_le32(dosattrs); 773 cifs_get_writable_path(tcon, name, FIND_WR_ANY, &cfile); 774 tmprc = smb2_compound_op(xid, tcon, cifs_sb, name, 775 FILE_WRITE_ATTRIBUTES, FILE_CREATE, 776 CREATE_NOT_FILE, ACL_NO_MODE, &in_iov, 777 &(int){SMB2_OP_SET_INFO}, 1, 778 cfile, NULL, NULL, NULL, NULL); 779 if (tmprc == 0) 780 cifs_i->cifsAttrs = dosattrs; 781 } 782 783 int 784 smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name, 785 struct cifs_sb_info *cifs_sb) 786 { 787 drop_cached_dir_by_name(xid, tcon, name, cifs_sb); 788 return smb2_compound_op(xid, tcon, cifs_sb, name, 789 DELETE, FILE_OPEN, CREATE_NOT_FILE, 790 ACL_NO_MODE, NULL, &(int){SMB2_OP_RMDIR}, 1, 791 NULL, NULL, NULL, NULL, NULL); 792 } 793 794 int 795 smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name, 796 struct cifs_sb_info *cifs_sb) 797 { 798 return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN, 799 CREATE_DELETE_ON_CLOSE | OPEN_REPARSE_POINT, 800 ACL_NO_MODE, NULL, &(int){SMB2_OP_DELETE}, 1, 801 NULL, NULL, NULL, NULL, NULL); 802 } 803 804 static int smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon, 805 const char *from_name, const char *to_name, 806 struct cifs_sb_info *cifs_sb, 807 __u32 create_options, __u32 access, 808 int command, struct cifsFileInfo *cfile) 809 { 810 struct kvec in_iov; 811 __le16 *smb2_to_name = NULL; 812 int rc; 813 814 smb2_to_name = cifs_convert_path_to_utf16(to_name, cifs_sb); 815 if (smb2_to_name == NULL) { 816 rc = -ENOMEM; 817 goto smb2_rename_path; 818 } 819 in_iov.iov_base = smb2_to_name; 820 in_iov.iov_len = 2 * UniStrnlen((wchar_t *)smb2_to_name, PATH_MAX); 821 822 rc = smb2_compound_op(xid, tcon, cifs_sb, from_name, access, 823 FILE_OPEN, 0, ACL_NO_MODE, &in_iov, 824 &command, 1, cfile, NULL, NULL, NULL, NULL); 825 smb2_rename_path: 826 kfree(smb2_to_name); 827 return rc; 828 } 829 830 int smb2_rename_path(const unsigned int xid, 831 struct cifs_tcon *tcon, 832 struct dentry *source_dentry, 833 const char *from_name, const char *to_name, 834 struct cifs_sb_info *cifs_sb) 835 { 836 struct cifsFileInfo *cfile; 837 __u32 co = file_create_options(source_dentry); 838 839 drop_cached_dir_by_name(xid, tcon, from_name, cifs_sb); 840 cifs_get_writable_path(tcon, from_name, FIND_WR_WITH_DELETE, &cfile); 841 842 return smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb, 843 co, DELETE, SMB2_OP_RENAME, cfile); 844 } 845 846 int smb2_create_hardlink(const unsigned int xid, 847 struct cifs_tcon *tcon, 848 struct dentry *source_dentry, 849 const char *from_name, const char *to_name, 850 struct cifs_sb_info *cifs_sb) 851 { 852 __u32 co = file_create_options(source_dentry); 853 854 return smb2_set_path_attr(xid, tcon, from_name, to_name, 855 cifs_sb, co, FILE_READ_ATTRIBUTES, 856 SMB2_OP_HARDLINK, NULL); 857 } 858 859 int 860 smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon, 861 const char *full_path, __u64 size, 862 struct cifs_sb_info *cifs_sb, bool set_alloc) 863 { 864 struct cifsFileInfo *cfile; 865 struct kvec in_iov; 866 __le64 eof = cpu_to_le64(size); 867 868 in_iov.iov_base = &eof; 869 in_iov.iov_len = sizeof(eof); 870 cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile); 871 return smb2_compound_op(xid, tcon, cifs_sb, full_path, 872 FILE_WRITE_DATA, FILE_OPEN, 873 0, ACL_NO_MODE, &in_iov, 874 &(int){SMB2_OP_SET_EOF}, 1, 875 cfile, NULL, NULL, NULL, NULL); 876 } 877 878 int 879 smb2_set_file_info(struct inode *inode, const char *full_path, 880 FILE_BASIC_INFO *buf, const unsigned int xid) 881 { 882 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 883 struct tcon_link *tlink; 884 struct cifs_tcon *tcon; 885 struct cifsFileInfo *cfile; 886 struct kvec in_iov = { .iov_base = buf, .iov_len = sizeof(*buf), }; 887 int rc; 888 889 if ((buf->CreationTime == 0) && (buf->LastAccessTime == 0) && 890 (buf->LastWriteTime == 0) && (buf->ChangeTime == 0) && 891 (buf->Attributes == 0)) 892 return 0; /* would be a no op, no sense sending this */ 893 894 tlink = cifs_sb_tlink(cifs_sb); 895 if (IS_ERR(tlink)) 896 return PTR_ERR(tlink); 897 tcon = tlink_tcon(tlink); 898 899 cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile); 900 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, 901 FILE_WRITE_ATTRIBUTES, FILE_OPEN, 902 0, ACL_NO_MODE, &in_iov, 903 &(int){SMB2_OP_SET_INFO}, 1, cfile, 904 NULL, NULL, NULL, NULL); 905 cifs_put_tlink(tlink); 906 return rc; 907 } 908