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