Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: LGPL-2.1
0002 /*
0003  *
0004  *   Copyright (C) International Business Machines  Corp., 2002, 2011
0005  *                 Etersoft, 2012
0006  *   Author(s): Pavel Shilovsky (pshilovsky@samba.org),
0007  *              Steve French (sfrench@us.ibm.com)
0008  *
0009  */
0010 #include <linux/fs.h>
0011 #include <linux/stat.h>
0012 #include <linux/slab.h>
0013 #include <linux/pagemap.h>
0014 #include <asm/div64.h>
0015 #include "cifsfs.h"
0016 #include "cifspdu.h"
0017 #include "cifsglob.h"
0018 #include "cifsproto.h"
0019 #include "cifs_debug.h"
0020 #include "cifs_fs_sb.h"
0021 #include "cifs_unicode.h"
0022 #include "fscache.h"
0023 #include "smb2glob.h"
0024 #include "smb2pdu.h"
0025 #include "smb2proto.h"
0026 #include "cached_dir.h"
0027 
0028 static void
0029 free_set_inf_compound(struct smb_rqst *rqst)
0030 {
0031     if (rqst[1].rq_iov)
0032         SMB2_set_info_free(&rqst[1]);
0033     if (rqst[2].rq_iov)
0034         SMB2_close_free(&rqst[2]);
0035 }
0036 
0037 
0038 struct cop_vars {
0039     struct cifs_open_parms oparms;
0040     struct kvec rsp_iov[3];
0041     struct smb_rqst rqst[3];
0042     struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
0043     struct kvec qi_iov[1];
0044     struct kvec si_iov[SMB2_SET_INFO_IOV_SIZE];
0045     struct kvec close_iov[1];
0046     struct smb2_file_rename_info rename_info;
0047     struct smb2_file_link_info link_info;
0048 };
0049 
0050 /*
0051  * note: If cfile is passed, the reference to it is dropped here.
0052  * So make sure that you do not reuse cfile after return from this func.
0053  */
0054 static int
0055 smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
0056          struct cifs_sb_info *cifs_sb, const char *full_path,
0057          __u32 desired_access, __u32 create_disposition,
0058          __u32 create_options, umode_t mode, void *ptr, int command,
0059          struct cifsFileInfo *cfile)
0060 {
0061     struct cop_vars *vars = NULL;
0062     struct kvec *rsp_iov;
0063     struct smb_rqst *rqst;
0064     int rc;
0065     __le16 *utf16_path = NULL;
0066     __u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
0067     struct cifs_fid fid;
0068     struct cifs_ses *ses = tcon->ses;
0069     struct TCP_Server_Info *server;
0070     int num_rqst = 0;
0071     int resp_buftype[3];
0072     struct smb2_query_info_rsp *qi_rsp = NULL;
0073     int flags = 0;
0074     __u8 delete_pending[8] = {1, 0, 0, 0, 0, 0, 0, 0};
0075     unsigned int size[2];
0076     void *data[2];
0077     int len;
0078 
0079     vars = kzalloc(sizeof(*vars), GFP_ATOMIC);
0080     if (vars == NULL)
0081         return -ENOMEM;
0082     rqst = &vars->rqst[0];
0083     rsp_iov = &vars->rsp_iov[0];
0084 
0085     server = cifs_pick_channel(ses);
0086 
0087     if (smb3_encryption_required(tcon))
0088         flags |= CIFS_TRANSFORM_REQ;
0089 
0090     resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
0091 
0092     /* We already have a handle so we can skip the open */
0093     if (cfile)
0094         goto after_open;
0095 
0096     /* Open */
0097     utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
0098     if (!utf16_path) {
0099         rc = -ENOMEM;
0100         goto finished;
0101     }
0102 
0103     vars->oparms.tcon = tcon;
0104     vars->oparms.desired_access = desired_access;
0105     vars->oparms.disposition = create_disposition;
0106     vars->oparms.create_options = cifs_create_options(cifs_sb, create_options);
0107     vars->oparms.fid = &fid;
0108     vars->oparms.reconnect = false;
0109     vars->oparms.mode = mode;
0110     vars->oparms.cifs_sb = cifs_sb;
0111 
0112     rqst[num_rqst].rq_iov = &vars->open_iov[0];
0113     rqst[num_rqst].rq_nvec = SMB2_CREATE_IOV_SIZE;
0114     rc = SMB2_open_init(tcon, server,
0115                 &rqst[num_rqst], &oplock, &vars->oparms,
0116                 utf16_path);
0117     kfree(utf16_path);
0118     if (rc)
0119         goto finished;
0120 
0121     smb2_set_next_command(tcon, &rqst[num_rqst]);
0122  after_open:
0123     num_rqst++;
0124     rc = 0;
0125 
0126     /* Operation */
0127     switch (command) {
0128     case SMB2_OP_QUERY_INFO:
0129         rqst[num_rqst].rq_iov = &vars->qi_iov[0];
0130         rqst[num_rqst].rq_nvec = 1;
0131 
0132         if (cfile)
0133             rc = SMB2_query_info_init(tcon, server,
0134                 &rqst[num_rqst],
0135                 cfile->fid.persistent_fid,
0136                 cfile->fid.volatile_fid,
0137                 FILE_ALL_INFORMATION,
0138                 SMB2_O_INFO_FILE, 0,
0139                 sizeof(struct smb2_file_all_info) +
0140                       PATH_MAX * 2, 0, NULL);
0141         else {
0142             rc = SMB2_query_info_init(tcon, server,
0143                 &rqst[num_rqst],
0144                 COMPOUND_FID,
0145                 COMPOUND_FID,
0146                 FILE_ALL_INFORMATION,
0147                 SMB2_O_INFO_FILE, 0,
0148                 sizeof(struct smb2_file_all_info) +
0149                       PATH_MAX * 2, 0, NULL);
0150             if (!rc) {
0151                 smb2_set_next_command(tcon, &rqst[num_rqst]);
0152                 smb2_set_related(&rqst[num_rqst]);
0153             }
0154         }
0155 
0156         if (rc)
0157             goto finished;
0158         num_rqst++;
0159         trace_smb3_query_info_compound_enter(xid, ses->Suid, tcon->tid,
0160                              full_path);
0161         break;
0162     case SMB2_OP_POSIX_QUERY_INFO:
0163         rqst[num_rqst].rq_iov = &vars->qi_iov[0];
0164         rqst[num_rqst].rq_nvec = 1;
0165 
0166         if (cfile)
0167             rc = SMB2_query_info_init(tcon, server,
0168                 &rqst[num_rqst],
0169                 cfile->fid.persistent_fid,
0170                 cfile->fid.volatile_fid,
0171                 SMB_FIND_FILE_POSIX_INFO,
0172                 SMB2_O_INFO_FILE, 0,
0173                 /* TBD: fix following to allow for longer SIDs */
0174                 sizeof(struct smb311_posix_qinfo *) + (PATH_MAX * 2) +
0175                 (sizeof(struct cifs_sid) * 2), 0, NULL);
0176         else {
0177             rc = SMB2_query_info_init(tcon, server,
0178                 &rqst[num_rqst],
0179                 COMPOUND_FID,
0180                 COMPOUND_FID,
0181                 SMB_FIND_FILE_POSIX_INFO,
0182                 SMB2_O_INFO_FILE, 0,
0183                 sizeof(struct smb311_posix_qinfo *) + (PATH_MAX * 2) +
0184                 (sizeof(struct cifs_sid) * 2), 0, NULL);
0185             if (!rc) {
0186                 smb2_set_next_command(tcon, &rqst[num_rqst]);
0187                 smb2_set_related(&rqst[num_rqst]);
0188             }
0189         }
0190 
0191         if (rc)
0192             goto finished;
0193         num_rqst++;
0194         trace_smb3_posix_query_info_compound_enter(xid, ses->Suid, tcon->tid, full_path);
0195         break;
0196     case SMB2_OP_DELETE:
0197         trace_smb3_delete_enter(xid, ses->Suid, tcon->tid, full_path);
0198         break;
0199     case SMB2_OP_MKDIR:
0200         /*
0201          * Directories are created through parameters in the
0202          * SMB2_open() call.
0203          */
0204         trace_smb3_mkdir_enter(xid, ses->Suid, tcon->tid, full_path);
0205         break;
0206     case SMB2_OP_RMDIR:
0207         rqst[num_rqst].rq_iov = &vars->si_iov[0];
0208         rqst[num_rqst].rq_nvec = 1;
0209 
0210         size[0] = 1; /* sizeof __u8 See MS-FSCC section 2.4.11 */
0211         data[0] = &delete_pending[0];
0212 
0213         rc = SMB2_set_info_init(tcon, server,
0214                     &rqst[num_rqst], COMPOUND_FID,
0215                     COMPOUND_FID, current->tgid,
0216                     FILE_DISPOSITION_INFORMATION,
0217                     SMB2_O_INFO_FILE, 0, data, size);
0218         if (rc)
0219             goto finished;
0220         smb2_set_next_command(tcon, &rqst[num_rqst]);
0221         smb2_set_related(&rqst[num_rqst++]);
0222         trace_smb3_rmdir_enter(xid, ses->Suid, tcon->tid, full_path);
0223         break;
0224     case SMB2_OP_SET_EOF:
0225         rqst[num_rqst].rq_iov = &vars->si_iov[0];
0226         rqst[num_rqst].rq_nvec = 1;
0227 
0228         size[0] = 8; /* sizeof __le64 */
0229         data[0] = ptr;
0230 
0231         rc = SMB2_set_info_init(tcon, server,
0232                     &rqst[num_rqst], COMPOUND_FID,
0233                     COMPOUND_FID, current->tgid,
0234                     FILE_END_OF_FILE_INFORMATION,
0235                     SMB2_O_INFO_FILE, 0, data, size);
0236         if (rc)
0237             goto finished;
0238         smb2_set_next_command(tcon, &rqst[num_rqst]);
0239         smb2_set_related(&rqst[num_rqst++]);
0240         trace_smb3_set_eof_enter(xid, ses->Suid, tcon->tid, full_path);
0241         break;
0242     case SMB2_OP_SET_INFO:
0243         rqst[num_rqst].rq_iov = &vars->si_iov[0];
0244         rqst[num_rqst].rq_nvec = 1;
0245 
0246 
0247         size[0] = sizeof(FILE_BASIC_INFO);
0248         data[0] = ptr;
0249 
0250         if (cfile)
0251             rc = SMB2_set_info_init(tcon, server,
0252                 &rqst[num_rqst],
0253                 cfile->fid.persistent_fid,
0254                 cfile->fid.volatile_fid, current->tgid,
0255                 FILE_BASIC_INFORMATION,
0256                 SMB2_O_INFO_FILE, 0, data, size);
0257         else {
0258             rc = SMB2_set_info_init(tcon, server,
0259                 &rqst[num_rqst],
0260                 COMPOUND_FID,
0261                 COMPOUND_FID, current->tgid,
0262                 FILE_BASIC_INFORMATION,
0263                 SMB2_O_INFO_FILE, 0, data, size);
0264             if (!rc) {
0265                 smb2_set_next_command(tcon, &rqst[num_rqst]);
0266                 smb2_set_related(&rqst[num_rqst]);
0267             }
0268         }
0269 
0270         if (rc)
0271             goto finished;
0272         num_rqst++;
0273         trace_smb3_set_info_compound_enter(xid, ses->Suid, tcon->tid,
0274                            full_path);
0275         break;
0276     case SMB2_OP_RENAME:
0277         rqst[num_rqst].rq_iov = &vars->si_iov[0];
0278         rqst[num_rqst].rq_nvec = 2;
0279 
0280         len = (2 * UniStrnlen((wchar_t *)ptr, PATH_MAX));
0281 
0282         vars->rename_info.ReplaceIfExists = 1;
0283         vars->rename_info.RootDirectory = 0;
0284         vars->rename_info.FileNameLength = cpu_to_le32(len);
0285 
0286         size[0] = sizeof(struct smb2_file_rename_info);
0287         data[0] = &vars->rename_info;
0288 
0289         size[1] = len + 2 /* null */;
0290         data[1] = (__le16 *)ptr;
0291 
0292         if (cfile)
0293             rc = SMB2_set_info_init(tcon, server,
0294                         &rqst[num_rqst],
0295                         cfile->fid.persistent_fid,
0296                         cfile->fid.volatile_fid,
0297                     current->tgid, FILE_RENAME_INFORMATION,
0298                     SMB2_O_INFO_FILE, 0, data, size);
0299         else {
0300             rc = SMB2_set_info_init(tcon, server,
0301                     &rqst[num_rqst],
0302                     COMPOUND_FID, COMPOUND_FID,
0303                     current->tgid, FILE_RENAME_INFORMATION,
0304                     SMB2_O_INFO_FILE, 0, data, size);
0305             if (!rc) {
0306                 smb2_set_next_command(tcon, &rqst[num_rqst]);
0307                 smb2_set_related(&rqst[num_rqst]);
0308             }
0309         }
0310         if (rc)
0311             goto finished;
0312         num_rqst++;
0313         trace_smb3_rename_enter(xid, ses->Suid, tcon->tid, full_path);
0314         break;
0315     case SMB2_OP_HARDLINK:
0316         rqst[num_rqst].rq_iov = &vars->si_iov[0];
0317         rqst[num_rqst].rq_nvec = 2;
0318 
0319         len = (2 * UniStrnlen((wchar_t *)ptr, PATH_MAX));
0320 
0321         vars->link_info.ReplaceIfExists = 0;
0322         vars->link_info.RootDirectory = 0;
0323         vars->link_info.FileNameLength = cpu_to_le32(len);
0324 
0325         size[0] = sizeof(struct smb2_file_link_info);
0326         data[0] = &vars->link_info;
0327 
0328         size[1] = len + 2 /* null */;
0329         data[1] = (__le16 *)ptr;
0330 
0331         rc = SMB2_set_info_init(tcon, server,
0332                     &rqst[num_rqst], COMPOUND_FID,
0333                     COMPOUND_FID, current->tgid,
0334                     FILE_LINK_INFORMATION,
0335                     SMB2_O_INFO_FILE, 0, data, size);
0336         if (rc)
0337             goto finished;
0338         smb2_set_next_command(tcon, &rqst[num_rqst]);
0339         smb2_set_related(&rqst[num_rqst++]);
0340         trace_smb3_hardlink_enter(xid, ses->Suid, tcon->tid, full_path);
0341         break;
0342     default:
0343         cifs_dbg(VFS, "Invalid command\n");
0344         rc = -EINVAL;
0345     }
0346     if (rc)
0347         goto finished;
0348 
0349     /* We already have a handle so we can skip the close */
0350     if (cfile)
0351         goto after_close;
0352     /* Close */
0353     flags |= CIFS_CP_CREATE_CLOSE_OP;
0354     rqst[num_rqst].rq_iov = &vars->close_iov[0];
0355     rqst[num_rqst].rq_nvec = 1;
0356     rc = SMB2_close_init(tcon, server,
0357                  &rqst[num_rqst], COMPOUND_FID,
0358                  COMPOUND_FID, false);
0359     smb2_set_related(&rqst[num_rqst]);
0360     if (rc)
0361         goto finished;
0362  after_close:
0363     num_rqst++;
0364 
0365     if (cfile) {
0366         rc = compound_send_recv(xid, ses, server,
0367                     flags, num_rqst - 2,
0368                     &rqst[1], &resp_buftype[1],
0369                     &rsp_iov[1]);
0370     } else
0371         rc = compound_send_recv(xid, ses, server,
0372                     flags, num_rqst,
0373                     rqst, resp_buftype,
0374                     rsp_iov);
0375 
0376  finished:
0377     if (cfile)
0378         cifsFileInfo_put(cfile);
0379 
0380     SMB2_open_free(&rqst[0]);
0381     if (rc == -EREMCHG) {
0382         pr_warn_once("server share %s deleted\n", tcon->treeName);
0383         tcon->need_reconnect = true;
0384     }
0385 
0386     switch (command) {
0387     case SMB2_OP_QUERY_INFO:
0388         if (rc == 0) {
0389             qi_rsp = (struct smb2_query_info_rsp *)
0390                 rsp_iov[1].iov_base;
0391             rc = smb2_validate_and_copy_iov(
0392                 le16_to_cpu(qi_rsp->OutputBufferOffset),
0393                 le32_to_cpu(qi_rsp->OutputBufferLength),
0394                 &rsp_iov[1], sizeof(struct smb2_file_all_info),
0395                 ptr);
0396         }
0397         if (rqst[1].rq_iov)
0398             SMB2_query_info_free(&rqst[1]);
0399         if (rqst[2].rq_iov)
0400             SMB2_close_free(&rqst[2]);
0401         if (rc)
0402             trace_smb3_query_info_compound_err(xid,  ses->Suid,
0403                         tcon->tid, rc);
0404         else
0405             trace_smb3_query_info_compound_done(xid, ses->Suid,
0406                         tcon->tid);
0407         break;
0408     case SMB2_OP_POSIX_QUERY_INFO:
0409         if (rc == 0) {
0410             qi_rsp = (struct smb2_query_info_rsp *)
0411                 rsp_iov[1].iov_base;
0412             rc = smb2_validate_and_copy_iov(
0413                 le16_to_cpu(qi_rsp->OutputBufferOffset),
0414                 le32_to_cpu(qi_rsp->OutputBufferLength),
0415                 &rsp_iov[1], sizeof(struct smb311_posix_qinfo) /* add SIDs */, ptr);
0416         }
0417         if (rqst[1].rq_iov)
0418             SMB2_query_info_free(&rqst[1]);
0419         if (rqst[2].rq_iov)
0420             SMB2_close_free(&rqst[2]);
0421         if (rc)
0422             trace_smb3_posix_query_info_compound_err(xid,  ses->Suid, tcon->tid, rc);
0423         else
0424             trace_smb3_posix_query_info_compound_done(xid, ses->Suid, tcon->tid);
0425         break;
0426     case SMB2_OP_DELETE:
0427         if (rc)
0428             trace_smb3_delete_err(xid,  ses->Suid, tcon->tid, rc);
0429         else
0430             trace_smb3_delete_done(xid, ses->Suid, tcon->tid);
0431         if (rqst[1].rq_iov)
0432             SMB2_close_free(&rqst[1]);
0433         break;
0434     case SMB2_OP_MKDIR:
0435         if (rc)
0436             trace_smb3_mkdir_err(xid,  ses->Suid, tcon->tid, rc);
0437         else
0438             trace_smb3_mkdir_done(xid, ses->Suid, tcon->tid);
0439         if (rqst[1].rq_iov)
0440             SMB2_close_free(&rqst[1]);
0441         break;
0442     case SMB2_OP_HARDLINK:
0443         if (rc)
0444             trace_smb3_hardlink_err(xid,  ses->Suid, tcon->tid, rc);
0445         else
0446             trace_smb3_hardlink_done(xid, ses->Suid, tcon->tid);
0447         free_set_inf_compound(rqst);
0448         break;
0449     case SMB2_OP_RENAME:
0450         if (rc)
0451             trace_smb3_rename_err(xid,  ses->Suid, tcon->tid, rc);
0452         else
0453             trace_smb3_rename_done(xid, ses->Suid, tcon->tid);
0454         free_set_inf_compound(rqst);
0455         break;
0456     case SMB2_OP_RMDIR:
0457         if (rc)
0458             trace_smb3_rmdir_err(xid,  ses->Suid, tcon->tid, rc);
0459         else
0460             trace_smb3_rmdir_done(xid, ses->Suid, tcon->tid);
0461         free_set_inf_compound(rqst);
0462         break;
0463     case SMB2_OP_SET_EOF:
0464         if (rc)
0465             trace_smb3_set_eof_err(xid,  ses->Suid, tcon->tid, rc);
0466         else
0467             trace_smb3_set_eof_done(xid, ses->Suid, tcon->tid);
0468         free_set_inf_compound(rqst);
0469         break;
0470     case SMB2_OP_SET_INFO:
0471         if (rc)
0472             trace_smb3_set_info_compound_err(xid,  ses->Suid,
0473                         tcon->tid, rc);
0474         else
0475             trace_smb3_set_info_compound_done(xid, ses->Suid,
0476                         tcon->tid);
0477         free_set_inf_compound(rqst);
0478         break;
0479     }
0480     free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
0481     free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
0482     free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base);
0483     kfree(vars);
0484     return rc;
0485 }
0486 
0487 void
0488 move_smb2_info_to_cifs(FILE_ALL_INFO *dst, struct smb2_file_all_info *src)
0489 {
0490     memcpy(dst, src, (size_t)(&src->CurrentByteOffset) - (size_t)src);
0491     dst->CurrentByteOffset = src->CurrentByteOffset;
0492     dst->Mode = src->Mode;
0493     dst->AlignmentRequirement = src->AlignmentRequirement;
0494     dst->IndexNumber1 = 0; /* we don't use it */
0495 }
0496 
0497 int
0498 smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
0499              struct cifs_sb_info *cifs_sb, const char *full_path,
0500              FILE_ALL_INFO *data, bool *adjust_tz, bool *reparse)
0501 {
0502     int rc;
0503     struct smb2_file_all_info *smb2_data;
0504     __u32 create_options = 0;
0505     struct cifsFileInfo *cfile;
0506     struct cached_fid *cfid = NULL;
0507 
0508     *adjust_tz = false;
0509     *reparse = false;
0510 
0511     smb2_data = kzalloc(sizeof(struct smb2_file_all_info) + PATH_MAX * 2,
0512                 GFP_KERNEL);
0513     if (smb2_data == NULL)
0514         return -ENOMEM;
0515 
0516     if (strcmp(full_path, ""))
0517         rc = -ENOENT;
0518     else
0519         rc = open_cached_dir(xid, tcon, full_path, cifs_sb, false, &cfid);
0520     /* If it is a root and its handle is cached then use it */
0521     if (!rc) {
0522         if (cfid->file_all_info_is_valid) {
0523             move_smb2_info_to_cifs(data,
0524                            &cfid->file_all_info);
0525         } else {
0526             rc = SMB2_query_info(xid, tcon,
0527                          cfid->fid.persistent_fid,
0528                          cfid->fid.volatile_fid, smb2_data);
0529             if (!rc)
0530                 move_smb2_info_to_cifs(data, smb2_data);
0531         }
0532         close_cached_dir(cfid);
0533         goto out;
0534     }
0535 
0536     cifs_get_readable_path(tcon, full_path, &cfile);
0537     rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
0538                   FILE_READ_ATTRIBUTES, FILE_OPEN, create_options,
0539                   ACL_NO_MODE, smb2_data, SMB2_OP_QUERY_INFO, cfile);
0540     if (rc == -EOPNOTSUPP) {
0541         *reparse = true;
0542         create_options |= OPEN_REPARSE_POINT;
0543 
0544         /* Failed on a symbolic link - query a reparse point info */
0545         cifs_get_readable_path(tcon, full_path, &cfile);
0546         rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
0547                       FILE_READ_ATTRIBUTES, FILE_OPEN,
0548                       create_options, ACL_NO_MODE,
0549                       smb2_data, SMB2_OP_QUERY_INFO, cfile);
0550     }
0551     if (rc)
0552         goto out;
0553 
0554     move_smb2_info_to_cifs(data, smb2_data);
0555 out:
0556     kfree(smb2_data);
0557     return rc;
0558 }
0559 
0560 
0561 int
0562 smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
0563              struct cifs_sb_info *cifs_sb, const char *full_path,
0564              struct smb311_posix_qinfo *data, bool *adjust_tz, bool *reparse)
0565 {
0566     int rc;
0567     __u32 create_options = 0;
0568     struct cifsFileInfo *cfile;
0569     struct smb311_posix_qinfo *smb2_data;
0570 
0571     *adjust_tz = false;
0572     *reparse = false;
0573 
0574     /* BB TODO: Make struct larger when add support for parsing owner SIDs */
0575     smb2_data = kzalloc(sizeof(struct smb311_posix_qinfo),
0576                 GFP_KERNEL);
0577     if (smb2_data == NULL)
0578         return -ENOMEM;
0579 
0580     /*
0581      * BB TODO: Add support for using the cached root handle.
0582      * Create SMB2_query_posix_info worker function to do non-compounded query
0583      * when we already have an open file handle for this. For now this is fast enough
0584      * (always using the compounded version).
0585      */
0586 
0587     cifs_get_readable_path(tcon, full_path, &cfile);
0588     rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
0589                   FILE_READ_ATTRIBUTES, FILE_OPEN, create_options,
0590                   ACL_NO_MODE, smb2_data, SMB2_OP_POSIX_QUERY_INFO, cfile);
0591     if (rc == -EOPNOTSUPP) {
0592         /* BB TODO: When support for special files added to Samba re-verify this path */
0593         *reparse = true;
0594         create_options |= OPEN_REPARSE_POINT;
0595 
0596         /* Failed on a symbolic link - query a reparse point info */
0597         cifs_get_readable_path(tcon, full_path, &cfile);
0598         rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
0599                       FILE_READ_ATTRIBUTES, FILE_OPEN,
0600                       create_options, ACL_NO_MODE,
0601                       smb2_data, SMB2_OP_POSIX_QUERY_INFO, cfile);
0602     }
0603     if (rc)
0604         goto out;
0605 
0606      /* TODO: will need to allow for the 2 SIDs when add support for getting owner UID/GID */
0607     memcpy(data, smb2_data, sizeof(struct smb311_posix_qinfo));
0608 
0609 out:
0610     kfree(smb2_data);
0611     return rc;
0612 }
0613 
0614 int
0615 smb2_mkdir(const unsigned int xid, struct inode *parent_inode, umode_t mode,
0616        struct cifs_tcon *tcon, const char *name,
0617        struct cifs_sb_info *cifs_sb)
0618 {
0619     return smb2_compound_op(xid, tcon, cifs_sb, name,
0620                 FILE_WRITE_ATTRIBUTES, FILE_CREATE,
0621                 CREATE_NOT_FILE, mode, NULL, SMB2_OP_MKDIR,
0622                 NULL);
0623 }
0624 
0625 void
0626 smb2_mkdir_setinfo(struct inode *inode, const char *name,
0627            struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon,
0628            const unsigned int xid)
0629 {
0630     FILE_BASIC_INFO data;
0631     struct cifsInodeInfo *cifs_i;
0632     struct cifsFileInfo *cfile;
0633     u32 dosattrs;
0634     int tmprc;
0635 
0636     memset(&data, 0, sizeof(data));
0637     cifs_i = CIFS_I(inode);
0638     dosattrs = cifs_i->cifsAttrs | ATTR_READONLY;
0639     data.Attributes = cpu_to_le32(dosattrs);
0640     cifs_get_writable_path(tcon, name, FIND_WR_ANY, &cfile);
0641     tmprc = smb2_compound_op(xid, tcon, cifs_sb, name,
0642                  FILE_WRITE_ATTRIBUTES, FILE_CREATE,
0643                  CREATE_NOT_FILE, ACL_NO_MODE,
0644                  &data, SMB2_OP_SET_INFO, cfile);
0645     if (tmprc == 0)
0646         cifs_i->cifsAttrs = dosattrs;
0647 }
0648 
0649 int
0650 smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
0651        struct cifs_sb_info *cifs_sb)
0652 {
0653     return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
0654                 CREATE_NOT_FILE, ACL_NO_MODE,
0655                 NULL, SMB2_OP_RMDIR, NULL);
0656 }
0657 
0658 int
0659 smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
0660         struct cifs_sb_info *cifs_sb)
0661 {
0662     return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
0663                 CREATE_DELETE_ON_CLOSE | OPEN_REPARSE_POINT,
0664                 ACL_NO_MODE, NULL, SMB2_OP_DELETE, NULL);
0665 }
0666 
0667 static int
0668 smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
0669            const char *from_name, const char *to_name,
0670            struct cifs_sb_info *cifs_sb, __u32 access, int command,
0671            struct cifsFileInfo *cfile)
0672 {
0673     __le16 *smb2_to_name = NULL;
0674     int rc;
0675 
0676     smb2_to_name = cifs_convert_path_to_utf16(to_name, cifs_sb);
0677     if (smb2_to_name == NULL) {
0678         rc = -ENOMEM;
0679         goto smb2_rename_path;
0680     }
0681     rc = smb2_compound_op(xid, tcon, cifs_sb, from_name, access,
0682                   FILE_OPEN, 0, ACL_NO_MODE, smb2_to_name,
0683                   command, cfile);
0684 smb2_rename_path:
0685     kfree(smb2_to_name);
0686     return rc;
0687 }
0688 
0689 int
0690 smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon,
0691          const char *from_name, const char *to_name,
0692          struct cifs_sb_info *cifs_sb)
0693 {
0694     struct cifsFileInfo *cfile;
0695 
0696     cifs_get_writable_path(tcon, from_name, FIND_WR_WITH_DELETE, &cfile);
0697 
0698     return smb2_set_path_attr(xid, tcon, from_name, to_name,
0699                   cifs_sb, DELETE, SMB2_OP_RENAME, cfile);
0700 }
0701 
0702 int
0703 smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
0704              const char *from_name, const char *to_name,
0705              struct cifs_sb_info *cifs_sb)
0706 {
0707     return smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
0708                   FILE_READ_ATTRIBUTES, SMB2_OP_HARDLINK,
0709                   NULL);
0710 }
0711 
0712 int
0713 smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
0714            const char *full_path, __u64 size,
0715            struct cifs_sb_info *cifs_sb, bool set_alloc)
0716 {
0717     __le64 eof = cpu_to_le64(size);
0718     struct cifsFileInfo *cfile;
0719 
0720     cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
0721     return smb2_compound_op(xid, tcon, cifs_sb, full_path,
0722                 FILE_WRITE_DATA, FILE_OPEN, 0, ACL_NO_MODE,
0723                 &eof, SMB2_OP_SET_EOF, cfile);
0724 }
0725 
0726 int
0727 smb2_set_file_info(struct inode *inode, const char *full_path,
0728            FILE_BASIC_INFO *buf, const unsigned int xid)
0729 {
0730     struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
0731     struct tcon_link *tlink;
0732     struct cifs_tcon *tcon;
0733     struct cifsFileInfo *cfile;
0734     int rc;
0735 
0736     if ((buf->CreationTime == 0) && (buf->LastAccessTime == 0) &&
0737         (buf->LastWriteTime == 0) && (buf->ChangeTime == 0) &&
0738         (buf->Attributes == 0))
0739         return 0; /* would be a no op, no sense sending this */
0740 
0741     tlink = cifs_sb_tlink(cifs_sb);
0742     if (IS_ERR(tlink))
0743         return PTR_ERR(tlink);
0744     tcon = tlink_tcon(tlink);
0745 
0746     cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
0747     rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
0748                   FILE_WRITE_ATTRIBUTES, FILE_OPEN,
0749                   0, ACL_NO_MODE, buf, SMB2_OP_SET_INFO, cfile);
0750     cifs_put_tlink(tlink);
0751     return rc;
0752 }