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
  50static int
  51smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
  52                 struct cifs_sb_info *cifs_sb, const char *full_path,
  53                 __u32 desired_access, __u32 create_disposition,
  54                 __u32 create_options, void *ptr, int command)
  55{
  56        int rc;
  57        __le16 *utf16_path = NULL;
  58        __u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
  59        struct cifs_open_parms oparms;
  60        struct cifs_fid fid;
  61        struct cifs_ses *ses = tcon->ses;
  62        int num_rqst = 0;
  63        struct smb_rqst rqst[3];
  64        int resp_buftype[3];
  65        struct kvec rsp_iov[3];
  66        struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
  67        struct kvec qi_iov[1];
  68        struct kvec si_iov[SMB2_SET_INFO_IOV_SIZE];
  69        struct kvec close_iov[1];
  70        struct smb2_query_info_rsp *qi_rsp = NULL;
  71        int flags = 0;
  72        __u8 delete_pending[8] = {1, 0, 0, 0, 0, 0, 0, 0};
  73        unsigned int size[2];
  74        void *data[2];
  75        struct smb2_file_rename_info rename_info;
  76        struct smb2_file_link_info link_info;
  77        int len;
  78
  79        if (smb3_encryption_required(tcon))
  80                flags |= CIFS_TRANSFORM_REQ;
  81
  82        memset(rqst, 0, sizeof(rqst));
  83        resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
  84        memset(rsp_iov, 0, sizeof(rsp_iov));
  85
  86        /* Open */
  87        utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
  88        if (!utf16_path)
  89                return -ENOMEM;
  90
  91        oparms.tcon = tcon;
  92        oparms.desired_access = desired_access;
  93        oparms.disposition = create_disposition;
  94        oparms.create_options = create_options;
  95        if (backup_cred(cifs_sb))
  96                oparms.create_options |= CREATE_OPEN_BACKUP_INTENT;
  97        oparms.fid = &fid;
  98        oparms.reconnect = false;
  99
 100        memset(&open_iov, 0, sizeof(open_iov));
 101        rqst[num_rqst].rq_iov = open_iov;
 102        rqst[num_rqst].rq_nvec = SMB2_CREATE_IOV_SIZE;
 103        rc = SMB2_open_init(tcon, &rqst[num_rqst], &oplock, &oparms,
 104                            utf16_path);
 105        kfree(utf16_path);
 106        if (rc)
 107                goto finished;
 108
 109        smb2_set_next_command(tcon, &rqst[num_rqst++]);
 110
 111        /* Operation */
 112        switch (command) {
 113        case SMB2_OP_QUERY_INFO:
 114                memset(&qi_iov, 0, sizeof(qi_iov));
 115                rqst[num_rqst].rq_iov = qi_iov;
 116                rqst[num_rqst].rq_nvec = 1;
 117
 118                rc = SMB2_query_info_init(tcon, &rqst[num_rqst], COMPOUND_FID,
 119                                COMPOUND_FID, FILE_ALL_INFORMATION,
 120                                SMB2_O_INFO_FILE, 0,
 121                                sizeof(struct smb2_file_all_info) +
 122                                          PATH_MAX * 2, 0, NULL);
 123                if (rc)
 124                        goto finished;
 125                smb2_set_next_command(tcon, &rqst[num_rqst]);
 126                smb2_set_related(&rqst[num_rqst++]);
 127                trace_smb3_query_info_compound_enter(xid, ses->Suid, tcon->tid,
 128                                                     full_path);
 129                break;
 130        case SMB2_OP_DELETE:
 131                trace_smb3_delete_enter(xid, ses->Suid, tcon->tid, full_path);
 132                break;
 133        case SMB2_OP_MKDIR:
 134                /*
 135                 * Directories are created through parameters in the
 136                 * SMB2_open() call.
 137                 */
 138                trace_smb3_mkdir_enter(xid, ses->Suid, tcon->tid, full_path);
 139                break;
 140        case SMB2_OP_RMDIR:
 141                memset(&si_iov, 0, sizeof(si_iov));
 142                rqst[num_rqst].rq_iov = si_iov;
 143                rqst[num_rqst].rq_nvec = 1;
 144
 145                size[0] = 1; /* sizeof __u8 See MS-FSCC section 2.4.11 */
 146                data[0] = &delete_pending[0];
 147
 148                rc = SMB2_set_info_init(tcon, &rqst[num_rqst], COMPOUND_FID,
 149                                        COMPOUND_FID, current->tgid,
 150                                        FILE_DISPOSITION_INFORMATION,
 151                                        SMB2_O_INFO_FILE, 0, data, size);
 152                if (rc)
 153                        goto finished;
 154                smb2_set_next_command(tcon, &rqst[num_rqst]);
 155                smb2_set_related(&rqst[num_rqst++]);
 156                trace_smb3_rmdir_enter(xid, ses->Suid, tcon->tid, full_path);
 157                break;
 158        case SMB2_OP_SET_EOF:
 159                memset(&si_iov, 0, sizeof(si_iov));
 160                rqst[num_rqst].rq_iov = si_iov;
 161                rqst[num_rqst].rq_nvec = 1;
 162
 163                size[0] = 8; /* sizeof __le64 */
 164                data[0] = ptr;
 165
 166                rc = SMB2_set_info_init(tcon, &rqst[num_rqst], COMPOUND_FID,
 167                                        COMPOUND_FID, current->tgid,
 168                                        FILE_END_OF_FILE_INFORMATION,
 169                                        SMB2_O_INFO_FILE, 0, data, size);
 170                if (rc)
 171                        goto finished;
 172                smb2_set_next_command(tcon, &rqst[num_rqst]);
 173                smb2_set_related(&rqst[num_rqst++]);
 174                trace_smb3_set_eof_enter(xid, ses->Suid, tcon->tid, full_path);
 175                break;
 176        case SMB2_OP_SET_INFO:
 177                memset(&si_iov, 0, sizeof(si_iov));
 178                rqst[num_rqst].rq_iov = si_iov;
 179                rqst[num_rqst].rq_nvec = 1;
 180
 181
 182                size[0] = sizeof(FILE_BASIC_INFO);
 183                data[0] = ptr;
 184
 185                rc = SMB2_set_info_init(tcon, &rqst[num_rqst], COMPOUND_FID,
 186                                        COMPOUND_FID, current->tgid,
 187                                        FILE_BASIC_INFORMATION,
 188                                        SMB2_O_INFO_FILE, 0, data, size);
 189                if (rc)
 190                        goto finished;
 191                smb2_set_next_command(tcon, &rqst[num_rqst]);
 192                smb2_set_related(&rqst[num_rqst++]);
 193                trace_smb3_set_info_compound_enter(xid, ses->Suid, tcon->tid,
 194                                                   full_path);
 195                break;
 196        case SMB2_OP_RENAME:
 197                memset(&si_iov, 0, sizeof(si_iov));
 198                rqst[num_rqst].rq_iov = si_iov;
 199                rqst[num_rqst].rq_nvec = 2;
 200
 201                len = (2 * UniStrnlen((wchar_t *)ptr, PATH_MAX));
 202
 203                rename_info.ReplaceIfExists = 1;
 204                rename_info.RootDirectory = 0;
 205                rename_info.FileNameLength = cpu_to_le32(len);
 206
 207                size[0] = sizeof(struct smb2_file_rename_info);
 208                data[0] = &rename_info;
 209
 210                size[1] = len + 2 /* null */;
 211                data[1] = (__le16 *)ptr;
 212
 213                rc = SMB2_set_info_init(tcon, &rqst[num_rqst], COMPOUND_FID,
 214                                        COMPOUND_FID, current->tgid,
 215                                        FILE_RENAME_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_rename_enter(xid, ses->Suid, tcon->tid, full_path);
 222                break;
 223        case SMB2_OP_HARDLINK:
 224                memset(&si_iov, 0, sizeof(si_iov));
 225                rqst[num_rqst].rq_iov = si_iov;
 226                rqst[num_rqst].rq_nvec = 2;
 227
 228                len = (2 * UniStrnlen((wchar_t *)ptr, PATH_MAX));
 229
 230                link_info.ReplaceIfExists = 0;
 231                link_info.RootDirectory = 0;
 232                link_info.FileNameLength = cpu_to_le32(len);
 233
 234                size[0] = sizeof(struct smb2_file_link_info);
 235                data[0] = &link_info;
 236
 237                size[1] = len + 2 /* null */;
 238                data[1] = (__le16 *)ptr;
 239
 240                rc = SMB2_set_info_init(tcon, &rqst[num_rqst], COMPOUND_FID,
 241                                        COMPOUND_FID, current->tgid,
 242                                        FILE_LINK_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_hardlink_enter(xid, ses->Suid, tcon->tid, full_path);
 249                break;
 250        default:
 251                cifs_dbg(VFS, "Invalid command\n");
 252                rc = -EINVAL;
 253        }
 254        if (rc)
 255                goto finished;
 256
 257        /* Close */
 258        memset(&close_iov, 0, sizeof(close_iov));
 259        rqst[num_rqst].rq_iov = close_iov;
 260        rqst[num_rqst].rq_nvec = 1;
 261        rc = SMB2_close_init(tcon, &rqst[num_rqst], COMPOUND_FID,
 262                             COMPOUND_FID);
 263        smb2_set_related(&rqst[num_rqst++]);
 264        if (rc)
 265                goto finished;
 266
 267        rc = compound_send_recv(xid, ses, flags, num_rqst, rqst,
 268                                resp_buftype, rsp_iov);
 269
 270 finished:
 271        SMB2_open_free(&rqst[0]);
 272        switch (command) {
 273        case SMB2_OP_QUERY_INFO:
 274                if (rc == 0) {
 275                        qi_rsp = (struct smb2_query_info_rsp *)
 276                                rsp_iov[1].iov_base;
 277                        rc = smb2_validate_and_copy_iov(
 278                                le16_to_cpu(qi_rsp->OutputBufferOffset),
 279                                le32_to_cpu(qi_rsp->OutputBufferLength),
 280                                &rsp_iov[1], sizeof(struct smb2_file_all_info),
 281                                ptr);
 282                }
 283                if (rqst[1].rq_iov)
 284                        SMB2_query_info_free(&rqst[1]);
 285                if (rqst[2].rq_iov)
 286                        SMB2_close_free(&rqst[2]);
 287                if (rc)
 288                        trace_smb3_query_info_compound_err(xid,  ses->Suid,
 289                                                tcon->tid, rc);
 290                else
 291                        trace_smb3_query_info_compound_done(xid, ses->Suid,
 292                                                tcon->tid);
 293                break;
 294        case SMB2_OP_DELETE:
 295                if (rc)
 296                        trace_smb3_delete_err(xid,  ses->Suid, tcon->tid, rc);
 297                else
 298                        trace_smb3_delete_done(xid, ses->Suid, tcon->tid);
 299                if (rqst[1].rq_iov)
 300                        SMB2_close_free(&rqst[1]);
 301                break;
 302        case SMB2_OP_MKDIR:
 303                if (rc)
 304                        trace_smb3_mkdir_err(xid,  ses->Suid, tcon->tid, rc);
 305                else
 306                        trace_smb3_mkdir_done(xid, ses->Suid, tcon->tid);
 307                if (rqst[1].rq_iov)
 308                        SMB2_close_free(&rqst[1]);
 309                break;
 310        case SMB2_OP_HARDLINK:
 311                if (rc)
 312                        trace_smb3_hardlink_err(xid,  ses->Suid, tcon->tid, rc);
 313                else
 314                        trace_smb3_hardlink_done(xid, ses->Suid, tcon->tid);
 315                free_set_inf_compound(rqst);
 316                break;
 317        case SMB2_OP_RENAME:
 318                if (rc)
 319                        trace_smb3_rename_err(xid,  ses->Suid, tcon->tid, rc);
 320                else
 321                        trace_smb3_rename_done(xid, ses->Suid, tcon->tid);
 322                free_set_inf_compound(rqst);
 323                break;
 324        case SMB2_OP_RMDIR:
 325                if (rc)
 326                        trace_smb3_rmdir_err(xid,  ses->Suid, tcon->tid, rc);
 327                else
 328                        trace_smb3_rmdir_done(xid, ses->Suid, tcon->tid);
 329                free_set_inf_compound(rqst);
 330                break;
 331        case SMB2_OP_SET_EOF:
 332                if (rc)
 333                        trace_smb3_set_eof_err(xid,  ses->Suid, tcon->tid, rc);
 334                else
 335                        trace_smb3_set_eof_done(xid, ses->Suid, tcon->tid);
 336                free_set_inf_compound(rqst);
 337                break;
 338        case SMB2_OP_SET_INFO:
 339                if (rc)
 340                        trace_smb3_set_info_compound_err(xid,  ses->Suid,
 341                                                tcon->tid, rc);
 342                else
 343                        trace_smb3_set_info_compound_done(xid, ses->Suid,
 344                                                tcon->tid);
 345                free_set_inf_compound(rqst);
 346                break;
 347        }
 348        free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
 349        free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
 350        free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base);
 351        return rc;
 352}
 353
 354void
 355move_smb2_info_to_cifs(FILE_ALL_INFO *dst, struct smb2_file_all_info *src)
 356{
 357        memcpy(dst, src, (size_t)(&src->CurrentByteOffset) - (size_t)src);
 358        dst->CurrentByteOffset = src->CurrentByteOffset;
 359        dst->Mode = src->Mode;
 360        dst->AlignmentRequirement = src->AlignmentRequirement;
 361        dst->IndexNumber1 = 0; /* we don't use it */
 362}
 363
 364int
 365smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
 366                     struct cifs_sb_info *cifs_sb, const char *full_path,
 367                     FILE_ALL_INFO *data, bool *adjust_tz, bool *symlink)
 368{
 369        int rc;
 370        struct smb2_file_all_info *smb2_data;
 371        __u32 create_options = 0;
 372        struct cifs_fid fid;
 373        bool no_cached_open = tcon->nohandlecache;
 374
 375        *adjust_tz = false;
 376        *symlink = false;
 377
 378        smb2_data = kzalloc(sizeof(struct smb2_file_all_info) + PATH_MAX * 2,
 379                            GFP_KERNEL);
 380        if (smb2_data == NULL)
 381                return -ENOMEM;
 382
 383        /* If it is a root and its handle is cached then use it */
 384        if (!strlen(full_path) && !no_cached_open) {
 385                rc = open_shroot(xid, tcon, &fid);
 386                if (rc)
 387                        goto out;
 388
 389                if (tcon->crfid.file_all_info_is_valid) {
 390                        move_smb2_info_to_cifs(data,
 391                                               &tcon->crfid.file_all_info);
 392                } else {
 393                        rc = SMB2_query_info(xid, tcon, fid.persistent_fid,
 394                                             fid.volatile_fid, smb2_data);
 395                        if (!rc)
 396                                move_smb2_info_to_cifs(data, smb2_data);
 397                }
 398                close_shroot(&tcon->crfid);
 399                goto out;
 400        }
 401
 402        if (backup_cred(cifs_sb))
 403                create_options |= CREATE_OPEN_BACKUP_INTENT;
 404
 405        rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
 406                              FILE_READ_ATTRIBUTES, FILE_OPEN, create_options,
 407                              smb2_data, SMB2_OP_QUERY_INFO);
 408        if (rc == -EOPNOTSUPP) {
 409                *symlink = true;
 410                create_options |= OPEN_REPARSE_POINT;
 411
 412                /* Failed on a symbolic link - query a reparse point info */
 413                rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
 414                                      FILE_READ_ATTRIBUTES, FILE_OPEN,
 415                                      create_options, smb2_data,
 416                                      SMB2_OP_QUERY_INFO);
 417        }
 418        if (rc)
 419                goto out;
 420
 421        move_smb2_info_to_cifs(data, smb2_data);
 422out:
 423        kfree(smb2_data);
 424        return rc;
 425}
 426
 427int
 428smb2_mkdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
 429           struct cifs_sb_info *cifs_sb)
 430{
 431        return smb2_compound_op(xid, tcon, cifs_sb, name,
 432                                FILE_WRITE_ATTRIBUTES, FILE_CREATE,
 433                                CREATE_NOT_FILE, NULL, SMB2_OP_MKDIR);
 434}
 435
 436void
 437smb2_mkdir_setinfo(struct inode *inode, const char *name,
 438                   struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon,
 439                   const unsigned int xid)
 440{
 441        FILE_BASIC_INFO data;
 442        struct cifsInodeInfo *cifs_i;
 443        u32 dosattrs;
 444        int tmprc;
 445
 446        memset(&data, 0, sizeof(data));
 447        cifs_i = CIFS_I(inode);
 448        dosattrs = cifs_i->cifsAttrs | ATTR_READONLY;
 449        data.Attributes = cpu_to_le32(dosattrs);
 450        tmprc = smb2_compound_op(xid, tcon, cifs_sb, name,
 451                                 FILE_WRITE_ATTRIBUTES, FILE_CREATE,
 452                                 CREATE_NOT_FILE, &data, SMB2_OP_SET_INFO);
 453        if (tmprc == 0)
 454                cifs_i->cifsAttrs = dosattrs;
 455}
 456
 457int
 458smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
 459           struct cifs_sb_info *cifs_sb)
 460{
 461        return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
 462                                CREATE_NOT_FILE,
 463                                NULL, SMB2_OP_RMDIR);
 464}
 465
 466int
 467smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
 468            struct cifs_sb_info *cifs_sb)
 469{
 470        return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
 471                                CREATE_DELETE_ON_CLOSE | OPEN_REPARSE_POINT,
 472                                NULL, SMB2_OP_DELETE);
 473}
 474
 475static int
 476smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
 477                   const char *from_name, const char *to_name,
 478                   struct cifs_sb_info *cifs_sb, __u32 access, int command)
 479{
 480        __le16 *smb2_to_name = NULL;
 481        int rc;
 482
 483        smb2_to_name = cifs_convert_path_to_utf16(to_name, cifs_sb);
 484        if (smb2_to_name == NULL) {
 485                rc = -ENOMEM;
 486                goto smb2_rename_path;
 487        }
 488        rc = smb2_compound_op(xid, tcon, cifs_sb, from_name, access,
 489                              FILE_OPEN, 0, smb2_to_name, command);
 490smb2_rename_path:
 491        kfree(smb2_to_name);
 492        return rc;
 493}
 494
 495int
 496smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon,
 497                 const char *from_name, const char *to_name,
 498                 struct cifs_sb_info *cifs_sb)
 499{
 500        return smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
 501                                  DELETE, SMB2_OP_RENAME);
 502}
 503
 504int
 505smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
 506                     const char *from_name, const char *to_name,
 507                     struct cifs_sb_info *cifs_sb)
 508{
 509        return smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
 510                                  FILE_READ_ATTRIBUTES, SMB2_OP_HARDLINK);
 511}
 512
 513int
 514smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
 515                   const char *full_path, __u64 size,
 516                   struct cifs_sb_info *cifs_sb, bool set_alloc)
 517{
 518        __le64 eof = cpu_to_le64(size);
 519
 520        return smb2_compound_op(xid, tcon, cifs_sb, full_path,
 521                                FILE_WRITE_DATA, FILE_OPEN, 0, &eof,
 522                                SMB2_OP_SET_EOF);
 523}
 524
 525int
 526smb2_set_file_info(struct inode *inode, const char *full_path,
 527                   FILE_BASIC_INFO *buf, const unsigned int xid)
 528{
 529        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
 530        struct tcon_link *tlink;
 531        int rc;
 532
 533        if ((buf->CreationTime == 0) && (buf->LastAccessTime == 0) &&
 534            (buf->LastWriteTime == 0) && (buf->ChangeTime == 0) &&
 535            (buf->Attributes == 0))
 536                return 0; /* would be a no op, no sense sending this */
 537
 538        tlink = cifs_sb_tlink(cifs_sb);
 539        if (IS_ERR(tlink))
 540                return PTR_ERR(tlink);
 541
 542        rc = smb2_compound_op(xid, tlink_tcon(tlink), cifs_sb, full_path,
 543                              FILE_WRITE_ATTRIBUTES, FILE_OPEN, 0, buf,
 544                              SMB2_OP_SET_INFO);
 545        cifs_put_tlink(tlink);
 546        return rc;
 547}
 548