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