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