162306a36Sopenharmony_ci// SPDX-License-Identifier: LGPL-2.1 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) International Business Machines Corp., 2002, 2011 562306a36Sopenharmony_ci * Etersoft, 2012 662306a36Sopenharmony_ci * Author(s): Pavel Shilovsky (pshilovsky@samba.org), 762306a36Sopenharmony_ci * Steve French (sfrench@us.ibm.com) 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci#include <linux/fs.h> 1162306a36Sopenharmony_ci#include <linux/stat.h> 1262306a36Sopenharmony_ci#include <linux/slab.h> 1362306a36Sopenharmony_ci#include <linux/pagemap.h> 1462306a36Sopenharmony_ci#include <asm/div64.h> 1562306a36Sopenharmony_ci#include "cifsfs.h" 1662306a36Sopenharmony_ci#include "cifspdu.h" 1762306a36Sopenharmony_ci#include "cifsglob.h" 1862306a36Sopenharmony_ci#include "cifsproto.h" 1962306a36Sopenharmony_ci#include "cifs_debug.h" 2062306a36Sopenharmony_ci#include "cifs_fs_sb.h" 2162306a36Sopenharmony_ci#include "cifs_unicode.h" 2262306a36Sopenharmony_ci#include "fscache.h" 2362306a36Sopenharmony_ci#include "smb2glob.h" 2462306a36Sopenharmony_ci#include "smb2pdu.h" 2562306a36Sopenharmony_ci#include "smb2proto.h" 2662306a36Sopenharmony_ci#include "cached_dir.h" 2762306a36Sopenharmony_ci#include "smb2status.h" 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistatic void 3062306a36Sopenharmony_cifree_set_inf_compound(struct smb_rqst *rqst) 3162306a36Sopenharmony_ci{ 3262306a36Sopenharmony_ci if (rqst[1].rq_iov) 3362306a36Sopenharmony_ci SMB2_set_info_free(&rqst[1]); 3462306a36Sopenharmony_ci if (rqst[2].rq_iov) 3562306a36Sopenharmony_ci SMB2_close_free(&rqst[2]); 3662306a36Sopenharmony_ci} 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic inline __u32 file_create_options(struct dentry *dentry) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci struct cifsInodeInfo *ci; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci if (dentry) { 4362306a36Sopenharmony_ci ci = CIFS_I(d_inode(dentry)); 4462306a36Sopenharmony_ci if (ci->cifsAttrs & ATTR_REPARSE) 4562306a36Sopenharmony_ci return OPEN_REPARSE_POINT; 4662306a36Sopenharmony_ci } 4762306a36Sopenharmony_ci return 0; 4862306a36Sopenharmony_ci} 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci/* 5162306a36Sopenharmony_ci * note: If cfile is passed, the reference to it is dropped here. 5262306a36Sopenharmony_ci * So make sure that you do not reuse cfile after return from this func. 5362306a36Sopenharmony_ci * 5462306a36Sopenharmony_ci * If passing @out_iov and @out_buftype, ensure to make them both large enough 5562306a36Sopenharmony_ci * (>= 3) to hold all compounded responses. Caller is also responsible for 5662306a36Sopenharmony_ci * freeing them up with free_rsp_buf(). 5762306a36Sopenharmony_ci */ 5862306a36Sopenharmony_cistatic int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, 5962306a36Sopenharmony_ci struct cifs_sb_info *cifs_sb, const char *full_path, 6062306a36Sopenharmony_ci __u32 desired_access, __u32 create_disposition, __u32 create_options, 6162306a36Sopenharmony_ci umode_t mode, void *ptr, int command, struct cifsFileInfo *cfile, 6262306a36Sopenharmony_ci __u8 **extbuf, size_t *extbuflen, 6362306a36Sopenharmony_ci struct kvec *out_iov, int *out_buftype) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci struct smb2_compound_vars *vars = NULL; 6662306a36Sopenharmony_ci struct kvec *rsp_iov; 6762306a36Sopenharmony_ci struct smb_rqst *rqst; 6862306a36Sopenharmony_ci int rc; 6962306a36Sopenharmony_ci __le16 *utf16_path = NULL; 7062306a36Sopenharmony_ci __u8 oplock = SMB2_OPLOCK_LEVEL_NONE; 7162306a36Sopenharmony_ci struct cifs_fid fid; 7262306a36Sopenharmony_ci struct cifs_ses *ses = tcon->ses; 7362306a36Sopenharmony_ci struct TCP_Server_Info *server; 7462306a36Sopenharmony_ci int num_rqst = 0; 7562306a36Sopenharmony_ci int resp_buftype[3]; 7662306a36Sopenharmony_ci struct smb2_query_info_rsp *qi_rsp = NULL; 7762306a36Sopenharmony_ci struct cifs_open_info_data *idata; 7862306a36Sopenharmony_ci int flags = 0; 7962306a36Sopenharmony_ci __u8 delete_pending[8] = {1, 0, 0, 0, 0, 0, 0, 0}; 8062306a36Sopenharmony_ci unsigned int size[2]; 8162306a36Sopenharmony_ci void *data[2]; 8262306a36Sopenharmony_ci int len; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci vars = kzalloc(sizeof(*vars), GFP_ATOMIC); 8562306a36Sopenharmony_ci if (vars == NULL) 8662306a36Sopenharmony_ci return -ENOMEM; 8762306a36Sopenharmony_ci rqst = &vars->rqst[0]; 8862306a36Sopenharmony_ci rsp_iov = &vars->rsp_iov[0]; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci server = cifs_pick_channel(ses); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci if (smb3_encryption_required(tcon)) 9362306a36Sopenharmony_ci flags |= CIFS_TRANSFORM_REQ; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci /* We already have a handle so we can skip the open */ 9862306a36Sopenharmony_ci if (cfile) 9962306a36Sopenharmony_ci goto after_open; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci /* Open */ 10262306a36Sopenharmony_ci utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb); 10362306a36Sopenharmony_ci if (!utf16_path) { 10462306a36Sopenharmony_ci rc = -ENOMEM; 10562306a36Sopenharmony_ci goto finished; 10662306a36Sopenharmony_ci } 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci vars->oparms = (struct cifs_open_parms) { 10962306a36Sopenharmony_ci .tcon = tcon, 11062306a36Sopenharmony_ci .path = full_path, 11162306a36Sopenharmony_ci .desired_access = desired_access, 11262306a36Sopenharmony_ci .disposition = create_disposition, 11362306a36Sopenharmony_ci .create_options = cifs_create_options(cifs_sb, create_options), 11462306a36Sopenharmony_ci .fid = &fid, 11562306a36Sopenharmony_ci .mode = mode, 11662306a36Sopenharmony_ci .cifs_sb = cifs_sb, 11762306a36Sopenharmony_ci }; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci rqst[num_rqst].rq_iov = &vars->open_iov[0]; 12062306a36Sopenharmony_ci rqst[num_rqst].rq_nvec = SMB2_CREATE_IOV_SIZE; 12162306a36Sopenharmony_ci rc = SMB2_open_init(tcon, server, 12262306a36Sopenharmony_ci &rqst[num_rqst], &oplock, &vars->oparms, 12362306a36Sopenharmony_ci utf16_path); 12462306a36Sopenharmony_ci kfree(utf16_path); 12562306a36Sopenharmony_ci if (rc) 12662306a36Sopenharmony_ci goto finished; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci smb2_set_next_command(tcon, &rqst[num_rqst]); 12962306a36Sopenharmony_ci after_open: 13062306a36Sopenharmony_ci num_rqst++; 13162306a36Sopenharmony_ci rc = 0; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci /* Operation */ 13462306a36Sopenharmony_ci switch (command) { 13562306a36Sopenharmony_ci case SMB2_OP_QUERY_INFO: 13662306a36Sopenharmony_ci rqst[num_rqst].rq_iov = &vars->qi_iov; 13762306a36Sopenharmony_ci rqst[num_rqst].rq_nvec = 1; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci if (cfile) 14062306a36Sopenharmony_ci rc = SMB2_query_info_init(tcon, server, 14162306a36Sopenharmony_ci &rqst[num_rqst], 14262306a36Sopenharmony_ci cfile->fid.persistent_fid, 14362306a36Sopenharmony_ci cfile->fid.volatile_fid, 14462306a36Sopenharmony_ci FILE_ALL_INFORMATION, 14562306a36Sopenharmony_ci SMB2_O_INFO_FILE, 0, 14662306a36Sopenharmony_ci sizeof(struct smb2_file_all_info) + 14762306a36Sopenharmony_ci PATH_MAX * 2, 0, NULL); 14862306a36Sopenharmony_ci else { 14962306a36Sopenharmony_ci rc = SMB2_query_info_init(tcon, server, 15062306a36Sopenharmony_ci &rqst[num_rqst], 15162306a36Sopenharmony_ci COMPOUND_FID, 15262306a36Sopenharmony_ci COMPOUND_FID, 15362306a36Sopenharmony_ci FILE_ALL_INFORMATION, 15462306a36Sopenharmony_ci SMB2_O_INFO_FILE, 0, 15562306a36Sopenharmony_ci sizeof(struct smb2_file_all_info) + 15662306a36Sopenharmony_ci PATH_MAX * 2, 0, NULL); 15762306a36Sopenharmony_ci if (!rc) { 15862306a36Sopenharmony_ci smb2_set_next_command(tcon, &rqst[num_rqst]); 15962306a36Sopenharmony_ci smb2_set_related(&rqst[num_rqst]); 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci } 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci if (rc) 16462306a36Sopenharmony_ci goto finished; 16562306a36Sopenharmony_ci num_rqst++; 16662306a36Sopenharmony_ci trace_smb3_query_info_compound_enter(xid, ses->Suid, tcon->tid, 16762306a36Sopenharmony_ci full_path); 16862306a36Sopenharmony_ci break; 16962306a36Sopenharmony_ci case SMB2_OP_POSIX_QUERY_INFO: 17062306a36Sopenharmony_ci rqst[num_rqst].rq_iov = &vars->qi_iov; 17162306a36Sopenharmony_ci rqst[num_rqst].rq_nvec = 1; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci if (cfile) 17462306a36Sopenharmony_ci rc = SMB2_query_info_init(tcon, server, 17562306a36Sopenharmony_ci &rqst[num_rqst], 17662306a36Sopenharmony_ci cfile->fid.persistent_fid, 17762306a36Sopenharmony_ci cfile->fid.volatile_fid, 17862306a36Sopenharmony_ci SMB_FIND_FILE_POSIX_INFO, 17962306a36Sopenharmony_ci SMB2_O_INFO_FILE, 0, 18062306a36Sopenharmony_ci /* TBD: fix following to allow for longer SIDs */ 18162306a36Sopenharmony_ci sizeof(struct smb311_posix_qinfo *) + (PATH_MAX * 2) + 18262306a36Sopenharmony_ci (sizeof(struct cifs_sid) * 2), 0, NULL); 18362306a36Sopenharmony_ci else { 18462306a36Sopenharmony_ci rc = SMB2_query_info_init(tcon, server, 18562306a36Sopenharmony_ci &rqst[num_rqst], 18662306a36Sopenharmony_ci COMPOUND_FID, 18762306a36Sopenharmony_ci COMPOUND_FID, 18862306a36Sopenharmony_ci SMB_FIND_FILE_POSIX_INFO, 18962306a36Sopenharmony_ci SMB2_O_INFO_FILE, 0, 19062306a36Sopenharmony_ci sizeof(struct smb311_posix_qinfo *) + (PATH_MAX * 2) + 19162306a36Sopenharmony_ci (sizeof(struct cifs_sid) * 2), 0, NULL); 19262306a36Sopenharmony_ci if (!rc) { 19362306a36Sopenharmony_ci smb2_set_next_command(tcon, &rqst[num_rqst]); 19462306a36Sopenharmony_ci smb2_set_related(&rqst[num_rqst]); 19562306a36Sopenharmony_ci } 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci if (rc) 19962306a36Sopenharmony_ci goto finished; 20062306a36Sopenharmony_ci num_rqst++; 20162306a36Sopenharmony_ci trace_smb3_posix_query_info_compound_enter(xid, ses->Suid, tcon->tid, full_path); 20262306a36Sopenharmony_ci break; 20362306a36Sopenharmony_ci case SMB2_OP_DELETE: 20462306a36Sopenharmony_ci trace_smb3_delete_enter(xid, ses->Suid, tcon->tid, full_path); 20562306a36Sopenharmony_ci break; 20662306a36Sopenharmony_ci case SMB2_OP_MKDIR: 20762306a36Sopenharmony_ci /* 20862306a36Sopenharmony_ci * Directories are created through parameters in the 20962306a36Sopenharmony_ci * SMB2_open() call. 21062306a36Sopenharmony_ci */ 21162306a36Sopenharmony_ci trace_smb3_mkdir_enter(xid, ses->Suid, tcon->tid, full_path); 21262306a36Sopenharmony_ci break; 21362306a36Sopenharmony_ci case SMB2_OP_RMDIR: 21462306a36Sopenharmony_ci rqst[num_rqst].rq_iov = &vars->si_iov[0]; 21562306a36Sopenharmony_ci rqst[num_rqst].rq_nvec = 1; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci size[0] = 1; /* sizeof __u8 See MS-FSCC section 2.4.11 */ 21862306a36Sopenharmony_ci data[0] = &delete_pending[0]; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci rc = SMB2_set_info_init(tcon, server, 22162306a36Sopenharmony_ci &rqst[num_rqst], COMPOUND_FID, 22262306a36Sopenharmony_ci COMPOUND_FID, current->tgid, 22362306a36Sopenharmony_ci FILE_DISPOSITION_INFORMATION, 22462306a36Sopenharmony_ci SMB2_O_INFO_FILE, 0, data, size); 22562306a36Sopenharmony_ci if (rc) 22662306a36Sopenharmony_ci goto finished; 22762306a36Sopenharmony_ci smb2_set_next_command(tcon, &rqst[num_rqst]); 22862306a36Sopenharmony_ci smb2_set_related(&rqst[num_rqst++]); 22962306a36Sopenharmony_ci trace_smb3_rmdir_enter(xid, ses->Suid, tcon->tid, full_path); 23062306a36Sopenharmony_ci break; 23162306a36Sopenharmony_ci case SMB2_OP_SET_EOF: 23262306a36Sopenharmony_ci rqst[num_rqst].rq_iov = &vars->si_iov[0]; 23362306a36Sopenharmony_ci rqst[num_rqst].rq_nvec = 1; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci size[0] = 8; /* sizeof __le64 */ 23662306a36Sopenharmony_ci data[0] = ptr; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci if (cfile) { 23962306a36Sopenharmony_ci rc = SMB2_set_info_init(tcon, server, 24062306a36Sopenharmony_ci &rqst[num_rqst], 24162306a36Sopenharmony_ci cfile->fid.persistent_fid, 24262306a36Sopenharmony_ci cfile->fid.volatile_fid, 24362306a36Sopenharmony_ci current->tgid, 24462306a36Sopenharmony_ci FILE_END_OF_FILE_INFORMATION, 24562306a36Sopenharmony_ci SMB2_O_INFO_FILE, 0, 24662306a36Sopenharmony_ci data, size); 24762306a36Sopenharmony_ci } else { 24862306a36Sopenharmony_ci rc = SMB2_set_info_init(tcon, server, 24962306a36Sopenharmony_ci &rqst[num_rqst], 25062306a36Sopenharmony_ci COMPOUND_FID, 25162306a36Sopenharmony_ci COMPOUND_FID, 25262306a36Sopenharmony_ci current->tgid, 25362306a36Sopenharmony_ci FILE_END_OF_FILE_INFORMATION, 25462306a36Sopenharmony_ci SMB2_O_INFO_FILE, 0, 25562306a36Sopenharmony_ci data, size); 25662306a36Sopenharmony_ci if (!rc) { 25762306a36Sopenharmony_ci smb2_set_next_command(tcon, &rqst[num_rqst]); 25862306a36Sopenharmony_ci smb2_set_related(&rqst[num_rqst]); 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci if (rc) 26262306a36Sopenharmony_ci goto finished; 26362306a36Sopenharmony_ci num_rqst++; 26462306a36Sopenharmony_ci trace_smb3_set_eof_enter(xid, ses->Suid, tcon->tid, full_path); 26562306a36Sopenharmony_ci break; 26662306a36Sopenharmony_ci case SMB2_OP_SET_INFO: 26762306a36Sopenharmony_ci rqst[num_rqst].rq_iov = &vars->si_iov[0]; 26862306a36Sopenharmony_ci rqst[num_rqst].rq_nvec = 1; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci size[0] = sizeof(FILE_BASIC_INFO); 27262306a36Sopenharmony_ci data[0] = ptr; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci if (cfile) 27562306a36Sopenharmony_ci rc = SMB2_set_info_init(tcon, server, 27662306a36Sopenharmony_ci &rqst[num_rqst], 27762306a36Sopenharmony_ci cfile->fid.persistent_fid, 27862306a36Sopenharmony_ci cfile->fid.volatile_fid, current->tgid, 27962306a36Sopenharmony_ci FILE_BASIC_INFORMATION, 28062306a36Sopenharmony_ci SMB2_O_INFO_FILE, 0, data, size); 28162306a36Sopenharmony_ci else { 28262306a36Sopenharmony_ci rc = SMB2_set_info_init(tcon, server, 28362306a36Sopenharmony_ci &rqst[num_rqst], 28462306a36Sopenharmony_ci COMPOUND_FID, 28562306a36Sopenharmony_ci COMPOUND_FID, current->tgid, 28662306a36Sopenharmony_ci FILE_BASIC_INFORMATION, 28762306a36Sopenharmony_ci SMB2_O_INFO_FILE, 0, data, size); 28862306a36Sopenharmony_ci if (!rc) { 28962306a36Sopenharmony_ci smb2_set_next_command(tcon, &rqst[num_rqst]); 29062306a36Sopenharmony_ci smb2_set_related(&rqst[num_rqst]); 29162306a36Sopenharmony_ci } 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci if (rc) 29562306a36Sopenharmony_ci goto finished; 29662306a36Sopenharmony_ci num_rqst++; 29762306a36Sopenharmony_ci trace_smb3_set_info_compound_enter(xid, ses->Suid, tcon->tid, 29862306a36Sopenharmony_ci full_path); 29962306a36Sopenharmony_ci break; 30062306a36Sopenharmony_ci case SMB2_OP_RENAME: 30162306a36Sopenharmony_ci rqst[num_rqst].rq_iov = &vars->si_iov[0]; 30262306a36Sopenharmony_ci rqst[num_rqst].rq_nvec = 2; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci len = (2 * UniStrnlen((wchar_t *)ptr, PATH_MAX)); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci vars->rename_info.ReplaceIfExists = 1; 30762306a36Sopenharmony_ci vars->rename_info.RootDirectory = 0; 30862306a36Sopenharmony_ci vars->rename_info.FileNameLength = cpu_to_le32(len); 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci size[0] = sizeof(struct smb2_file_rename_info); 31162306a36Sopenharmony_ci data[0] = &vars->rename_info; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci size[1] = len + 2 /* null */; 31462306a36Sopenharmony_ci data[1] = (__le16 *)ptr; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci if (cfile) 31762306a36Sopenharmony_ci rc = SMB2_set_info_init(tcon, server, 31862306a36Sopenharmony_ci &rqst[num_rqst], 31962306a36Sopenharmony_ci cfile->fid.persistent_fid, 32062306a36Sopenharmony_ci cfile->fid.volatile_fid, 32162306a36Sopenharmony_ci current->tgid, FILE_RENAME_INFORMATION, 32262306a36Sopenharmony_ci SMB2_O_INFO_FILE, 0, data, size); 32362306a36Sopenharmony_ci else { 32462306a36Sopenharmony_ci rc = SMB2_set_info_init(tcon, server, 32562306a36Sopenharmony_ci &rqst[num_rqst], 32662306a36Sopenharmony_ci COMPOUND_FID, COMPOUND_FID, 32762306a36Sopenharmony_ci current->tgid, FILE_RENAME_INFORMATION, 32862306a36Sopenharmony_ci SMB2_O_INFO_FILE, 0, data, size); 32962306a36Sopenharmony_ci if (!rc) { 33062306a36Sopenharmony_ci smb2_set_next_command(tcon, &rqst[num_rqst]); 33162306a36Sopenharmony_ci smb2_set_related(&rqst[num_rqst]); 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci if (rc) 33562306a36Sopenharmony_ci goto finished; 33662306a36Sopenharmony_ci num_rqst++; 33762306a36Sopenharmony_ci trace_smb3_rename_enter(xid, ses->Suid, tcon->tid, full_path); 33862306a36Sopenharmony_ci break; 33962306a36Sopenharmony_ci case SMB2_OP_HARDLINK: 34062306a36Sopenharmony_ci rqst[num_rqst].rq_iov = &vars->si_iov[0]; 34162306a36Sopenharmony_ci rqst[num_rqst].rq_nvec = 2; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci len = (2 * UniStrnlen((wchar_t *)ptr, PATH_MAX)); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci vars->link_info.ReplaceIfExists = 0; 34662306a36Sopenharmony_ci vars->link_info.RootDirectory = 0; 34762306a36Sopenharmony_ci vars->link_info.FileNameLength = cpu_to_le32(len); 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci size[0] = sizeof(struct smb2_file_link_info); 35062306a36Sopenharmony_ci data[0] = &vars->link_info; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci size[1] = len + 2 /* null */; 35362306a36Sopenharmony_ci data[1] = (__le16 *)ptr; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci rc = SMB2_set_info_init(tcon, server, 35662306a36Sopenharmony_ci &rqst[num_rqst], COMPOUND_FID, 35762306a36Sopenharmony_ci COMPOUND_FID, current->tgid, 35862306a36Sopenharmony_ci FILE_LINK_INFORMATION, 35962306a36Sopenharmony_ci SMB2_O_INFO_FILE, 0, data, size); 36062306a36Sopenharmony_ci if (rc) 36162306a36Sopenharmony_ci goto finished; 36262306a36Sopenharmony_ci smb2_set_next_command(tcon, &rqst[num_rqst]); 36362306a36Sopenharmony_ci smb2_set_related(&rqst[num_rqst++]); 36462306a36Sopenharmony_ci trace_smb3_hardlink_enter(xid, ses->Suid, tcon->tid, full_path); 36562306a36Sopenharmony_ci break; 36662306a36Sopenharmony_ci default: 36762306a36Sopenharmony_ci cifs_dbg(VFS, "Invalid command\n"); 36862306a36Sopenharmony_ci rc = -EINVAL; 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci if (rc) 37162306a36Sopenharmony_ci goto finished; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci /* We already have a handle so we can skip the close */ 37462306a36Sopenharmony_ci if (cfile) 37562306a36Sopenharmony_ci goto after_close; 37662306a36Sopenharmony_ci /* Close */ 37762306a36Sopenharmony_ci flags |= CIFS_CP_CREATE_CLOSE_OP; 37862306a36Sopenharmony_ci rqst[num_rqst].rq_iov = &vars->close_iov; 37962306a36Sopenharmony_ci rqst[num_rqst].rq_nvec = 1; 38062306a36Sopenharmony_ci rc = SMB2_close_init(tcon, server, 38162306a36Sopenharmony_ci &rqst[num_rqst], COMPOUND_FID, 38262306a36Sopenharmony_ci COMPOUND_FID, false); 38362306a36Sopenharmony_ci smb2_set_related(&rqst[num_rqst]); 38462306a36Sopenharmony_ci if (rc) 38562306a36Sopenharmony_ci goto finished; 38662306a36Sopenharmony_ci after_close: 38762306a36Sopenharmony_ci num_rqst++; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci if (cfile) { 39062306a36Sopenharmony_ci rc = compound_send_recv(xid, ses, server, 39162306a36Sopenharmony_ci flags, num_rqst - 2, 39262306a36Sopenharmony_ci &rqst[1], &resp_buftype[1], 39362306a36Sopenharmony_ci &rsp_iov[1]); 39462306a36Sopenharmony_ci } else 39562306a36Sopenharmony_ci rc = compound_send_recv(xid, ses, server, 39662306a36Sopenharmony_ci flags, num_rqst, 39762306a36Sopenharmony_ci rqst, resp_buftype, 39862306a36Sopenharmony_ci rsp_iov); 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci finished: 40162306a36Sopenharmony_ci SMB2_open_free(&rqst[0]); 40262306a36Sopenharmony_ci if (rc == -EREMCHG) { 40362306a36Sopenharmony_ci pr_warn_once("server share %s deleted\n", tcon->tree_name); 40462306a36Sopenharmony_ci tcon->need_reconnect = true; 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci switch (command) { 40862306a36Sopenharmony_ci case SMB2_OP_QUERY_INFO: 40962306a36Sopenharmony_ci idata = ptr; 41062306a36Sopenharmony_ci if (rc == 0 && cfile && cfile->symlink_target) { 41162306a36Sopenharmony_ci idata->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL); 41262306a36Sopenharmony_ci if (!idata->symlink_target) 41362306a36Sopenharmony_ci rc = -ENOMEM; 41462306a36Sopenharmony_ci } 41562306a36Sopenharmony_ci if (rc == 0) { 41662306a36Sopenharmony_ci qi_rsp = (struct smb2_query_info_rsp *) 41762306a36Sopenharmony_ci rsp_iov[1].iov_base; 41862306a36Sopenharmony_ci rc = smb2_validate_and_copy_iov( 41962306a36Sopenharmony_ci le16_to_cpu(qi_rsp->OutputBufferOffset), 42062306a36Sopenharmony_ci le32_to_cpu(qi_rsp->OutputBufferLength), 42162306a36Sopenharmony_ci &rsp_iov[1], sizeof(idata->fi), (char *)&idata->fi); 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci if (rqst[1].rq_iov) 42462306a36Sopenharmony_ci SMB2_query_info_free(&rqst[1]); 42562306a36Sopenharmony_ci if (rqst[2].rq_iov) 42662306a36Sopenharmony_ci SMB2_close_free(&rqst[2]); 42762306a36Sopenharmony_ci if (rc) 42862306a36Sopenharmony_ci trace_smb3_query_info_compound_err(xid, ses->Suid, 42962306a36Sopenharmony_ci tcon->tid, rc); 43062306a36Sopenharmony_ci else 43162306a36Sopenharmony_ci trace_smb3_query_info_compound_done(xid, ses->Suid, 43262306a36Sopenharmony_ci tcon->tid); 43362306a36Sopenharmony_ci break; 43462306a36Sopenharmony_ci case SMB2_OP_POSIX_QUERY_INFO: 43562306a36Sopenharmony_ci idata = ptr; 43662306a36Sopenharmony_ci if (rc == 0 && cfile && cfile->symlink_target) { 43762306a36Sopenharmony_ci idata->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL); 43862306a36Sopenharmony_ci if (!idata->symlink_target) 43962306a36Sopenharmony_ci rc = -ENOMEM; 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ci if (rc == 0) { 44262306a36Sopenharmony_ci qi_rsp = (struct smb2_query_info_rsp *) 44362306a36Sopenharmony_ci rsp_iov[1].iov_base; 44462306a36Sopenharmony_ci rc = smb2_validate_and_copy_iov( 44562306a36Sopenharmony_ci le16_to_cpu(qi_rsp->OutputBufferOffset), 44662306a36Sopenharmony_ci le32_to_cpu(qi_rsp->OutputBufferLength), 44762306a36Sopenharmony_ci &rsp_iov[1], sizeof(idata->posix_fi) /* add SIDs */, 44862306a36Sopenharmony_ci (char *)&idata->posix_fi); 44962306a36Sopenharmony_ci } 45062306a36Sopenharmony_ci if (rc == 0) { 45162306a36Sopenharmony_ci unsigned int length = le32_to_cpu(qi_rsp->OutputBufferLength); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci if (length > sizeof(idata->posix_fi)) { 45462306a36Sopenharmony_ci char *base = (char *)rsp_iov[1].iov_base + 45562306a36Sopenharmony_ci le16_to_cpu(qi_rsp->OutputBufferOffset) + 45662306a36Sopenharmony_ci sizeof(idata->posix_fi); 45762306a36Sopenharmony_ci *extbuflen = length - sizeof(idata->posix_fi); 45862306a36Sopenharmony_ci *extbuf = kmemdup(base, *extbuflen, GFP_KERNEL); 45962306a36Sopenharmony_ci if (!*extbuf) 46062306a36Sopenharmony_ci rc = -ENOMEM; 46162306a36Sopenharmony_ci } else { 46262306a36Sopenharmony_ci rc = -EINVAL; 46362306a36Sopenharmony_ci } 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci if (rqst[1].rq_iov) 46662306a36Sopenharmony_ci SMB2_query_info_free(&rqst[1]); 46762306a36Sopenharmony_ci if (rqst[2].rq_iov) 46862306a36Sopenharmony_ci SMB2_close_free(&rqst[2]); 46962306a36Sopenharmony_ci if (rc) 47062306a36Sopenharmony_ci trace_smb3_posix_query_info_compound_err(xid, ses->Suid, tcon->tid, rc); 47162306a36Sopenharmony_ci else 47262306a36Sopenharmony_ci trace_smb3_posix_query_info_compound_done(xid, ses->Suid, tcon->tid); 47362306a36Sopenharmony_ci break; 47462306a36Sopenharmony_ci case SMB2_OP_DELETE: 47562306a36Sopenharmony_ci if (rc) 47662306a36Sopenharmony_ci trace_smb3_delete_err(xid, ses->Suid, tcon->tid, rc); 47762306a36Sopenharmony_ci else 47862306a36Sopenharmony_ci trace_smb3_delete_done(xid, ses->Suid, tcon->tid); 47962306a36Sopenharmony_ci if (rqst[1].rq_iov) 48062306a36Sopenharmony_ci SMB2_close_free(&rqst[1]); 48162306a36Sopenharmony_ci break; 48262306a36Sopenharmony_ci case SMB2_OP_MKDIR: 48362306a36Sopenharmony_ci if (rc) 48462306a36Sopenharmony_ci trace_smb3_mkdir_err(xid, ses->Suid, tcon->tid, rc); 48562306a36Sopenharmony_ci else 48662306a36Sopenharmony_ci trace_smb3_mkdir_done(xid, ses->Suid, tcon->tid); 48762306a36Sopenharmony_ci if (rqst[1].rq_iov) 48862306a36Sopenharmony_ci SMB2_close_free(&rqst[1]); 48962306a36Sopenharmony_ci break; 49062306a36Sopenharmony_ci case SMB2_OP_HARDLINK: 49162306a36Sopenharmony_ci if (rc) 49262306a36Sopenharmony_ci trace_smb3_hardlink_err(xid, ses->Suid, tcon->tid, rc); 49362306a36Sopenharmony_ci else 49462306a36Sopenharmony_ci trace_smb3_hardlink_done(xid, ses->Suid, tcon->tid); 49562306a36Sopenharmony_ci free_set_inf_compound(rqst); 49662306a36Sopenharmony_ci break; 49762306a36Sopenharmony_ci case SMB2_OP_RENAME: 49862306a36Sopenharmony_ci if (rc) 49962306a36Sopenharmony_ci trace_smb3_rename_err(xid, ses->Suid, tcon->tid, rc); 50062306a36Sopenharmony_ci else 50162306a36Sopenharmony_ci trace_smb3_rename_done(xid, ses->Suid, tcon->tid); 50262306a36Sopenharmony_ci free_set_inf_compound(rqst); 50362306a36Sopenharmony_ci break; 50462306a36Sopenharmony_ci case SMB2_OP_RMDIR: 50562306a36Sopenharmony_ci if (rc) 50662306a36Sopenharmony_ci trace_smb3_rmdir_err(xid, ses->Suid, tcon->tid, rc); 50762306a36Sopenharmony_ci else 50862306a36Sopenharmony_ci trace_smb3_rmdir_done(xid, ses->Suid, tcon->tid); 50962306a36Sopenharmony_ci free_set_inf_compound(rqst); 51062306a36Sopenharmony_ci break; 51162306a36Sopenharmony_ci case SMB2_OP_SET_EOF: 51262306a36Sopenharmony_ci if (rc) 51362306a36Sopenharmony_ci trace_smb3_set_eof_err(xid, ses->Suid, tcon->tid, rc); 51462306a36Sopenharmony_ci else 51562306a36Sopenharmony_ci trace_smb3_set_eof_done(xid, ses->Suid, tcon->tid); 51662306a36Sopenharmony_ci free_set_inf_compound(rqst); 51762306a36Sopenharmony_ci break; 51862306a36Sopenharmony_ci case SMB2_OP_SET_INFO: 51962306a36Sopenharmony_ci if (rc) 52062306a36Sopenharmony_ci trace_smb3_set_info_compound_err(xid, ses->Suid, 52162306a36Sopenharmony_ci tcon->tid, rc); 52262306a36Sopenharmony_ci else 52362306a36Sopenharmony_ci trace_smb3_set_info_compound_done(xid, ses->Suid, 52462306a36Sopenharmony_ci tcon->tid); 52562306a36Sopenharmony_ci free_set_inf_compound(rqst); 52662306a36Sopenharmony_ci break; 52762306a36Sopenharmony_ci } 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci if (cfile) 53062306a36Sopenharmony_ci cifsFileInfo_put(cfile); 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci if (out_iov && out_buftype) { 53362306a36Sopenharmony_ci memcpy(out_iov, rsp_iov, 3 * sizeof(*out_iov)); 53462306a36Sopenharmony_ci memcpy(out_buftype, resp_buftype, 3 * sizeof(*out_buftype)); 53562306a36Sopenharmony_ci } else { 53662306a36Sopenharmony_ci free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base); 53762306a36Sopenharmony_ci free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base); 53862306a36Sopenharmony_ci free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base); 53962306a36Sopenharmony_ci } 54062306a36Sopenharmony_ci kfree(vars); 54162306a36Sopenharmony_ci return rc; 54262306a36Sopenharmony_ci} 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_cistatic int parse_create_response(struct cifs_open_info_data *data, 54562306a36Sopenharmony_ci struct cifs_sb_info *cifs_sb, 54662306a36Sopenharmony_ci const struct kvec *iov) 54762306a36Sopenharmony_ci{ 54862306a36Sopenharmony_ci struct smb2_create_rsp *rsp = iov->iov_base; 54962306a36Sopenharmony_ci bool reparse_point = false; 55062306a36Sopenharmony_ci u32 tag = 0; 55162306a36Sopenharmony_ci int rc = 0; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci switch (rsp->hdr.Status) { 55462306a36Sopenharmony_ci case STATUS_IO_REPARSE_TAG_NOT_HANDLED: 55562306a36Sopenharmony_ci reparse_point = true; 55662306a36Sopenharmony_ci break; 55762306a36Sopenharmony_ci case STATUS_STOPPED_ON_SYMLINK: 55862306a36Sopenharmony_ci rc = smb2_parse_symlink_response(cifs_sb, iov, 55962306a36Sopenharmony_ci &data->symlink_target); 56062306a36Sopenharmony_ci if (rc) 56162306a36Sopenharmony_ci return rc; 56262306a36Sopenharmony_ci tag = IO_REPARSE_TAG_SYMLINK; 56362306a36Sopenharmony_ci reparse_point = true; 56462306a36Sopenharmony_ci break; 56562306a36Sopenharmony_ci case STATUS_SUCCESS: 56662306a36Sopenharmony_ci reparse_point = !!(rsp->Flags & SMB2_CREATE_FLAG_REPARSEPOINT); 56762306a36Sopenharmony_ci break; 56862306a36Sopenharmony_ci } 56962306a36Sopenharmony_ci data->reparse_point = reparse_point; 57062306a36Sopenharmony_ci data->reparse.tag = tag; 57162306a36Sopenharmony_ci return rc; 57262306a36Sopenharmony_ci} 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ciint smb2_query_path_info(const unsigned int xid, 57562306a36Sopenharmony_ci struct cifs_tcon *tcon, 57662306a36Sopenharmony_ci struct cifs_sb_info *cifs_sb, 57762306a36Sopenharmony_ci const char *full_path, 57862306a36Sopenharmony_ci struct cifs_open_info_data *data) 57962306a36Sopenharmony_ci{ 58062306a36Sopenharmony_ci __u32 create_options = 0; 58162306a36Sopenharmony_ci struct cifsFileInfo *cfile; 58262306a36Sopenharmony_ci struct cached_fid *cfid = NULL; 58362306a36Sopenharmony_ci struct smb2_hdr *hdr; 58462306a36Sopenharmony_ci struct kvec out_iov[3] = {}; 58562306a36Sopenharmony_ci int out_buftype[3] = {}; 58662306a36Sopenharmony_ci bool islink; 58762306a36Sopenharmony_ci int rc, rc2; 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci data->adjust_tz = false; 59062306a36Sopenharmony_ci data->reparse_point = false; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci if (strcmp(full_path, "")) 59362306a36Sopenharmony_ci rc = -ENOENT; 59462306a36Sopenharmony_ci else 59562306a36Sopenharmony_ci rc = open_cached_dir(xid, tcon, full_path, cifs_sb, false, &cfid); 59662306a36Sopenharmony_ci /* If it is a root and its handle is cached then use it */ 59762306a36Sopenharmony_ci if (!rc) { 59862306a36Sopenharmony_ci if (cfid->file_all_info_is_valid) { 59962306a36Sopenharmony_ci memcpy(&data->fi, &cfid->file_all_info, sizeof(data->fi)); 60062306a36Sopenharmony_ci } else { 60162306a36Sopenharmony_ci rc = SMB2_query_info(xid, tcon, cfid->fid.persistent_fid, 60262306a36Sopenharmony_ci cfid->fid.volatile_fid, &data->fi); 60362306a36Sopenharmony_ci } 60462306a36Sopenharmony_ci close_cached_dir(cfid); 60562306a36Sopenharmony_ci return rc; 60662306a36Sopenharmony_ci } 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci cifs_get_readable_path(tcon, full_path, &cfile); 60962306a36Sopenharmony_ci rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_READ_ATTRIBUTES, FILE_OPEN, 61062306a36Sopenharmony_ci create_options, ACL_NO_MODE, data, SMB2_OP_QUERY_INFO, cfile, 61162306a36Sopenharmony_ci NULL, NULL, out_iov, out_buftype); 61262306a36Sopenharmony_ci hdr = out_iov[0].iov_base; 61362306a36Sopenharmony_ci /* 61462306a36Sopenharmony_ci * If first iov is unset, then SMB session was dropped or we've got a 61562306a36Sopenharmony_ci * cached open file (@cfile). 61662306a36Sopenharmony_ci */ 61762306a36Sopenharmony_ci if (!hdr || out_buftype[0] == CIFS_NO_BUFFER) 61862306a36Sopenharmony_ci goto out; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci switch (rc) { 62162306a36Sopenharmony_ci case 0: 62262306a36Sopenharmony_ci case -EOPNOTSUPP: 62362306a36Sopenharmony_ci rc = parse_create_response(data, cifs_sb, &out_iov[0]); 62462306a36Sopenharmony_ci if (rc || !data->reparse_point) 62562306a36Sopenharmony_ci goto out; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci create_options |= OPEN_REPARSE_POINT; 62862306a36Sopenharmony_ci /* Failed on a symbolic link - query a reparse point info */ 62962306a36Sopenharmony_ci cifs_get_readable_path(tcon, full_path, &cfile); 63062306a36Sopenharmony_ci rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, 63162306a36Sopenharmony_ci FILE_READ_ATTRIBUTES, FILE_OPEN, 63262306a36Sopenharmony_ci create_options, ACL_NO_MODE, data, 63362306a36Sopenharmony_ci SMB2_OP_QUERY_INFO, cfile, NULL, NULL, 63462306a36Sopenharmony_ci NULL, NULL); 63562306a36Sopenharmony_ci break; 63662306a36Sopenharmony_ci case -EREMOTE: 63762306a36Sopenharmony_ci break; 63862306a36Sopenharmony_ci default: 63962306a36Sopenharmony_ci if (hdr->Status != STATUS_OBJECT_NAME_INVALID) 64062306a36Sopenharmony_ci break; 64162306a36Sopenharmony_ci rc2 = cifs_inval_name_dfs_link_error(xid, tcon, cifs_sb, 64262306a36Sopenharmony_ci full_path, &islink); 64362306a36Sopenharmony_ci if (rc2) { 64462306a36Sopenharmony_ci rc = rc2; 64562306a36Sopenharmony_ci goto out; 64662306a36Sopenharmony_ci } 64762306a36Sopenharmony_ci if (islink) 64862306a36Sopenharmony_ci rc = -EREMOTE; 64962306a36Sopenharmony_ci } 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ciout: 65262306a36Sopenharmony_ci free_rsp_buf(out_buftype[0], out_iov[0].iov_base); 65362306a36Sopenharmony_ci free_rsp_buf(out_buftype[1], out_iov[1].iov_base); 65462306a36Sopenharmony_ci free_rsp_buf(out_buftype[2], out_iov[2].iov_base); 65562306a36Sopenharmony_ci return rc; 65662306a36Sopenharmony_ci} 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ciint smb311_posix_query_path_info(const unsigned int xid, 65962306a36Sopenharmony_ci struct cifs_tcon *tcon, 66062306a36Sopenharmony_ci struct cifs_sb_info *cifs_sb, 66162306a36Sopenharmony_ci const char *full_path, 66262306a36Sopenharmony_ci struct cifs_open_info_data *data, 66362306a36Sopenharmony_ci struct cifs_sid *owner, 66462306a36Sopenharmony_ci struct cifs_sid *group) 66562306a36Sopenharmony_ci{ 66662306a36Sopenharmony_ci int rc; 66762306a36Sopenharmony_ci __u32 create_options = 0; 66862306a36Sopenharmony_ci struct cifsFileInfo *cfile; 66962306a36Sopenharmony_ci struct kvec out_iov[3] = {}; 67062306a36Sopenharmony_ci int out_buftype[3] = {}; 67162306a36Sopenharmony_ci __u8 *sidsbuf = NULL; 67262306a36Sopenharmony_ci __u8 *sidsbuf_end = NULL; 67362306a36Sopenharmony_ci size_t sidsbuflen = 0; 67462306a36Sopenharmony_ci size_t owner_len, group_len; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci data->adjust_tz = false; 67762306a36Sopenharmony_ci data->reparse_point = false; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci /* 68062306a36Sopenharmony_ci * BB TODO: Add support for using the cached root handle. 68162306a36Sopenharmony_ci * Create SMB2_query_posix_info worker function to do non-compounded query 68262306a36Sopenharmony_ci * when we already have an open file handle for this. For now this is fast enough 68362306a36Sopenharmony_ci * (always using the compounded version). 68462306a36Sopenharmony_ci */ 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci cifs_get_readable_path(tcon, full_path, &cfile); 68762306a36Sopenharmony_ci rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_READ_ATTRIBUTES, FILE_OPEN, 68862306a36Sopenharmony_ci create_options, ACL_NO_MODE, data, SMB2_OP_POSIX_QUERY_INFO, cfile, 68962306a36Sopenharmony_ci &sidsbuf, &sidsbuflen, out_iov, out_buftype); 69062306a36Sopenharmony_ci /* 69162306a36Sopenharmony_ci * If first iov is unset, then SMB session was dropped or we've got a 69262306a36Sopenharmony_ci * cached open file (@cfile). 69362306a36Sopenharmony_ci */ 69462306a36Sopenharmony_ci if (!out_iov[0].iov_base || out_buftype[0] == CIFS_NO_BUFFER) 69562306a36Sopenharmony_ci goto out; 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci switch (rc) { 69862306a36Sopenharmony_ci case 0: 69962306a36Sopenharmony_ci case -EOPNOTSUPP: 70062306a36Sopenharmony_ci /* BB TODO: When support for special files added to Samba re-verify this path */ 70162306a36Sopenharmony_ci rc = parse_create_response(data, cifs_sb, &out_iov[0]); 70262306a36Sopenharmony_ci if (rc || !data->reparse_point) 70362306a36Sopenharmony_ci goto out; 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci create_options |= OPEN_REPARSE_POINT; 70662306a36Sopenharmony_ci /* Failed on a symbolic link - query a reparse point info */ 70762306a36Sopenharmony_ci cifs_get_readable_path(tcon, full_path, &cfile); 70862306a36Sopenharmony_ci rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_READ_ATTRIBUTES, 70962306a36Sopenharmony_ci FILE_OPEN, create_options, ACL_NO_MODE, data, 71062306a36Sopenharmony_ci SMB2_OP_POSIX_QUERY_INFO, cfile, 71162306a36Sopenharmony_ci &sidsbuf, &sidsbuflen, NULL, NULL); 71262306a36Sopenharmony_ci break; 71362306a36Sopenharmony_ci } 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ciout: 71662306a36Sopenharmony_ci if (rc == 0) { 71762306a36Sopenharmony_ci sidsbuf_end = sidsbuf + sidsbuflen; 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci owner_len = posix_info_sid_size(sidsbuf, sidsbuf_end); 72062306a36Sopenharmony_ci if (owner_len == -1) { 72162306a36Sopenharmony_ci rc = -EINVAL; 72262306a36Sopenharmony_ci goto out; 72362306a36Sopenharmony_ci } 72462306a36Sopenharmony_ci memcpy(owner, sidsbuf, owner_len); 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci group_len = posix_info_sid_size( 72762306a36Sopenharmony_ci sidsbuf + owner_len, sidsbuf_end); 72862306a36Sopenharmony_ci if (group_len == -1) { 72962306a36Sopenharmony_ci rc = -EINVAL; 73062306a36Sopenharmony_ci goto out; 73162306a36Sopenharmony_ci } 73262306a36Sopenharmony_ci memcpy(group, sidsbuf + owner_len, group_len); 73362306a36Sopenharmony_ci } 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci kfree(sidsbuf); 73662306a36Sopenharmony_ci free_rsp_buf(out_buftype[0], out_iov[0].iov_base); 73762306a36Sopenharmony_ci free_rsp_buf(out_buftype[1], out_iov[1].iov_base); 73862306a36Sopenharmony_ci free_rsp_buf(out_buftype[2], out_iov[2].iov_base); 73962306a36Sopenharmony_ci return rc; 74062306a36Sopenharmony_ci} 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ciint 74362306a36Sopenharmony_cismb2_mkdir(const unsigned int xid, struct inode *parent_inode, umode_t mode, 74462306a36Sopenharmony_ci struct cifs_tcon *tcon, const char *name, 74562306a36Sopenharmony_ci struct cifs_sb_info *cifs_sb) 74662306a36Sopenharmony_ci{ 74762306a36Sopenharmony_ci return smb2_compound_op(xid, tcon, cifs_sb, name, 74862306a36Sopenharmony_ci FILE_WRITE_ATTRIBUTES, FILE_CREATE, 74962306a36Sopenharmony_ci CREATE_NOT_FILE, mode, NULL, SMB2_OP_MKDIR, 75062306a36Sopenharmony_ci NULL, NULL, NULL, NULL, NULL); 75162306a36Sopenharmony_ci} 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_civoid 75462306a36Sopenharmony_cismb2_mkdir_setinfo(struct inode *inode, const char *name, 75562306a36Sopenharmony_ci struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon, 75662306a36Sopenharmony_ci const unsigned int xid) 75762306a36Sopenharmony_ci{ 75862306a36Sopenharmony_ci FILE_BASIC_INFO data; 75962306a36Sopenharmony_ci struct cifsInodeInfo *cifs_i; 76062306a36Sopenharmony_ci struct cifsFileInfo *cfile; 76162306a36Sopenharmony_ci u32 dosattrs; 76262306a36Sopenharmony_ci int tmprc; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci memset(&data, 0, sizeof(data)); 76562306a36Sopenharmony_ci cifs_i = CIFS_I(inode); 76662306a36Sopenharmony_ci dosattrs = cifs_i->cifsAttrs | ATTR_READONLY; 76762306a36Sopenharmony_ci data.Attributes = cpu_to_le32(dosattrs); 76862306a36Sopenharmony_ci cifs_get_writable_path(tcon, name, FIND_WR_ANY, &cfile); 76962306a36Sopenharmony_ci tmprc = smb2_compound_op(xid, tcon, cifs_sb, name, 77062306a36Sopenharmony_ci FILE_WRITE_ATTRIBUTES, FILE_CREATE, 77162306a36Sopenharmony_ci CREATE_NOT_FILE, ACL_NO_MODE, 77262306a36Sopenharmony_ci &data, SMB2_OP_SET_INFO, cfile, NULL, NULL, NULL, NULL); 77362306a36Sopenharmony_ci if (tmprc == 0) 77462306a36Sopenharmony_ci cifs_i->cifsAttrs = dosattrs; 77562306a36Sopenharmony_ci} 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ciint 77862306a36Sopenharmony_cismb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name, 77962306a36Sopenharmony_ci struct cifs_sb_info *cifs_sb) 78062306a36Sopenharmony_ci{ 78162306a36Sopenharmony_ci drop_cached_dir_by_name(xid, tcon, name, cifs_sb); 78262306a36Sopenharmony_ci return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN, 78362306a36Sopenharmony_ci CREATE_NOT_FILE, ACL_NO_MODE, 78462306a36Sopenharmony_ci NULL, SMB2_OP_RMDIR, NULL, NULL, NULL, NULL, NULL); 78562306a36Sopenharmony_ci} 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ciint 78862306a36Sopenharmony_cismb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name, 78962306a36Sopenharmony_ci struct cifs_sb_info *cifs_sb) 79062306a36Sopenharmony_ci{ 79162306a36Sopenharmony_ci return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN, 79262306a36Sopenharmony_ci CREATE_DELETE_ON_CLOSE | OPEN_REPARSE_POINT, 79362306a36Sopenharmony_ci ACL_NO_MODE, NULL, SMB2_OP_DELETE, NULL, NULL, NULL, NULL, NULL); 79462306a36Sopenharmony_ci} 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_cistatic int smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon, 79762306a36Sopenharmony_ci const char *from_name, const char *to_name, 79862306a36Sopenharmony_ci struct cifs_sb_info *cifs_sb, 79962306a36Sopenharmony_ci __u32 create_options, __u32 access, 80062306a36Sopenharmony_ci int command, struct cifsFileInfo *cfile) 80162306a36Sopenharmony_ci{ 80262306a36Sopenharmony_ci __le16 *smb2_to_name = NULL; 80362306a36Sopenharmony_ci int rc; 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci smb2_to_name = cifs_convert_path_to_utf16(to_name, cifs_sb); 80662306a36Sopenharmony_ci if (smb2_to_name == NULL) { 80762306a36Sopenharmony_ci rc = -ENOMEM; 80862306a36Sopenharmony_ci goto smb2_rename_path; 80962306a36Sopenharmony_ci } 81062306a36Sopenharmony_ci rc = smb2_compound_op(xid, tcon, cifs_sb, from_name, access, 81162306a36Sopenharmony_ci FILE_OPEN, create_options, ACL_NO_MODE, smb2_to_name, 81262306a36Sopenharmony_ci command, cfile, NULL, NULL, NULL, NULL); 81362306a36Sopenharmony_cismb2_rename_path: 81462306a36Sopenharmony_ci kfree(smb2_to_name); 81562306a36Sopenharmony_ci return rc; 81662306a36Sopenharmony_ci} 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ciint smb2_rename_path(const unsigned int xid, 81962306a36Sopenharmony_ci struct cifs_tcon *tcon, 82062306a36Sopenharmony_ci struct dentry *source_dentry, 82162306a36Sopenharmony_ci const char *from_name, const char *to_name, 82262306a36Sopenharmony_ci struct cifs_sb_info *cifs_sb) 82362306a36Sopenharmony_ci{ 82462306a36Sopenharmony_ci struct cifsFileInfo *cfile; 82562306a36Sopenharmony_ci __u32 co = file_create_options(source_dentry); 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci drop_cached_dir_by_name(xid, tcon, from_name, cifs_sb); 82862306a36Sopenharmony_ci cifs_get_writable_path(tcon, from_name, FIND_WR_WITH_DELETE, &cfile); 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci return smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb, 83162306a36Sopenharmony_ci co, DELETE, SMB2_OP_RENAME, cfile); 83262306a36Sopenharmony_ci} 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ciint smb2_create_hardlink(const unsigned int xid, 83562306a36Sopenharmony_ci struct cifs_tcon *tcon, 83662306a36Sopenharmony_ci struct dentry *source_dentry, 83762306a36Sopenharmony_ci const char *from_name, const char *to_name, 83862306a36Sopenharmony_ci struct cifs_sb_info *cifs_sb) 83962306a36Sopenharmony_ci{ 84062306a36Sopenharmony_ci __u32 co = file_create_options(source_dentry); 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci return smb2_set_path_attr(xid, tcon, from_name, to_name, 84362306a36Sopenharmony_ci cifs_sb, co, FILE_READ_ATTRIBUTES, 84462306a36Sopenharmony_ci SMB2_OP_HARDLINK, NULL); 84562306a36Sopenharmony_ci} 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ciint 84862306a36Sopenharmony_cismb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon, 84962306a36Sopenharmony_ci const char *full_path, __u64 size, 85062306a36Sopenharmony_ci struct cifs_sb_info *cifs_sb, bool set_alloc) 85162306a36Sopenharmony_ci{ 85262306a36Sopenharmony_ci __le64 eof = cpu_to_le64(size); 85362306a36Sopenharmony_ci struct cifsFileInfo *cfile; 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile); 85662306a36Sopenharmony_ci return smb2_compound_op(xid, tcon, cifs_sb, full_path, 85762306a36Sopenharmony_ci FILE_WRITE_DATA, FILE_OPEN, 0, ACL_NO_MODE, 85862306a36Sopenharmony_ci &eof, SMB2_OP_SET_EOF, cfile, NULL, NULL, NULL, NULL); 85962306a36Sopenharmony_ci} 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ciint 86262306a36Sopenharmony_cismb2_set_file_info(struct inode *inode, const char *full_path, 86362306a36Sopenharmony_ci FILE_BASIC_INFO *buf, const unsigned int xid) 86462306a36Sopenharmony_ci{ 86562306a36Sopenharmony_ci struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 86662306a36Sopenharmony_ci struct tcon_link *tlink; 86762306a36Sopenharmony_ci struct cifs_tcon *tcon; 86862306a36Sopenharmony_ci struct cifsFileInfo *cfile; 86962306a36Sopenharmony_ci int rc; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci if ((buf->CreationTime == 0) && (buf->LastAccessTime == 0) && 87262306a36Sopenharmony_ci (buf->LastWriteTime == 0) && (buf->ChangeTime == 0) && 87362306a36Sopenharmony_ci (buf->Attributes == 0)) 87462306a36Sopenharmony_ci return 0; /* would be a no op, no sense sending this */ 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci tlink = cifs_sb_tlink(cifs_sb); 87762306a36Sopenharmony_ci if (IS_ERR(tlink)) 87862306a36Sopenharmony_ci return PTR_ERR(tlink); 87962306a36Sopenharmony_ci tcon = tlink_tcon(tlink); 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile); 88262306a36Sopenharmony_ci rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, 88362306a36Sopenharmony_ci FILE_WRITE_ATTRIBUTES, FILE_OPEN, 88462306a36Sopenharmony_ci 0, ACL_NO_MODE, buf, SMB2_OP_SET_INFO, cfile, 88562306a36Sopenharmony_ci NULL, NULL, NULL, NULL); 88662306a36Sopenharmony_ci cifs_put_tlink(tlink); 88762306a36Sopenharmony_ci return rc; 88862306a36Sopenharmony_ci} 889