linux/fs/cifs/dir.c
<<
>>
Prefs
   1/*
   2 *   fs/cifs/dir.c
   3 *
   4 *   vfs operations that deal with dentries
   5 *
   6 *   Copyright (C) International Business Machines  Corp., 2002,2007
   7 *   Author(s): 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/namei.h>
  27#include "cifsfs.h"
  28#include "cifspdu.h"
  29#include "cifsglob.h"
  30#include "cifsproto.h"
  31#include "cifs_debug.h"
  32#include "cifs_fs_sb.h"
  33
  34static void
  35renew_parental_timestamps(struct dentry *direntry)
  36{
  37        /* BB check if there is a way to get the kernel to do this or if we
  38           really need this */
  39        do {
  40                direntry->d_time = jiffies;
  41                direntry = direntry->d_parent;
  42        } while (!IS_ROOT(direntry));
  43}
  44
  45/* Note: caller must free return buffer */
  46char *
  47build_path_from_dentry(struct dentry *direntry)
  48{
  49        struct dentry *temp;
  50        int namelen;
  51        int pplen;
  52        char *full_path;
  53        char dirsep;
  54
  55        if (direntry == NULL)
  56                return NULL;  /* not much we can do if dentry is freed and
  57                we need to reopen the file after it was closed implicitly
  58                when the server crashed */
  59
  60        dirsep = CIFS_DIR_SEP(CIFS_SB(direntry->d_sb));
  61        pplen = CIFS_SB(direntry->d_sb)->prepathlen;
  62cifs_bp_rename_retry:
  63        namelen = pplen;
  64        for (temp = direntry; !IS_ROOT(temp);) {
  65                namelen += (1 + temp->d_name.len);
  66                temp = temp->d_parent;
  67                if (temp == NULL) {
  68                        cERROR(1, ("corrupt dentry"));
  69                        return NULL;
  70                }
  71        }
  72
  73        full_path = kmalloc(namelen+1, GFP_KERNEL);
  74        if (full_path == NULL)
  75                return full_path;
  76        full_path[namelen] = 0; /* trailing null */
  77        for (temp = direntry; !IS_ROOT(temp);) {
  78                namelen -= 1 + temp->d_name.len;
  79                if (namelen < 0) {
  80                        break;
  81                } else {
  82                        full_path[namelen] = dirsep;
  83                        strncpy(full_path + namelen + 1, temp->d_name.name,
  84                                temp->d_name.len);
  85                        cFYI(0, ("name: %s", full_path + namelen));
  86                }
  87                temp = temp->d_parent;
  88                if (temp == NULL) {
  89                        cERROR(1, ("corrupt dentry"));
  90                        kfree(full_path);
  91                        return NULL;
  92                }
  93        }
  94        if (namelen != pplen) {
  95                cERROR(1,
  96                       ("did not end path lookup where expected namelen is %d",
  97                        namelen));
  98                /* presumably this is only possible if racing with a rename
  99                of one of the parent directories  (we can not lock the dentries
 100                above us to prevent this, but retrying should be harmless) */
 101                kfree(full_path);
 102                goto cifs_bp_rename_retry;
 103        }
 104        /* DIR_SEP already set for byte  0 / vs \ but not for
 105           subsequent slashes in prepath which currently must
 106           be entered the right way - not sure if there is an alternative
 107           since the '\' is a valid posix character so we can not switch
 108           those safely to '/' if any are found in the middle of the prepath */
 109        /* BB test paths to Windows with '/' in the midst of prepath */
 110        strncpy(full_path, CIFS_SB(direntry->d_sb)->prepath, pplen);
 111        return full_path;
 112}
 113
 114/* char * build_wildcard_path_from_dentry(struct dentry *direntry)
 115{
 116        if(full_path == NULL)
 117                return full_path;
 118
 119        full_path[namelen] = '\\';
 120        full_path[namelen+1] = '*';
 121        full_path[namelen+2] = 0;
 122BB remove above eight lines BB */
 123
 124/* Inode operations in similar order to how they appear in Linux file fs.h */
 125
 126int
 127cifs_create(struct inode *inode, struct dentry *direntry, int mode,
 128                struct nameidata *nd)
 129{
 130        int rc = -ENOENT;
 131        int xid;
 132        int oplock = 0;
 133        int desiredAccess = GENERIC_READ | GENERIC_WRITE;
 134        __u16 fileHandle;
 135        struct cifs_sb_info *cifs_sb;
 136        struct cifsTconInfo *pTcon;
 137        char *full_path = NULL;
 138        FILE_ALL_INFO *buf = NULL;
 139        struct inode *newinode = NULL;
 140        struct cifsFileInfo *pCifsFile = NULL;
 141        struct cifsInodeInfo *pCifsInode;
 142        int disposition = FILE_OVERWRITE_IF;
 143        int write_only = FALSE;
 144
 145        xid = GetXid();
 146
 147        cifs_sb = CIFS_SB(inode->i_sb);
 148        pTcon = cifs_sb->tcon;
 149
 150        full_path = build_path_from_dentry(direntry);
 151        if (full_path == NULL) {
 152                FreeXid(xid);
 153                return -ENOMEM;
 154        }
 155
 156        if (nd && (nd->flags & LOOKUP_OPEN)) {
 157                int oflags = nd->intent.open.flags;
 158
 159                desiredAccess = 0;
 160                if (oflags & FMODE_READ)
 161                        desiredAccess |= GENERIC_READ;
 162                if (oflags & FMODE_WRITE) {
 163                        desiredAccess |= GENERIC_WRITE;
 164                        if (!(oflags & FMODE_READ))
 165                                write_only = TRUE;
 166                }
 167
 168                if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
 169                        disposition = FILE_CREATE;
 170                else if ((oflags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
 171                        disposition = FILE_OVERWRITE_IF;
 172                else if ((oflags & O_CREAT) == O_CREAT)
 173                        disposition = FILE_OPEN_IF;
 174                else {
 175                        cFYI(1, ("Create flag not set in create function"));
 176                }
 177        }
 178
 179        /* BB add processing to set equivalent of mode - e.g. via CreateX with
 180           ACLs */
 181        if (oplockEnabled)
 182                oplock = REQ_OPLOCK;
 183
 184        buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
 185        if (buf == NULL) {
 186                kfree(full_path);
 187                FreeXid(xid);
 188                return -ENOMEM;
 189        }
 190        if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS)
 191                rc = CIFSSMBOpen(xid, pTcon, full_path, disposition,
 192                         desiredAccess, CREATE_NOT_DIR,
 193                         &fileHandle, &oplock, buf, cifs_sb->local_nls,
 194                         cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
 195        else
 196                rc = -EIO; /* no NT SMB support fall into legacy open below */
 197
 198        if (rc == -EIO) {
 199                /* old server, retry the open legacy style */
 200                rc = SMBLegacyOpen(xid, pTcon, full_path, disposition,
 201                        desiredAccess, CREATE_NOT_DIR,
 202                        &fileHandle, &oplock, buf, cifs_sb->local_nls,
 203                        cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
 204        }
 205        if (rc) {
 206                cFYI(1, ("cifs_create returned 0x%x", rc));
 207        } else {
 208                /* If Open reported that we actually created a file
 209                then we now have to set the mode if possible */
 210                if ((pTcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) {
 211                        mode &= ~current->fs->umask;
 212                        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
 213                                CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
 214                                        (__u64)current->fsuid,
 215                                        (__u64)current->fsgid,
 216                                        0 /* dev */,
 217                                        cifs_sb->local_nls,
 218                                        cifs_sb->mnt_cifs_flags &
 219                                                CIFS_MOUNT_MAP_SPECIAL_CHR);
 220                        } else {
 221                                CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
 222                                        (__u64)-1,
 223                                        (__u64)-1,
 224                                        0 /* dev */,
 225                                        cifs_sb->local_nls,
 226                                        cifs_sb->mnt_cifs_flags &
 227                                                CIFS_MOUNT_MAP_SPECIAL_CHR);
 228                        }
 229                } else {
 230                        /* BB implement mode setting via Windows security
 231                           descriptors e.g. */
 232                        /* CIFSSMBWinSetPerms(xid,pTcon,path,mode,-1,-1,nls);*/
 233
 234                        /* Could set r/o dos attribute if mode & 0222 == 0 */
 235                }
 236
 237                /* server might mask mode so we have to query for it */
 238                if (pTcon->unix_ext)
 239                        rc = cifs_get_inode_info_unix(&newinode, full_path,
 240                                                 inode->i_sb, xid);
 241                else {
 242                        rc = cifs_get_inode_info(&newinode, full_path,
 243                                                 buf, inode->i_sb, xid);
 244                        if (newinode) {
 245                                newinode->i_mode = mode;
 246                                if ((oplock & CIFS_CREATE_ACTION) &&
 247                                    (cifs_sb->mnt_cifs_flags &
 248                                     CIFS_MOUNT_SET_UID)) {
 249                                        newinode->i_uid = current->fsuid;
 250                                        newinode->i_gid = current->fsgid;
 251                                }
 252                        }
 253                }
 254
 255                if (rc != 0) {
 256                        cFYI(1,
 257                             ("Create worked but get_inode_info failed rc = %d",
 258                              rc));
 259                } else {
 260                        if (pTcon->nocase)
 261                                direntry->d_op = &cifs_ci_dentry_ops;
 262                        else
 263                                direntry->d_op = &cifs_dentry_ops;
 264                        d_instantiate(direntry, newinode);
 265                }
 266                if ((nd == NULL /* nfsd case - nfs srv does not set nd */) ||
 267                        ((nd->flags & LOOKUP_OPEN) == FALSE)) {
 268                        /* mknod case - do not leave file open */
 269                        CIFSSMBClose(xid, pTcon, fileHandle);
 270                } else if (newinode) {
 271                        pCifsFile =
 272                           kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
 273
 274                        if (pCifsFile == NULL)
 275                                goto cifs_create_out;
 276                        pCifsFile->netfid = fileHandle;
 277                        pCifsFile->pid = current->tgid;
 278                        pCifsFile->pInode = newinode;
 279                        pCifsFile->invalidHandle = FALSE;
 280                        pCifsFile->closePend     = FALSE;
 281                        init_MUTEX(&pCifsFile->fh_sem);
 282                        mutex_init(&pCifsFile->lock_mutex);
 283                        INIT_LIST_HEAD(&pCifsFile->llist);
 284                        atomic_set(&pCifsFile->wrtPending, 0);
 285
 286                        /* set the following in open now
 287                                pCifsFile->pfile = file; */
 288                        write_lock(&GlobalSMBSeslock);
 289                        list_add(&pCifsFile->tlist, &pTcon->openFileList);
 290                        pCifsInode = CIFS_I(newinode);
 291                        if (pCifsInode) {
 292                                /* if readable file instance put first in list*/
 293                                if (write_only == TRUE) {
 294                                        list_add_tail(&pCifsFile->flist,
 295                                                &pCifsInode->openFileList);
 296                                } else {
 297                                        list_add(&pCifsFile->flist,
 298                                                &pCifsInode->openFileList);
 299                                }
 300                                if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
 301                                        pCifsInode->clientCanCacheAll = TRUE;
 302                                        pCifsInode->clientCanCacheRead = TRUE;
 303                                        cFYI(1, ("Exclusive Oplock inode %p",
 304                                                newinode));
 305                                } else if ((oplock & 0xF) == OPLOCK_READ)
 306                                        pCifsInode->clientCanCacheRead = TRUE;
 307                        }
 308                        write_unlock(&GlobalSMBSeslock);
 309                }
 310        }
 311cifs_create_out:
 312        kfree(buf);
 313        kfree(full_path);
 314        FreeXid(xid);
 315        return rc;
 316}
 317
 318int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
 319                dev_t device_number)
 320{
 321        int rc = -EPERM;
 322        int xid;
 323        struct cifs_sb_info *cifs_sb;
 324        struct cifsTconInfo *pTcon;
 325        char *full_path = NULL;
 326        struct inode *newinode = NULL;
 327
 328        if (!old_valid_dev(device_number))
 329                return -EINVAL;
 330
 331        xid = GetXid();
 332
 333        cifs_sb = CIFS_SB(inode->i_sb);
 334        pTcon = cifs_sb->tcon;
 335
 336        full_path = build_path_from_dentry(direntry);
 337        if (full_path == NULL)
 338                rc = -ENOMEM;
 339        else if (pTcon->unix_ext) {
 340                mode &= ~current->fs->umask;
 341                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
 342                        rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path,
 343                                mode, (__u64)current->fsuid,
 344                                (__u64)current->fsgid,
 345                                device_number, cifs_sb->local_nls,
 346                                cifs_sb->mnt_cifs_flags &
 347                                        CIFS_MOUNT_MAP_SPECIAL_CHR);
 348                } else {
 349                        rc = CIFSSMBUnixSetPerms(xid, pTcon,
 350                                full_path, mode, (__u64)-1, (__u64)-1,
 351                                device_number, cifs_sb->local_nls,
 352                                cifs_sb->mnt_cifs_flags &
 353                                        CIFS_MOUNT_MAP_SPECIAL_CHR);
 354                }
 355
 356                if (!rc) {
 357                        rc = cifs_get_inode_info_unix(&newinode, full_path,
 358                                                inode->i_sb, xid);
 359                        if (pTcon->nocase)
 360                                direntry->d_op = &cifs_ci_dentry_ops;
 361                        else
 362                                direntry->d_op = &cifs_dentry_ops;
 363                        if (rc == 0)
 364                                d_instantiate(direntry, newinode);
 365                }
 366        } else {
 367                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
 368                        int oplock = 0;
 369                        u16 fileHandle;
 370                        FILE_ALL_INFO * buf;
 371
 372                        cFYI(1, ("sfu compat create special file"));
 373
 374                        buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
 375                        if (buf == NULL) {
 376                                kfree(full_path);
 377                                FreeXid(xid);
 378                                return -ENOMEM;
 379                        }
 380
 381                        rc = CIFSSMBOpen(xid, pTcon, full_path,
 382                                         FILE_CREATE, /* fail if exists */
 383                                         GENERIC_WRITE /* BB would
 384                                          WRITE_OWNER | WRITE_DAC be better? */,
 385                                         /* Create a file and set the
 386                                            file attribute to SYSTEM */
 387                                         CREATE_NOT_DIR | CREATE_OPTION_SPECIAL,
 388                                         &fileHandle, &oplock, buf,
 389                                         cifs_sb->local_nls,
 390                                         cifs_sb->mnt_cifs_flags &
 391                                            CIFS_MOUNT_MAP_SPECIAL_CHR);
 392
 393                        /* BB FIXME - add handling for backlevel servers
 394                           which need legacy open and check for all
 395                           calls to SMBOpen for fallback to SMBLeagcyOpen */
 396                        if (!rc) {
 397                                /* BB Do not bother to decode buf since no
 398                                   local inode yet to put timestamps in,
 399                                   but we can reuse it safely */
 400                                unsigned int bytes_written;
 401                                struct win_dev *pdev;
 402                                pdev = (struct win_dev *)buf;
 403                                if (S_ISCHR(mode)) {
 404                                        memcpy(pdev->type, "IntxCHR", 8);
 405                                        pdev->major =
 406                                              cpu_to_le64(MAJOR(device_number));
 407                                        pdev->minor =
 408                                              cpu_to_le64(MINOR(device_number));
 409                                        rc = CIFSSMBWrite(xid, pTcon,
 410                                                fileHandle,
 411                                                sizeof(struct win_dev),
 412                                                0, &bytes_written, (char *)pdev,
 413                                                NULL, 0);
 414                                } else if (S_ISBLK(mode)) {
 415                                        memcpy(pdev->type, "IntxBLK", 8);
 416                                        pdev->major =
 417                                              cpu_to_le64(MAJOR(device_number));
 418                                        pdev->minor =
 419                                              cpu_to_le64(MINOR(device_number));
 420                                        rc = CIFSSMBWrite(xid, pTcon,
 421                                                fileHandle,
 422                                                sizeof(struct win_dev),
 423                                                0, &bytes_written, (char *)pdev,
 424                                                NULL, 0);
 425                                } /* else if(S_ISFIFO */
 426                                CIFSSMBClose(xid, pTcon, fileHandle);
 427                                d_drop(direntry);
 428                        }
 429                        kfree(buf);
 430                        /* add code here to set EAs */
 431                }
 432        }
 433
 434        kfree(full_path);
 435        FreeXid(xid);
 436        return rc;
 437}
 438
 439
 440struct dentry *
 441cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
 442            struct nameidata *nd)
 443{
 444        int xid;
 445        int rc = 0; /* to get around spurious gcc warning, set to zero here */
 446        struct cifs_sb_info *cifs_sb;
 447        struct cifsTconInfo *pTcon;
 448        struct inode *newInode = NULL;
 449        char *full_path = NULL;
 450
 451        xid = GetXid();
 452
 453        cFYI(1, (" parent inode = 0x%p name is: %s and dentry = 0x%p",
 454              parent_dir_inode, direntry->d_name.name, direntry));
 455
 456        /* check whether path exists */
 457
 458        cifs_sb = CIFS_SB(parent_dir_inode->i_sb);
 459        pTcon = cifs_sb->tcon;
 460
 461        /*
 462         * Don't allow the separator character in a path component.
 463         * The VFS will not allow "/", but "\" is allowed by posix.
 464         */
 465        if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)) {
 466                int i;
 467                for (i = 0; i < direntry->d_name.len; i++)
 468                        if (direntry->d_name.name[i] == '\\') {
 469                                cFYI(1, ("Invalid file name"));
 470                                FreeXid(xid);
 471                                return ERR_PTR(-EINVAL);
 472                        }
 473        }
 474
 475        /* can not grab the rename sem here since it would
 476        deadlock in the cases (beginning of sys_rename itself)
 477        in which we already have the sb rename sem */
 478        full_path = build_path_from_dentry(direntry);
 479        if (full_path == NULL) {
 480                FreeXid(xid);
 481                return ERR_PTR(-ENOMEM);
 482        }
 483
 484        if (direntry->d_inode != NULL) {
 485                cFYI(1, (" non-NULL inode in lookup"));
 486        } else {
 487                cFYI(1, (" NULL inode in lookup"));
 488        }
 489        cFYI(1,
 490             (" Full path: %s inode = 0x%p", full_path, direntry->d_inode));
 491
 492        if (pTcon->unix_ext)
 493                rc = cifs_get_inode_info_unix(&newInode, full_path,
 494                                              parent_dir_inode->i_sb, xid);
 495        else
 496                rc = cifs_get_inode_info(&newInode, full_path, NULL,
 497                                         parent_dir_inode->i_sb, xid);
 498
 499        if ((rc == 0) && (newInode != NULL)) {
 500                if (pTcon->nocase)
 501                        direntry->d_op = &cifs_ci_dentry_ops;
 502                else
 503                        direntry->d_op = &cifs_dentry_ops;
 504                d_add(direntry, newInode);
 505
 506                /* since paths are not looked up by component - the parent
 507                   directories are presumed to be good here */
 508                renew_parental_timestamps(direntry);
 509
 510        } else if (rc == -ENOENT) {
 511                rc = 0;
 512                direntry->d_time = jiffies;
 513                if (pTcon->nocase)
 514                        direntry->d_op = &cifs_ci_dentry_ops;
 515                else
 516                        direntry->d_op = &cifs_dentry_ops;
 517                d_add(direntry, NULL);
 518        /*      if it was once a directory (but how can we tell?) we could do
 519                shrink_dcache_parent(direntry); */
 520        } else {
 521                cERROR(1, ("Error 0x%x on cifs_get_inode_info in lookup of %s",
 522                           rc, full_path));
 523                /* BB special case check for Access Denied - watch security
 524                exposure of returning dir info implicitly via different rc
 525                if file exists or not but no access BB */
 526        }
 527
 528        kfree(full_path);
 529        FreeXid(xid);
 530        return ERR_PTR(rc);
 531}
 532
 533static int
 534cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd)
 535{
 536        int isValid = 1;
 537
 538        if (direntry->d_inode) {
 539                if (cifs_revalidate(direntry)) {
 540                        return 0;
 541                }
 542        } else {
 543                cFYI(1, ("neg dentry 0x%p name = %s",
 544                         direntry, direntry->d_name.name));
 545                if (time_after(jiffies, direntry->d_time + HZ) ||
 546                        !lookupCacheEnabled) {
 547                        d_drop(direntry);
 548                        isValid = 0;
 549                }
 550        }
 551
 552        return isValid;
 553}
 554
 555/* static int cifs_d_delete(struct dentry *direntry)
 556{
 557        int rc = 0;
 558
 559        cFYI(1, ("In cifs d_delete, name = %s", direntry->d_name.name));
 560
 561        return rc;
 562}     */
 563
 564struct dentry_operations cifs_dentry_ops = {
 565        .d_revalidate = cifs_d_revalidate,
 566/* d_delete:       cifs_d_delete,      */ /* not needed except for debugging */
 567};
 568
 569static int cifs_ci_hash(struct dentry *dentry, struct qstr *q)
 570{
 571        struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls;
 572        unsigned long hash;
 573        int i;
 574
 575        hash = init_name_hash();
 576        for (i = 0; i < q->len; i++)
 577                hash = partial_name_hash(nls_tolower(codepage, q->name[i]),
 578                                         hash);
 579        q->hash = end_name_hash(hash);
 580
 581        return 0;
 582}
 583
 584static int cifs_ci_compare(struct dentry *dentry, struct qstr *a,
 585                           struct qstr *b)
 586{
 587        struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls;
 588
 589        if ((a->len == b->len) &&
 590            (nls_strnicmp(codepage, a->name, b->name, a->len) == 0)) {
 591                /*
 592                 * To preserve case, don't let an existing negative dentry's
 593                 * case take precedence.  If a is not a negative dentry, this
 594                 * should have no side effects
 595                 */
 596                memcpy(a->name, b->name, a->len);
 597                return 0;
 598        }
 599        return 1;
 600}
 601
 602struct dentry_operations cifs_ci_dentry_ops = {
 603        .d_revalidate = cifs_d_revalidate,
 604        .d_hash = cifs_ci_hash,
 605        .d_compare = cifs_ci_compare,
 606};
 607