linux/fs/cifs/smb2inode.c
<<
>>
Prefs
   1// SPDX-License-Identifier: LGPL-2.1
   2/*
   3 *
   4 *   Copyright (C) International Business Machines  Corp., 2002, 2011
   5 *                 Etersoft, 2012
   6 *   Author(s): Pavel Shilovsky (pshilovsky@samba.org),
   7 *              Steve French (sfrench@us.ibm.com)
   8 *
   9 */
  10#include <linux/fs.h>
  11#include <linux/stat.h>
  12#include <linux/slab.h>
  13#include <linux/pagemap.h>
  14#include <asm/div64.h>
  15#include "cifsfs.h"
  16#include "cifspdu.h"
  17#include "cifsglob.h"
  18#include "cifsproto.h"
  19#include "cifs_debug.h"
  20#include "cifs_fs_sb.h"
  21#include "cifs_unicode.h"
  22#include "fscache.h"
  23#include "smb2glob.h"
  24#include "smb2pdu.h"
  25#include "smb2proto.h"
  26
  27static void
  28free_set_inf_compound(struct smb_rqst *rqst)
  29{
  30        if (rqst[1].rq_iov)
  31                SMB2_set_info_free(&rqst[1]);
  32        if (rqst[2].rq_iov)
  33                SMB2_close_free(&rqst[2]);
  34}
  35
  36
  37struct cop_vars {
  38        struct cifs_open_parms oparms;
  39        struct kvec rsp_iov[3];
  40        struct smb_rqst rqst[3];
  41        struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
  42        struct kvec qi_iov[1];
  43        struct kvec si_iov[SMB2_SET_INFO_IOV_SIZE];
  44        struct kvec close_iov[1];
  45        struct smb2_file_rename_info rename_info;
  46        struct smb2_file_link_info link_info;
  47};
  48
  49/*
  50 * note: If cfile is passed, the reference to it is dropped here.
  51 * So make sure that you do not reuse cfile after return from this func.
  52 */
  53static int
  54smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
  55                 struct cifs_sb_info *cifs_sb, const char *full_path,
  56                 __u32 desired_access, __u32 create_disposition,
  57                 __u32 create_options, umode_t mode, void *ptr, int command,
  58                 struct cifsFileInfo *cfile)
  59{
  60        struct cop_vars *vars = NULL;
  61        struct kvec *rsp_iov;
  62        struct smb_rqst *rqst;
  63        int rc;
  64        __le16 *utf16_path = NULL;
  65        __u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
  66        struct cifs_fid fid;
  67        struct cifs_ses *ses = tcon->ses;
  68        struct TCP_Server_Info *server;
  69        int num_rqst = 0;
  70        int resp_buftype[3];
  71        struct smb2_query_info_rsp *qi_rsp = NULL;
  72        int flags = 0;
  73        __u8 delete_pending[8] = {1, 0, 0, 0, 0, 0, 0, 0};
  74        unsigned int size[2];
  75        void *data[2];
  76        int len;
  77
  78        vars = kzalloc(sizeof(*vars), GFP_ATOMIC);
  79        if (vars == NULL)
  80                return -ENOMEM;
  81        rqst = &vars->rqst[0];
  82        rsp_iov = &vars->rsp_iov[0];
  83
  84        server = cifs_pick_channel(ses);
  85
  86        if (smb3_encryption_required(tcon))
  87                flags |= CIFS_TRANSFORM_REQ;
  88
  89        resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
  90
  91        /* We already have a handle so we can skip the open */
  92        if (cfile)
  93                goto after_open;
  94
  95        /* Open */
  96        utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
  97        if (!utf16_path) {
  98                rc = -ENOMEM;
  99                goto finished;
 100        }
 101
 102        vars->oparms.tcon = tcon;
 103        vars->oparms.desired_access = desired_access;
 104        vars->oparms.disposition = create_disposition;
 105        vars->oparms.create_options = cifs_create_options(cifs_sb, create_options);
 106        vars->oparms.fid = &fid;
 107        vars->oparms.reconnect = false;
 108        vars->oparms.mode = mode;
 109        vars->oparms.cifs_sb = cifs_sb;
 110
 111        rqst[num_rqst].rq_iov = &vars->open_iov[0];
 112        rqst[num_rqst].rq_nvec = SMB2_CREATE_IOV_SIZE;
 113        rc = SMB2_open_init(tcon, server,
 114                            &rqst[num_rqst], &oplock, &vars->oparms,
 115                            utf16_path);
 116        kfree(utf16_path);
 117        if (rc)
 118                goto finished;
 119
 120        smb2_set_next_command(tcon, &rqst[num_rqst]);
 121 after_open:
 122        num_rqst++;
 123        rc = 0;
 124
 125        /* Operation */
 126        switch (command) {
 127        case SMB2_OP_QUERY_INFO:
 128                rqst[num_rqst].rq_iov = &vars->qi_iov[0];
 129                rqst[num_rqst].rq_nvec = 1;
 130
 131                if (cfile)
 132                        rc = SMB2_query_info_init(tcon, server,
 133                                &rqst[num_rqst],
 134                                cfile->fid.persistent_fid,
 135                                cfile->fid.volatile_fid,
 136                                FILE_ALL_INFORMATION,
 137                                SMB2_O_INFO_FILE, 0,
 138                                sizeof(struct smb2_file_all_info) +
 139                                          PATH_MAX * 2, 0, NULL);
 140                else {
 141                        rc = SMB2_query_info_init(tcon, server,
 142                                &rqst[num_rqst],
 143                                COMPOUND_FID,
 144                                COMPOUND_FID,
 145                                FILE_ALL_INFORMATION,
 146                                SMB2_O_INFO_FILE, 0,
 147                                sizeof(struct smb2_file_all_info) +
 148                                          PATH_MAX * 2, 0, NULL);
 149                        if (!rc) {
 150                                smb2_set_next_command(tcon, &rqst[num_rqst]);
 151                                smb2_set_related(&rqst[num_rqst]);
 152                        }
 153                }
 154
 155                if (rc)
 156                        goto finished;
 157                num_rqst++;
 158                trace_smb3_query_info_compound_enter(xid, ses->Suid, tcon->tid,
 159                                                     full_path);
 160                break;
 161        case SMB2_OP_POSIX_QUERY_INFO:
 162                rqst[num_rqst].rq_iov = &vars->qi_iov[0];
 163                rqst[num_rqst].rq_nvec = 1;
 164
 165                if (cfile)
 166                        rc = SMB2_query_info_init(tcon, server,
 167                                &rqst[num_rqst],
 168                                cfile->fid.persistent_fid,
 169                                cfile->fid.volatile_fid,
 170                                SMB_FIND_FILE_POSIX_INFO,
 171                                SMB2_O_INFO_FILE, 0,
 172                                /* TBD: fix following to allow for longer SIDs */
 173                                sizeof(struct smb311_posix_qinfo *) + (PATH_MAX * 2) +
 174                                (sizeof(struct cifs_sid) * 2), 0, NULL);
 175                else {
 176                        rc = SMB2_query_info_init(tcon, server,
 177                                &rqst[num_rqst],
 178                                COMPOUND_FID,
 179                                COMPOUND_FID,
 180                                SMB_FIND_FILE_POSIX_INFO,
 181                                SMB2_O_INFO_FILE, 0,
 182                                sizeof(struct smb311_posix_qinfo *) + (PATH_MAX * 2) +
 183                                (sizeof(struct cifs_sid) * 2), 0, NULL);
 184                        if (!rc) {
 185                                smb2_set_next_command(tcon, &rqst[num_rqst]);
 186                                smb2_set_related(&rqst[num_rqst]);
 187                        }
 188                }
 189
 190                if (rc)
 191                        goto finished;
 192                num_rqst++;
 193                trace_smb3_posix_query_info_compound_enter(xid, ses->Suid, tcon->tid, full_path);
 194                break;
 195        case SMB2_OP_DELETE:
 196                trace_smb3_delete_enter(xid, ses->Suid, tcon->tid, full_path);
 197                break;
 198        case SMB2_OP_MKDIR:
 199                /*
 200                 * Directories are created through parameters in the
 201                 * SMB2_open() call.
 202                 */
 203                trace_smb3_mkdir_enter(xid, ses->Suid, tcon->tid, full_path);
 204                break;
 205        case SMB2_OP_RMDIR:
 206                rqst[num_rqst].rq_iov = &vars->si_iov[0];
 207                rqst[num_rqst].rq_nvec = 1;
 208
 209                size[0] = 1; /* sizeof __u8 See MS-FSCC section 2.4.11 */
 210                data[0] = &delete_pending[0];
 211
 212                rc = SMB2_set_info_init(tcon, server,
 213                                        &rqst[num_rqst], COMPOUND_FID,
 214                                        COMPOUND_FID, current->tgid,
 215                                        FILE_DISPOSITION_INFORMATION,
 216                                        SMB2_O_INFO_FILE, 0, data, size);
 217                if (rc)
 218                        goto finished;
 219                smb2_set_next_command(tcon, &rqst[num_rqst]);
 220                smb2_set_related(&rqst[num_rqst++]);
 221                trace_smb3_rmdir_enter(xid, ses->Suid, tcon->tid, full_path);
 222                break;
 223        case SMB2_OP_SET_EOF:
 224                rqst[num_rqst].rq_iov = &vars->si_iov[0];
 225                rqst[num_rqst].rq_nvec = 1;
 226
 227                size[0] = 8; /* sizeof __le64 */
 228                data[0] = ptr;
 229
 230                rc = SMB2_set_info_init(tcon, server,
 231                                        &rqst[num_rqst], COMPOUND_FID,
 232                                        COMPOUND_FID, current->tgid,
 233                                        FILE_END_OF_FILE_INFORMATION,
 234                                        SMB2_O_INFO_FILE, 0, data, size);
 235                if (rc)
 236                        goto finished;
 237                smb2_set_next_command(tcon, &rqst[num_rqst]);
 238                smb2_set_related(&rqst[num_rqst++]);
 239                trace_smb3_set_eof_enter(xid, ses->Suid, tcon->tid, full_path);
 240                break;
 241        case SMB2_OP_SET_INFO:
 242                rqst[num_rqst].rq_iov = &vars->si_iov[0];
 243                rqst[num_rqst].rq_nvec = 1;
 244
 245
 246                size[0] = sizeof(FILE_BASIC_INFO);
 247                data[0] = ptr;
 248
 249                if (cfile)
 250                        rc = SMB2_set_info_init(tcon, server,
 251                                &rqst[num_rqst],
 252                                cfile->fid.persistent_fid,
 253                                cfile->fid.volatile_fid, current->tgid,
 254                                FILE_BASIC_INFORMATION,
 255                                SMB2_O_INFO_FILE, 0, data, size);
 256                else {
 257                        rc = SMB2_set_info_init(tcon, server,
 258                                &rqst[num_rqst],
 259                                COMPOUND_FID,
 260                                COMPOUND_FID, current->tgid,
 261                                FILE_BASIC_INFORMATION,
 262                                SMB2_O_INFO_FILE, 0, data, size);
 263                        if (!rc) {
 264                                smb2_set_next_command(tcon, &rqst[num_rqst]);
 265                                smb2_set_related(&rqst[num_rqst]);
 266                        }
 267                }
 268
 269                if (rc)
 270                        goto finished;
 271                num_rqst++;
 272                trace_smb3_set_info_compound_enter(xid, ses->Suid, tcon->tid,
 273                                                   full_path);
 274                break;
 275        case SMB2_OP_RENAME:
 276                rqst[num_rqst].rq_iov = &vars->si_iov[0];
 277                rqst[num_rqst].rq_nvec = 2;
 278
 279                len = (2 * UniStrnlen((wchar_t *)ptr, PATH_MAX));
 280
 281                vars->rename_info.ReplaceIfExists = 1;
 282                vars->rename_info.RootDirectory = 0;
 283                vars->rename_info.FileNameLength = cpu_to_le32(len);
 284
 285                size[0] = sizeof(struct smb2_file_rename_info);
 286                data[0] = &vars->rename_info;
 287
 288                size[1] = len + 2 /* null */;
 289                data[1] = (__le16 *)ptr;
 290
 291                if (cfile)
 292                        rc = SMB2_set_info_init(tcon, server,
 293                                                &rqst[num_rqst],
 294                                                cfile->fid.persistent_fid,
 295                                                cfile->fid.volatile_fid,
 296                                        current->tgid, FILE_RENAME_INFORMATION,
 297                                        SMB2_O_INFO_FILE, 0, data, size);
 298                else {
 299                        rc = SMB2_set_info_init(tcon, server,
 300                                        &rqst[num_rqst],
 301                                        COMPOUND_FID, COMPOUND_FID,
 302                                        current->tgid, FILE_RENAME_INFORMATION,
 303                                        SMB2_O_INFO_FILE, 0, data, size);
 304                        if (!rc) {
 305                                smb2_set_next_command(tcon, &rqst[num_rqst]);
 306                                smb2_set_related(&rqst[num_rqst]);
 307                        }
 308                }
 309                if (rc)
 310                        goto finished;
 311                num_rqst++;
 312                trace_smb3_rename_enter(xid, ses->Suid, tcon->tid, full_path);
 313                break;
 314        case SMB2_OP_HARDLINK:
 315                rqst[num_rqst].rq_iov = &vars->si_iov[0];
 316                rqst[num_rqst].rq_nvec = 2;
 317
 318                len = (2 * UniStrnlen((wchar_t *)ptr, PATH_MAX));
 319
 320                vars->link_info.ReplaceIfExists = 0;
 321                vars->link_info.RootDirectory = 0;
 322                vars->link_info.FileNameLength = cpu_to_le32(len);
 323
 324                size[0] = sizeof(struct smb2_file_link_info);
 325                data[0] = &vars->link_info;
 326
 327                size[1] = len + 2 /* null */;
 328                data[1] = (__le16 *)ptr;
 329
 330                rc = SMB2_set_info_init(tcon, server,
 331                                        &rqst[num_rqst], COMPOUND_FID,
 332                                        COMPOUND_FID, current->tgid,
 333                                        FILE_LINK_INFORMATION,
 334                                        SMB2_O_INFO_FILE, 0, data, size);
 335                if (rc)
 336                        goto finished;
 337                smb2_set_next_command(tcon, &rqst[num_rqst]);
 338                smb2_set_related(&rqst[num_rqst++]);
 339                trace_smb3_hardlink_enter(xid, ses->Suid, tcon->tid, full_path);
 340                break;
 341        default:
 342                cifs_dbg(VFS, "Invalid command\n");
 343                rc = -EINVAL;
 344        }
 345        if (rc)
 346                goto finished;
 347
 348        /* We already have a handle so we can skip the close */
 349        if (cfile)
 350                goto after_close;
 351        /* Close */
 352        flags |= CIFS_CP_CREATE_CLOSE_OP;
 353        rqst[num_rqst].rq_iov = &vars->close_iov[0];
 354        rqst[num_rqst].rq_nvec = 1;
 355        rc = SMB2_close_init(tcon, server,
 356                             &rqst[num_rqst], COMPOUND_FID,
 357                             COMPOUND_FID, false);
 358        smb2_set_related(&rqst[num_rqst]);
 359        if (rc)
 360                goto finished;
 361 after_close:
 362        num_rqst++;
 363
 364        if (cfile) {
 365                cifsFileInfo_put(cfile);
 366                cfile = NULL;
 367                rc = compound_send_recv(xid, ses, server,
 368                                        flags, num_rqst - 2,
 369                                        &rqst[1], &resp_buftype[1],
 370                                        &rsp_iov[1]);
 371        } else
 372                rc = compound_send_recv(xid, ses, server,
 373                                        flags, num_rqst,
 374                                        rqst, resp_buftype,
 375                                        rsp_iov);
 376
 377 finished:
 378        if (cfile)
 379                cifsFileInfo_put(cfile);
 380
 381        SMB2_open_free(&rqst[0]);
 382        if (rc == -EREMCHG) {
 383                pr_warn_once("server share %s deleted\n", tcon->treeName);
 384                tcon->need_reconnect = true;
 385        }
 386
 387        switch (command) {
 388        case SMB2_OP_QUERY_INFO:
 389                if (rc == 0) {
 390                        qi_rsp = (struct smb2_query_info_rsp *)
 391                                rsp_iov[1].iov_base;
 392                        rc = smb2_validate_and_copy_iov(
 393                                le16_to_cpu(qi_rsp->OutputBufferOffset),
 394                                le32_to_cpu(qi_rsp->OutputBufferLength),
 395                                &rsp_iov[1], sizeof(struct smb2_file_all_info),
 396                                ptr);
 397                }
 398                if (rqst[1].rq_iov)
 399                        SMB2_query_info_free(&rqst[1]);
 400                if (rqst[2].rq_iov)
 401                        SMB2_close_free(&rqst[2]);
 402                if (rc)
 403                        trace_smb3_query_info_compound_err(xid,  ses->Suid,
 404                                                tcon->tid, rc);
 405                else
 406                        trace_smb3_query_info_compound_done(xid, ses->Suid,
 407                                                tcon->tid);
 408                break;
 409        case SMB2_OP_POSIX_QUERY_INFO:
 410                if (rc == 0) {
 411                        qi_rsp = (struct smb2_query_info_rsp *)
 412                                rsp_iov[1].iov_base;
 413                        rc = smb2_validate_and_copy_iov(
 414                                le16_to_cpu(qi_rsp->OutputBufferOffset),
 415                                le32_to_cpu(qi_rsp->OutputBufferLength),
 416                                &rsp_iov[1], sizeof(struct smb311_posix_qinfo) /* add SIDs */, ptr);
 417                }
 418                if (rqst[1].rq_iov)
 419                        SMB2_query_info_free(&rqst[1]);
 420                if (rqst[2].rq_iov)
 421                        SMB2_close_free(&rqst[2]);
 422                if (rc)
 423                        trace_smb3_posix_query_info_compound_err(xid,  ses->Suid, tcon->tid, rc);
 424                else
 425                        trace_smb3_posix_query_info_compound_done(xid, ses->Suid, tcon->tid);
 426                break;
 427        case SMB2_OP_DELETE:
 428                if (rc)
 429                        trace_smb3_delete_err(xid,  ses->Suid, tcon->tid, rc);
 430                else
 431                        trace_smb3_delete_done(xid, ses->Suid, tcon->tid);
 432                if (rqst[1].rq_iov)
 433                        SMB2_close_free(&rqst[1]);
 434                break;
 435        case SMB2_OP_MKDIR:
 436                if (rc)
 437                        trace_smb3_mkdir_err(xid,  ses->Suid, tcon->tid, rc);
 438                else
 439                        trace_smb3_mkdir_done(xid, ses->Suid, tcon->tid);
 440                if (rqst[1].rq_iov)
 441                        SMB2_close_free(&rqst[1]);
 442                break;
 443        case SMB2_OP_HARDLINK:
 444                if (rc)
 445                        trace_smb3_hardlink_err(xid,  ses->Suid, tcon->tid, rc);
 446                else
 447                        trace_smb3_hardlink_done(xid, ses->Suid, tcon->tid);
 448                free_set_inf_compound(rqst);
 449                break;
 450        case SMB2_OP_RENAME:
 451                if (rc)
 452                        trace_smb3_rename_err(xid,  ses->Suid, tcon->tid, rc);
 453                else
 454                        trace_smb3_rename_done(xid, ses->Suid, tcon->tid);
 455                free_set_inf_compound(rqst);
 456                break;
 457        case SMB2_OP_RMDIR:
 458                if (rc)
 459                        trace_smb3_rmdir_err(xid,  ses->Suid, tcon->tid, rc);
 460                else
 461                        trace_smb3_rmdir_done(xid, ses->Suid, tcon->tid);
 462                free_set_inf_compound(rqst);
 463                break;
 464        case SMB2_OP_SET_EOF:
 465                if (rc)
 466                        trace_smb3_set_eof_err(xid,  ses->Suid, tcon->tid, rc);
 467                else
 468                        trace_smb3_set_eof_done(xid, ses->Suid, tcon->tid);
 469                free_set_inf_compound(rqst);
 470                break;
 471        case SMB2_OP_SET_INFO:
 472                if (rc)
 473                        trace_smb3_set_info_compound_err(xid,  ses->Suid,
 474                                                tcon->tid, rc);
 475                else
 476                        trace_smb3_set_info_compound_done(xid, ses->Suid,
 477                                                tcon->tid);
 478                free_set_inf_compound(rqst);
 479                break;
 480        }
 481        free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
 482        free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
 483        free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base);
 484        kfree(vars);
 485        return rc;
 486}
 487
 488void
 489move_smb2_info_to_cifs(FILE_ALL_INFO *dst, struct smb2_file_all_info *src)
 490{
 491        memcpy(dst, src, (size_t)(&src->CurrentByteOffset) - (size_t)src);
 492        dst->CurrentByteOffset = src->CurrentByteOffset;
 493        dst->Mode = src->Mode;
 494        dst->AlignmentRequirement = src->AlignmentRequirement;
 495        dst->IndexNumber1 = 0; /* we don't use it */
 496}
 497
 498int
 499smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
 500                     struct cifs_sb_info *cifs_sb, const char *full_path,
 501                     FILE_ALL_INFO *data, bool *adjust_tz, bool *reparse)
 502{
 503        int rc;
 504        struct smb2_file_all_info *smb2_data;
 505        __u32 create_options = 0;
 506        struct cifsFileInfo *cfile;
 507        struct cached_fid *cfid = NULL;
 508
 509        *adjust_tz = false;
 510        *reparse = false;
 511
 512        smb2_data = kzalloc(sizeof(struct smb2_file_all_info) + PATH_MAX * 2,
 513                            GFP_KERNEL);
 514        if (smb2_data == NULL)
 515                return -ENOMEM;
 516
 517        /* If it is a root and its handle is cached then use it */
 518        rc = open_cached_dir(xid, tcon, full_path, cifs_sb, &cfid);
 519        if (!rc) {
 520                if (tcon->crfid.file_all_info_is_valid) {
 521                        move_smb2_info_to_cifs(data,
 522                                               &tcon->crfid.file_all_info);
 523                } else {
 524                        rc = SMB2_query_info(xid, tcon,
 525                                             cfid->fid->persistent_fid,
 526                                             cfid->fid->volatile_fid, smb2_data);
 527                        if (!rc)
 528                                move_smb2_info_to_cifs(data, smb2_data);
 529                }
 530                close_cached_dir(cfid);
 531                goto out;
 532        }
 533
 534        cifs_get_readable_path(tcon, full_path, &cfile);
 535        rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
 536                              FILE_READ_ATTRIBUTES, FILE_OPEN, create_options,
 537                              ACL_NO_MODE, smb2_data, SMB2_OP_QUERY_INFO, cfile);
 538        if (rc == -EOPNOTSUPP) {
 539                *reparse = true;
 540                create_options |= OPEN_REPARSE_POINT;
 541
 542                /* Failed on a symbolic link - query a reparse point info */
 543                cifs_get_readable_path(tcon, full_path, &cfile);
 544                rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
 545                                      FILE_READ_ATTRIBUTES, FILE_OPEN,
 546                                      create_options, ACL_NO_MODE,
 547                                      smb2_data, SMB2_OP_QUERY_INFO, cfile);
 548        }
 549        if (rc)
 550                goto out;
 551
 552        move_smb2_info_to_cifs(data, smb2_data);
 553out:
 554        kfree(smb2_data);
 555        return rc;
 556}
 557
 558
 559int
 560smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
 561                     struct cifs_sb_info *cifs_sb, const char *full_path,
 562                     struct smb311_posix_qinfo *data, bool *adjust_tz, bool *reparse)
 563{
 564        int rc;
 565        __u32 create_options = 0;
 566        struct cifsFileInfo *cfile;
 567        struct smb311_posix_qinfo *smb2_data;
 568
 569        *adjust_tz = false;
 570        *reparse = false;
 571
 572        /* BB TODO: Make struct larger when add support for parsing owner SIDs */
 573        smb2_data = kzalloc(sizeof(struct smb311_posix_qinfo),
 574                            GFP_KERNEL);
 575        if (smb2_data == NULL)
 576                return -ENOMEM;
 577
 578        /*
 579         * BB TODO: Add support for using the cached root handle.
 580         * Create SMB2_query_posix_info worker function to do non-compounded query
 581         * when we already have an open file handle for this. For now this is fast enough
 582         * (always using the compounded version).
 583         */
 584
 585        cifs_get_readable_path(tcon, full_path, &cfile);
 586        rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
 587                              FILE_READ_ATTRIBUTES, FILE_OPEN, create_options,
 588                              ACL_NO_MODE, smb2_data, SMB2_OP_POSIX_QUERY_INFO, cfile);
 589        if (rc == -EOPNOTSUPP) {
 590                /* BB TODO: When support for special files added to Samba re-verify this path */
 591                *reparse = true;
 592                create_options |= OPEN_REPARSE_POINT;
 593
 594                /* Failed on a symbolic link - query a reparse point info */
 595                cifs_get_readable_path(tcon, full_path, &cfile);
 596                rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
 597                                      FILE_READ_ATTRIBUTES, FILE_OPEN,
 598                                      create_options, ACL_NO_MODE,
 599                                      smb2_data, SMB2_OP_POSIX_QUERY_INFO, cfile);
 600        }
 601        if (rc)
 602                goto out;
 603
 604         /* TODO: will need to allow for the 2 SIDs when add support for getting owner UID/GID */
 605        memcpy(data, smb2_data, sizeof(struct smb311_posix_qinfo));
 606
 607out:
 608        kfree(smb2_data);
 609        return rc;
 610}
 611
 612int
 613smb2_mkdir(const unsigned int xid, struct inode *parent_inode, umode_t mode,
 614           struct cifs_tcon *tcon, const char *name,
 615           struct cifs_sb_info *cifs_sb)
 616{
 617        return smb2_compound_op(xid, tcon, cifs_sb, name,
 618                                FILE_WRITE_ATTRIBUTES, FILE_CREATE,
 619                                CREATE_NOT_FILE, mode, NULL, SMB2_OP_MKDIR,
 620                                NULL);
 621}
 622
 623void
 624smb2_mkdir_setinfo(struct inode *inode, const char *name,
 625                   struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon,
 626                   const unsigned int xid)
 627{
 628        FILE_BASIC_INFO data;
 629        struct cifsInodeInfo *cifs_i;
 630        struct cifsFileInfo *cfile;
 631        u32 dosattrs;
 632        int tmprc;
 633
 634        memset(&data, 0, sizeof(data));
 635        cifs_i = CIFS_I(inode);
 636        dosattrs = cifs_i->cifsAttrs | ATTR_READONLY;
 637        data.Attributes = cpu_to_le32(dosattrs);
 638        cifs_get_writable_path(tcon, name, FIND_WR_ANY, &cfile);
 639        tmprc = smb2_compound_op(xid, tcon, cifs_sb, name,
 640                                 FILE_WRITE_ATTRIBUTES, FILE_CREATE,
 641                                 CREATE_NOT_FILE, ACL_NO_MODE,
 642                                 &data, SMB2_OP_SET_INFO, cfile);
 643        if (tmprc == 0)
 644                cifs_i->cifsAttrs = dosattrs;
 645}
 646
 647int
 648smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
 649           struct cifs_sb_info *cifs_sb)
 650{
 651        return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
 652                                CREATE_NOT_FILE, ACL_NO_MODE,
 653                                NULL, SMB2_OP_RMDIR, NULL);
 654}
 655
 656int
 657smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
 658            struct cifs_sb_info *cifs_sb)
 659{
 660        return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
 661                                CREATE_DELETE_ON_CLOSE | OPEN_REPARSE_POINT,
 662                                ACL_NO_MODE, NULL, SMB2_OP_DELETE, NULL);
 663}
 664
 665static int
 666smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
 667                   const char *from_name, const char *to_name,
 668                   struct cifs_sb_info *cifs_sb, __u32 access, int command,
 669                   struct cifsFileInfo *cfile)
 670{
 671        __le16 *smb2_to_name = NULL;
 672        int rc;
 673
 674        smb2_to_name = cifs_convert_path_to_utf16(to_name, cifs_sb);
 675        if (smb2_to_name == NULL) {
 676                rc = -ENOMEM;
 677                goto smb2_rename_path;
 678        }
 679        rc = smb2_compound_op(xid, tcon, cifs_sb, from_name, access,
 680                              FILE_OPEN, 0, ACL_NO_MODE, smb2_to_name,
 681                              command, cfile);
 682smb2_rename_path:
 683        kfree(smb2_to_name);
 684        return rc;
 685}
 686
 687int
 688smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon,
 689                 const char *from_name, const char *to_name,
 690                 struct cifs_sb_info *cifs_sb)
 691{
 692        struct cifsFileInfo *cfile;
 693
 694        cifs_get_writable_path(tcon, from_name, FIND_WR_WITH_DELETE, &cfile);
 695
 696        return smb2_set_path_attr(xid, tcon, from_name, to_name,
 697                                  cifs_sb, DELETE, SMB2_OP_RENAME, cfile);
 698}
 699
 700int
 701smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
 702                     const char *from_name, const char *to_name,
 703                     struct cifs_sb_info *cifs_sb)
 704{
 705        return smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
 706                                  FILE_READ_ATTRIBUTES, SMB2_OP_HARDLINK,
 707                                  NULL);
 708}
 709
 710int
 711smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
 712                   const char *full_path, __u64 size,
 713                   struct cifs_sb_info *cifs_sb, bool set_alloc)
 714{
 715        __le64 eof = cpu_to_le64(size);
 716        struct cifsFileInfo *cfile;
 717
 718        cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
 719        return smb2_compound_op(xid, tcon, cifs_sb, full_path,
 720                                FILE_WRITE_DATA, FILE_OPEN, 0, ACL_NO_MODE,
 721                                &eof, SMB2_OP_SET_EOF, cfile);
 722}
 723
 724int
 725smb2_set_file_info(struct inode *inode, const char *full_path,
 726                   FILE_BASIC_INFO *buf, const unsigned int xid)
 727{
 728        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
 729        struct tcon_link *tlink;
 730        struct cifs_tcon *tcon;
 731        struct cifsFileInfo *cfile;
 732        int rc;
 733
 734        if ((buf->CreationTime == 0) && (buf->LastAccessTime == 0) &&
 735            (buf->LastWriteTime == 0) && (buf->ChangeTime == 0) &&
 736            (buf->Attributes == 0))
 737                return 0; /* would be a no op, no sense sending this */
 738
 739        tlink = cifs_sb_tlink(cifs_sb);
 740        if (IS_ERR(tlink))
 741                return PTR_ERR(tlink);
 742        tcon = tlink_tcon(tlink);
 743
 744        cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
 745        rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
 746                              FILE_WRITE_ATTRIBUTES, FILE_OPEN,
 747                              0, ACL_NO_MODE, buf, SMB2_OP_SET_INFO, cfile);
 748        cifs_put_tlink(tlink);
 749        return rc;
 750}
 751