0001
0002
0003
0004
0005
0006
0007
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
0052
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
0093 if (cfile)
0094 goto after_open;
0095
0096
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
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
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
0202
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;
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;
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 ;
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 ;
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
0350 if (cfile)
0351 goto after_close;
0352
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) , 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;
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
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
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
0575 smb2_data = kzalloc(sizeof(struct smb311_posix_qinfo),
0576 GFP_KERNEL);
0577 if (smb2_data == NULL)
0578 return -ENOMEM;
0579
0580
0581
0582
0583
0584
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
0593 *reparse = true;
0594 create_options |= OPEN_REPARSE_POINT;
0595
0596
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
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;
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 }