138c8a9a5SSteve French // SPDX-License-Identifier: LGPL-2.1 238c8a9a5SSteve French /* 338c8a9a5SSteve French * 438c8a9a5SSteve French * Copyright (C) International Business Machines Corp., 2002, 2011 538c8a9a5SSteve French * Etersoft, 2012 638c8a9a5SSteve French * Author(s): Pavel Shilovsky (pshilovsky@samba.org), 738c8a9a5SSteve French * Steve French (sfrench@us.ibm.com) 838c8a9a5SSteve French * 938c8a9a5SSteve French */ 1038c8a9a5SSteve French #include <linux/fs.h> 1138c8a9a5SSteve French #include <linux/stat.h> 1238c8a9a5SSteve French #include <linux/slab.h> 1338c8a9a5SSteve French #include <linux/pagemap.h> 1438c8a9a5SSteve French #include <asm/div64.h> 1538c8a9a5SSteve French #include "cifsfs.h" 1638c8a9a5SSteve French #include "cifspdu.h" 1738c8a9a5SSteve French #include "cifsglob.h" 1838c8a9a5SSteve French #include "cifsproto.h" 1938c8a9a5SSteve French #include "cifs_debug.h" 2038c8a9a5SSteve French #include "cifs_fs_sb.h" 2138c8a9a5SSteve French #include "cifs_unicode.h" 2238c8a9a5SSteve French #include "fscache.h" 2338c8a9a5SSteve French #include "smb2glob.h" 2438c8a9a5SSteve French #include "smb2pdu.h" 2538c8a9a5SSteve French #include "smb2proto.h" 2638c8a9a5SSteve French #include "cached_dir.h" 2738c8a9a5SSteve French #include "smb2status.h" 2838c8a9a5SSteve French 298c944f8aSPaulo Alcantara static inline __u32 file_create_options(struct dentry *dentry) 308c944f8aSPaulo Alcantara { 318c944f8aSPaulo Alcantara struct cifsInodeInfo *ci; 328c944f8aSPaulo Alcantara 338c944f8aSPaulo Alcantara if (dentry) { 348c944f8aSPaulo Alcantara ci = CIFS_I(d_inode(dentry)); 358c944f8aSPaulo Alcantara if (ci->cifsAttrs & ATTR_REPARSE) 368c944f8aSPaulo Alcantara return OPEN_REPARSE_POINT; 378c944f8aSPaulo Alcantara } 388c944f8aSPaulo Alcantara return 0; 398c944f8aSPaulo Alcantara } 408c944f8aSPaulo Alcantara 41a158bb66SSteve French static struct reparse_data_buffer *reparse_buf_ptr(struct kvec *iov) 42a158bb66SSteve French { 43a158bb66SSteve French struct reparse_data_buffer *buf; 44a158bb66SSteve French struct smb2_ioctl_rsp *io = iov->iov_base; 45a158bb66SSteve French u32 off, count, len; 46a158bb66SSteve French 47a158bb66SSteve French count = le32_to_cpu(io->OutputCount); 48a158bb66SSteve French off = le32_to_cpu(io->OutputOffset); 49a158bb66SSteve French if (check_add_overflow(off, count, &len) || len > iov->iov_len) 50a158bb66SSteve French return ERR_PTR(-EIO); 51a158bb66SSteve French 52a158bb66SSteve French buf = (struct reparse_data_buffer *)((u8 *)io + off); 53a158bb66SSteve French len = sizeof(*buf); 54a158bb66SSteve French if (count < len || count < le16_to_cpu(buf->ReparseDataLength) + len) 55a158bb66SSteve French return ERR_PTR(-EIO); 56a158bb66SSteve French return buf; 57a158bb66SSteve French } 58a158bb66SSteve French 59a90f37e3SSteve French /* Parse owner and group from SMB3.1.1 POSIX query info */ 60a90f37e3SSteve French static int parse_posix_sids(struct cifs_open_info_data *data, 61a90f37e3SSteve French struct kvec *rsp_iov) 62a90f37e3SSteve French { 63a90f37e3SSteve French struct smb2_query_info_rsp *qi = rsp_iov->iov_base; 64a90f37e3SSteve French unsigned int out_len = le32_to_cpu(qi->OutputBufferLength); 65a90f37e3SSteve French unsigned int qi_len = sizeof(data->posix_fi); 66a90f37e3SSteve French int owner_len, group_len; 67a90f37e3SSteve French u8 *sidsbuf, *sidsbuf_end; 68a90f37e3SSteve French 69a90f37e3SSteve French if (out_len <= qi_len) 70a90f37e3SSteve French return -EINVAL; 71a90f37e3SSteve French 72a90f37e3SSteve French sidsbuf = (u8 *)qi + le16_to_cpu(qi->OutputBufferOffset) + qi_len; 73a90f37e3SSteve French sidsbuf_end = sidsbuf + out_len - qi_len; 74a90f37e3SSteve French 75a90f37e3SSteve French owner_len = posix_info_sid_size(sidsbuf, sidsbuf_end); 76a90f37e3SSteve French if (owner_len == -1) 77a90f37e3SSteve French return -EINVAL; 78a90f37e3SSteve French 79a90f37e3SSteve French memcpy(&data->posix_owner, sidsbuf, owner_len); 80a90f37e3SSteve French group_len = posix_info_sid_size(sidsbuf + owner_len, sidsbuf_end); 81a90f37e3SSteve French if (group_len == -1) 82a90f37e3SSteve French return -EINVAL; 83a90f37e3SSteve French 84a90f37e3SSteve French memcpy(&data->posix_group, sidsbuf + owner_len, group_len); 85a90f37e3SSteve French return 0; 86a90f37e3SSteve French } 87a90f37e3SSteve French 8838c8a9a5SSteve French /* 8938c8a9a5SSteve French * note: If cfile is passed, the reference to it is dropped here. 9038c8a9a5SSteve French * So make sure that you do not reuse cfile after return from this func. 9138c8a9a5SSteve French * 92c5f44a3dSPaulo Alcantara * If passing @out_iov and @out_buftype, ensure to make them both large enough 93c5f44a3dSPaulo Alcantara * (>= 3) to hold all compounded responses. Caller is also responsible for 94c5f44a3dSPaulo Alcantara * freeing them up with free_rsp_buf(). 9538c8a9a5SSteve French */ 9638c8a9a5SSteve French static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, 9738c8a9a5SSteve French struct cifs_sb_info *cifs_sb, const char *full_path, 98886b7fb4SSteve French __u32 desired_access, __u32 create_disposition, 99886b7fb4SSteve French __u32 create_options, umode_t mode, struct kvec *in_iov, 100886b7fb4SSteve French int *cmds, int num_cmds, struct cifsFileInfo *cfile, 101f93d145fSMeetakshi Setiya struct kvec *out_iov, int *out_buftype, struct dentry *dentry) 10238c8a9a5SSteve French { 103a158bb66SSteve French 104a158bb66SSteve French struct reparse_data_buffer *rbuf; 105f4e5ceb6SPaulo Alcantara struct smb2_compound_vars *vars = NULL; 106a158bb66SSteve French struct kvec *rsp_iov, *iov; 10738c8a9a5SSteve French struct smb_rqst *rqst; 10838c8a9a5SSteve French int rc; 10938c8a9a5SSteve French __le16 *utf16_path = NULL; 11038c8a9a5SSteve French __u8 oplock = SMB2_OPLOCK_LEVEL_NONE; 11138c8a9a5SSteve French struct cifs_fid fid; 11238c8a9a5SSteve French struct cifs_ses *ses = tcon->ses; 11338c8a9a5SSteve French struct TCP_Server_Info *server; 114886b7fb4SSteve French int num_rqst = 0, i; 115886b7fb4SSteve French int resp_buftype[MAX_COMPOUND]; 11638c8a9a5SSteve French struct smb2_query_info_rsp *qi_rsp = NULL; 11738c8a9a5SSteve French struct cifs_open_info_data *idata; 118f93d145fSMeetakshi Setiya struct inode *inode = NULL; 11938c8a9a5SSteve French int flags = 0; 12038c8a9a5SSteve French __u8 delete_pending[8] = {1, 0, 0, 0, 0, 0, 0, 0}; 12138c8a9a5SSteve French unsigned int size[2]; 12238c8a9a5SSteve French void *data[2]; 12338c8a9a5SSteve French int len; 124433042a9SShyam Prasad N int retries = 0, cur_sleep = 1; 125433042a9SShyam Prasad N 126433042a9SShyam Prasad N replay_again: 127433042a9SShyam Prasad N /* reinitialize for possible replay */ 128433042a9SShyam Prasad N flags = 0; 129433042a9SShyam Prasad N oplock = SMB2_OPLOCK_LEVEL_NONE; 130433042a9SShyam Prasad N num_rqst = 0; 131433042a9SShyam Prasad N server = cifs_pick_channel(ses); 13238c8a9a5SSteve French 13338c8a9a5SSteve French vars = kzalloc(sizeof(*vars), GFP_ATOMIC); 13438c8a9a5SSteve French if (vars == NULL) 13538c8a9a5SSteve French return -ENOMEM; 13638c8a9a5SSteve French rqst = &vars->rqst[0]; 13738c8a9a5SSteve French rsp_iov = &vars->rsp_iov[0]; 13838c8a9a5SSteve French 13938c8a9a5SSteve French if (smb3_encryption_required(tcon)) 14038c8a9a5SSteve French flags |= CIFS_TRANSFORM_REQ; 14138c8a9a5SSteve French 142886b7fb4SSteve French for (i = 0; i < ARRAY_SIZE(resp_buftype); i++) 143886b7fb4SSteve French resp_buftype[i] = CIFS_NO_BUFFER; 14438c8a9a5SSteve French 14538c8a9a5SSteve French /* We already have a handle so we can skip the open */ 14638c8a9a5SSteve French if (cfile) 14738c8a9a5SSteve French goto after_open; 14838c8a9a5SSteve French 14938c8a9a5SSteve French /* Open */ 15038c8a9a5SSteve French utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb); 15138c8a9a5SSteve French if (!utf16_path) { 15238c8a9a5SSteve French rc = -ENOMEM; 15338c8a9a5SSteve French goto finished; 15438c8a9a5SSteve French } 15538c8a9a5SSteve French 156f93d145fSMeetakshi Setiya /* if there is an existing lease, reuse it */ 157f93d145fSMeetakshi Setiya if (dentry) { 158f93d145fSMeetakshi Setiya inode = d_inode(dentry); 159f93d145fSMeetakshi Setiya if (CIFS_I(inode)->lease_granted && server->ops->get_lease_key) { 160f93d145fSMeetakshi Setiya oplock = SMB2_OPLOCK_LEVEL_LEASE; 161f93d145fSMeetakshi Setiya server->ops->get_lease_key(inode, &fid); 162f93d145fSMeetakshi Setiya } 163f93d145fSMeetakshi Setiya } 164f93d145fSMeetakshi Setiya 16538c8a9a5SSteve French vars->oparms = (struct cifs_open_parms) { 16638c8a9a5SSteve French .tcon = tcon, 16738c8a9a5SSteve French .path = full_path, 16838c8a9a5SSteve French .desired_access = desired_access, 16938c8a9a5SSteve French .disposition = create_disposition, 17038c8a9a5SSteve French .create_options = cifs_create_options(cifs_sb, create_options), 17138c8a9a5SSteve French .fid = &fid, 17238c8a9a5SSteve French .mode = mode, 17338c8a9a5SSteve French .cifs_sb = cifs_sb, 17438c8a9a5SSteve French }; 17538c8a9a5SSteve French 17638c8a9a5SSteve French rqst[num_rqst].rq_iov = &vars->open_iov[0]; 17738c8a9a5SSteve French rqst[num_rqst].rq_nvec = SMB2_CREATE_IOV_SIZE; 17838c8a9a5SSteve French rc = SMB2_open_init(tcon, server, 17938c8a9a5SSteve French &rqst[num_rqst], &oplock, &vars->oparms, 18038c8a9a5SSteve French utf16_path); 18138c8a9a5SSteve French kfree(utf16_path); 18238c8a9a5SSteve French if (rc) 18338c8a9a5SSteve French goto finished; 18438c8a9a5SSteve French 18538c8a9a5SSteve French smb2_set_next_command(tcon, &rqst[num_rqst]); 18638c8a9a5SSteve French after_open: 18738c8a9a5SSteve French num_rqst++; 18838c8a9a5SSteve French rc = 0; 18938c8a9a5SSteve French 190886b7fb4SSteve French for (i = 0; i < num_cmds; i++) { 19138c8a9a5SSteve French /* Operation */ 192886b7fb4SSteve French switch (cmds[i]) { 19338c8a9a5SSteve French case SMB2_OP_QUERY_INFO: 194f4e5ceb6SPaulo Alcantara rqst[num_rqst].rq_iov = &vars->qi_iov; 19538c8a9a5SSteve French rqst[num_rqst].rq_nvec = 1; 19638c8a9a5SSteve French 197886b7fb4SSteve French if (cfile) { 19838c8a9a5SSteve French rc = SMB2_query_info_init(tcon, server, 19938c8a9a5SSteve French &rqst[num_rqst], 20038c8a9a5SSteve French cfile->fid.persistent_fid, 20138c8a9a5SSteve French cfile->fid.volatile_fid, 20238c8a9a5SSteve French FILE_ALL_INFORMATION, 20338c8a9a5SSteve French SMB2_O_INFO_FILE, 0, 20438c8a9a5SSteve French sizeof(struct smb2_file_all_info) + 20538c8a9a5SSteve French PATH_MAX * 2, 0, NULL); 206886b7fb4SSteve French } else { 20738c8a9a5SSteve French rc = SMB2_query_info_init(tcon, server, 20838c8a9a5SSteve French &rqst[num_rqst], 20938c8a9a5SSteve French COMPOUND_FID, 21038c8a9a5SSteve French COMPOUND_FID, 21138c8a9a5SSteve French FILE_ALL_INFORMATION, 21238c8a9a5SSteve French SMB2_O_INFO_FILE, 0, 21338c8a9a5SSteve French sizeof(struct smb2_file_all_info) + 21438c8a9a5SSteve French PATH_MAX * 2, 0, NULL); 21538c8a9a5SSteve French if (!rc) { 21638c8a9a5SSteve French smb2_set_next_command(tcon, &rqst[num_rqst]); 21738c8a9a5SSteve French smb2_set_related(&rqst[num_rqst]); 21838c8a9a5SSteve French } 21938c8a9a5SSteve French } 22038c8a9a5SSteve French 22138c8a9a5SSteve French if (rc) 22238c8a9a5SSteve French goto finished; 22338c8a9a5SSteve French num_rqst++; 224886b7fb4SSteve French trace_smb3_query_info_compound_enter(xid, ses->Suid, 225886b7fb4SSteve French tcon->tid, full_path); 22638c8a9a5SSteve French break; 22738c8a9a5SSteve French case SMB2_OP_POSIX_QUERY_INFO: 228f4e5ceb6SPaulo Alcantara rqst[num_rqst].rq_iov = &vars->qi_iov; 22938c8a9a5SSteve French rqst[num_rqst].rq_nvec = 1; 23038c8a9a5SSteve French 231886b7fb4SSteve French if (cfile) { 232886b7fb4SSteve French /* TBD: fix following to allow for longer SIDs */ 23338c8a9a5SSteve French rc = SMB2_query_info_init(tcon, server, 23438c8a9a5SSteve French &rqst[num_rqst], 23538c8a9a5SSteve French cfile->fid.persistent_fid, 23638c8a9a5SSteve French cfile->fid.volatile_fid, 23738c8a9a5SSteve French SMB_FIND_FILE_POSIX_INFO, 23838c8a9a5SSteve French SMB2_O_INFO_FILE, 0, 239886b7fb4SSteve French sizeof(struct smb311_posix_qinfo *) + 240886b7fb4SSteve French (PATH_MAX * 2) + 24138c8a9a5SSteve French (sizeof(struct cifs_sid) * 2), 0, NULL); 242886b7fb4SSteve French } else { 24338c8a9a5SSteve French rc = SMB2_query_info_init(tcon, server, 24438c8a9a5SSteve French &rqst[num_rqst], 24538c8a9a5SSteve French COMPOUND_FID, 24638c8a9a5SSteve French COMPOUND_FID, 24738c8a9a5SSteve French SMB_FIND_FILE_POSIX_INFO, 24838c8a9a5SSteve French SMB2_O_INFO_FILE, 0, 249886b7fb4SSteve French sizeof(struct smb311_posix_qinfo *) + 250886b7fb4SSteve French (PATH_MAX * 2) + 25138c8a9a5SSteve French (sizeof(struct cifs_sid) * 2), 0, NULL); 25238c8a9a5SSteve French if (!rc) { 25338c8a9a5SSteve French smb2_set_next_command(tcon, &rqst[num_rqst]); 25438c8a9a5SSteve French smb2_set_related(&rqst[num_rqst]); 25538c8a9a5SSteve French } 25638c8a9a5SSteve French } 25738c8a9a5SSteve French 25838c8a9a5SSteve French if (rc) 25938c8a9a5SSteve French goto finished; 26038c8a9a5SSteve French num_rqst++; 261886b7fb4SSteve French trace_smb3_posix_query_info_compound_enter(xid, ses->Suid, 262886b7fb4SSteve French tcon->tid, full_path); 26338c8a9a5SSteve French break; 26438c8a9a5SSteve French case SMB2_OP_DELETE: 26538c8a9a5SSteve French trace_smb3_delete_enter(xid, ses->Suid, tcon->tid, full_path); 26638c8a9a5SSteve French break; 26738c8a9a5SSteve French case SMB2_OP_MKDIR: 26838c8a9a5SSteve French /* 26938c8a9a5SSteve French * Directories are created through parameters in the 27038c8a9a5SSteve French * SMB2_open() call. 27138c8a9a5SSteve French */ 27238c8a9a5SSteve French trace_smb3_mkdir_enter(xid, ses->Suid, tcon->tid, full_path); 27338c8a9a5SSteve French break; 27438c8a9a5SSteve French case SMB2_OP_RMDIR: 27538c8a9a5SSteve French rqst[num_rqst].rq_iov = &vars->si_iov[0]; 27638c8a9a5SSteve French rqst[num_rqst].rq_nvec = 1; 27738c8a9a5SSteve French 27838c8a9a5SSteve French size[0] = 1; /* sizeof __u8 See MS-FSCC section 2.4.11 */ 27938c8a9a5SSteve French data[0] = &delete_pending[0]; 28038c8a9a5SSteve French 28138c8a9a5SSteve French rc = SMB2_set_info_init(tcon, server, 28238c8a9a5SSteve French &rqst[num_rqst], COMPOUND_FID, 28338c8a9a5SSteve French COMPOUND_FID, current->tgid, 28438c8a9a5SSteve French FILE_DISPOSITION_INFORMATION, 28538c8a9a5SSteve French SMB2_O_INFO_FILE, 0, data, size); 28638c8a9a5SSteve French if (rc) 28738c8a9a5SSteve French goto finished; 28838c8a9a5SSteve French smb2_set_next_command(tcon, &rqst[num_rqst]); 28938c8a9a5SSteve French smb2_set_related(&rqst[num_rqst++]); 29038c8a9a5SSteve French trace_smb3_rmdir_enter(xid, ses->Suid, tcon->tid, full_path); 29138c8a9a5SSteve French break; 29238c8a9a5SSteve French case SMB2_OP_SET_EOF: 29338c8a9a5SSteve French rqst[num_rqst].rq_iov = &vars->si_iov[0]; 29438c8a9a5SSteve French rqst[num_rqst].rq_nvec = 1; 29538c8a9a5SSteve French 296886b7fb4SSteve French size[0] = in_iov[i].iov_len; 297886b7fb4SSteve French data[0] = in_iov[i].iov_base; 29838c8a9a5SSteve French 29938c8a9a5SSteve French if (cfile) { 30038c8a9a5SSteve French rc = SMB2_set_info_init(tcon, server, 30138c8a9a5SSteve French &rqst[num_rqst], 30238c8a9a5SSteve French cfile->fid.persistent_fid, 30338c8a9a5SSteve French cfile->fid.volatile_fid, 30438c8a9a5SSteve French current->tgid, 30538c8a9a5SSteve French FILE_END_OF_FILE_INFORMATION, 30638c8a9a5SSteve French SMB2_O_INFO_FILE, 0, 30738c8a9a5SSteve French data, size); 30838c8a9a5SSteve French } else { 30938c8a9a5SSteve French rc = SMB2_set_info_init(tcon, server, 31038c8a9a5SSteve French &rqst[num_rqst], 31138c8a9a5SSteve French COMPOUND_FID, 31238c8a9a5SSteve French COMPOUND_FID, 31338c8a9a5SSteve French current->tgid, 31438c8a9a5SSteve French FILE_END_OF_FILE_INFORMATION, 31538c8a9a5SSteve French SMB2_O_INFO_FILE, 0, 31638c8a9a5SSteve French data, size); 31738c8a9a5SSteve French if (!rc) { 31838c8a9a5SSteve French smb2_set_next_command(tcon, &rqst[num_rqst]); 31938c8a9a5SSteve French smb2_set_related(&rqst[num_rqst]); 32038c8a9a5SSteve French } 32138c8a9a5SSteve French } 32238c8a9a5SSteve French if (rc) 32338c8a9a5SSteve French goto finished; 32438c8a9a5SSteve French num_rqst++; 32538c8a9a5SSteve French trace_smb3_set_eof_enter(xid, ses->Suid, tcon->tid, full_path); 32638c8a9a5SSteve French break; 32738c8a9a5SSteve French case SMB2_OP_SET_INFO: 32838c8a9a5SSteve French rqst[num_rqst].rq_iov = &vars->si_iov[0]; 32938c8a9a5SSteve French rqst[num_rqst].rq_nvec = 1; 33038c8a9a5SSteve French 331886b7fb4SSteve French size[0] = in_iov[i].iov_len; 332886b7fb4SSteve French data[0] = in_iov[i].iov_base; 33338c8a9a5SSteve French 334886b7fb4SSteve French if (cfile) { 33538c8a9a5SSteve French rc = SMB2_set_info_init(tcon, server, 33638c8a9a5SSteve French &rqst[num_rqst], 33738c8a9a5SSteve French cfile->fid.persistent_fid, 33838c8a9a5SSteve French cfile->fid.volatile_fid, current->tgid, 33938c8a9a5SSteve French FILE_BASIC_INFORMATION, 34038c8a9a5SSteve French SMB2_O_INFO_FILE, 0, data, size); 341886b7fb4SSteve French } else { 34238c8a9a5SSteve French rc = SMB2_set_info_init(tcon, server, 34338c8a9a5SSteve French &rqst[num_rqst], 34438c8a9a5SSteve French COMPOUND_FID, 34538c8a9a5SSteve French COMPOUND_FID, current->tgid, 34638c8a9a5SSteve French FILE_BASIC_INFORMATION, 34738c8a9a5SSteve French SMB2_O_INFO_FILE, 0, data, size); 34838c8a9a5SSteve French if (!rc) { 34938c8a9a5SSteve French smb2_set_next_command(tcon, &rqst[num_rqst]); 35038c8a9a5SSteve French smb2_set_related(&rqst[num_rqst]); 35138c8a9a5SSteve French } 35238c8a9a5SSteve French } 35338c8a9a5SSteve French 35438c8a9a5SSteve French if (rc) 35538c8a9a5SSteve French goto finished; 35638c8a9a5SSteve French num_rqst++; 357886b7fb4SSteve French trace_smb3_set_info_compound_enter(xid, ses->Suid, 358886b7fb4SSteve French tcon->tid, full_path); 35938c8a9a5SSteve French break; 36038c8a9a5SSteve French case SMB2_OP_RENAME: 36138c8a9a5SSteve French rqst[num_rqst].rq_iov = &vars->si_iov[0]; 36238c8a9a5SSteve French rqst[num_rqst].rq_nvec = 2; 36338c8a9a5SSteve French 364886b7fb4SSteve French len = in_iov[i].iov_len; 36538c8a9a5SSteve French 36638c8a9a5SSteve French vars->rename_info.ReplaceIfExists = 1; 36738c8a9a5SSteve French vars->rename_info.RootDirectory = 0; 36838c8a9a5SSteve French vars->rename_info.FileNameLength = cpu_to_le32(len); 36938c8a9a5SSteve French 37038c8a9a5SSteve French size[0] = sizeof(struct smb2_file_rename_info); 37138c8a9a5SSteve French data[0] = &vars->rename_info; 37238c8a9a5SSteve French 37338c8a9a5SSteve French size[1] = len + 2 /* null */; 374886b7fb4SSteve French data[1] = in_iov[i].iov_base; 37538c8a9a5SSteve French 376886b7fb4SSteve French if (cfile) { 37738c8a9a5SSteve French rc = SMB2_set_info_init(tcon, server, 37838c8a9a5SSteve French &rqst[num_rqst], 37938c8a9a5SSteve French cfile->fid.persistent_fid, 38038c8a9a5SSteve French cfile->fid.volatile_fid, 38138c8a9a5SSteve French current->tgid, FILE_RENAME_INFORMATION, 38238c8a9a5SSteve French SMB2_O_INFO_FILE, 0, data, size); 383886b7fb4SSteve French } else { 38438c8a9a5SSteve French rc = SMB2_set_info_init(tcon, server, 38538c8a9a5SSteve French &rqst[num_rqst], 38638c8a9a5SSteve French COMPOUND_FID, COMPOUND_FID, 38738c8a9a5SSteve French current->tgid, FILE_RENAME_INFORMATION, 38838c8a9a5SSteve French SMB2_O_INFO_FILE, 0, data, size); 38938c8a9a5SSteve French if (!rc) { 39038c8a9a5SSteve French smb2_set_next_command(tcon, &rqst[num_rqst]); 39138c8a9a5SSteve French smb2_set_related(&rqst[num_rqst]); 39238c8a9a5SSteve French } 39338c8a9a5SSteve French } 39438c8a9a5SSteve French if (rc) 39538c8a9a5SSteve French goto finished; 39638c8a9a5SSteve French num_rqst++; 39738c8a9a5SSteve French trace_smb3_rename_enter(xid, ses->Suid, tcon->tid, full_path); 39838c8a9a5SSteve French break; 39938c8a9a5SSteve French case SMB2_OP_HARDLINK: 40038c8a9a5SSteve French rqst[num_rqst].rq_iov = &vars->si_iov[0]; 40138c8a9a5SSteve French rqst[num_rqst].rq_nvec = 2; 40238c8a9a5SSteve French 403886b7fb4SSteve French len = in_iov[i].iov_len; 40438c8a9a5SSteve French 40538c8a9a5SSteve French vars->link_info.ReplaceIfExists = 0; 40638c8a9a5SSteve French vars->link_info.RootDirectory = 0; 40738c8a9a5SSteve French vars->link_info.FileNameLength = cpu_to_le32(len); 40838c8a9a5SSteve French 40938c8a9a5SSteve French size[0] = sizeof(struct smb2_file_link_info); 41038c8a9a5SSteve French data[0] = &vars->link_info; 41138c8a9a5SSteve French 41238c8a9a5SSteve French size[1] = len + 2 /* null */; 413886b7fb4SSteve French data[1] = in_iov[i].iov_base; 41438c8a9a5SSteve French 41538c8a9a5SSteve French rc = SMB2_set_info_init(tcon, server, 41638c8a9a5SSteve French &rqst[num_rqst], COMPOUND_FID, 41738c8a9a5SSteve French COMPOUND_FID, current->tgid, 41838c8a9a5SSteve French FILE_LINK_INFORMATION, 41938c8a9a5SSteve French SMB2_O_INFO_FILE, 0, data, size); 42038c8a9a5SSteve French if (rc) 42138c8a9a5SSteve French goto finished; 42238c8a9a5SSteve French smb2_set_next_command(tcon, &rqst[num_rqst]); 42338c8a9a5SSteve French smb2_set_related(&rqst[num_rqst++]); 42438c8a9a5SSteve French trace_smb3_hardlink_enter(xid, ses->Suid, tcon->tid, full_path); 42538c8a9a5SSteve French break; 42602bcf865SSteve French case SMB2_OP_SET_REPARSE: 42702bcf865SSteve French rqst[num_rqst].rq_iov = vars->io_iov; 42802bcf865SSteve French rqst[num_rqst].rq_nvec = ARRAY_SIZE(vars->io_iov); 42902bcf865SSteve French 43002bcf865SSteve French rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst], 43102bcf865SSteve French COMPOUND_FID, COMPOUND_FID, 43202bcf865SSteve French FSCTL_SET_REPARSE_POINT, 43302bcf865SSteve French in_iov[i].iov_base, 43402bcf865SSteve French in_iov[i].iov_len, 0); 43502bcf865SSteve French if (rc) 43602bcf865SSteve French goto finished; 43702bcf865SSteve French smb2_set_next_command(tcon, &rqst[num_rqst]); 43802bcf865SSteve French smb2_set_related(&rqst[num_rqst++]); 43902bcf865SSteve French trace_smb3_set_reparse_compound_enter(xid, ses->Suid, 44002bcf865SSteve French tcon->tid, full_path); 44102bcf865SSteve French break; 442a158bb66SSteve French case SMB2_OP_GET_REPARSE: 443a158bb66SSteve French rqst[num_rqst].rq_iov = vars->io_iov; 444a158bb66SSteve French rqst[num_rqst].rq_nvec = ARRAY_SIZE(vars->io_iov); 445a158bb66SSteve French 446a158bb66SSteve French rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst], 447a158bb66SSteve French COMPOUND_FID, COMPOUND_FID, 448a158bb66SSteve French FSCTL_GET_REPARSE_POINT, 449a158bb66SSteve French NULL, 0, CIFSMaxBufSize); 450a158bb66SSteve French if (rc) 451a158bb66SSteve French goto finished; 452a158bb66SSteve French smb2_set_next_command(tcon, &rqst[num_rqst]); 453a158bb66SSteve French smb2_set_related(&rqst[num_rqst++]); 454a158bb66SSteve French trace_smb3_get_reparse_compound_enter(xid, ses->Suid, 455a158bb66SSteve French tcon->tid, full_path); 456a158bb66SSteve French break; 45738c8a9a5SSteve French default: 45838c8a9a5SSteve French cifs_dbg(VFS, "Invalid command\n"); 45938c8a9a5SSteve French rc = -EINVAL; 46038c8a9a5SSteve French } 461886b7fb4SSteve French } 46238c8a9a5SSteve French if (rc) 46338c8a9a5SSteve French goto finished; 46438c8a9a5SSteve French 46538c8a9a5SSteve French /* We already have a handle so we can skip the close */ 46638c8a9a5SSteve French if (cfile) 46738c8a9a5SSteve French goto after_close; 46838c8a9a5SSteve French /* Close */ 46938c8a9a5SSteve French flags |= CIFS_CP_CREATE_CLOSE_OP; 470f4e5ceb6SPaulo Alcantara rqst[num_rqst].rq_iov = &vars->close_iov; 47138c8a9a5SSteve French rqst[num_rqst].rq_nvec = 1; 47238c8a9a5SSteve French rc = SMB2_close_init(tcon, server, 47338c8a9a5SSteve French &rqst[num_rqst], COMPOUND_FID, 47438c8a9a5SSteve French COMPOUND_FID, false); 47538c8a9a5SSteve French smb2_set_related(&rqst[num_rqst]); 47638c8a9a5SSteve French if (rc) 47738c8a9a5SSteve French goto finished; 47838c8a9a5SSteve French after_close: 47938c8a9a5SSteve French num_rqst++; 48038c8a9a5SSteve French 48138c8a9a5SSteve French if (cfile) { 482433042a9SShyam Prasad N if (retries) 483433042a9SShyam Prasad N for (i = 1; i < num_rqst - 2; i++) 484433042a9SShyam Prasad N smb2_set_replay(server, &rqst[i]); 485433042a9SShyam Prasad N 48638c8a9a5SSteve French rc = compound_send_recv(xid, ses, server, 48738c8a9a5SSteve French flags, num_rqst - 2, 48838c8a9a5SSteve French &rqst[1], &resp_buftype[1], 48938c8a9a5SSteve French &rsp_iov[1]); 490433042a9SShyam Prasad N } else { 491433042a9SShyam Prasad N if (retries) 492433042a9SShyam Prasad N for (i = 0; i < num_rqst; i++) 493433042a9SShyam Prasad N smb2_set_replay(server, &rqst[i]); 494433042a9SShyam Prasad N 49538c8a9a5SSteve French rc = compound_send_recv(xid, ses, server, 49638c8a9a5SSteve French flags, num_rqst, 49738c8a9a5SSteve French rqst, resp_buftype, 49838c8a9a5SSteve French rsp_iov); 499433042a9SShyam Prasad N } 50038c8a9a5SSteve French 50138c8a9a5SSteve French finished: 502886b7fb4SSteve French num_rqst = 0; 503886b7fb4SSteve French SMB2_open_free(&rqst[num_rqst++]); 50438c8a9a5SSteve French if (rc == -EREMCHG) { 50538c8a9a5SSteve French pr_warn_once("server share %s deleted\n", tcon->tree_name); 50638c8a9a5SSteve French tcon->need_reconnect = true; 50738c8a9a5SSteve French } 50838c8a9a5SSteve French 509886b7fb4SSteve French for (i = 0; i < num_cmds; i++) { 510886b7fb4SSteve French switch (cmds[i]) { 51138c8a9a5SSteve French case SMB2_OP_QUERY_INFO: 512886b7fb4SSteve French idata = in_iov[i].iov_base; 51338c8a9a5SSteve French if (rc == 0 && cfile && cfile->symlink_target) { 51438c8a9a5SSteve French idata->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL); 51538c8a9a5SSteve French if (!idata->symlink_target) 51638c8a9a5SSteve French rc = -ENOMEM; 51738c8a9a5SSteve French } 51838c8a9a5SSteve French if (rc == 0) { 51938c8a9a5SSteve French qi_rsp = (struct smb2_query_info_rsp *) 520886b7fb4SSteve French rsp_iov[i + 1].iov_base; 52138c8a9a5SSteve French rc = smb2_validate_and_copy_iov( 52238c8a9a5SSteve French le16_to_cpu(qi_rsp->OutputBufferOffset), 52338c8a9a5SSteve French le32_to_cpu(qi_rsp->OutputBufferLength), 524886b7fb4SSteve French &rsp_iov[i + 1], sizeof(idata->fi), (char *)&idata->fi); 52538c8a9a5SSteve French } 526886b7fb4SSteve French SMB2_query_info_free(&rqst[num_rqst++]); 52738c8a9a5SSteve French if (rc) 52838c8a9a5SSteve French trace_smb3_query_info_compound_err(xid, ses->Suid, 52938c8a9a5SSteve French tcon->tid, rc); 53038c8a9a5SSteve French else 53138c8a9a5SSteve French trace_smb3_query_info_compound_done(xid, ses->Suid, 53238c8a9a5SSteve French tcon->tid); 53338c8a9a5SSteve French break; 53438c8a9a5SSteve French case SMB2_OP_POSIX_QUERY_INFO: 535886b7fb4SSteve French idata = in_iov[i].iov_base; 53638c8a9a5SSteve French if (rc == 0 && cfile && cfile->symlink_target) { 53738c8a9a5SSteve French idata->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL); 53838c8a9a5SSteve French if (!idata->symlink_target) 53938c8a9a5SSteve French rc = -ENOMEM; 54038c8a9a5SSteve French } 54138c8a9a5SSteve French if (rc == 0) { 54238c8a9a5SSteve French qi_rsp = (struct smb2_query_info_rsp *) 543886b7fb4SSteve French rsp_iov[i + 1].iov_base; 54438c8a9a5SSteve French rc = smb2_validate_and_copy_iov( 54538c8a9a5SSteve French le16_to_cpu(qi_rsp->OutputBufferOffset), 54638c8a9a5SSteve French le32_to_cpu(qi_rsp->OutputBufferLength), 547886b7fb4SSteve French &rsp_iov[i + 1], sizeof(idata->posix_fi) /* add SIDs */, 54838c8a9a5SSteve French (char *)&idata->posix_fi); 54938c8a9a5SSteve French } 550a90f37e3SSteve French if (rc == 0) 551a90f37e3SSteve French rc = parse_posix_sids(idata, &rsp_iov[i + 1]); 55238c8a9a5SSteve French 553886b7fb4SSteve French SMB2_query_info_free(&rqst[num_rqst++]); 55438c8a9a5SSteve French if (rc) 555886b7fb4SSteve French trace_smb3_posix_query_info_compound_err(xid, ses->Suid, 556886b7fb4SSteve French tcon->tid, rc); 55738c8a9a5SSteve French else 558886b7fb4SSteve French trace_smb3_posix_query_info_compound_done(xid, ses->Suid, 559886b7fb4SSteve French tcon->tid); 56038c8a9a5SSteve French break; 56138c8a9a5SSteve French case SMB2_OP_DELETE: 56238c8a9a5SSteve French if (rc) 56338c8a9a5SSteve French trace_smb3_delete_err(xid, ses->Suid, tcon->tid, rc); 564b6e27f7fSSteve French else { 565b6e27f7fSSteve French /* 566b6e27f7fSSteve French * If dentry (hence, inode) is NULL, lease break is going to 567b6e27f7fSSteve French * take care of degrading leases on handles for deleted files. 568b6e27f7fSSteve French */ 569b6e27f7fSSteve French if (inode) 570b6e27f7fSSteve French cifs_mark_open_handles_for_deleted_file(inode, full_path); 57138c8a9a5SSteve French trace_smb3_delete_done(xid, ses->Suid, tcon->tid); 572b6e27f7fSSteve French } 57338c8a9a5SSteve French break; 57438c8a9a5SSteve French case SMB2_OP_MKDIR: 57538c8a9a5SSteve French if (rc) 57638c8a9a5SSteve French trace_smb3_mkdir_err(xid, ses->Suid, tcon->tid, rc); 57738c8a9a5SSteve French else 57838c8a9a5SSteve French trace_smb3_mkdir_done(xid, ses->Suid, tcon->tid); 57938c8a9a5SSteve French break; 58038c8a9a5SSteve French case SMB2_OP_HARDLINK: 58138c8a9a5SSteve French if (rc) 58238c8a9a5SSteve French trace_smb3_hardlink_err(xid, ses->Suid, tcon->tid, rc); 58338c8a9a5SSteve French else 58438c8a9a5SSteve French trace_smb3_hardlink_done(xid, ses->Suid, tcon->tid); 585886b7fb4SSteve French SMB2_set_info_free(&rqst[num_rqst++]); 58638c8a9a5SSteve French break; 58738c8a9a5SSteve French case SMB2_OP_RENAME: 58838c8a9a5SSteve French if (rc) 58938c8a9a5SSteve French trace_smb3_rename_err(xid, ses->Suid, tcon->tid, rc); 59038c8a9a5SSteve French else 59138c8a9a5SSteve French trace_smb3_rename_done(xid, ses->Suid, tcon->tid); 592886b7fb4SSteve French SMB2_set_info_free(&rqst[num_rqst++]); 59338c8a9a5SSteve French break; 59438c8a9a5SSteve French case SMB2_OP_RMDIR: 59538c8a9a5SSteve French if (rc) 59638c8a9a5SSteve French trace_smb3_rmdir_err(xid, ses->Suid, tcon->tid, rc); 59738c8a9a5SSteve French else 59838c8a9a5SSteve French trace_smb3_rmdir_done(xid, ses->Suid, tcon->tid); 599886b7fb4SSteve French SMB2_set_info_free(&rqst[num_rqst++]); 60038c8a9a5SSteve French break; 60138c8a9a5SSteve French case SMB2_OP_SET_EOF: 60238c8a9a5SSteve French if (rc) 60338c8a9a5SSteve French trace_smb3_set_eof_err(xid, ses->Suid, tcon->tid, rc); 60438c8a9a5SSteve French else 60538c8a9a5SSteve French trace_smb3_set_eof_done(xid, ses->Suid, tcon->tid); 606886b7fb4SSteve French SMB2_set_info_free(&rqst[num_rqst++]); 60738c8a9a5SSteve French break; 60838c8a9a5SSteve French case SMB2_OP_SET_INFO: 60938c8a9a5SSteve French if (rc) 61038c8a9a5SSteve French trace_smb3_set_info_compound_err(xid, ses->Suid, 61138c8a9a5SSteve French tcon->tid, rc); 61238c8a9a5SSteve French else 61338c8a9a5SSteve French trace_smb3_set_info_compound_done(xid, ses->Suid, 61438c8a9a5SSteve French tcon->tid); 615886b7fb4SSteve French SMB2_set_info_free(&rqst[num_rqst++]); 61638c8a9a5SSteve French break; 61702bcf865SSteve French case SMB2_OP_SET_REPARSE: 61802bcf865SSteve French if (rc) { 61902bcf865SSteve French trace_smb3_set_reparse_compound_err(xid, ses->Suid, 62002bcf865SSteve French tcon->tid, rc); 62102bcf865SSteve French } else { 62202bcf865SSteve French trace_smb3_set_reparse_compound_done(xid, ses->Suid, 62302bcf865SSteve French tcon->tid); 62402bcf865SSteve French } 62502bcf865SSteve French SMB2_ioctl_free(&rqst[num_rqst++]); 62602bcf865SSteve French break; 627a158bb66SSteve French case SMB2_OP_GET_REPARSE: 628a158bb66SSteve French if (!rc) { 629a158bb66SSteve French iov = &rsp_iov[i + 1]; 630a158bb66SSteve French idata = in_iov[i].iov_base; 631a158bb66SSteve French idata->reparse.io.iov = *iov; 632a158bb66SSteve French idata->reparse.io.buftype = resp_buftype[i + 1]; 633a158bb66SSteve French rbuf = reparse_buf_ptr(iov); 634a158bb66SSteve French if (IS_ERR(rbuf)) { 635a158bb66SSteve French rc = PTR_ERR(rbuf); 636a158bb66SSteve French trace_smb3_set_reparse_compound_err(xid, ses->Suid, 637a158bb66SSteve French tcon->tid, rc); 638a158bb66SSteve French } else { 639a158bb66SSteve French idata->reparse.tag = le32_to_cpu(rbuf->ReparseTag); 640a158bb66SSteve French trace_smb3_set_reparse_compound_done(xid, ses->Suid, 641a158bb66SSteve French tcon->tid); 642a158bb66SSteve French } 643a158bb66SSteve French memset(iov, 0, sizeof(*iov)); 644a158bb66SSteve French resp_buftype[i + 1] = CIFS_NO_BUFFER; 645a158bb66SSteve French } else { 646a158bb66SSteve French trace_smb3_set_reparse_compound_err(xid, ses->Suid, 647a158bb66SSteve French tcon->tid, rc); 648a158bb66SSteve French } 649a158bb66SSteve French SMB2_ioctl_free(&rqst[num_rqst++]); 650a158bb66SSteve French break; 65138c8a9a5SSteve French } 652886b7fb4SSteve French } 653886b7fb4SSteve French SMB2_close_free(&rqst[num_rqst]); 65438c8a9a5SSteve French 655886b7fb4SSteve French num_cmds += 2; 656c5f44a3dSPaulo Alcantara if (out_iov && out_buftype) { 657886b7fb4SSteve French memcpy(out_iov, rsp_iov, num_cmds * sizeof(*out_iov)); 658886b7fb4SSteve French memcpy(out_buftype, resp_buftype, 659886b7fb4SSteve French num_cmds * sizeof(*out_buftype)); 66038c8a9a5SSteve French } else { 661886b7fb4SSteve French for (i = 0; i < num_cmds; i++) 662886b7fb4SSteve French free_rsp_buf(resp_buftype[i], rsp_iov[i].iov_base); 66338c8a9a5SSteve French } 664433042a9SShyam Prasad N num_cmds -= 2; /* correct num_cmds as there could be a retry */ 66538c8a9a5SSteve French kfree(vars); 666433042a9SShyam Prasad N 667433042a9SShyam Prasad N if (is_replayable_error(rc) && 668433042a9SShyam Prasad N smb2_should_replay(tcon, &retries, &cur_sleep)) 669433042a9SShyam Prasad N goto replay_again; 670433042a9SShyam Prasad N 671433042a9SShyam Prasad N if (cfile) 672433042a9SShyam Prasad N cifsFileInfo_put(cfile); 673433042a9SShyam Prasad N 67438c8a9a5SSteve French return rc; 67538c8a9a5SSteve French } 67638c8a9a5SSteve French 6775f71ebc4SPaulo Alcantara static int parse_create_response(struct cifs_open_info_data *data, 6785f71ebc4SPaulo Alcantara struct cifs_sb_info *cifs_sb, 6795f71ebc4SPaulo Alcantara const struct kvec *iov) 6805f71ebc4SPaulo Alcantara { 6815f71ebc4SPaulo Alcantara struct smb2_create_rsp *rsp = iov->iov_base; 6825f71ebc4SPaulo Alcantara bool reparse_point = false; 6835f71ebc4SPaulo Alcantara u32 tag = 0; 6845f71ebc4SPaulo Alcantara int rc = 0; 6855f71ebc4SPaulo Alcantara 6865f71ebc4SPaulo Alcantara switch (rsp->hdr.Status) { 6877fb77d9cSPaulo Alcantara case STATUS_IO_REPARSE_TAG_NOT_HANDLED: 6887fb77d9cSPaulo Alcantara reparse_point = true; 6897fb77d9cSPaulo Alcantara break; 6905f71ebc4SPaulo Alcantara case STATUS_STOPPED_ON_SYMLINK: 6915f71ebc4SPaulo Alcantara rc = smb2_parse_symlink_response(cifs_sb, iov, 6925f71ebc4SPaulo Alcantara &data->symlink_target); 6935f71ebc4SPaulo Alcantara if (rc) 6945f71ebc4SPaulo Alcantara return rc; 6955f71ebc4SPaulo Alcantara tag = IO_REPARSE_TAG_SYMLINK; 6965f71ebc4SPaulo Alcantara reparse_point = true; 6975f71ebc4SPaulo Alcantara break; 6985f71ebc4SPaulo Alcantara case STATUS_SUCCESS: 6995f71ebc4SPaulo Alcantara reparse_point = !!(rsp->Flags & SMB2_CREATE_FLAG_REPARSEPOINT); 7005f71ebc4SPaulo Alcantara break; 7015f71ebc4SPaulo Alcantara } 7025f71ebc4SPaulo Alcantara data->reparse_point = reparse_point; 703df32e887SPaulo Alcantara data->reparse.tag = tag; 7045f71ebc4SPaulo Alcantara return rc; 7055f71ebc4SPaulo Alcantara } 7065f71ebc4SPaulo Alcantara 7078b4e285dSPaulo Alcantara int smb2_query_path_info(const unsigned int xid, 7088b4e285dSPaulo Alcantara struct cifs_tcon *tcon, 7098b4e285dSPaulo Alcantara struct cifs_sb_info *cifs_sb, 7108b4e285dSPaulo Alcantara const char *full_path, 7118b4e285dSPaulo Alcantara struct cifs_open_info_data *data) 71238c8a9a5SSteve French { 71338c8a9a5SSteve French __u32 create_options = 0; 71438c8a9a5SSteve French struct cifsFileInfo *cfile; 71538c8a9a5SSteve French struct cached_fid *cfid = NULL; 7165f71ebc4SPaulo Alcantara struct smb2_hdr *hdr; 717a158bb66SSteve French struct kvec in_iov[2], out_iov[3] = {}; 718c5f44a3dSPaulo Alcantara int out_buftype[3] = {}; 719cfb8f73dSPaulo Alcantara int cmds[2]; 72038c8a9a5SSteve French bool islink; 721a158bb66SSteve French int i, num_cmds; 72238c8a9a5SSteve French int rc, rc2; 72338c8a9a5SSteve French 7248b4e285dSPaulo Alcantara data->adjust_tz = false; 7258b4e285dSPaulo Alcantara data->reparse_point = false; 72638c8a9a5SSteve French 727cfb8f73dSPaulo Alcantara /* 728cfb8f73dSPaulo Alcantara * BB TODO: Add support for using cached root handle in SMB3.1.1 POSIX. 729cfb8f73dSPaulo Alcantara * Create SMB2_query_posix_info worker function to do non-compounded 730cfb8f73dSPaulo Alcantara * query when we already have an open file handle for this. For now this 731cfb8f73dSPaulo Alcantara * is fast enough (always using the compounded version). 732cfb8f73dSPaulo Alcantara */ 733cfb8f73dSPaulo Alcantara if (!tcon->posix_extensions) { 734cfb8f73dSPaulo Alcantara if (*full_path) { 73538c8a9a5SSteve French rc = -ENOENT; 736cfb8f73dSPaulo Alcantara } else { 737cfb8f73dSPaulo Alcantara rc = open_cached_dir(xid, tcon, full_path, 738cfb8f73dSPaulo Alcantara cifs_sb, false, &cfid); 739cfb8f73dSPaulo Alcantara } 74038c8a9a5SSteve French /* If it is a root and its handle is cached then use it */ 74138c8a9a5SSteve French if (!rc) { 74238c8a9a5SSteve French if (cfid->file_all_info_is_valid) { 743cfb8f73dSPaulo Alcantara memcpy(&data->fi, &cfid->file_all_info, 744cfb8f73dSPaulo Alcantara sizeof(data->fi)); 74538c8a9a5SSteve French } else { 746cfb8f73dSPaulo Alcantara rc = SMB2_query_info(xid, tcon, 747cfb8f73dSPaulo Alcantara cfid->fid.persistent_fid, 748cfb8f73dSPaulo Alcantara cfid->fid.volatile_fid, 749cfb8f73dSPaulo Alcantara &data->fi); 75038c8a9a5SSteve French } 75138c8a9a5SSteve French close_cached_dir(cfid); 75238c8a9a5SSteve French return rc; 75338c8a9a5SSteve French } 754cfb8f73dSPaulo Alcantara cmds[0] = SMB2_OP_QUERY_INFO; 755cfb8f73dSPaulo Alcantara } else { 756cfb8f73dSPaulo Alcantara cmds[0] = SMB2_OP_POSIX_QUERY_INFO; 757cfb8f73dSPaulo Alcantara } 75838c8a9a5SSteve French 759a158bb66SSteve French in_iov[0].iov_base = data; 760a158bb66SSteve French in_iov[0].iov_len = sizeof(*data); 761a158bb66SSteve French in_iov[1] = in_iov[0]; 762886b7fb4SSteve French 76338c8a9a5SSteve French cifs_get_readable_path(tcon, full_path, &cfile); 764886b7fb4SSteve French rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, 765886b7fb4SSteve French FILE_READ_ATTRIBUTES, FILE_OPEN, 766a90f37e3SSteve French create_options, ACL_NO_MODE, in_iov, 767f93d145fSMeetakshi Setiya cmds, 1, cfile, out_iov, out_buftype, NULL); 7685f71ebc4SPaulo Alcantara hdr = out_iov[0].iov_base; 7695f71ebc4SPaulo Alcantara /* 7705f71ebc4SPaulo Alcantara * If first iov is unset, then SMB session was dropped or we've got a 7715f71ebc4SPaulo Alcantara * cached open file (@cfile). 7725f71ebc4SPaulo Alcantara */ 7735f71ebc4SPaulo Alcantara if (!hdr || out_buftype[0] == CIFS_NO_BUFFER) 77438c8a9a5SSteve French goto out; 77538c8a9a5SSteve French 7765f71ebc4SPaulo Alcantara switch (rc) { 7775f71ebc4SPaulo Alcantara case 0: 7785f71ebc4SPaulo Alcantara case -EOPNOTSUPP: 779cfb8f73dSPaulo Alcantara /* 780cfb8f73dSPaulo Alcantara * BB TODO: When support for special files added to Samba 781cfb8f73dSPaulo Alcantara * re-verify this path. 782cfb8f73dSPaulo Alcantara */ 7835f71ebc4SPaulo Alcantara rc = parse_create_response(data, cifs_sb, &out_iov[0]); 7845f71ebc4SPaulo Alcantara if (rc || !data->reparse_point) 7855f71ebc4SPaulo Alcantara goto out; 7865f71ebc4SPaulo Alcantara 787a158bb66SSteve French if (data->reparse.tag == IO_REPARSE_TAG_SYMLINK) { 788a158bb66SSteve French /* symlink already parsed in create response */ 789a158bb66SSteve French num_cmds = 1; 790a158bb66SSteve French } else { 791a158bb66SSteve French cmds[1] = SMB2_OP_GET_REPARSE; 792a158bb66SSteve French num_cmds = 2; 793a158bb66SSteve French } 79438c8a9a5SSteve French create_options |= OPEN_REPARSE_POINT; 79538c8a9a5SSteve French cifs_get_readable_path(tcon, full_path, &cfile); 79638c8a9a5SSteve French rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, 79738c8a9a5SSteve French FILE_READ_ATTRIBUTES, FILE_OPEN, 798a90f37e3SSteve French create_options, ACL_NO_MODE, in_iov, 799f93d145fSMeetakshi Setiya cmds, num_cmds, cfile, NULL, NULL, NULL); 8005f71ebc4SPaulo Alcantara break; 8015f71ebc4SPaulo Alcantara case -EREMOTE: 8025f71ebc4SPaulo Alcantara break; 8035f71ebc4SPaulo Alcantara default: 8045f71ebc4SPaulo Alcantara if (hdr->Status != STATUS_OBJECT_NAME_INVALID) 8055f71ebc4SPaulo Alcantara break; 80638c8a9a5SSteve French rc2 = cifs_inval_name_dfs_link_error(xid, tcon, cifs_sb, 80738c8a9a5SSteve French full_path, &islink); 80838c8a9a5SSteve French if (rc2) { 80938c8a9a5SSteve French rc = rc2; 81038c8a9a5SSteve French goto out; 81138c8a9a5SSteve French } 81238c8a9a5SSteve French if (islink) 81338c8a9a5SSteve French rc = -EREMOTE; 81438c8a9a5SSteve French } 81538c8a9a5SSteve French 81638c8a9a5SSteve French out: 817a158bb66SSteve French for (i = 0; i < ARRAY_SIZE(out_buftype); i++) 818a158bb66SSteve French free_rsp_buf(out_buftype[i], out_iov[i].iov_base); 81938c8a9a5SSteve French return rc; 82038c8a9a5SSteve French } 82138c8a9a5SSteve French 82238c8a9a5SSteve French int 82338c8a9a5SSteve French smb2_mkdir(const unsigned int xid, struct inode *parent_inode, umode_t mode, 82438c8a9a5SSteve French struct cifs_tcon *tcon, const char *name, 82538c8a9a5SSteve French struct cifs_sb_info *cifs_sb) 82638c8a9a5SSteve French { 82738c8a9a5SSteve French return smb2_compound_op(xid, tcon, cifs_sb, name, 82838c8a9a5SSteve French FILE_WRITE_ATTRIBUTES, FILE_CREATE, 829a90f37e3SSteve French CREATE_NOT_FILE, mode, 830a90f37e3SSteve French NULL, &(int){SMB2_OP_MKDIR}, 1, 831f93d145fSMeetakshi Setiya NULL, NULL, NULL, NULL); 83238c8a9a5SSteve French } 83338c8a9a5SSteve French 83438c8a9a5SSteve French void 83538c8a9a5SSteve French smb2_mkdir_setinfo(struct inode *inode, const char *name, 83638c8a9a5SSteve French struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon, 83738c8a9a5SSteve French const unsigned int xid) 83838c8a9a5SSteve French { 839886b7fb4SSteve French FILE_BASIC_INFO data = {}; 84038c8a9a5SSteve French struct cifsInodeInfo *cifs_i; 84138c8a9a5SSteve French struct cifsFileInfo *cfile; 842886b7fb4SSteve French struct kvec in_iov; 84338c8a9a5SSteve French u32 dosattrs; 84438c8a9a5SSteve French int tmprc; 84538c8a9a5SSteve French 846886b7fb4SSteve French in_iov.iov_base = &data; 847886b7fb4SSteve French in_iov.iov_len = sizeof(data); 84838c8a9a5SSteve French cifs_i = CIFS_I(inode); 84938c8a9a5SSteve French dosattrs = cifs_i->cifsAttrs | ATTR_READONLY; 85038c8a9a5SSteve French data.Attributes = cpu_to_le32(dosattrs); 85138c8a9a5SSteve French cifs_get_writable_path(tcon, name, FIND_WR_ANY, &cfile); 85238c8a9a5SSteve French tmprc = smb2_compound_op(xid, tcon, cifs_sb, name, 85338c8a9a5SSteve French FILE_WRITE_ATTRIBUTES, FILE_CREATE, 854886b7fb4SSteve French CREATE_NOT_FILE, ACL_NO_MODE, &in_iov, 855886b7fb4SSteve French &(int){SMB2_OP_SET_INFO}, 1, 856f93d145fSMeetakshi Setiya cfile, NULL, NULL, NULL); 85738c8a9a5SSteve French if (tmprc == 0) 85838c8a9a5SSteve French cifs_i->cifsAttrs = dosattrs; 85938c8a9a5SSteve French } 86038c8a9a5SSteve French 86138c8a9a5SSteve French int 86238c8a9a5SSteve French smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name, 86338c8a9a5SSteve French struct cifs_sb_info *cifs_sb) 86438c8a9a5SSteve French { 86538c8a9a5SSteve French drop_cached_dir_by_name(xid, tcon, name, cifs_sb); 866886b7fb4SSteve French return smb2_compound_op(xid, tcon, cifs_sb, name, 867886b7fb4SSteve French DELETE, FILE_OPEN, CREATE_NOT_FILE, 868a90f37e3SSteve French ACL_NO_MODE, NULL, 869a90f37e3SSteve French &(int){SMB2_OP_RMDIR}, 1, 870f93d145fSMeetakshi Setiya NULL, NULL, NULL, NULL); 87138c8a9a5SSteve French } 87238c8a9a5SSteve French 87338c8a9a5SSteve French int 87438c8a9a5SSteve French smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name, 875f93d145fSMeetakshi Setiya struct cifs_sb_info *cifs_sb, struct dentry *dentry) 87638c8a9a5SSteve French { 87738c8a9a5SSteve French return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN, 87838c8a9a5SSteve French CREATE_DELETE_ON_CLOSE | OPEN_REPARSE_POINT, 879a90f37e3SSteve French ACL_NO_MODE, NULL, 880a90f37e3SSteve French &(int){SMB2_OP_DELETE}, 1, 881f93d145fSMeetakshi Setiya NULL, NULL, NULL, dentry); 88238c8a9a5SSteve French } 88338c8a9a5SSteve French 884c586b0c7SPaulo Alcantara static int smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon, 88538c8a9a5SSteve French const char *from_name, const char *to_name, 886c586b0c7SPaulo Alcantara struct cifs_sb_info *cifs_sb, 887c586b0c7SPaulo Alcantara __u32 create_options, __u32 access, 888f93d145fSMeetakshi Setiya int command, struct cifsFileInfo *cfile, 889f93d145fSMeetakshi Setiya struct dentry *dentry) 89038c8a9a5SSteve French { 891886b7fb4SSteve French struct kvec in_iov; 89238c8a9a5SSteve French __le16 *smb2_to_name = NULL; 89338c8a9a5SSteve French int rc; 89438c8a9a5SSteve French 89538c8a9a5SSteve French smb2_to_name = cifs_convert_path_to_utf16(to_name, cifs_sb); 89638c8a9a5SSteve French if (smb2_to_name == NULL) { 89738c8a9a5SSteve French rc = -ENOMEM; 89838c8a9a5SSteve French goto smb2_rename_path; 89938c8a9a5SSteve French } 900886b7fb4SSteve French in_iov.iov_base = smb2_to_name; 901886b7fb4SSteve French in_iov.iov_len = 2 * UniStrnlen((wchar_t *)smb2_to_name, PATH_MAX); 90238c8a9a5SSteve French rc = smb2_compound_op(xid, tcon, cifs_sb, from_name, access, 903a90f37e3SSteve French FILE_OPEN, create_options, ACL_NO_MODE, 904f93d145fSMeetakshi Setiya &in_iov, &command, 1, cfile, NULL, NULL, dentry); 90538c8a9a5SSteve French smb2_rename_path: 90638c8a9a5SSteve French kfree(smb2_to_name); 90738c8a9a5SSteve French return rc; 90838c8a9a5SSteve French } 90938c8a9a5SSteve French 910c586b0c7SPaulo Alcantara int smb2_rename_path(const unsigned int xid, 911c586b0c7SPaulo Alcantara struct cifs_tcon *tcon, 912c586b0c7SPaulo Alcantara struct dentry *source_dentry, 91338c8a9a5SSteve French const char *from_name, const char *to_name, 91438c8a9a5SSteve French struct cifs_sb_info *cifs_sb) 91538c8a9a5SSteve French { 91638c8a9a5SSteve French struct cifsFileInfo *cfile; 9178c944f8aSPaulo Alcantara __u32 co = file_create_options(source_dentry); 91838c8a9a5SSteve French 91938c8a9a5SSteve French drop_cached_dir_by_name(xid, tcon, from_name, cifs_sb); 92038c8a9a5SSteve French cifs_get_writable_path(tcon, from_name, FIND_WR_WITH_DELETE, &cfile); 92138c8a9a5SSteve French 922c586b0c7SPaulo Alcantara return smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb, 923f93d145fSMeetakshi Setiya co, DELETE, SMB2_OP_RENAME, cfile, source_dentry); 92438c8a9a5SSteve French } 92538c8a9a5SSteve French 9268c944f8aSPaulo Alcantara int smb2_create_hardlink(const unsigned int xid, 9278c944f8aSPaulo Alcantara struct cifs_tcon *tcon, 9288c944f8aSPaulo Alcantara struct dentry *source_dentry, 92938c8a9a5SSteve French const char *from_name, const char *to_name, 93038c8a9a5SSteve French struct cifs_sb_info *cifs_sb) 93138c8a9a5SSteve French { 9328c944f8aSPaulo Alcantara __u32 co = file_create_options(source_dentry); 9338c944f8aSPaulo Alcantara 934c586b0c7SPaulo Alcantara return smb2_set_path_attr(xid, tcon, from_name, to_name, 9358c944f8aSPaulo Alcantara cifs_sb, co, FILE_READ_ATTRIBUTES, 936f93d145fSMeetakshi Setiya SMB2_OP_HARDLINK, NULL, NULL); 93738c8a9a5SSteve French } 93838c8a9a5SSteve French 93938c8a9a5SSteve French int 94038c8a9a5SSteve French smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon, 94138c8a9a5SSteve French const char *full_path, __u64 size, 942f93d145fSMeetakshi Setiya struct cifs_sb_info *cifs_sb, bool set_alloc, 943f93d145fSMeetakshi Setiya struct dentry *dentry) 94438c8a9a5SSteve French { 94538c8a9a5SSteve French struct cifsFileInfo *cfile; 946886b7fb4SSteve French struct kvec in_iov; 947886b7fb4SSteve French __le64 eof = cpu_to_le64(size); 94838c8a9a5SSteve French 949886b7fb4SSteve French in_iov.iov_base = &eof; 950886b7fb4SSteve French in_iov.iov_len = sizeof(eof); 95138c8a9a5SSteve French cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile); 95238c8a9a5SSteve French return smb2_compound_op(xid, tcon, cifs_sb, full_path, 953886b7fb4SSteve French FILE_WRITE_DATA, FILE_OPEN, 954886b7fb4SSteve French 0, ACL_NO_MODE, &in_iov, 955886b7fb4SSteve French &(int){SMB2_OP_SET_EOF}, 1, 956f93d145fSMeetakshi Setiya cfile, NULL, NULL, dentry); 95738c8a9a5SSteve French } 95838c8a9a5SSteve French 95938c8a9a5SSteve French int 96038c8a9a5SSteve French smb2_set_file_info(struct inode *inode, const char *full_path, 96138c8a9a5SSteve French FILE_BASIC_INFO *buf, const unsigned int xid) 96238c8a9a5SSteve French { 96338c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 96438c8a9a5SSteve French struct tcon_link *tlink; 96538c8a9a5SSteve French struct cifs_tcon *tcon; 96638c8a9a5SSteve French struct cifsFileInfo *cfile; 967886b7fb4SSteve French struct kvec in_iov = { .iov_base = buf, .iov_len = sizeof(*buf), }; 96838c8a9a5SSteve French int rc; 96938c8a9a5SSteve French 97038c8a9a5SSteve French if ((buf->CreationTime == 0) && (buf->LastAccessTime == 0) && 97138c8a9a5SSteve French (buf->LastWriteTime == 0) && (buf->ChangeTime == 0) && 97238c8a9a5SSteve French (buf->Attributes == 0)) 97338c8a9a5SSteve French return 0; /* would be a no op, no sense sending this */ 97438c8a9a5SSteve French 97538c8a9a5SSteve French tlink = cifs_sb_tlink(cifs_sb); 97638c8a9a5SSteve French if (IS_ERR(tlink)) 97738c8a9a5SSteve French return PTR_ERR(tlink); 97838c8a9a5SSteve French tcon = tlink_tcon(tlink); 97938c8a9a5SSteve French 98038c8a9a5SSteve French cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile); 98138c8a9a5SSteve French rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, 98238c8a9a5SSteve French FILE_WRITE_ATTRIBUTES, FILE_OPEN, 983886b7fb4SSteve French 0, ACL_NO_MODE, &in_iov, 984a90f37e3SSteve French &(int){SMB2_OP_SET_INFO}, 1, 985f93d145fSMeetakshi Setiya cfile, NULL, NULL, NULL); 98638c8a9a5SSteve French cifs_put_tlink(tlink); 98738c8a9a5SSteve French return rc; 98838c8a9a5SSteve French } 98902bcf865SSteve French 99002bcf865SSteve French struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data, 99102bcf865SSteve French struct super_block *sb, 99202bcf865SSteve French const unsigned int xid, 99302bcf865SSteve French struct cifs_tcon *tcon, 99402bcf865SSteve French const char *full_path, 99502bcf865SSteve French struct kvec *iov) 99602bcf865SSteve French { 99702bcf865SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 99802bcf865SSteve French struct cifsFileInfo *cfile; 99902bcf865SSteve French struct inode *new = NULL; 100002bcf865SSteve French struct kvec in_iov[2]; 100102bcf865SSteve French int cmds[2]; 100202bcf865SSteve French int da, co, cd; 100302bcf865SSteve French int rc; 100402bcf865SSteve French 100502bcf865SSteve French da = SYNCHRONIZE | DELETE | 100602bcf865SSteve French FILE_READ_ATTRIBUTES | 100702bcf865SSteve French FILE_WRITE_ATTRIBUTES; 100802bcf865SSteve French co = CREATE_NOT_DIR | OPEN_REPARSE_POINT; 100902bcf865SSteve French cd = FILE_CREATE; 101002bcf865SSteve French cmds[0] = SMB2_OP_SET_REPARSE; 101102bcf865SSteve French in_iov[0] = *iov; 101202bcf865SSteve French in_iov[1].iov_base = data; 101302bcf865SSteve French in_iov[1].iov_len = sizeof(*data); 101402bcf865SSteve French 101502bcf865SSteve French if (tcon->posix_extensions) { 101602bcf865SSteve French cmds[1] = SMB2_OP_POSIX_QUERY_INFO; 101702bcf865SSteve French cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile); 101802bcf865SSteve French rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, 101902bcf865SSteve French da, cd, co, ACL_NO_MODE, in_iov, 1020f93d145fSMeetakshi Setiya cmds, 2, cfile, NULL, NULL, NULL); 102102bcf865SSteve French if (!rc) { 102202bcf865SSteve French rc = smb311_posix_get_inode_info(&new, full_path, 102302bcf865SSteve French data, sb, xid); 102402bcf865SSteve French } 102502bcf865SSteve French } else { 102602bcf865SSteve French cmds[1] = SMB2_OP_QUERY_INFO; 102702bcf865SSteve French cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile); 102802bcf865SSteve French rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, 102902bcf865SSteve French da, cd, co, ACL_NO_MODE, in_iov, 1030f93d145fSMeetakshi Setiya cmds, 2, cfile, NULL, NULL, NULL); 103102bcf865SSteve French if (!rc) { 103202bcf865SSteve French rc = cifs_get_inode_info(&new, full_path, 103302bcf865SSteve French data, sb, xid, NULL); 103402bcf865SSteve French } 103502bcf865SSteve French } 103602bcf865SSteve French return rc ? ERR_PTR(rc) : new; 103702bcf865SSteve French } 1038870c73abSPaulo Alcantara 1039870c73abSPaulo Alcantara int smb2_query_reparse_point(const unsigned int xid, 1040870c73abSPaulo Alcantara struct cifs_tcon *tcon, 1041870c73abSPaulo Alcantara struct cifs_sb_info *cifs_sb, 1042870c73abSPaulo Alcantara const char *full_path, 1043870c73abSPaulo Alcantara u32 *tag, struct kvec *rsp, 1044870c73abSPaulo Alcantara int *rsp_buftype) 1045870c73abSPaulo Alcantara { 1046870c73abSPaulo Alcantara struct cifs_open_info_data data = {}; 1047870c73abSPaulo Alcantara struct cifsFileInfo *cfile; 1048870c73abSPaulo Alcantara struct kvec in_iov = { .iov_base = &data, .iov_len = sizeof(data), }; 1049870c73abSPaulo Alcantara int rc; 1050870c73abSPaulo Alcantara 1051870c73abSPaulo Alcantara cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path); 1052870c73abSPaulo Alcantara 1053870c73abSPaulo Alcantara cifs_get_readable_path(tcon, full_path, &cfile); 1054870c73abSPaulo Alcantara rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, 1055870c73abSPaulo Alcantara FILE_READ_ATTRIBUTES, FILE_OPEN, 1056870c73abSPaulo Alcantara OPEN_REPARSE_POINT, ACL_NO_MODE, &in_iov, 1057a90f37e3SSteve French &(int){SMB2_OP_GET_REPARSE}, 1, 1058f93d145fSMeetakshi Setiya cfile, NULL, NULL, NULL); 1059870c73abSPaulo Alcantara if (rc) 1060870c73abSPaulo Alcantara goto out; 1061870c73abSPaulo Alcantara 1062870c73abSPaulo Alcantara *tag = data.reparse.tag; 1063870c73abSPaulo Alcantara *rsp = data.reparse.io.iov; 1064870c73abSPaulo Alcantara *rsp_buftype = data.reparse.io.buftype; 1065870c73abSPaulo Alcantara memset(&data.reparse.io.iov, 0, sizeof(data.reparse.io.iov)); 1066870c73abSPaulo Alcantara data.reparse.io.buftype = CIFS_NO_BUFFER; 1067870c73abSPaulo Alcantara out: 1068870c73abSPaulo Alcantara cifs_free_open_info(&data); 1069870c73abSPaulo Alcantara return rc; 1070870c73abSPaulo Alcantara } 1071