smb2inode.c (20720B)
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 27static void 28free_set_inf_compound(struct smb_rqst *rqst) 29{ 30 if (rqst[1].rq_iov) 31 SMB2_set_info_free(&rqst[1]); 32 if (rqst[2].rq_iov) 33 SMB2_close_free(&rqst[2]); 34} 35 36 37struct cop_vars { 38 struct cifs_open_parms oparms; 39 struct kvec rsp_iov[3]; 40 struct smb_rqst rqst[3]; 41 struct kvec open_iov[SMB2_CREATE_IOV_SIZE]; 42 struct kvec qi_iov[1]; 43 struct kvec si_iov[SMB2_SET_INFO_IOV_SIZE]; 44 struct kvec close_iov[1]; 45 struct smb2_file_rename_info rename_info; 46 struct smb2_file_link_info link_info; 47}; 48 49/* 50 * note: If cfile is passed, the reference to it is dropped here. 51 * So make sure that you do not reuse cfile after return from this func. 52 */ 53static int 54smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, 55 struct cifs_sb_info *cifs_sb, const char *full_path, 56 __u32 desired_access, __u32 create_disposition, 57 __u32 create_options, umode_t mode, void *ptr, int command, 58 struct cifsFileInfo *cfile) 59{ 60 struct cop_vars *vars = NULL; 61 struct kvec *rsp_iov; 62 struct smb_rqst *rqst; 63 int rc; 64 __le16 *utf16_path = NULL; 65 __u8 oplock = SMB2_OPLOCK_LEVEL_NONE; 66 struct cifs_fid fid; 67 struct cifs_ses *ses = tcon->ses; 68 struct TCP_Server_Info *server; 69 int num_rqst = 0; 70 int resp_buftype[3]; 71 struct smb2_query_info_rsp *qi_rsp = NULL; 72 int flags = 0; 73 __u8 delete_pending[8] = {1, 0, 0, 0, 0, 0, 0, 0}; 74 unsigned int size[2]; 75 void *data[2]; 76 int len; 77 78 vars = kzalloc(sizeof(*vars), GFP_ATOMIC); 79 if (vars == NULL) 80 return -ENOMEM; 81 rqst = &vars->rqst[0]; 82 rsp_iov = &vars->rsp_iov[0]; 83 84 server = cifs_pick_channel(ses); 85 86 if (smb3_encryption_required(tcon)) 87 flags |= CIFS_TRANSFORM_REQ; 88 89 resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER; 90 91 /* We already have a handle so we can skip the open */ 92 if (cfile) 93 goto after_open; 94 95 /* Open */ 96 utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb); 97 if (!utf16_path) { 98 rc = -ENOMEM; 99 goto finished; 100 } 101 102 vars->oparms.tcon = tcon; 103 vars->oparms.desired_access = desired_access; 104 vars->oparms.disposition = create_disposition; 105 vars->oparms.create_options = cifs_create_options(cifs_sb, create_options); 106 vars->oparms.fid = &fid; 107 vars->oparms.reconnect = false; 108 vars->oparms.mode = mode; 109 vars->oparms.cifs_sb = cifs_sb; 110 111 rqst[num_rqst].rq_iov = &vars->open_iov[0]; 112 rqst[num_rqst].rq_nvec = SMB2_CREATE_IOV_SIZE; 113 rc = SMB2_open_init(tcon, server, 114 &rqst[num_rqst], &oplock, &vars->oparms, 115 utf16_path); 116 kfree(utf16_path); 117 if (rc) 118 goto finished; 119 120 smb2_set_next_command(tcon, &rqst[num_rqst]); 121 after_open: 122 num_rqst++; 123 rc = 0; 124 125 /* Operation */ 126 switch (command) { 127 case SMB2_OP_QUERY_INFO: 128 rqst[num_rqst].rq_iov = &vars->qi_iov[0]; 129 rqst[num_rqst].rq_nvec = 1; 130 131 if (cfile) 132 rc = SMB2_query_info_init(tcon, server, 133 &rqst[num_rqst], 134 cfile->fid.persistent_fid, 135 cfile->fid.volatile_fid, 136 FILE_ALL_INFORMATION, 137 SMB2_O_INFO_FILE, 0, 138 sizeof(struct smb2_file_all_info) + 139 PATH_MAX * 2, 0, NULL); 140 else { 141 rc = SMB2_query_info_init(tcon, server, 142 &rqst[num_rqst], 143 COMPOUND_FID, 144 COMPOUND_FID, 145 FILE_ALL_INFORMATION, 146 SMB2_O_INFO_FILE, 0, 147 sizeof(struct smb2_file_all_info) + 148 PATH_MAX * 2, 0, NULL); 149 if (!rc) { 150 smb2_set_next_command(tcon, &rqst[num_rqst]); 151 smb2_set_related(&rqst[num_rqst]); 152 } 153 } 154 155 if (rc) 156 goto finished; 157 num_rqst++; 158 trace_smb3_query_info_compound_enter(xid, ses->Suid, tcon->tid, 159 full_path); 160 break; 161 case SMB2_OP_POSIX_QUERY_INFO: 162 rqst[num_rqst].rq_iov = &vars->qi_iov[0]; 163 rqst[num_rqst].rq_nvec = 1; 164 165 if (cfile) 166 rc = SMB2_query_info_init(tcon, server, 167 &rqst[num_rqst], 168 cfile->fid.persistent_fid, 169 cfile->fid.volatile_fid, 170 SMB_FIND_FILE_POSIX_INFO, 171 SMB2_O_INFO_FILE, 0, 172 /* TBD: fix following to allow for longer SIDs */ 173 sizeof(struct smb311_posix_qinfo *) + (PATH_MAX * 2) + 174 (sizeof(struct cifs_sid) * 2), 0, NULL); 175 else { 176 rc = SMB2_query_info_init(tcon, server, 177 &rqst[num_rqst], 178 COMPOUND_FID, 179 COMPOUND_FID, 180 SMB_FIND_FILE_POSIX_INFO, 181 SMB2_O_INFO_FILE, 0, 182 sizeof(struct smb311_posix_qinfo *) + (PATH_MAX * 2) + 183 (sizeof(struct cifs_sid) * 2), 0, NULL); 184 if (!rc) { 185 smb2_set_next_command(tcon, &rqst[num_rqst]); 186 smb2_set_related(&rqst[num_rqst]); 187 } 188 } 189 190 if (rc) 191 goto finished; 192 num_rqst++; 193 trace_smb3_posix_query_info_compound_enter(xid, ses->Suid, tcon->tid, full_path); 194 break; 195 case SMB2_OP_DELETE: 196 trace_smb3_delete_enter(xid, ses->Suid, tcon->tid, full_path); 197 break; 198 case SMB2_OP_MKDIR: 199 /* 200 * Directories are created through parameters in the 201 * SMB2_open() call. 202 */ 203 trace_smb3_mkdir_enter(xid, ses->Suid, tcon->tid, full_path); 204 break; 205 case SMB2_OP_RMDIR: 206 rqst[num_rqst].rq_iov = &vars->si_iov[0]; 207 rqst[num_rqst].rq_nvec = 1; 208 209 size[0] = 1; /* sizeof __u8 See MS-FSCC section 2.4.11 */ 210 data[0] = &delete_pending[0]; 211 212 rc = SMB2_set_info_init(tcon, server, 213 &rqst[num_rqst], COMPOUND_FID, 214 COMPOUND_FID, current->tgid, 215 FILE_DISPOSITION_INFORMATION, 216 SMB2_O_INFO_FILE, 0, data, size); 217 if (rc) 218 goto finished; 219 smb2_set_next_command(tcon, &rqst[num_rqst]); 220 smb2_set_related(&rqst[num_rqst++]); 221 trace_smb3_rmdir_enter(xid, ses->Suid, tcon->tid, full_path); 222 break; 223 case SMB2_OP_SET_EOF: 224 rqst[num_rqst].rq_iov = &vars->si_iov[0]; 225 rqst[num_rqst].rq_nvec = 1; 226 227 size[0] = 8; /* sizeof __le64 */ 228 data[0] = ptr; 229 230 rc = SMB2_set_info_init(tcon, server, 231 &rqst[num_rqst], COMPOUND_FID, 232 COMPOUND_FID, current->tgid, 233 FILE_END_OF_FILE_INFORMATION, 234 SMB2_O_INFO_FILE, 0, data, size); 235 if (rc) 236 goto finished; 237 smb2_set_next_command(tcon, &rqst[num_rqst]); 238 smb2_set_related(&rqst[num_rqst++]); 239 trace_smb3_set_eof_enter(xid, ses->Suid, tcon->tid, full_path); 240 break; 241 case SMB2_OP_SET_INFO: 242 rqst[num_rqst].rq_iov = &vars->si_iov[0]; 243 rqst[num_rqst].rq_nvec = 1; 244 245 246 size[0] = sizeof(FILE_BASIC_INFO); 247 data[0] = ptr; 248 249 if (cfile) 250 rc = SMB2_set_info_init(tcon, server, 251 &rqst[num_rqst], 252 cfile->fid.persistent_fid, 253 cfile->fid.volatile_fid, current->tgid, 254 FILE_BASIC_INFORMATION, 255 SMB2_O_INFO_FILE, 0, data, size); 256 else { 257 rc = SMB2_set_info_init(tcon, server, 258 &rqst[num_rqst], 259 COMPOUND_FID, 260 COMPOUND_FID, current->tgid, 261 FILE_BASIC_INFORMATION, 262 SMB2_O_INFO_FILE, 0, data, size); 263 if (!rc) { 264 smb2_set_next_command(tcon, &rqst[num_rqst]); 265 smb2_set_related(&rqst[num_rqst]); 266 } 267 } 268 269 if (rc) 270 goto finished; 271 num_rqst++; 272 trace_smb3_set_info_compound_enter(xid, ses->Suid, tcon->tid, 273 full_path); 274 break; 275 case SMB2_OP_RENAME: 276 rqst[num_rqst].rq_iov = &vars->si_iov[0]; 277 rqst[num_rqst].rq_nvec = 2; 278 279 len = (2 * UniStrnlen((wchar_t *)ptr, PATH_MAX)); 280 281 vars->rename_info.ReplaceIfExists = 1; 282 vars->rename_info.RootDirectory = 0; 283 vars->rename_info.FileNameLength = cpu_to_le32(len); 284 285 size[0] = sizeof(struct smb2_file_rename_info); 286 data[0] = &vars->rename_info; 287 288 size[1] = len + 2 /* null */; 289 data[1] = (__le16 *)ptr; 290 291 if (cfile) 292 rc = SMB2_set_info_init(tcon, server, 293 &rqst[num_rqst], 294 cfile->fid.persistent_fid, 295 cfile->fid.volatile_fid, 296 current->tgid, FILE_RENAME_INFORMATION, 297 SMB2_O_INFO_FILE, 0, data, size); 298 else { 299 rc = SMB2_set_info_init(tcon, server, 300 &rqst[num_rqst], 301 COMPOUND_FID, COMPOUND_FID, 302 current->tgid, FILE_RENAME_INFORMATION, 303 SMB2_O_INFO_FILE, 0, data, size); 304 if (!rc) { 305 smb2_set_next_command(tcon, &rqst[num_rqst]); 306 smb2_set_related(&rqst[num_rqst]); 307 } 308 } 309 if (rc) 310 goto finished; 311 num_rqst++; 312 trace_smb3_rename_enter(xid, ses->Suid, tcon->tid, full_path); 313 break; 314 case SMB2_OP_HARDLINK: 315 rqst[num_rqst].rq_iov = &vars->si_iov[0]; 316 rqst[num_rqst].rq_nvec = 2; 317 318 len = (2 * UniStrnlen((wchar_t *)ptr, PATH_MAX)); 319 320 vars->link_info.ReplaceIfExists = 0; 321 vars->link_info.RootDirectory = 0; 322 vars->link_info.FileNameLength = cpu_to_le32(len); 323 324 size[0] = sizeof(struct smb2_file_link_info); 325 data[0] = &vars->link_info; 326 327 size[1] = len + 2 /* null */; 328 data[1] = (__le16 *)ptr; 329 330 rc = SMB2_set_info_init(tcon, server, 331 &rqst[num_rqst], COMPOUND_FID, 332 COMPOUND_FID, current->tgid, 333 FILE_LINK_INFORMATION, 334 SMB2_O_INFO_FILE, 0, data, size); 335 if (rc) 336 goto finished; 337 smb2_set_next_command(tcon, &rqst[num_rqst]); 338 smb2_set_related(&rqst[num_rqst++]); 339 trace_smb3_hardlink_enter(xid, ses->Suid, tcon->tid, full_path); 340 break; 341 default: 342 cifs_dbg(VFS, "Invalid command\n"); 343 rc = -EINVAL; 344 } 345 if (rc) 346 goto finished; 347 348 /* We already have a handle so we can skip the close */ 349 if (cfile) 350 goto after_close; 351 /* Close */ 352 flags |= CIFS_CP_CREATE_CLOSE_OP; 353 rqst[num_rqst].rq_iov = &vars->close_iov[0]; 354 rqst[num_rqst].rq_nvec = 1; 355 rc = SMB2_close_init(tcon, server, 356 &rqst[num_rqst], COMPOUND_FID, 357 COMPOUND_FID, false); 358 smb2_set_related(&rqst[num_rqst]); 359 if (rc) 360 goto finished; 361 after_close: 362 num_rqst++; 363 364 if (cfile) { 365 rc = compound_send_recv(xid, ses, server, 366 flags, num_rqst - 2, 367 &rqst[1], &resp_buftype[1], 368 &rsp_iov[1]); 369 } else 370 rc = compound_send_recv(xid, ses, server, 371 flags, num_rqst, 372 rqst, resp_buftype, 373 rsp_iov); 374 375 finished: 376 if (cfile) 377 cifsFileInfo_put(cfile); 378 379 SMB2_open_free(&rqst[0]); 380 if (rc == -EREMCHG) { 381 pr_warn_once("server share %s deleted\n", tcon->treeName); 382 tcon->need_reconnect = true; 383 } 384 385 switch (command) { 386 case SMB2_OP_QUERY_INFO: 387 if (rc == 0) { 388 qi_rsp = (struct smb2_query_info_rsp *) 389 rsp_iov[1].iov_base; 390 rc = smb2_validate_and_copy_iov( 391 le16_to_cpu(qi_rsp->OutputBufferOffset), 392 le32_to_cpu(qi_rsp->OutputBufferLength), 393 &rsp_iov[1], sizeof(struct smb2_file_all_info), 394 ptr); 395 } 396 if (rqst[1].rq_iov) 397 SMB2_query_info_free(&rqst[1]); 398 if (rqst[2].rq_iov) 399 SMB2_close_free(&rqst[2]); 400 if (rc) 401 trace_smb3_query_info_compound_err(xid, ses->Suid, 402 tcon->tid, rc); 403 else 404 trace_smb3_query_info_compound_done(xid, ses->Suid, 405 tcon->tid); 406 break; 407 case SMB2_OP_POSIX_QUERY_INFO: 408 if (rc == 0) { 409 qi_rsp = (struct smb2_query_info_rsp *) 410 rsp_iov[1].iov_base; 411 rc = smb2_validate_and_copy_iov( 412 le16_to_cpu(qi_rsp->OutputBufferOffset), 413 le32_to_cpu(qi_rsp->OutputBufferLength), 414 &rsp_iov[1], sizeof(struct smb311_posix_qinfo) /* add SIDs */, ptr); 415 } 416 if (rqst[1].rq_iov) 417 SMB2_query_info_free(&rqst[1]); 418 if (rqst[2].rq_iov) 419 SMB2_close_free(&rqst[2]); 420 if (rc) 421 trace_smb3_posix_query_info_compound_err(xid, ses->Suid, tcon->tid, rc); 422 else 423 trace_smb3_posix_query_info_compound_done(xid, ses->Suid, tcon->tid); 424 break; 425 case SMB2_OP_DELETE: 426 if (rc) 427 trace_smb3_delete_err(xid, ses->Suid, tcon->tid, rc); 428 else 429 trace_smb3_delete_done(xid, ses->Suid, tcon->tid); 430 if (rqst[1].rq_iov) 431 SMB2_close_free(&rqst[1]); 432 break; 433 case SMB2_OP_MKDIR: 434 if (rc) 435 trace_smb3_mkdir_err(xid, ses->Suid, tcon->tid, rc); 436 else 437 trace_smb3_mkdir_done(xid, ses->Suid, tcon->tid); 438 if (rqst[1].rq_iov) 439 SMB2_close_free(&rqst[1]); 440 break; 441 case SMB2_OP_HARDLINK: 442 if (rc) 443 trace_smb3_hardlink_err(xid, ses->Suid, tcon->tid, rc); 444 else 445 trace_smb3_hardlink_done(xid, ses->Suid, tcon->tid); 446 free_set_inf_compound(rqst); 447 break; 448 case SMB2_OP_RENAME: 449 if (rc) 450 trace_smb3_rename_err(xid, ses->Suid, tcon->tid, rc); 451 else 452 trace_smb3_rename_done(xid, ses->Suid, tcon->tid); 453 free_set_inf_compound(rqst); 454 break; 455 case SMB2_OP_RMDIR: 456 if (rc) 457 trace_smb3_rmdir_err(xid, ses->Suid, tcon->tid, rc); 458 else 459 trace_smb3_rmdir_done(xid, ses->Suid, tcon->tid); 460 free_set_inf_compound(rqst); 461 break; 462 case SMB2_OP_SET_EOF: 463 if (rc) 464 trace_smb3_set_eof_err(xid, ses->Suid, tcon->tid, rc); 465 else 466 trace_smb3_set_eof_done(xid, ses->Suid, tcon->tid); 467 free_set_inf_compound(rqst); 468 break; 469 case SMB2_OP_SET_INFO: 470 if (rc) 471 trace_smb3_set_info_compound_err(xid, ses->Suid, 472 tcon->tid, rc); 473 else 474 trace_smb3_set_info_compound_done(xid, ses->Suid, 475 tcon->tid); 476 free_set_inf_compound(rqst); 477 break; 478 } 479 free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base); 480 free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base); 481 free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base); 482 kfree(vars); 483 return rc; 484} 485 486void 487move_smb2_info_to_cifs(FILE_ALL_INFO *dst, struct smb2_file_all_info *src) 488{ 489 memcpy(dst, src, (size_t)(&src->CurrentByteOffset) - (size_t)src); 490 dst->CurrentByteOffset = src->CurrentByteOffset; 491 dst->Mode = src->Mode; 492 dst->AlignmentRequirement = src->AlignmentRequirement; 493 dst->IndexNumber1 = 0; /* we don't use it */ 494} 495 496int 497smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, 498 struct cifs_sb_info *cifs_sb, const char *full_path, 499 FILE_ALL_INFO *data, bool *adjust_tz, bool *reparse) 500{ 501 int rc; 502 struct smb2_file_all_info *smb2_data; 503 __u32 create_options = 0; 504 struct cifsFileInfo *cfile; 505 struct cached_fid *cfid = NULL; 506 507 *adjust_tz = false; 508 *reparse = false; 509 510 smb2_data = kzalloc(sizeof(struct smb2_file_all_info) + PATH_MAX * 2, 511 GFP_KERNEL); 512 if (smb2_data == NULL) 513 return -ENOMEM; 514 515 if (strcmp(full_path, "")) 516 rc = -ENOENT; 517 else 518 rc = open_cached_dir(xid, tcon, full_path, cifs_sb, &cfid); 519 /* If it is a root and its handle is cached then use it */ 520 if (!rc) { 521 if (tcon->crfid.file_all_info_is_valid) { 522 move_smb2_info_to_cifs(data, 523 &tcon->crfid.file_all_info); 524 } else { 525 rc = SMB2_query_info(xid, tcon, 526 cfid->fid->persistent_fid, 527 cfid->fid->volatile_fid, smb2_data); 528 if (!rc) 529 move_smb2_info_to_cifs(data, smb2_data); 530 } 531 close_cached_dir(cfid); 532 goto out; 533 } 534 535 cifs_get_readable_path(tcon, full_path, &cfile); 536 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, 537 FILE_READ_ATTRIBUTES, FILE_OPEN, create_options, 538 ACL_NO_MODE, smb2_data, SMB2_OP_QUERY_INFO, cfile); 539 if (rc == -EOPNOTSUPP) { 540 *reparse = true; 541 create_options |= OPEN_REPARSE_POINT; 542 543 /* Failed on a symbolic link - query a reparse point info */ 544 cifs_get_readable_path(tcon, full_path, &cfile); 545 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, 546 FILE_READ_ATTRIBUTES, FILE_OPEN, 547 create_options, ACL_NO_MODE, 548 smb2_data, SMB2_OP_QUERY_INFO, cfile); 549 } 550 if (rc) 551 goto out; 552 553 move_smb2_info_to_cifs(data, smb2_data); 554out: 555 kfree(smb2_data); 556 return rc; 557} 558 559 560int 561smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, 562 struct cifs_sb_info *cifs_sb, const char *full_path, 563 struct smb311_posix_qinfo *data, bool *adjust_tz, bool *reparse) 564{ 565 int rc; 566 __u32 create_options = 0; 567 struct cifsFileInfo *cfile; 568 struct smb311_posix_qinfo *smb2_data; 569 570 *adjust_tz = false; 571 *reparse = false; 572 573 /* BB TODO: Make struct larger when add support for parsing owner SIDs */ 574 smb2_data = kzalloc(sizeof(struct smb311_posix_qinfo), 575 GFP_KERNEL); 576 if (smb2_data == NULL) 577 return -ENOMEM; 578 579 /* 580 * BB TODO: Add support for using the cached root handle. 581 * Create SMB2_query_posix_info worker function to do non-compounded query 582 * when we already have an open file handle for this. For now this is fast enough 583 * (always using the compounded version). 584 */ 585 586 cifs_get_readable_path(tcon, full_path, &cfile); 587 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, 588 FILE_READ_ATTRIBUTES, FILE_OPEN, create_options, 589 ACL_NO_MODE, smb2_data, SMB2_OP_POSIX_QUERY_INFO, cfile); 590 if (rc == -EOPNOTSUPP) { 591 /* BB TODO: When support for special files added to Samba re-verify this path */ 592 *reparse = true; 593 create_options |= OPEN_REPARSE_POINT; 594 595 /* Failed on a symbolic link - query a reparse point info */ 596 cifs_get_readable_path(tcon, full_path, &cfile); 597 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, 598 FILE_READ_ATTRIBUTES, FILE_OPEN, 599 create_options, ACL_NO_MODE, 600 smb2_data, SMB2_OP_POSIX_QUERY_INFO, cfile); 601 } 602 if (rc) 603 goto out; 604 605 /* TODO: will need to allow for the 2 SIDs when add support for getting owner UID/GID */ 606 memcpy(data, smb2_data, sizeof(struct smb311_posix_qinfo)); 607 608out: 609 kfree(smb2_data); 610 return rc; 611} 612 613int 614smb2_mkdir(const unsigned int xid, struct inode *parent_inode, umode_t mode, 615 struct cifs_tcon *tcon, const char *name, 616 struct cifs_sb_info *cifs_sb) 617{ 618 return smb2_compound_op(xid, tcon, cifs_sb, name, 619 FILE_WRITE_ATTRIBUTES, FILE_CREATE, 620 CREATE_NOT_FILE, mode, NULL, SMB2_OP_MKDIR, 621 NULL); 622} 623 624void 625smb2_mkdir_setinfo(struct inode *inode, const char *name, 626 struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon, 627 const unsigned int xid) 628{ 629 FILE_BASIC_INFO data; 630 struct cifsInodeInfo *cifs_i; 631 struct cifsFileInfo *cfile; 632 u32 dosattrs; 633 int tmprc; 634 635 memset(&data, 0, sizeof(data)); 636 cifs_i = CIFS_I(inode); 637 dosattrs = cifs_i->cifsAttrs | ATTR_READONLY; 638 data.Attributes = cpu_to_le32(dosattrs); 639 cifs_get_writable_path(tcon, name, FIND_WR_ANY, &cfile); 640 tmprc = smb2_compound_op(xid, tcon, cifs_sb, name, 641 FILE_WRITE_ATTRIBUTES, FILE_CREATE, 642 CREATE_NOT_FILE, ACL_NO_MODE, 643 &data, SMB2_OP_SET_INFO, cfile); 644 if (tmprc == 0) 645 cifs_i->cifsAttrs = dosattrs; 646} 647 648int 649smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name, 650 struct cifs_sb_info *cifs_sb) 651{ 652 return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN, 653 CREATE_NOT_FILE, ACL_NO_MODE, 654 NULL, SMB2_OP_RMDIR, NULL); 655} 656 657int 658smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name, 659 struct cifs_sb_info *cifs_sb) 660{ 661 return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN, 662 CREATE_DELETE_ON_CLOSE | OPEN_REPARSE_POINT, 663 ACL_NO_MODE, NULL, SMB2_OP_DELETE, NULL); 664} 665 666static int 667smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon, 668 const char *from_name, const char *to_name, 669 struct cifs_sb_info *cifs_sb, __u32 access, int command, 670 struct cifsFileInfo *cfile) 671{ 672 __le16 *smb2_to_name = NULL; 673 int rc; 674 675 smb2_to_name = cifs_convert_path_to_utf16(to_name, cifs_sb); 676 if (smb2_to_name == NULL) { 677 rc = -ENOMEM; 678 goto smb2_rename_path; 679 } 680 rc = smb2_compound_op(xid, tcon, cifs_sb, from_name, access, 681 FILE_OPEN, 0, ACL_NO_MODE, smb2_to_name, 682 command, cfile); 683smb2_rename_path: 684 kfree(smb2_to_name); 685 return rc; 686} 687 688int 689smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon, 690 const char *from_name, const char *to_name, 691 struct cifs_sb_info *cifs_sb) 692{ 693 struct cifsFileInfo *cfile; 694 695 cifs_get_writable_path(tcon, from_name, FIND_WR_WITH_DELETE, &cfile); 696 697 return smb2_set_path_attr(xid, tcon, from_name, to_name, 698 cifs_sb, DELETE, SMB2_OP_RENAME, cfile); 699} 700 701int 702smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon, 703 const char *from_name, const char *to_name, 704 struct cifs_sb_info *cifs_sb) 705{ 706 return smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb, 707 FILE_READ_ATTRIBUTES, SMB2_OP_HARDLINK, 708 NULL); 709} 710 711int 712smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon, 713 const char *full_path, __u64 size, 714 struct cifs_sb_info *cifs_sb, bool set_alloc) 715{ 716 __le64 eof = cpu_to_le64(size); 717 struct cifsFileInfo *cfile; 718 719 cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile); 720 return smb2_compound_op(xid, tcon, cifs_sb, full_path, 721 FILE_WRITE_DATA, FILE_OPEN, 0, ACL_NO_MODE, 722 &eof, SMB2_OP_SET_EOF, cfile); 723} 724 725int 726smb2_set_file_info(struct inode *inode, const char *full_path, 727 FILE_BASIC_INFO *buf, const unsigned int xid) 728{ 729 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 730 struct tcon_link *tlink; 731 struct cifs_tcon *tcon; 732 struct cifsFileInfo *cfile; 733 int rc; 734 735 if ((buf->CreationTime == 0) && (buf->LastAccessTime == 0) && 736 (buf->LastWriteTime == 0) && (buf->ChangeTime == 0) && 737 (buf->Attributes == 0)) 738 return 0; /* would be a no op, no sense sending this */ 739 740 tlink = cifs_sb_tlink(cifs_sb); 741 if (IS_ERR(tlink)) 742 return PTR_ERR(tlink); 743 tcon = tlink_tcon(tlink); 744 745 cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile); 746 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, 747 FILE_WRITE_ATTRIBUTES, FILE_OPEN, 748 0, ACL_NO_MODE, buf, SMB2_OP_SET_INFO, cfile); 749 cifs_put_tlink(tlink); 750 return rc; 751}