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