Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.2-rc2 535 lines 15 kB view raw
1/* 2 * fs/cifs/smb2inode.c 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 * This library is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU Lesser General Public License as published 11 * by the Free Software Foundation; either version 2.1 of the License, or 12 * (at your option) any later version. 13 * 14 * This library is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 17 * the GNU Lesser General Public License for more details. 18 * 19 * You should have received a copy of the GNU Lesser General Public License 20 * along with this library; if not, write to the Free Software 21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22 */ 23#include <linux/fs.h> 24#include <linux/stat.h> 25#include <linux/slab.h> 26#include <linux/pagemap.h> 27#include <asm/div64.h> 28#include "cifsfs.h" 29#include "cifspdu.h" 30#include "cifsglob.h" 31#include "cifsproto.h" 32#include "cifs_debug.h" 33#include "cifs_fs_sb.h" 34#include "cifs_unicode.h" 35#include "fscache.h" 36#include "smb2glob.h" 37#include "smb2pdu.h" 38#include "smb2proto.h" 39 40static void 41free_set_inf_compound(struct smb_rqst *rqst) 42{ 43 if (rqst[1].rq_iov) 44 SMB2_set_info_free(&rqst[1]); 45 if (rqst[2].rq_iov) 46 SMB2_close_free(&rqst[2]); 47} 48 49 50static int 51smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, 52 struct cifs_sb_info *cifs_sb, const char *full_path, 53 __u32 desired_access, __u32 create_disposition, 54 __u32 create_options, void *ptr, int command) 55{ 56 int rc; 57 __le16 *utf16_path = NULL; 58 __u8 oplock = SMB2_OPLOCK_LEVEL_NONE; 59 struct cifs_open_parms oparms; 60 struct cifs_fid fid; 61 struct cifs_ses *ses = tcon->ses; 62 int num_rqst = 0; 63 struct smb_rqst rqst[3]; 64 int resp_buftype[3]; 65 struct kvec rsp_iov[3]; 66 struct kvec open_iov[SMB2_CREATE_IOV_SIZE]; 67 struct kvec qi_iov[1]; 68 struct kvec si_iov[SMB2_SET_INFO_IOV_SIZE]; 69 struct kvec close_iov[1]; 70 struct smb2_query_info_rsp *qi_rsp = NULL; 71 int flags = 0; 72 __u8 delete_pending[8] = {1, 0, 0, 0, 0, 0, 0, 0}; 73 unsigned int size[2]; 74 void *data[2]; 75 struct smb2_file_rename_info rename_info; 76 struct smb2_file_link_info link_info; 77 int len; 78 79 if (smb3_encryption_required(tcon)) 80 flags |= CIFS_TRANSFORM_REQ; 81 82 memset(rqst, 0, sizeof(rqst)); 83 resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER; 84 memset(rsp_iov, 0, sizeof(rsp_iov)); 85 86 /* Open */ 87 utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb); 88 if (!utf16_path) 89 return -ENOMEM; 90 91 oparms.tcon = tcon; 92 oparms.desired_access = desired_access; 93 oparms.disposition = create_disposition; 94 oparms.create_options = create_options; 95 if (backup_cred(cifs_sb)) 96 oparms.create_options |= CREATE_OPEN_BACKUP_INTENT; 97 oparms.fid = &fid; 98 oparms.reconnect = false; 99 100 memset(&open_iov, 0, sizeof(open_iov)); 101 rqst[num_rqst].rq_iov = open_iov; 102 rqst[num_rqst].rq_nvec = SMB2_CREATE_IOV_SIZE; 103 rc = SMB2_open_init(tcon, &rqst[num_rqst], &oplock, &oparms, 104 utf16_path); 105 kfree(utf16_path); 106 if (rc) 107 goto finished; 108 109 smb2_set_next_command(tcon, &rqst[num_rqst++]); 110 111 /* Operation */ 112 switch (command) { 113 case SMB2_OP_QUERY_INFO: 114 memset(&qi_iov, 0, sizeof(qi_iov)); 115 rqst[num_rqst].rq_iov = qi_iov; 116 rqst[num_rqst].rq_nvec = 1; 117 118 rc = SMB2_query_info_init(tcon, &rqst[num_rqst], COMPOUND_FID, 119 COMPOUND_FID, FILE_ALL_INFORMATION, 120 SMB2_O_INFO_FILE, 0, 121 sizeof(struct smb2_file_all_info) + 122 PATH_MAX * 2, 0, NULL); 123 smb2_set_next_command(tcon, &rqst[num_rqst]); 124 smb2_set_related(&rqst[num_rqst++]); 125 trace_smb3_query_info_compound_enter(xid, ses->Suid, tcon->tid, 126 full_path); 127 break; 128 case SMB2_OP_DELETE: 129 trace_smb3_delete_enter(xid, ses->Suid, tcon->tid, full_path); 130 break; 131 case SMB2_OP_MKDIR: 132 /* 133 * Directories are created through parameters in the 134 * SMB2_open() call. 135 */ 136 trace_smb3_mkdir_enter(xid, ses->Suid, tcon->tid, full_path); 137 break; 138 case SMB2_OP_RMDIR: 139 memset(&si_iov, 0, sizeof(si_iov)); 140 rqst[num_rqst].rq_iov = si_iov; 141 rqst[num_rqst].rq_nvec = 1; 142 143 size[0] = 1; /* sizeof __u8 See MS-FSCC section 2.4.11 */ 144 data[0] = &delete_pending[0]; 145 146 rc = SMB2_set_info_init(tcon, &rqst[num_rqst], COMPOUND_FID, 147 COMPOUND_FID, current->tgid, 148 FILE_DISPOSITION_INFORMATION, 149 SMB2_O_INFO_FILE, 0, data, size); 150 smb2_set_next_command(tcon, &rqst[num_rqst]); 151 smb2_set_related(&rqst[num_rqst++]); 152 trace_smb3_rmdir_enter(xid, ses->Suid, tcon->tid, full_path); 153 break; 154 case SMB2_OP_SET_EOF: 155 memset(&si_iov, 0, sizeof(si_iov)); 156 rqst[num_rqst].rq_iov = si_iov; 157 rqst[num_rqst].rq_nvec = 1; 158 159 size[0] = 8; /* sizeof __le64 */ 160 data[0] = ptr; 161 162 rc = SMB2_set_info_init(tcon, &rqst[num_rqst], COMPOUND_FID, 163 COMPOUND_FID, current->tgid, 164 FILE_END_OF_FILE_INFORMATION, 165 SMB2_O_INFO_FILE, 0, data, size); 166 smb2_set_next_command(tcon, &rqst[num_rqst]); 167 smb2_set_related(&rqst[num_rqst++]); 168 trace_smb3_set_eof_enter(xid, ses->Suid, tcon->tid, full_path); 169 break; 170 case SMB2_OP_SET_INFO: 171 memset(&si_iov, 0, sizeof(si_iov)); 172 rqst[num_rqst].rq_iov = si_iov; 173 rqst[num_rqst].rq_nvec = 1; 174 175 176 size[0] = sizeof(FILE_BASIC_INFO); 177 data[0] = ptr; 178 179 rc = SMB2_set_info_init(tcon, &rqst[num_rqst], COMPOUND_FID, 180 COMPOUND_FID, current->tgid, 181 FILE_BASIC_INFORMATION, 182 SMB2_O_INFO_FILE, 0, data, size); 183 smb2_set_next_command(tcon, &rqst[num_rqst]); 184 smb2_set_related(&rqst[num_rqst++]); 185 trace_smb3_set_info_compound_enter(xid, ses->Suid, tcon->tid, 186 full_path); 187 break; 188 case SMB2_OP_RENAME: 189 memset(&si_iov, 0, sizeof(si_iov)); 190 rqst[num_rqst].rq_iov = si_iov; 191 rqst[num_rqst].rq_nvec = 2; 192 193 len = (2 * UniStrnlen((wchar_t *)ptr, PATH_MAX)); 194 195 rename_info.ReplaceIfExists = 1; 196 rename_info.RootDirectory = 0; 197 rename_info.FileNameLength = cpu_to_le32(len); 198 199 size[0] = sizeof(struct smb2_file_rename_info); 200 data[0] = &rename_info; 201 202 size[1] = len + 2 /* null */; 203 data[1] = (__le16 *)ptr; 204 205 rc = SMB2_set_info_init(tcon, &rqst[num_rqst], COMPOUND_FID, 206 COMPOUND_FID, current->tgid, 207 FILE_RENAME_INFORMATION, 208 SMB2_O_INFO_FILE, 0, data, size); 209 smb2_set_next_command(tcon, &rqst[num_rqst]); 210 smb2_set_related(&rqst[num_rqst++]); 211 trace_smb3_rename_enter(xid, ses->Suid, tcon->tid, full_path); 212 break; 213 case SMB2_OP_HARDLINK: 214 memset(&si_iov, 0, sizeof(si_iov)); 215 rqst[num_rqst].rq_iov = si_iov; 216 rqst[num_rqst].rq_nvec = 2; 217 218 len = (2 * UniStrnlen((wchar_t *)ptr, PATH_MAX)); 219 220 link_info.ReplaceIfExists = 0; 221 link_info.RootDirectory = 0; 222 link_info.FileNameLength = cpu_to_le32(len); 223 224 size[0] = sizeof(struct smb2_file_link_info); 225 data[0] = &link_info; 226 227 size[1] = len + 2 /* null */; 228 data[1] = (__le16 *)ptr; 229 230 rc = SMB2_set_info_init(tcon, &rqst[num_rqst], COMPOUND_FID, 231 COMPOUND_FID, current->tgid, 232 FILE_LINK_INFORMATION, 233 SMB2_O_INFO_FILE, 0, data, size); 234 smb2_set_next_command(tcon, &rqst[num_rqst]); 235 smb2_set_related(&rqst[num_rqst++]); 236 trace_smb3_hardlink_enter(xid, ses->Suid, tcon->tid, full_path); 237 break; 238 default: 239 cifs_dbg(VFS, "Invalid command\n"); 240 rc = -EINVAL; 241 } 242 if (rc) 243 goto finished; 244 245 /* Close */ 246 memset(&close_iov, 0, sizeof(close_iov)); 247 rqst[num_rqst].rq_iov = close_iov; 248 rqst[num_rqst].rq_nvec = 1; 249 rc = SMB2_close_init(tcon, &rqst[num_rqst], COMPOUND_FID, 250 COMPOUND_FID); 251 smb2_set_related(&rqst[num_rqst++]); 252 if (rc) 253 goto finished; 254 255 rc = compound_send_recv(xid, ses, flags, num_rqst, rqst, 256 resp_buftype, rsp_iov); 257 258 finished: 259 SMB2_open_free(&rqst[0]); 260 switch (command) { 261 case SMB2_OP_QUERY_INFO: 262 if (rc == 0) { 263 qi_rsp = (struct smb2_query_info_rsp *) 264 rsp_iov[1].iov_base; 265 rc = smb2_validate_and_copy_iov( 266 le16_to_cpu(qi_rsp->OutputBufferOffset), 267 le32_to_cpu(qi_rsp->OutputBufferLength), 268 &rsp_iov[1], sizeof(struct smb2_file_all_info), 269 ptr); 270 } 271 if (rqst[1].rq_iov) 272 SMB2_query_info_free(&rqst[1]); 273 if (rqst[2].rq_iov) 274 SMB2_close_free(&rqst[2]); 275 if (rc) 276 trace_smb3_query_info_compound_err(xid, ses->Suid, 277 tcon->tid, rc); 278 else 279 trace_smb3_query_info_compound_done(xid, ses->Suid, 280 tcon->tid); 281 break; 282 case SMB2_OP_DELETE: 283 if (rc) 284 trace_smb3_delete_err(xid, ses->Suid, tcon->tid, rc); 285 else 286 trace_smb3_delete_done(xid, ses->Suid, tcon->tid); 287 if (rqst[1].rq_iov) 288 SMB2_close_free(&rqst[1]); 289 break; 290 case SMB2_OP_MKDIR: 291 if (rc) 292 trace_smb3_mkdir_err(xid, ses->Suid, tcon->tid, rc); 293 else 294 trace_smb3_mkdir_done(xid, ses->Suid, tcon->tid); 295 if (rqst[1].rq_iov) 296 SMB2_close_free(&rqst[1]); 297 break; 298 case SMB2_OP_HARDLINK: 299 if (rc) 300 trace_smb3_hardlink_err(xid, ses->Suid, tcon->tid, rc); 301 else 302 trace_smb3_hardlink_done(xid, ses->Suid, tcon->tid); 303 free_set_inf_compound(rqst); 304 break; 305 case SMB2_OP_RENAME: 306 if (rc) 307 trace_smb3_rename_err(xid, ses->Suid, tcon->tid, rc); 308 else 309 trace_smb3_rename_done(xid, ses->Suid, tcon->tid); 310 free_set_inf_compound(rqst); 311 break; 312 case SMB2_OP_RMDIR: 313 if (rc) 314 trace_smb3_rmdir_err(xid, ses->Suid, tcon->tid, rc); 315 else 316 trace_smb3_rmdir_done(xid, ses->Suid, tcon->tid); 317 free_set_inf_compound(rqst); 318 break; 319 case SMB2_OP_SET_EOF: 320 if (rc) 321 trace_smb3_set_eof_err(xid, ses->Suid, tcon->tid, rc); 322 else 323 trace_smb3_set_eof_done(xid, ses->Suid, tcon->tid); 324 free_set_inf_compound(rqst); 325 break; 326 case SMB2_OP_SET_INFO: 327 if (rc) 328 trace_smb3_set_info_compound_err(xid, ses->Suid, 329 tcon->tid, rc); 330 else 331 trace_smb3_set_info_compound_done(xid, ses->Suid, 332 tcon->tid); 333 free_set_inf_compound(rqst); 334 break; 335 } 336 free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base); 337 free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base); 338 free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base); 339 return rc; 340} 341 342void 343move_smb2_info_to_cifs(FILE_ALL_INFO *dst, struct smb2_file_all_info *src) 344{ 345 memcpy(dst, src, (size_t)(&src->CurrentByteOffset) - (size_t)src); 346 dst->CurrentByteOffset = src->CurrentByteOffset; 347 dst->Mode = src->Mode; 348 dst->AlignmentRequirement = src->AlignmentRequirement; 349 dst->IndexNumber1 = 0; /* we don't use it */ 350} 351 352int 353smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, 354 struct cifs_sb_info *cifs_sb, const char *full_path, 355 FILE_ALL_INFO *data, bool *adjust_tz, bool *symlink) 356{ 357 int rc; 358 struct smb2_file_all_info *smb2_data; 359 __u32 create_options = 0; 360 struct cifs_fid fid; 361 bool no_cached_open = tcon->nohandlecache; 362 363 *adjust_tz = false; 364 *symlink = false; 365 366 smb2_data = kzalloc(sizeof(struct smb2_file_all_info) + PATH_MAX * 2, 367 GFP_KERNEL); 368 if (smb2_data == NULL) 369 return -ENOMEM; 370 371 /* If it is a root and its handle is cached then use it */ 372 if (!strlen(full_path) && !no_cached_open) { 373 rc = open_shroot(xid, tcon, &fid); 374 if (rc) 375 goto out; 376 377 if (tcon->crfid.file_all_info_is_valid) { 378 move_smb2_info_to_cifs(data, 379 &tcon->crfid.file_all_info); 380 } else { 381 rc = SMB2_query_info(xid, tcon, fid.persistent_fid, 382 fid.volatile_fid, smb2_data); 383 if (!rc) 384 move_smb2_info_to_cifs(data, smb2_data); 385 } 386 close_shroot(&tcon->crfid); 387 goto out; 388 } 389 390 if (backup_cred(cifs_sb)) 391 create_options |= CREATE_OPEN_BACKUP_INTENT; 392 393 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, 394 FILE_READ_ATTRIBUTES, FILE_OPEN, create_options, 395 smb2_data, SMB2_OP_QUERY_INFO); 396 if (rc == -EOPNOTSUPP) { 397 *symlink = true; 398 create_options |= OPEN_REPARSE_POINT; 399 400 /* Failed on a symbolic link - query a reparse point info */ 401 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, 402 FILE_READ_ATTRIBUTES, FILE_OPEN, 403 create_options, smb2_data, 404 SMB2_OP_QUERY_INFO); 405 } 406 if (rc) 407 goto out; 408 409 move_smb2_info_to_cifs(data, smb2_data); 410out: 411 kfree(smb2_data); 412 return rc; 413} 414 415int 416smb2_mkdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name, 417 struct cifs_sb_info *cifs_sb) 418{ 419 return smb2_compound_op(xid, tcon, cifs_sb, name, 420 FILE_WRITE_ATTRIBUTES, FILE_CREATE, 421 CREATE_NOT_FILE, NULL, SMB2_OP_MKDIR); 422} 423 424void 425smb2_mkdir_setinfo(struct inode *inode, const char *name, 426 struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon, 427 const unsigned int xid) 428{ 429 FILE_BASIC_INFO data; 430 struct cifsInodeInfo *cifs_i; 431 u32 dosattrs; 432 int tmprc; 433 434 memset(&data, 0, sizeof(data)); 435 cifs_i = CIFS_I(inode); 436 dosattrs = cifs_i->cifsAttrs | ATTR_READONLY; 437 data.Attributes = cpu_to_le32(dosattrs); 438 tmprc = smb2_compound_op(xid, tcon, cifs_sb, name, 439 FILE_WRITE_ATTRIBUTES, FILE_CREATE, 440 CREATE_NOT_FILE, &data, SMB2_OP_SET_INFO); 441 if (tmprc == 0) 442 cifs_i->cifsAttrs = dosattrs; 443} 444 445int 446smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name, 447 struct cifs_sb_info *cifs_sb) 448{ 449 return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN, 450 CREATE_NOT_FILE, 451 NULL, SMB2_OP_RMDIR); 452} 453 454int 455smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name, 456 struct cifs_sb_info *cifs_sb) 457{ 458 return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN, 459 CREATE_DELETE_ON_CLOSE | OPEN_REPARSE_POINT, 460 NULL, SMB2_OP_DELETE); 461} 462 463static int 464smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon, 465 const char *from_name, const char *to_name, 466 struct cifs_sb_info *cifs_sb, __u32 access, int command) 467{ 468 __le16 *smb2_to_name = NULL; 469 int rc; 470 471 smb2_to_name = cifs_convert_path_to_utf16(to_name, cifs_sb); 472 if (smb2_to_name == NULL) { 473 rc = -ENOMEM; 474 goto smb2_rename_path; 475 } 476 rc = smb2_compound_op(xid, tcon, cifs_sb, from_name, access, 477 FILE_OPEN, 0, smb2_to_name, command); 478smb2_rename_path: 479 kfree(smb2_to_name); 480 return rc; 481} 482 483int 484smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon, 485 const char *from_name, const char *to_name, 486 struct cifs_sb_info *cifs_sb) 487{ 488 return smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb, 489 DELETE, SMB2_OP_RENAME); 490} 491 492int 493smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon, 494 const char *from_name, const char *to_name, 495 struct cifs_sb_info *cifs_sb) 496{ 497 return smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb, 498 FILE_READ_ATTRIBUTES, SMB2_OP_HARDLINK); 499} 500 501int 502smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon, 503 const char *full_path, __u64 size, 504 struct cifs_sb_info *cifs_sb, bool set_alloc) 505{ 506 __le64 eof = cpu_to_le64(size); 507 508 return smb2_compound_op(xid, tcon, cifs_sb, full_path, 509 FILE_WRITE_DATA, FILE_OPEN, 0, &eof, 510 SMB2_OP_SET_EOF); 511} 512 513int 514smb2_set_file_info(struct inode *inode, const char *full_path, 515 FILE_BASIC_INFO *buf, const unsigned int xid) 516{ 517 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 518 struct tcon_link *tlink; 519 int rc; 520 521 if ((buf->CreationTime == 0) && (buf->LastAccessTime == 0) && 522 (buf->LastWriteTime == 0) && (buf->ChangeTime == 0) && 523 (buf->Attributes == 0)) 524 return 0; /* would be a no op, no sense sending this */ 525 526 tlink = cifs_sb_tlink(cifs_sb); 527 if (IS_ERR(tlink)) 528 return PTR_ERR(tlink); 529 530 rc = smb2_compound_op(xid, tlink_tcon(tlink), cifs_sb, full_path, 531 FILE_WRITE_ATTRIBUTES, FILE_OPEN, 0, buf, 532 SMB2_OP_SET_INFO); 533 cifs_put_tlink(tlink); 534 return rc; 535}