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 "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
  35static void
  36renew_parental_timestamps(struct dentry *direntry)
  37{
  38        /* BB check if there is a way to get the kernel to do this or if we
  39           really need this */
  40        do {
  41                direntry->d_time = jiffies;
  42                direntry = direntry->d_parent;
  43        } while (!IS_ROOT(direntry));
  44}
  45
  46/* Note: caller must free return buffer */
  47char *
  48build_path_from_dentry(struct dentry *direntry)
  49{
  50        struct dentry *temp;
  51        int namelen;
  52        int pplen;
  53        int dfsplen;
  54        char *full_path;
  55        char dirsep;
  56        struct cifs_sb_info *cifs_sb;
  57
  58        if (direntry == NULL)
  59                return NULL;  /* not much we can do if dentry is freed and
  60                we need to reopen the file after it was closed implicitly
  61                when the server crashed */
  62
  63        cifs_sb = CIFS_SB(direntry->d_sb);
  64        dirsep = CIFS_DIR_SEP(cifs_sb);
  65        pplen = cifs_sb->prepathlen;
  66        if (cifs_sb->tcon && (cifs_sb->tcon->Flags & SMB_SHARE_IS_IN_DFS))
  67                dfsplen = strnlen(cifs_sb->tcon->treeName, MAX_TREE_SIZE + 1);
  68        else
  69                dfsplen = 0;
  70cifs_bp_rename_retry:
  71        namelen = pplen + dfsplen;
  72        for (temp = direntry; !IS_ROOT(temp);) {
  73                namelen += (1 + temp->d_name.len);
  74                temp = temp->d_parent;
  75                if (temp == NULL) {
  76                        cERROR(1, ("corrupt dentry"));
  77                        return NULL;
  78                }
  79        }
  80
  81        full_path = kmalloc(namelen+1, GFP_KERNEL);
  82        if (full_path == NULL)
  83                return full_path;
  84        full_path[namelen] = 0; /* trailing null */
  85        for (temp = direntry; !IS_ROOT(temp);) {
  86                namelen -= 1 + temp->d_name.len;
  87                if (namelen < 0) {
  88                        break;
  89                } else {
  90                        full_path[namelen] = dirsep;
  91                        strncpy(full_path + namelen + 1, temp->d_name.name,
  92                                temp->d_name.len);
  93                        cFYI(0, ("name: %s", full_path + namelen));
  94                }
  95                temp = temp->d_parent;
  96                if (temp == NULL) {
  97                        cERROR(1, ("corrupt dentry"));
  98                        kfree(full_path);
  99                        return NULL;
 100                }
 101        }
 102        if (namelen != pplen + dfsplen) {
 103                cERROR(1,
 104                       ("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, cifs_sb->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
 133struct cifsFileInfo *
 134cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle,
 135                  struct file *file, struct vfsmount *mnt, unsigned int oflags)
 136{
 137        int oplock = 0;
 138        struct cifsFileInfo *pCifsFile;
 139        struct cifsInodeInfo *pCifsInode;
 140        struct cifs_sb_info *cifs_sb = CIFS_SB(mnt->mnt_sb);
 141
 142        pCifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
 143        if (pCifsFile == NULL)
 144                return pCifsFile;
 145
 146        if (oplockEnabled)
 147                oplock = REQ_OPLOCK;
 148
 149        pCifsFile->netfid = fileHandle;
 150        pCifsFile->pid = current->tgid;
 151        pCifsFile->pInode = igrab(newinode);
 152        pCifsFile->mnt = mnt;
 153        pCifsFile->pfile = file;
 154        pCifsFile->invalidHandle = false;
 155        pCifsFile->closePend = false;
 156        mutex_init(&pCifsFile->fh_mutex);
 157        mutex_init(&pCifsFile->lock_mutex);
 158        INIT_LIST_HEAD(&pCifsFile->llist);
 159        atomic_set(&pCifsFile->count, 1);
 160        slow_work_init(&pCifsFile->oplock_break, &cifs_oplock_break_ops);
 161
 162        write_lock(&GlobalSMBSeslock);
 163        list_add(&pCifsFile->tlist, &cifs_sb->tcon->openFileList);
 164        pCifsInode = CIFS_I(newinode);
 165        if (pCifsInode) {
 166                /* if readable file instance put first in list*/
 167                if (oflags & FMODE_READ)
 168                        list_add(&pCifsFile->flist, &pCifsInode->openFileList);
 169                else
 170                        list_add_tail(&pCifsFile->flist,
 171                                      &pCifsInode->openFileList);
 172
 173                if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
 174                        pCifsInode->clientCanCacheAll = true;
 175                        pCifsInode->clientCanCacheRead = true;
 176                        cFYI(1, ("Exclusive Oplock inode %p", newinode));
 177                } else if ((oplock & 0xF) == OPLOCK_READ)
 178                                pCifsInode->clientCanCacheRead = true;
 179        }
 180        write_unlock(&GlobalSMBSeslock);
 181
 182        return pCifsFile;
 183}
 184
 185int cifs_posix_open(char *full_path, struct inode **pinode,
 186                    struct vfsmount *mnt, int mode, int oflags,
 187                    __u32 *poplock, __u16 *pnetfid, int xid)
 188{
 189        int rc;
 190        FILE_UNIX_BASIC_INFO *presp_data;
 191        __u32 posix_flags = 0;
 192        struct cifs_sb_info *cifs_sb = CIFS_SB(mnt->mnt_sb);
 193        struct cifs_fattr fattr;
 194
 195        cFYI(1, ("posix open %s", full_path));
 196
 197        presp_data = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
 198        if (presp_data == NULL)
 199                return -ENOMEM;
 200
 201/* So far cifs posix extensions can only map the following flags.
 202   There are other valid fmode oflags such as FMODE_LSEEK, FMODE_PREAD, but
 203   so far we do not seem to need them, and we can treat them as local only */
 204        if ((oflags & (FMODE_READ | FMODE_WRITE)) ==
 205                (FMODE_READ | FMODE_WRITE))
 206                posix_flags = SMB_O_RDWR;
 207        else if (oflags & FMODE_READ)
 208                posix_flags = SMB_O_RDONLY;
 209        else if (oflags & FMODE_WRITE)
 210                posix_flags = SMB_O_WRONLY;
 211        if (oflags & O_CREAT)
 212                posix_flags |= SMB_O_CREAT;
 213        if (oflags & O_EXCL)
 214                posix_flags |= SMB_O_EXCL;
 215        if (oflags & O_TRUNC)
 216                posix_flags |= SMB_O_TRUNC;
 217        if (oflags & O_SYNC)
 218                posix_flags |= SMB_O_SYNC;
 219        if (oflags & O_DIRECTORY)
 220                posix_flags |= SMB_O_DIRECTORY;
 221        if (oflags & O_NOFOLLOW)
 222                posix_flags |= SMB_O_NOFOLLOW;
 223        if (oflags & O_DIRECT)
 224                posix_flags |= SMB_O_DIRECT;
 225
 226        mode &= ~current_umask();
 227        rc = CIFSPOSIXCreate(xid, cifs_sb->tcon, posix_flags, mode,
 228                        pnetfid, presp_data, poplock, full_path,
 229                        cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
 230                                        CIFS_MOUNT_MAP_SPECIAL_CHR);
 231        if (rc)
 232                goto posix_open_ret;
 233
 234        if (presp_data->Type == cpu_to_le32(-1))
 235                goto posix_open_ret; /* open ok, caller does qpathinfo */
 236
 237        if (!pinode)
 238                goto posix_open_ret; /* caller does not need info */
 239
 240        cifs_unix_basic_to_fattr(&fattr, presp_data, cifs_sb);
 241
 242        /* get new inode and set it up */
 243        if (*pinode == NULL) {
 244                *pinode = cifs_iget(mnt->mnt_sb, &fattr);
 245                if (!*pinode) {
 246                        rc = -ENOMEM;
 247                        goto posix_open_ret;
 248                }
 249        } else {
 250                cifs_fattr_to_inode(*pinode, &fattr);
 251        }
 252
 253        cifs_new_fileinfo(*pinode, *pnetfid, NULL, mnt, oflags);
 254
 255posix_open_ret:
 256        kfree(presp_data);
 257        return rc;
 258}
 259
 260static void setup_cifs_dentry(struct cifsTconInfo *tcon,
 261                              struct dentry *direntry,
 262                              struct inode *newinode)
 263{
 264        if (tcon->nocase)
 265                direntry->d_op = &cifs_ci_dentry_ops;
 266        else
 267                direntry->d_op = &cifs_dentry_ops;
 268        d_instantiate(direntry, newinode);
 269}
 270
 271/* Inode operations in similar order to how they appear in Linux file fs.h */
 272
 273int
 274cifs_create(struct inode *inode, struct dentry *direntry, int mode,
 275                struct nameidata *nd)
 276{
 277        int rc = -ENOENT;
 278        int xid;
 279        int create_options = CREATE_NOT_DIR;
 280        __u32 oplock = 0;
 281        int oflags;
 282        bool posix_create = false;
 283        /*
 284         * BB below access is probably too much for mknod to request
 285         *    but we have to do query and setpathinfo so requesting
 286         *    less could fail (unless we want to request getatr and setatr
 287         *    permissions (only).  At least for POSIX we do not have to
 288         *    request so much.
 289         */
 290        int desiredAccess = GENERIC_READ | GENERIC_WRITE;
 291        __u16 fileHandle;
 292        struct cifs_sb_info *cifs_sb;
 293        struct cifsTconInfo *tcon;
 294        char *full_path = NULL;
 295        FILE_ALL_INFO *buf = NULL;
 296        struct inode *newinode = NULL;
 297        int disposition = FILE_OVERWRITE_IF;
 298
 299        xid = GetXid();
 300
 301        cifs_sb = CIFS_SB(inode->i_sb);
 302        tcon = cifs_sb->tcon;
 303
 304        full_path = build_path_from_dentry(direntry);
 305        if (full_path == NULL) {
 306                rc = -ENOMEM;
 307                FreeXid(xid);
 308                return rc;
 309        }
 310
 311        if (oplockEnabled)
 312                oplock = REQ_OPLOCK;
 313
 314        if (nd && (nd->flags & LOOKUP_OPEN))
 315                oflags = nd->intent.open.flags;
 316        else
 317                oflags = FMODE_READ;
 318
 319        if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
 320            (CIFS_UNIX_POSIX_PATH_OPS_CAP &
 321                        le64_to_cpu(tcon->fsUnixInfo.Capability))) {
 322                rc = cifs_posix_open(full_path, &newinode, nd->path.mnt,
 323                                     mode, oflags, &oplock, &fileHandle, xid);
 324                /* EIO could indicate that (posix open) operation is not
 325                   supported, despite what server claimed in capability
 326                   negotation.  EREMOTE indicates DFS junction, which is not
 327                   handled in posix open */
 328
 329                if (rc == 0) {
 330                        posix_create = true;
 331                        if (newinode == NULL) /* query inode info */
 332                                goto cifs_create_get_file_info;
 333                        else /* success, no need to query */
 334                                goto cifs_create_set_dentry;
 335                } else if ((rc != -EIO) && (rc != -EREMOTE) &&
 336                         (rc != -EOPNOTSUPP) && (rc != -EINVAL))
 337                        goto cifs_create_out;
 338                /* else fallthrough to retry, using older open call, this is
 339                   case where server does not support this SMB level, and
 340                   falsely claims capability (also get here for DFS case
 341                   which should be rare for path not covered on files) */
 342        }
 343
 344        if (nd && (nd->flags & LOOKUP_OPEN)) {
 345                /* if the file is going to stay open, then we
 346                   need to set the desired access properly */
 347                desiredAccess = 0;
 348                if (oflags & FMODE_READ)
 349                        desiredAccess |= GENERIC_READ; /* is this too little? */
 350                if (oflags & FMODE_WRITE)
 351                        desiredAccess |= GENERIC_WRITE;
 352
 353                if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
 354                        disposition = FILE_CREATE;
 355                else if ((oflags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
 356                        disposition = FILE_OVERWRITE_IF;
 357                else if ((oflags & O_CREAT) == O_CREAT)
 358                        disposition = FILE_OPEN_IF;
 359                else
 360                        cFYI(1, ("Create flag not set in create function"));
 361        }
 362
 363        /* BB add processing to set equivalent of mode - e.g. via CreateX with
 364           ACLs */
 365
 366        buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
 367        if (buf == NULL) {
 368                kfree(full_path);
 369                FreeXid(xid);
 370                return -ENOMEM;
 371        }
 372
 373        /*
 374         * if we're not using unix extensions, see if we need to set
 375         * ATTR_READONLY on the create call
 376         */
 377        if (!tcon->unix_ext && (mode & S_IWUGO) == 0)
 378                create_options |= CREATE_OPTION_READONLY;
 379
 380        if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS)
 381                rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
 382                         desiredAccess, create_options,
 383                         &fileHandle, &oplock, buf, cifs_sb->local_nls,
 384                         cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
 385        else
 386                rc = -EIO; /* no NT SMB support fall into legacy open below */
 387
 388        if (rc == -EIO) {
 389                /* old server, retry the open legacy style */
 390                rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
 391                        desiredAccess, create_options,
 392                        &fileHandle, &oplock, buf, cifs_sb->local_nls,
 393                        cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
 394        }
 395        if (rc) {
 396                cFYI(1, ("cifs_create returned 0x%x", rc));
 397                goto cifs_create_out;
 398        }
 399
 400        /* If Open reported that we actually created a file
 401           then we now have to set the mode if possible */
 402        if ((tcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) {
 403                struct cifs_unix_set_info_args args = {
 404                                .mode   = mode,
 405                                .ctime  = NO_CHANGE_64,
 406                                .atime  = NO_CHANGE_64,
 407                                .mtime  = NO_CHANGE_64,
 408                                .device = 0,
 409                };
 410
 411                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
 412                        args.uid = (__u64) current_fsuid();
 413                        if (inode->i_mode & S_ISGID)
 414                                args.gid = (__u64) inode->i_gid;
 415                        else
 416                                args.gid = (__u64) current_fsgid();
 417                } else {
 418                        args.uid = NO_CHANGE_64;
 419                        args.gid = NO_CHANGE_64;
 420                }
 421                CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
 422                                        cifs_sb->local_nls,
 423                                        cifs_sb->mnt_cifs_flags &
 424                                                CIFS_MOUNT_MAP_SPECIAL_CHR);
 425        } else {
 426                /* BB implement mode setting via Windows security
 427                   descriptors e.g. */
 428                /* CIFSSMBWinSetPerms(xid,tcon,path,mode,-1,-1,nls);*/
 429
 430                /* Could set r/o dos attribute if mode & 0222 == 0 */
 431        }
 432
 433cifs_create_get_file_info:
 434        /* server might mask mode so we have to query for it */
 435        if (tcon->unix_ext)
 436                rc = cifs_get_inode_info_unix(&newinode, full_path,
 437                                              inode->i_sb, xid);
 438        else {
 439                rc = cifs_get_inode_info(&newinode, full_path, buf,
 440                                         inode->i_sb, xid, &fileHandle);
 441                if (newinode) {
 442                        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
 443                                newinode->i_mode = mode;
 444                        if ((oplock & CIFS_CREATE_ACTION) &&
 445                            (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) {
 446                                newinode->i_uid = current_fsuid();
 447                                if (inode->i_mode & S_ISGID)
 448                                        newinode->i_gid = inode->i_gid;
 449                                else
 450                                        newinode->i_gid = current_fsgid();
 451                        }
 452                }
 453        }
 454
 455cifs_create_set_dentry:
 456        if (rc == 0)
 457                setup_cifs_dentry(tcon, direntry, newinode);
 458        else
 459                cFYI(1, ("Create worked, get_inode_info failed rc = %d", rc));
 460
 461        /* nfsd case - nfs srv does not set nd */
 462        if ((nd == NULL) || (!(nd->flags & LOOKUP_OPEN))) {
 463                /* mknod case - do not leave file open */
 464                CIFSSMBClose(xid, tcon, fileHandle);
 465        } else if (!(posix_create) && (newinode)) {
 466                        cifs_new_fileinfo(newinode, fileHandle, NULL,
 467                                                nd->path.mnt, oflags);
 468        }
 469cifs_create_out:
 470        kfree(buf);
 471        kfree(full_path);
 472        FreeXid(xid);
 473        return rc;
 474}
 475
 476int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
 477                dev_t device_number)
 478{
 479        int rc = -EPERM;
 480        int xid;
 481        struct cifs_sb_info *cifs_sb;
 482        struct cifsTconInfo *pTcon;
 483        char *full_path = NULL;
 484        struct inode *newinode = NULL;
 485
 486        if (!old_valid_dev(device_number))
 487                return -EINVAL;
 488
 489        xid = GetXid();
 490
 491        cifs_sb = CIFS_SB(inode->i_sb);
 492        pTcon = cifs_sb->tcon;
 493
 494        full_path = build_path_from_dentry(direntry);
 495        if (full_path == NULL)
 496                rc = -ENOMEM;
 497        else if (pTcon->unix_ext) {
 498                struct cifs_unix_set_info_args args = {
 499                        .mode   = mode & ~current_umask(),
 500                        .ctime  = NO_CHANGE_64,
 501                        .atime  = NO_CHANGE_64,
 502                        .mtime  = NO_CHANGE_64,
 503                        .device = device_number,
 504                };
 505                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
 506                        args.uid = (__u64) current_fsuid();
 507                        args.gid = (__u64) current_fsgid();
 508                } else {
 509                        args.uid = NO_CHANGE_64;
 510                        args.gid = NO_CHANGE_64;
 511                }
 512                rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, &args,
 513                                            cifs_sb->local_nls,
 514                                            cifs_sb->mnt_cifs_flags &
 515                                                CIFS_MOUNT_MAP_SPECIAL_CHR);
 516
 517                if (!rc) {
 518                        rc = cifs_get_inode_info_unix(&newinode, full_path,
 519                                                inode->i_sb, xid);
 520                        if (pTcon->nocase)
 521                                direntry->d_op = &cifs_ci_dentry_ops;
 522                        else
 523                                direntry->d_op = &cifs_dentry_ops;
 524                        if (rc == 0)
 525                                d_instantiate(direntry, newinode);
 526                }
 527        } else {
 528                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
 529                        int oplock = 0;
 530                        u16 fileHandle;
 531                        FILE_ALL_INFO *buf;
 532
 533                        cFYI(1, ("sfu compat create special file"));
 534
 535                        buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
 536                        if (buf == NULL) {
 537                                kfree(full_path);
 538                                rc = -ENOMEM;
 539                                FreeXid(xid);
 540                                return rc;
 541                        }
 542
 543                        rc = CIFSSMBOpen(xid, pTcon, full_path,
 544                                         FILE_CREATE, /* fail if exists */
 545                                         GENERIC_WRITE /* BB would
 546                                          WRITE_OWNER | WRITE_DAC be better? */,
 547                                         /* Create a file and set the
 548                                            file attribute to SYSTEM */
 549                                         CREATE_NOT_DIR | CREATE_OPTION_SPECIAL,
 550                                         &fileHandle, &oplock, buf,
 551                                         cifs_sb->local_nls,
 552                                         cifs_sb->mnt_cifs_flags &
 553                                            CIFS_MOUNT_MAP_SPECIAL_CHR);
 554
 555                        /* BB FIXME - add handling for backlevel servers
 556                           which need legacy open and check for all
 557                           calls to SMBOpen for fallback to SMBLeagcyOpen */
 558                        if (!rc) {
 559                                /* BB Do not bother to decode buf since no
 560                                   local inode yet to put timestamps in,
 561                                   but we can reuse it safely */
 562                                unsigned int bytes_written;
 563                                struct win_dev *pdev;
 564                                pdev = (struct win_dev *)buf;
 565                                if (S_ISCHR(mode)) {
 566                                        memcpy(pdev->type, "IntxCHR", 8);
 567                                        pdev->major =
 568                                              cpu_to_le64(MAJOR(device_number));
 569                                        pdev->minor =
 570                                              cpu_to_le64(MINOR(device_number));
 571                                        rc = CIFSSMBWrite(xid, pTcon,
 572                                                fileHandle,
 573                                                sizeof(struct win_dev),
 574                                                0, &bytes_written, (char *)pdev,
 575                                                NULL, 0);
 576                                } else if (S_ISBLK(mode)) {
 577                                        memcpy(pdev->type, "IntxBLK", 8);
 578                                        pdev->major =
 579                                              cpu_to_le64(MAJOR(device_number));
 580                                        pdev->minor =
 581                                              cpu_to_le64(MINOR(device_number));
 582                                        rc = CIFSSMBWrite(xid, pTcon,
 583                                                fileHandle,
 584                                                sizeof(struct win_dev),
 585                                                0, &bytes_written, (char *)pdev,
 586                                                NULL, 0);
 587                                } /* else if(S_ISFIFO */
 588                                CIFSSMBClose(xid, pTcon, fileHandle);
 589                                d_drop(direntry);
 590                        }
 591                        kfree(buf);
 592                        /* add code here to set EAs */
 593                }
 594        }
 595
 596        kfree(full_path);
 597        FreeXid(xid);
 598        return rc;
 599}
 600
 601struct dentry *
 602cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
 603            struct nameidata *nd)
 604{
 605        int xid;
 606        int rc = 0; /* to get around spurious gcc warning, set to zero here */
 607        __u32 oplock = 0;
 608        __u16 fileHandle = 0;
 609        bool posix_open = false;
 610        struct cifs_sb_info *cifs_sb;
 611        struct cifsTconInfo *pTcon;
 612        struct inode *newInode = NULL;
 613        char *full_path = NULL;
 614        struct file *filp;
 615
 616        xid = GetXid();
 617
 618        cFYI(1, ("parent inode = 0x%p name is: %s and dentry = 0x%p",
 619              parent_dir_inode, direntry->d_name.name, direntry));
 620
 621        /* check whether path exists */
 622
 623        cifs_sb = CIFS_SB(parent_dir_inode->i_sb);
 624        pTcon = cifs_sb->tcon;
 625
 626        /*
 627         * Don't allow the separator character in a path component.
 628         * The VFS will not allow "/", but "\" is allowed by posix.
 629         */
 630        if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)) {
 631                int i;
 632                for (i = 0; i < direntry->d_name.len; i++)
 633                        if (direntry->d_name.name[i] == '\\') {
 634                                cFYI(1, ("Invalid file name"));
 635                                FreeXid(xid);
 636                                return ERR_PTR(-EINVAL);
 637                        }
 638        }
 639
 640        /*
 641         * O_EXCL: optimize away the lookup, but don't hash the dentry. Let
 642         * the VFS handle the create.
 643         */
 644        if (nd && (nd->flags & LOOKUP_EXCL)) {
 645                d_instantiate(direntry, NULL);
 646                return NULL;
 647        }
 648
 649        /* can not grab the rename sem here since it would
 650        deadlock in the cases (beginning of sys_rename itself)
 651        in which we already have the sb rename sem */
 652        full_path = build_path_from_dentry(direntry);
 653        if (full_path == NULL) {
 654                FreeXid(xid);
 655                return ERR_PTR(-ENOMEM);
 656        }
 657
 658        if (direntry->d_inode != NULL) {
 659                cFYI(1, ("non-NULL inode in lookup"));
 660        } else {
 661                cFYI(1, ("NULL inode in lookup"));
 662        }
 663        cFYI(1, ("Full path: %s inode = 0x%p", full_path, direntry->d_inode));
 664
 665        /* Posix open is only called (at lookup time) for file create now.
 666         * For opens (rather than creates), because we do not know if it
 667         * is a file or directory yet, and current Samba no longer allows
 668         * us to do posix open on dirs, we could end up wasting an open call
 669         * on what turns out to be a dir. For file opens, we wait to call posix
 670         * open till cifs_open.  It could be added here (lookup) in the future
 671         * but the performance tradeoff of the extra network request when EISDIR
 672         * or EACCES is returned would have to be weighed against the 50%
 673         * reduction in network traffic in the other paths.
 674         */
 675        if (pTcon->unix_ext) {
 676                if (nd && !(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY)) &&
 677                     (nd->flags & LOOKUP_OPEN) && !pTcon->broken_posix_open &&
 678                     (nd->intent.open.flags & O_CREAT)) {
 679                        rc = cifs_posix_open(full_path, &newInode, nd->path.mnt,
 680                                        nd->intent.open.create_mode,
 681                                        nd->intent.open.flags, &oplock,
 682                                        &fileHandle, xid);
 683                        /*
 684                         * The check below works around a bug in POSIX
 685                         * open in samba versions 3.3.1 and earlier where
 686                         * open could incorrectly fail with invalid parameter.
 687                         * If either that or op not supported returned, follow
 688                         * the normal lookup.
 689                         */
 690                        if ((rc == 0) || (rc == -ENOENT))
 691                                posix_open = true;
 692                        else if ((rc == -EINVAL) || (rc != -EOPNOTSUPP))
 693                                pTcon->broken_posix_open = true;
 694                }
 695                if (!posix_open)
 696                        rc = cifs_get_inode_info_unix(&newInode, full_path,
 697                                                parent_dir_inode->i_sb, xid);
 698        } else
 699                rc = cifs_get_inode_info(&newInode, full_path, NULL,
 700                                parent_dir_inode->i_sb, xid, NULL);
 701
 702        if ((rc == 0) && (newInode != NULL)) {
 703                if (pTcon->nocase)
 704                        direntry->d_op = &cifs_ci_dentry_ops;
 705                else
 706                        direntry->d_op = &cifs_dentry_ops;
 707                d_add(direntry, newInode);
 708                if (posix_open)
 709                        filp = lookup_instantiate_filp(nd, direntry, NULL);
 710                /* since paths are not looked up by component - the parent
 711                   directories are presumed to be good here */
 712                renew_parental_timestamps(direntry);
 713
 714        } else if (rc == -ENOENT) {
 715                rc = 0;
 716                direntry->d_time = jiffies;
 717                if (pTcon->nocase)
 718                        direntry->d_op = &cifs_ci_dentry_ops;
 719                else
 720                        direntry->d_op = &cifs_dentry_ops;
 721                d_add(direntry, NULL);
 722        /*      if it was once a directory (but how can we tell?) we could do
 723                shrink_dcache_parent(direntry); */
 724        } else if (rc != -EACCES) {
 725                cERROR(1, ("Unexpected lookup error %d", rc));
 726                /* We special case check for Access Denied - since that
 727                is a common return code */
 728        }
 729
 730        kfree(full_path);
 731        FreeXid(xid);
 732        return ERR_PTR(rc);
 733}
 734
 735static int
 736cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd)
 737{
 738        int isValid = 1;
 739
 740        if (direntry->d_inode) {
 741                if (cifs_revalidate(direntry))
 742                        return 0;
 743        } else {
 744                cFYI(1, ("neg dentry 0x%p name = %s",
 745                         direntry, direntry->d_name.name));
 746                if (time_after(jiffies, direntry->d_time + HZ) ||
 747                        !lookupCacheEnabled) {
 748                        d_drop(direntry);
 749                        isValid = 0;
 750                }
 751        }
 752
 753        return isValid;
 754}
 755
 756/* static int cifs_d_delete(struct dentry *direntry)
 757{
 758        int rc = 0;
 759
 760        cFYI(1, ("In cifs d_delete, name = %s", direntry->d_name.name));
 761
 762        return rc;
 763}     */
 764
 765const struct dentry_operations cifs_dentry_ops = {
 766        .d_revalidate = cifs_d_revalidate,
 767/* d_delete:       cifs_d_delete,      */ /* not needed except for debugging */
 768};
 769
 770static int cifs_ci_hash(struct dentry *dentry, struct qstr *q)
 771{
 772        struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls;
 773        unsigned long hash;
 774        int i;
 775
 776        hash = init_name_hash();
 777        for (i = 0; i < q->len; i++)
 778                hash = partial_name_hash(nls_tolower(codepage, q->name[i]),
 779                                         hash);
 780        q->hash = end_name_hash(hash);
 781
 782        return 0;
 783}
 784
 785static int cifs_ci_compare(struct dentry *dentry, struct qstr *a,
 786                           struct qstr *b)
 787{
 788        struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls;
 789
 790        if ((a->len == b->len) &&
 791            (nls_strnicmp(codepage, a->name, b->name, a->len) == 0)) {
 792                /*
 793                 * To preserve case, don't let an existing negative dentry's
 794                 * case take precedence.  If a is not a negative dentry, this
 795                 * should have no side effects
 796                 */
 797                memcpy((void *)a->name, b->name, a->len);
 798                return 0;
 799        }
 800        return 1;
 801}
 802
 803const struct dentry_operations cifs_ci_dentry_ops = {
 804        .d_revalidate = cifs_d_revalidate,
 805        .d_hash = cifs_ci_hash,
 806        .d_compare = cifs_ci_compare,
 807};
 808