0521492f5b3b284dc24aa918ce6fb182bdeae333
[firefly-linux-kernel-4.4.55.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                    negotiation.  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         struct cifs_io_parms io_parms;
361         char *full_path = NULL;
362         struct inode *newinode = NULL;
363         int oplock = 0;
364         u16 fileHandle;
365         FILE_ALL_INFO *buf = NULL;
366         unsigned int bytes_written;
367         struct win_dev *pdev;
368
369         if (!old_valid_dev(device_number))
370                 return -EINVAL;
371
372         cifs_sb = CIFS_SB(inode->i_sb);
373         tlink = cifs_sb_tlink(cifs_sb);
374         if (IS_ERR(tlink))
375                 return PTR_ERR(tlink);
376
377         pTcon = tlink_tcon(tlink);
378
379         xid = GetXid();
380
381         full_path = build_path_from_dentry(direntry);
382         if (full_path == NULL) {
383                 rc = -ENOMEM;
384                 goto mknod_out;
385         }
386
387         if (pTcon->unix_ext) {
388                 struct cifs_unix_set_info_args args = {
389                         .mode   = mode & ~current_umask(),
390                         .ctime  = NO_CHANGE_64,
391                         .atime  = NO_CHANGE_64,
392                         .mtime  = NO_CHANGE_64,
393                         .device = device_number,
394                 };
395                 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
396                         args.uid = (__u64) current_fsuid();
397                         args.gid = (__u64) current_fsgid();
398                 } else {
399                         args.uid = NO_CHANGE_64;
400                         args.gid = NO_CHANGE_64;
401                 }
402                 rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, &args,
403                                             cifs_sb->local_nls,
404                                             cifs_sb->mnt_cifs_flags &
405                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
406                 if (rc)
407                         goto mknod_out;
408
409                 rc = cifs_get_inode_info_unix(&newinode, full_path,
410                                                 inode->i_sb, xid);
411
412                 if (rc == 0)
413                         d_instantiate(direntry, newinode);
414                 goto mknod_out;
415         }
416
417         if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL))
418                 goto mknod_out;
419
420
421         cFYI(1, "sfu compat create special file");
422
423         buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
424         if (buf == NULL) {
425                 kfree(full_path);
426                 rc = -ENOMEM;
427                 FreeXid(xid);
428                 return rc;
429         }
430
431         /* FIXME: would WRITE_OWNER | WRITE_DAC be better? */
432         rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_CREATE,
433                          GENERIC_WRITE, CREATE_NOT_DIR | CREATE_OPTION_SPECIAL,
434                          &fileHandle, &oplock, buf, cifs_sb->local_nls,
435                          cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
436         if (rc)
437                 goto mknod_out;
438
439         /* BB Do not bother to decode buf since no local inode yet to put
440          * timestamps in, but we can reuse it safely */
441
442         pdev = (struct win_dev *)buf;
443         io_parms.netfid = fileHandle;
444         io_parms.pid = current->tgid;
445         io_parms.tcon = pTcon;
446         io_parms.offset = 0;
447         io_parms.length = sizeof(struct win_dev);
448         if (S_ISCHR(mode)) {
449                 memcpy(pdev->type, "IntxCHR", 8);
450                 pdev->major =
451                       cpu_to_le64(MAJOR(device_number));
452                 pdev->minor =
453                       cpu_to_le64(MINOR(device_number));
454                 rc = CIFSSMBWrite(xid, &io_parms,
455                         &bytes_written, (char *)pdev,
456                         NULL, 0);
457         } else if (S_ISBLK(mode)) {
458                 memcpy(pdev->type, "IntxBLK", 8);
459                 pdev->major =
460                       cpu_to_le64(MAJOR(device_number));
461                 pdev->minor =
462                       cpu_to_le64(MINOR(device_number));
463                 rc = CIFSSMBWrite(xid, &io_parms,
464                         &bytes_written, (char *)pdev,
465                         NULL, 0);
466         } /* else if (S_ISFIFO) */
467         CIFSSMBClose(xid, pTcon, fileHandle);
468         d_drop(direntry);
469
470         /* FIXME: add code here to set EAs */
471
472 mknod_out:
473         kfree(full_path);
474         kfree(buf);
475         FreeXid(xid);
476         cifs_put_tlink(tlink);
477         return rc;
478 }
479
480 struct dentry *
481 cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
482             struct nameidata *nd)
483 {
484         int xid;
485         int rc = 0; /* to get around spurious gcc warning, set to zero here */
486         __u32 oplock = 0;
487         __u16 fileHandle = 0;
488         bool posix_open = false;
489         struct cifs_sb_info *cifs_sb;
490         struct tcon_link *tlink;
491         struct cifsTconInfo *pTcon;
492         struct cifsFileInfo *cfile;
493         struct inode *newInode = NULL;
494         char *full_path = NULL;
495         struct file *filp;
496
497         xid = GetXid();
498
499         cFYI(1, "parent inode = 0x%p name is: %s and dentry = 0x%p",
500               parent_dir_inode, direntry->d_name.name, direntry);
501
502         /* check whether path exists */
503
504         cifs_sb = CIFS_SB(parent_dir_inode->i_sb);
505         tlink = cifs_sb_tlink(cifs_sb);
506         if (IS_ERR(tlink)) {
507                 FreeXid(xid);
508                 return (struct dentry *)tlink;
509         }
510         pTcon = tlink_tcon(tlink);
511
512         /*
513          * Don't allow the separator character in a path component.
514          * The VFS will not allow "/", but "\" is allowed by posix.
515          */
516         if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)) {
517                 int i;
518                 for (i = 0; i < direntry->d_name.len; i++)
519                         if (direntry->d_name.name[i] == '\\') {
520                                 cFYI(1, "Invalid file name");
521                                 rc = -EINVAL;
522                                 goto lookup_out;
523                         }
524         }
525
526         /*
527          * O_EXCL: optimize away the lookup, but don't hash the dentry. Let
528          * the VFS handle the create.
529          */
530         if (nd && (nd->flags & LOOKUP_EXCL)) {
531                 d_instantiate(direntry, NULL);
532                 rc = 0;
533                 goto lookup_out;
534         }
535
536         /* can not grab the rename sem here since it would
537         deadlock in the cases (beginning of sys_rename itself)
538         in which we already have the sb rename sem */
539         full_path = build_path_from_dentry(direntry);
540         if (full_path == NULL) {
541                 rc = -ENOMEM;
542                 goto lookup_out;
543         }
544
545         if (direntry->d_inode != NULL) {
546                 cFYI(1, "non-NULL inode in lookup");
547         } else {
548                 cFYI(1, "NULL inode in lookup");
549         }
550         cFYI(1, "Full path: %s inode = 0x%p", full_path, direntry->d_inode);
551
552         /* Posix open is only called (at lookup time) for file create now.
553          * For opens (rather than creates), because we do not know if it
554          * is a file or directory yet, and current Samba no longer allows
555          * us to do posix open on dirs, we could end up wasting an open call
556          * on what turns out to be a dir. For file opens, we wait to call posix
557          * open till cifs_open.  It could be added here (lookup) in the future
558          * but the performance tradeoff of the extra network request when EISDIR
559          * or EACCES is returned would have to be weighed against the 50%
560          * reduction in network traffic in the other paths.
561          */
562         if (pTcon->unix_ext) {
563                 if (nd && !(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY)) &&
564                      (nd->flags & LOOKUP_OPEN) && !pTcon->broken_posix_open &&
565                      (nd->intent.open.file->f_flags & O_CREAT)) {
566                         rc = cifs_posix_open(full_path, &newInode,
567                                         parent_dir_inode->i_sb,
568                                         nd->intent.open.create_mode,
569                                         nd->intent.open.file->f_flags, &oplock,
570                                         &fileHandle, xid);
571                         /*
572                          * The check below works around a bug in POSIX
573                          * open in samba versions 3.3.1 and earlier where
574                          * open could incorrectly fail with invalid parameter.
575                          * If either that or op not supported returned, follow
576                          * the normal lookup.
577                          */
578                         if ((rc == 0) || (rc == -ENOENT))
579                                 posix_open = true;
580                         else if ((rc == -EINVAL) || (rc != -EOPNOTSUPP))
581                                 pTcon->broken_posix_open = true;
582                 }
583                 if (!posix_open)
584                         rc = cifs_get_inode_info_unix(&newInode, full_path,
585                                                 parent_dir_inode->i_sb, xid);
586         } else
587                 rc = cifs_get_inode_info(&newInode, full_path, NULL,
588                                 parent_dir_inode->i_sb, xid, NULL);
589
590         if ((rc == 0) && (newInode != NULL)) {
591                 d_add(direntry, newInode);
592                 if (posix_open) {
593                         filp = lookup_instantiate_filp(nd, direntry,
594                                                        generic_file_open);
595                         if (IS_ERR(filp)) {
596                                 rc = PTR_ERR(filp);
597                                 CIFSSMBClose(xid, pTcon, fileHandle);
598                                 goto lookup_out;
599                         }
600
601                         cfile = cifs_new_fileinfo(fileHandle, filp, tlink,
602                                                   oplock);
603                         if (cfile == NULL) {
604                                 fput(filp);
605                                 CIFSSMBClose(xid, pTcon, fileHandle);
606                                 rc = -ENOMEM;
607                                 goto lookup_out;
608                         }
609                 }
610                 /* since paths are not looked up by component - the parent
611                    directories are presumed to be good here */
612                 renew_parental_timestamps(direntry);
613
614         } else if (rc == -ENOENT) {
615                 rc = 0;
616                 direntry->d_time = jiffies;
617                 d_add(direntry, NULL);
618         /*      if it was once a directory (but how can we tell?) we could do
619                 shrink_dcache_parent(direntry); */
620         } else if (rc != -EACCES) {
621                 cERROR(1, "Unexpected lookup error %d", rc);
622                 /* We special case check for Access Denied - since that
623                 is a common return code */
624         }
625
626 lookup_out:
627         kfree(full_path);
628         cifs_put_tlink(tlink);
629         FreeXid(xid);
630         return ERR_PTR(rc);
631 }
632
633 static int
634 cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd)
635 {
636         if (nd->flags & LOOKUP_RCU)
637                 return -ECHILD;
638
639         if (direntry->d_inode) {
640                 if (cifs_revalidate_dentry(direntry))
641                         return 0;
642                 else
643                         return 1;
644         }
645
646         /*
647          * This may be nfsd (or something), anyway, we can't see the
648          * intent of this. So, since this can be for creation, drop it.
649          */
650         if (!nd)
651                 return 0;
652
653         /*
654          * Drop the negative dentry, in order to make sure to use the
655          * case sensitive name which is specified by user if this is
656          * for creation.
657          */
658         if (!(nd->flags & (LOOKUP_CONTINUE | LOOKUP_PARENT))) {
659                 if (nd->flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET))
660                         return 0;
661         }
662
663         if (time_after(jiffies, direntry->d_time + HZ) || !lookupCacheEnabled)
664                 return 0;
665
666         return 1;
667 }
668
669 /* static int cifs_d_delete(struct dentry *direntry)
670 {
671         int rc = 0;
672
673         cFYI(1, "In cifs d_delete, name = %s", direntry->d_name.name);
674
675         return rc;
676 }     */
677
678 const struct dentry_operations cifs_dentry_ops = {
679         .d_revalidate = cifs_d_revalidate,
680         .d_automount = cifs_dfs_d_automount,
681 /* d_delete:       cifs_d_delete,      */ /* not needed except for debugging */
682 };
683
684 static int cifs_ci_hash(const struct dentry *dentry, const struct inode *inode,
685                 struct qstr *q)
686 {
687         struct nls_table *codepage = CIFS_SB(dentry->d_sb)->local_nls;
688         unsigned long hash;
689         int i;
690
691         hash = init_name_hash();
692         for (i = 0; i < q->len; i++)
693                 hash = partial_name_hash(nls_tolower(codepage, q->name[i]),
694                                          hash);
695         q->hash = end_name_hash(hash);
696
697         return 0;
698 }
699
700 static int cifs_ci_compare(const struct dentry *parent,
701                 const struct inode *pinode,
702                 const struct dentry *dentry, const struct inode *inode,
703                 unsigned int len, const char *str, const struct qstr *name)
704 {
705         struct nls_table *codepage = CIFS_SB(pinode->i_sb)->local_nls;
706
707         if ((name->len == len) &&
708             (nls_strnicmp(codepage, name->name, str, len) == 0))
709                 return 0;
710         return 1;
711 }
712
713 const struct dentry_operations cifs_ci_dentry_ops = {
714         .d_revalidate = cifs_d_revalidate,
715         .d_hash = cifs_ci_hash,
716         .d_compare = cifs_ci_compare,
717         .d_automount = cifs_dfs_d_automount,
718 };