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,2009
   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 <linux/mount.h>
  28#include <linux/file.h>
  29#include "cifsfs.h"
  30#include "cifspdu.h"
  31#include "cifsglob.h"
  32#include "cifsproto.h"
  33#include "cifs_debug.h"
  34#include "cifs_fs_sb.h"
  35
  36static void
  37renew_parental_timestamps(struct dentry *direntry)
  38{
  39        /* BB check if there is a way to get the kernel to do this or if we
  40           really need this */
  41        do {
  42                direntry->d_time = jiffies;
  43                direntry = direntry->d_parent;
  44        } while (!IS_ROOT(direntry));
  45}
  46
  47/* Note: caller must free return buffer */
  48char *
  49build_path_from_dentry(struct dentry *direntry)
  50{
  51        struct dentry *temp;
  52        int namelen;
  53        int pplen;
  54        int dfsplen;
  55        char *full_path;
  56        char dirsep;
  57        struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
  58        struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb);
  59
  60        if (direntry == NULL)
  61                return NULL;  /* not much we can do if dentry is freed and
  62                we need to reopen the file after it was closed implicitly
  63                when the server crashed */
  64
  65        dirsep = CIFS_DIR_SEP(cifs_sb);
  66        pplen = cifs_sb->prepathlen;
  67        if (tcon->Flags & SMB_SHARE_IS_IN_DFS)
  68                dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1);
  69        else
  70                dfsplen = 0;
  71cifs_bp_rename_retry:
  72        namelen = pplen + dfsplen;
  73        for (temp = direntry; !IS_ROOT(temp);) {
  74                namelen += (1 + temp->d_name.len);
  75                temp = temp->d_parent;
  76                if (temp == NULL) {
  77                        cERROR(1, "corrupt dentry");
  78                        return NULL;
  79                }
  80        }
  81
  82        full_path = kmalloc(namelen+1, GFP_KERNEL);
  83        if (full_path == NULL)
  84                return full_path;
  85        full_path[namelen] = 0; /* trailing null */
  86        for (temp = direntry; !IS_ROOT(temp);) {
  87                namelen -= 1 + temp->d_name.len;
  88                if (namelen < 0) {
  89                        break;
  90                } else {
  91                        full_path[namelen] = dirsep;
  92                        strncpy(full_path + namelen + 1, temp->d_name.name,
  93                                temp->d_name.len);
  94                        cFYI(0, "name: %s", full_path + namelen);
  95                }
  96                temp = temp->d_parent;
  97                if (temp == NULL) {
  98                        cERROR(1, "corrupt dentry");
  99                        kfree(full_path);
 100                        return NULL;
 101                }
 102        }
 103        if (namelen != pplen + dfsplen) {
 104                cERROR(1, "did not end path lookup where expected namelen is %d",
 105                        namelen);
 106                /* presumably this is only possible if racing with a rename
 107                of one of the parent directories  (we can not lock the dentries
 108                above us to prevent this, but retrying should be harmless) */
 109                kfree(full_path);
 110                goto cifs_bp_rename_retry;
 111        }
 112        /* DIR_SEP already set for byte  0 / vs \ but not for
 113           subsequent slashes in prepath which currently must
 114           be entered the right way - not sure if there is an alternative
 115           since the '\' is a valid posix character so we can not switch
 116           those safely to '/' if any are found in the middle of the prepath */
 117        /* BB test paths to Windows with '/' in the midst of prepath */
 118
 119        if (dfsplen) {
 120                strncpy(full_path, tcon->treeName, dfsplen);
 121                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
 122                        int i;
 123                        for (i = 0; i < dfsplen; i++) {
 124                                if (full_path[i] == '\\')
 125                                        full_path[i] = '/';
 126                        }
 127                }
 128        }
 129        strncpy(full_path + dfsplen, CIFS_SB(direntry->d_sb)->prepath, pplen);
 130        return full_path;
 131}
 132
 133/* Inode operations in similar order to how they appear in Linux file fs.h */
 134
 135int
 136cifs_create(struct inode *inode, struct dentry *direntry, int mode,
 137                struct nameidata *nd)
 138{
 139        int rc = -ENOENT;
 140        int xid;
 141        int create_options = CREATE_NOT_DIR;
 142        __u32 oplock = 0;
 143        int oflags;
 144        /*
 145         * BB below access is probably too much for mknod to request
 146         *    but we have to do query and setpathinfo so requesting
 147         *    less could fail (unless we want to request getatr and setatr
 148         *    permissions (only).  At least for POSIX we do not have to
 149         *    request so much.
 150         */
 151        int desiredAccess = GENERIC_READ | GENERIC_WRITE;
 152        __u16 fileHandle;
 153        struct cifs_sb_info *cifs_sb;
 154        struct tcon_link *tlink;
 155        struct cifsTconInfo *tcon;
 156        char *full_path = NULL;
 157        FILE_ALL_INFO *buf = NULL;
 158        struct inode *newinode = NULL;
 159        int disposition = FILE_OVERWRITE_IF;
 160
 161        xid = GetXid();
 162
 163        cifs_sb = CIFS_SB(inode->i_sb);
 164        tlink = cifs_sb_tlink(cifs_sb);
 165        if (IS_ERR(tlink)) {
 166                FreeXid(xid);
 167                return PTR_ERR(tlink);
 168        }
 169        tcon = tlink_tcon(tlink);
 170
 171        if (oplockEnabled)
 172                oplock = REQ_OPLOCK;
 173
 174        if (nd && (nd->flags & LOOKUP_OPEN))
 175                oflags = nd->intent.open.file->f_flags;
 176        else
 177                oflags = O_RDONLY | O_CREAT;
 178
 179        full_path = build_path_from_dentry(direntry);
 180        if (full_path == NULL) {
 181                rc = -ENOMEM;
 182                goto cifs_create_out;
 183        }
 184
 185        if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
 186            (CIFS_UNIX_POSIX_PATH_OPS_CAP &
 187                        le64_to_cpu(tcon->fsUnixInfo.Capability))) {
 188                rc = cifs_posix_open(full_path, &newinode,
 189                        inode->i_sb, mode, oflags, &oplock, &fileHandle, xid);
 190                /* EIO could indicate that (posix open) operation is not
 191                   supported, despite what server claimed in capability
 192                   negotation.  EREMOTE indicates DFS junction, which is not
 193                   handled in posix open */
 194
 195                if (rc == 0) {
 196                        if (newinode == NULL) /* query inode info */
 197                                goto cifs_create_get_file_info;
 198                        else /* success, no need to query */
 199                                goto cifs_create_set_dentry;
 200                } else if ((rc != -EIO) && (rc != -EREMOTE) &&
 201                         (rc != -EOPNOTSUPP) && (rc != -EINVAL))
 202                        goto cifs_create_out;
 203                /* else fallthrough to retry, using older open call, this is
 204                   case where server does not support this SMB level, and
 205                   falsely claims capability (also get here for DFS case
 206                   which should be rare for path not covered on files) */
 207        }
 208
 209        if (nd && (nd->flags & LOOKUP_OPEN)) {
 210                /* if the file is going to stay open, then we
 211                   need to set the desired access properly */
 212                desiredAccess = 0;
 213                if (OPEN_FMODE(oflags) & FMODE_READ)
 214                        desiredAccess |= GENERIC_READ; /* is this too little? */
 215                if (OPEN_FMODE(oflags) & FMODE_WRITE)
 216                        desiredAccess |= GENERIC_WRITE;
 217
 218                if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
 219                        disposition = FILE_CREATE;
 220                else if ((oflags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
 221                        disposition = FILE_OVERWRITE_IF;
 222                else if ((oflags & O_CREAT) == O_CREAT)
 223                        disposition = FILE_OPEN_IF;
 224                else
 225                        cFYI(1, "Create flag not set in create function");
 226        }
 227
 228        /* BB add processing to set equivalent of mode - e.g. via CreateX with
 229           ACLs */
 230
 231        buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
 232        if (buf == NULL) {
 233                rc = -ENOMEM;
 234                goto cifs_create_out;
 235        }
 236
 237        /*
 238         * if we're not using unix extensions, see if we need to set
 239         * ATTR_READONLY on the create call
 240         */
 241        if (!tcon->unix_ext && (mode & S_IWUGO) == 0)
 242                create_options |= CREATE_OPTION_READONLY;
 243
 244        if (tcon->ses->capabilities & CAP_NT_SMBS)
 245                rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
 246                         desiredAccess, create_options,
 247                         &fileHandle, &oplock, buf, cifs_sb->local_nls,
 248                         cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
 249        else
 250                rc = -EIO; /* no NT SMB support fall into legacy open below */
 251
 252        if (rc == -EIO) {
 253                /* old server, retry the open legacy style */
 254                rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
 255                        desiredAccess, create_options,
 256                        &fileHandle, &oplock, buf, cifs_sb->local_nls,
 257                        cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
 258        }
 259        if (rc) {
 260                cFYI(1, "cifs_create returned 0x%x", rc);
 261                goto cifs_create_out;
 262        }
 263
 264        /* If Open reported that we actually created a file
 265           then we now have to set the mode if possible */
 266        if ((tcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) {
 267                struct cifs_unix_set_info_args args = {
 268                                .mode   = mode,
 269                                .ctime  = NO_CHANGE_64,
 270                                .atime  = NO_CHANGE_64,
 271                                .mtime  = NO_CHANGE_64,
 272                                .device = 0,
 273                };
 274
 275                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
 276                        args.uid = (__u64) current_fsuid();
 277                        if (inode->i_mode & S_ISGID)
 278                                args.gid = (__u64) inode->i_gid;
 279                        else
 280                                args.gid = (__u64) current_fsgid();
 281                } else {
 282                        args.uid = NO_CHANGE_64;
 283                        args.gid = NO_CHANGE_64;
 284                }
 285                CIFSSMBUnixSetFileInfo(xid, tcon, &args, fileHandle,
 286                                        current->tgid);
 287        } else {
 288                /* BB implement mode setting via Windows security
 289                   descriptors e.g. */
 290                /* CIFSSMBWinSetPerms(xid,tcon,path,mode,-1,-1,nls);*/
 291
 292                /* Could set r/o dos attribute if mode & 0222 == 0 */
 293        }
 294
 295cifs_create_get_file_info:
 296        /* server might mask mode so we have to query for it */
 297        if (tcon->unix_ext)
 298                rc = cifs_get_inode_info_unix(&newinode, full_path,
 299                                              inode->i_sb, xid);
 300        else {
 301                rc = cifs_get_inode_info(&newinode, full_path, buf,
 302                                         inode->i_sb, xid, &fileHandle);
 303                if (newinode) {
 304                        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
 305                                newinode->i_mode = mode;
 306                        if ((oplock & CIFS_CREATE_ACTION) &&
 307                            (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) {
 308                                newinode->i_uid = current_fsuid();
 309                                if (inode->i_mode & S_ISGID)
 310                                        newinode->i_gid = inode->i_gid;
 311                                else
 312                                        newinode->i_gid = current_fsgid();
 313                        }
 314                }
 315        }
 316
 317cifs_create_set_dentry:
 318        if (rc == 0)
 319                d_instantiate(direntry, newinode);
 320        else
 321                cFYI(1, "Create worked, get_inode_info failed rc = %d", rc);
 322
 323        if (newinode && nd && (nd->flags & LOOKUP_OPEN)) {
 324                struct cifsFileInfo *pfile_info;
 325                struct file *filp;
 326
 327                filp = lookup_instantiate_filp(nd, direntry, generic_file_open);
 328                if (IS_ERR(filp)) {
 329                        rc = PTR_ERR(filp);
 330                        CIFSSMBClose(xid, tcon, fileHandle);
 331                        goto cifs_create_out;
 332                }
 333
 334                pfile_info = cifs_new_fileinfo(fileHandle, filp, tlink, oplock);
 335                if (pfile_info == NULL) {
 336                        fput(filp);
 337                        CIFSSMBClose(xid, tcon, fileHandle);
 338                        rc = -ENOMEM;
 339                }
 340        } else {
 341                CIFSSMBClose(xid, tcon, fileHandle);
 342        }
 343
 344cifs_create_out:
 345        kfree(buf);
 346        kfree(full_path);
 347        cifs_put_tlink(tlink);
 348        FreeXid(xid);
 349        return rc;
 350}
 351
 352int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
 353                dev_t device_number)
 354{
 355        int rc = -EPERM;
 356        int xid;
 357        struct cifs_sb_info *cifs_sb;
 358        struct tcon_link *tlink;
 359        struct cifsTconInfo *pTcon;
 360        char *full_path = NULL;
 361        struct inode *newinode = NULL;
 362        int oplock = 0;
 363        u16 fileHandle;
 364        FILE_ALL_INFO *buf = NULL;
 365        unsigned int bytes_written;
 366        struct win_dev *pdev;
 367
 368        if (!old_valid_dev(device_number))
 369                return -EINVAL;
 370
 371        cifs_sb = CIFS_SB(inode->i_sb);
 372        tlink = cifs_sb_tlink(cifs_sb);
 373        if (IS_ERR(tlink))
 374                return PTR_ERR(tlink);
 375
 376        pTcon = tlink_tcon(tlink);
 377
 378        xid = GetXid();
 379
 380        full_path = build_path_from_dentry(direntry);
 381        if (full_path == NULL) {
 382                rc = -ENOMEM;
 383                goto mknod_out;
 384        }
 385
 386        if (pTcon->unix_ext) {
 387                struct cifs_unix_set_info_args args = {
 388                        .mode   = mode & ~current_umask(),
 389                        .ctime  = NO_CHANGE_64,
 390                        .atime  = NO_CHANGE_64,
 391                        .mtime  = NO_CHANGE_64,
 392                        .device = device_number,
 393                };
 394                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
 395                        args.uid = (__u64) current_fsuid();
 396                        args.gid = (__u64) current_fsgid();
 397                } else {
 398                        args.uid = NO_CHANGE_64;
 399                        args.gid = NO_CHANGE_64;
 400                }
 401                rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, &args,
 402                                            cifs_sb->local_nls,
 403                                            cifs_sb->mnt_cifs_flags &
 404                                                CIFS_MOUNT_MAP_SPECIAL_CHR);
 405                if (rc)
 406                        goto mknod_out;
 407
 408                rc = cifs_get_inode_info_unix(&newinode, full_path,
 409                                                inode->i_sb, xid);
 410
 411                if (rc == 0)
 412                        d_instantiate(direntry, newinode);
 413                goto mknod_out;
 414        }
 415
 416        if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL))
 417                goto mknod_out;
 418
 419
 420        cFYI(1, "sfu compat create special file");
 421
 422        buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
 423        if (buf == NULL) {
 424                kfree(full_path);
 425                rc = -ENOMEM;
 426                FreeXid(xid);
 427                return rc;
 428        }
 429
 430        /* FIXME: would WRITE_OWNER | WRITE_DAC be better? */
 431        rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_CREATE,
 432                         GENERIC_WRITE, CREATE_NOT_DIR | CREATE_OPTION_SPECIAL,
 433                         &fileHandle, &oplock, buf, cifs_sb->local_nls,
 434                         cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
 435        if (rc)
 436                goto mknod_out;
 437
 438        /* BB Do not bother to decode buf since no local inode yet to put
 439         * timestamps in, but we can reuse it safely */
 440
 441        pdev = (struct win_dev *)buf;
 442        if (S_ISCHR(mode)) {
 443                memcpy(pdev->type, "IntxCHR", 8);
 444                pdev->major =
 445                      cpu_to_le64(MAJOR(device_number));
 446                pdev->minor =
 447                      cpu_to_le64(MINOR(device_number));
 448                rc = CIFSSMBWrite(xid, pTcon,
 449                        fileHandle,
 450                        sizeof(struct win_dev),
 451                        0, &bytes_written, (char *)pdev,
 452                        NULL, 0);
 453        } else if (S_ISBLK(mode)) {
 454                memcpy(pdev->type, "IntxBLK", 8);
 455                pdev->major =
 456                      cpu_to_le64(MAJOR(device_number));
 457                pdev->minor =
 458                      cpu_to_le64(MINOR(device_number));
 459                rc = CIFSSMBWrite(xid, pTcon,
 460                        fileHandle,
 461                        sizeof(struct win_dev),
 462                        0, &bytes_written, (char *)pdev,
 463                        NULL, 0);
 464        } /* else if (S_ISFIFO) */
 465        CIFSSMBClose(xid, pTcon, fileHandle);
 466        d_drop(direntry);
 467
 468        /* FIXME: add code here to set EAs */
 469
 470mknod_out:
 471        kfree(full_path);
 472        kfree(buf);
 473        FreeXid(xid);
 474        cifs_put_tlink(tlink);
 475        return rc;
 476}
 477
 478struct dentry *
 479cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
 480            struct nameidata *nd)
 481{
 482        int xid;
 483        int rc = 0; /* to get around spurious gcc warning, set to zero here */
 484        __u32 oplock = 0;
 485        __u16 fileHandle = 0;
 486        bool posix_open = false;
 487        struct cifs_sb_info *cifs_sb;
 488        struct tcon_link *tlink;
 489        struct cifsTconInfo *pTcon;
 490        struct cifsFileInfo *cfile;
 491        struct inode *newInode = NULL;
 492        char *full_path = NULL;
 493        struct file *filp;
 494
 495        xid = GetXid();
 496
 497        cFYI(1, "parent inode = 0x%p name is: %s and dentry = 0x%p",
 498              parent_dir_inode, direntry->d_name.name, direntry);
 499
 500        /* check whether path exists */
 501
 502        cifs_sb = CIFS_SB(parent_dir_inode->i_sb);
 503        tlink = cifs_sb_tlink(cifs_sb);
 504        if (IS_ERR(tlink)) {
 505                FreeXid(xid);
 506                return (struct dentry *)tlink;
 507        }
 508        pTcon = tlink_tcon(tlink);
 509
 510        /*
 511         * Don't allow the separator character in a path component.
 512         * The VFS will not allow "/", but "\" is allowed by posix.
 513         */
 514        if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)) {
 515                int i;
 516                for (i = 0; i < direntry->d_name.len; i++)
 517                        if (direntry->d_name.name[i] == '\\') {
 518                                cFYI(1, "Invalid file name");
 519                                rc = -EINVAL;
 520                                goto lookup_out;
 521                        }
 522        }
 523
 524        /*
 525         * O_EXCL: optimize away the lookup, but don't hash the dentry. Let
 526         * the VFS handle the create.
 527         */
 528        if (nd && (nd->flags & LOOKUP_EXCL)) {
 529                d_instantiate(direntry, NULL);
 530                rc = 0;
 531                goto lookup_out;
 532        }
 533
 534        /* can not grab the rename sem here since it would
 535        deadlock in the cases (beginning of sys_rename itself)
 536        in which we already have the sb rename sem */
 537        full_path = build_path_from_dentry(direntry);
 538        if (full_path == NULL) {
 539                rc = -ENOMEM;
 540                goto lookup_out;
 541        }
 542
 543        if (direntry->d_inode != NULL) {
 544                cFYI(1, "non-NULL inode in lookup");
 545        } else {
 546                cFYI(1, "NULL inode in lookup");
 547        }
 548        cFYI(1, "Full path: %s inode = 0x%p", full_path, direntry->d_inode);
 549
 550        /* Posix open is only called (at lookup time) for file create now.
 551         * For opens (rather than creates), because we do not know if it
 552         * is a file or directory yet, and current Samba no longer allows
 553         * us to do posix open on dirs, we could end up wasting an open call
 554         * on what turns out to be a dir. For file opens, we wait to call posix
 555         * open till cifs_open.  It could be added here (lookup) in the future
 556         * but the performance tradeoff of the extra network request when EISDIR
 557         * or EACCES is returned would have to be weighed against the 50%
 558         * reduction in network traffic in the other paths.
 559         */
 560        if (pTcon->unix_ext) {
 561                if (nd && !(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY)) &&
 562                     (nd->flags & LOOKUP_OPEN) && !pTcon->broken_posix_open &&
 563                     (nd->intent.open.file->f_flags & O_CREAT)) {
 564                        rc = cifs_posix_open(full_path, &newInode,
 565                                        parent_dir_inode->i_sb,
 566                                        nd->intent.open.create_mode,
 567                                        nd->intent.open.file->f_flags, &oplock,
 568                                        &fileHandle, xid);
 569                        /*
 570                         * The check below works around a bug in POSIX
 571                         * open in samba versions 3.3.1 and earlier where
 572                         * open could incorrectly fail with invalid parameter.
 573                         * If either that or op not supported returned, follow
 574                         * the normal lookup.
 575                         */
 576                        if ((rc == 0) || (rc == -ENOENT))
 577                                posix_open = true;
 578                        else if ((rc == -EINVAL) || (rc != -EOPNOTSUPP))
 579                                pTcon->broken_posix_open = true;
 580                }
 581                if (!posix_open)
 582                        rc = cifs_get_inode_info_unix(&newInode, full_path,
 583                                                parent_dir_inode->i_sb, xid);
 584        } else
 585                rc = cifs_get_inode_info(&newInode, full_path, NULL,
 586                                parent_dir_inode->i_sb, xid, NULL);
 587
 588        if ((rc == 0) && (newInode != NULL)) {
 589                d_add(direntry, newInode);
 590                if (posix_open) {
 591                        filp = lookup_instantiate_filp(nd, direntry,
 592                                                       generic_file_open);
 593                        if (IS_ERR(filp)) {
 594                                rc = PTR_ERR(filp);
 595                                CIFSSMBClose(xid, pTcon, fileHandle);
 596                                goto lookup_out;
 597                        }
 598
 599                        cfile = cifs_new_fileinfo(fileHandle, filp, tlink,
 600                                                  oplock);
 601                        if (cfile == NULL) {
 602                                fput(filp);
 603                                CIFSSMBClose(xid, pTcon, fileHandle);
 604                                rc = -ENOMEM;
 605                                goto lookup_out;
 606                        }
 607                }
 608                /* since paths are not looked up by component - the parent
 609                   directories are presumed to be good here */
 610                renew_parental_timestamps(direntry);
 611
 612        } else if (rc == -ENOENT) {
 613                rc = 0;
 614                direntry->d_time = jiffies;
 615                d_add(direntry, NULL);
 616        /*      if it was once a directory (but how can we tell?) we could do
 617                shrink_dcache_parent(direntry); */
 618        } else if (rc != -EACCES) {
 619                cERROR(1, "Unexpected lookup error %d", rc);
 620                /* We special case check for Access Denied - since that
 621                is a common return code */
 622        }
 623
 624lookup_out:
 625        kfree(full_path);
 626        cifs_put_tlink(tlink);
 627        FreeXid(xid);
 628        return ERR_PTR(rc);
 629}
 630
 631static int
 632cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd)
 633{
 634        if (nd->flags & LOOKUP_RCU)
 635                return -ECHILD;
 636
 637        if (direntry->d_inode) {
 638                if (cifs_revalidate_dentry(direntry))
 639                        return 0;
 640                else
 641                        return 1;
 642        }
 643
 644        /*
 645         * This may be nfsd (or something), anyway, we can't see the
 646         * intent of this. So, since this can be for creation, drop it.
 647         */
 648        if (!nd)
 649                return 0;
 650
 651        /*
 652         * Drop the negative dentry, in order to make sure to use the
 653         * case sensitive name which is specified by user if this is
 654         * for creation.
 655         */
 656        if (!(nd->flags & (LOOKUP_CONTINUE | LOOKUP_PARENT))) {
 657                if (nd->flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET))
 658                        return 0;
 659        }
 660
 661        if (time_after(jiffies, direntry->d_time + HZ) || !lookupCacheEnabled)
 662                return 0;
 663
 664        return 1;
 665}
 666
 667/* static int cifs_d_delete(struct dentry *direntry)
 668{
 669        int rc = 0;
 670
 671        cFYI(1, "In cifs d_delete, name = %s", direntry->d_name.name);
 672
 673        return rc;
 674}     */
 675
 676const struct dentry_operations cifs_dentry_ops = {
 677        .d_revalidate = cifs_d_revalidate,
 678        .d_automount = cifs_dfs_d_automount,
 679/* d_delete:       cifs_d_delete,      */ /* not needed except for debugging */
 680};
 681
 682static int cifs_ci_hash(const struct dentry *dentry, const struct inode *inode,
 683                struct qstr *q)
 684{
 685        struct nls_table *codepage = CIFS_SB(dentry->d_sb)->local_nls;
 686        unsigned long hash;
 687        int i;
 688
 689        hash = init_name_hash();
 690        for (i = 0; i < q->len; i++)
 691                hash = partial_name_hash(nls_tolower(codepage, q->name[i]),
 692                                         hash);
 693        q->hash = end_name_hash(hash);
 694
 695        return 0;
 696}
 697
 698static int cifs_ci_compare(const struct dentry *parent,
 699                const struct inode *pinode,
 700                const struct dentry *dentry, const struct inode *inode,
 701                unsigned int len, const char *str, const struct qstr *name)
 702{
 703        struct nls_table *codepage = CIFS_SB(pinode->i_sb)->local_nls;
 704
 705        if ((name->len == len) &&
 706            (nls_strnicmp(codepage, name->name, str, len) == 0))
 707                return 0;
 708        return 1;
 709}
 710
 711const struct dentry_operations cifs_ci_dentry_ops = {
 712        .d_revalidate = cifs_d_revalidate,
 713        .d_hash = cifs_ci_hash,
 714        .d_compare = cifs_ci_compare,
 715        .d_automount = cifs_dfs_d_automount,
 716};
 717