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