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