[CIFS] improve posix semantics of file create
[linux-2.6] / fs / cifs / dir.c
1 /*
2  *   fs/cifs/dir.c
3  *
4  *   vfs operations that deal with dentries
5  *
6  *   Copyright (C) International Business Machines  Corp., 2002,2009
7  *   Author(s): Steve French (sfrench@us.ibm.com)
8  *
9  *   This library is free software; you can redistribute it and/or modify
10  *   it under the terms of the GNU Lesser General Public License as published
11  *   by the Free Software Foundation; either version 2.1 of the License, or
12  *   (at your option) any later version.
13  *
14  *   This library is distributed in the hope that it will be useful,
15  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
17  *   the GNU Lesser General Public License for more details.
18  *
19  *   You should have received a copy of the GNU Lesser General Public License
20  *   along with this library; if not, write to the Free Software
21  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22  */
23 #include <linux/fs.h>
24 #include <linux/stat.h>
25 #include <linux/slab.h>
26 #include <linux/namei.h>
27 #include "cifsfs.h"
28 #include "cifspdu.h"
29 #include "cifsglob.h"
30 #include "cifsproto.h"
31 #include "cifs_debug.h"
32 #include "cifs_fs_sb.h"
33
34 static void
35 renew_parental_timestamps(struct dentry *direntry)
36 {
37         /* BB check if there is a way to get the kernel to do this or if we
38            really need this */
39         do {
40                 direntry->d_time = jiffies;
41                 direntry = direntry->d_parent;
42         } while (!IS_ROOT(direntry));
43 }
44
45 /* Note: caller must free return buffer */
46 char *
47 build_path_from_dentry(struct dentry *direntry)
48 {
49         struct dentry *temp;
50         int namelen;
51         int pplen;
52         int dfsplen;
53         char *full_path;
54         char dirsep;
55         struct cifs_sb_info *cifs_sb;
56
57         if (direntry == NULL)
58                 return NULL;  /* not much we can do if dentry is freed and
59                 we need to reopen the file after it was closed implicitly
60                 when the server crashed */
61
62         cifs_sb = CIFS_SB(direntry->d_sb);
63         dirsep = CIFS_DIR_SEP(cifs_sb);
64         pplen = cifs_sb->prepathlen;
65         if (cifs_sb->tcon && (cifs_sb->tcon->Flags & SMB_SHARE_IS_IN_DFS))
66                 dfsplen = strnlen(cifs_sb->tcon->treeName, MAX_TREE_SIZE + 1);
67         else
68                 dfsplen = 0;
69 cifs_bp_rename_retry:
70         namelen = pplen + dfsplen;
71         for (temp = direntry; !IS_ROOT(temp);) {
72                 namelen += (1 + temp->d_name.len);
73                 temp = temp->d_parent;
74                 if (temp == NULL) {
75                         cERROR(1, ("corrupt dentry"));
76                         return NULL;
77                 }
78         }
79
80         full_path = kmalloc(namelen+1, GFP_KERNEL);
81         if (full_path == NULL)
82                 return full_path;
83         full_path[namelen] = 0; /* trailing null */
84         for (temp = direntry; !IS_ROOT(temp);) {
85                 namelen -= 1 + temp->d_name.len;
86                 if (namelen < 0) {
87                         break;
88                 } else {
89                         full_path[namelen] = dirsep;
90                         strncpy(full_path + namelen + 1, temp->d_name.name,
91                                 temp->d_name.len);
92                         cFYI(0, ("name: %s", full_path + namelen));
93                 }
94                 temp = temp->d_parent;
95                 if (temp == NULL) {
96                         cERROR(1, ("corrupt dentry"));
97                         kfree(full_path);
98                         return NULL;
99                 }
100         }
101         if (namelen != pplen + dfsplen) {
102                 cERROR(1,
103                        ("did not end path lookup where expected namelen is %d",
104                         namelen));
105                 /* presumably this is only possible if racing with a rename
106                 of one of the parent directories  (we can not lock the dentries
107                 above us to prevent this, but retrying should be harmless) */
108                 kfree(full_path);
109                 goto cifs_bp_rename_retry;
110         }
111         /* DIR_SEP already set for byte  0 / vs \ but not for
112            subsequent slashes in prepath which currently must
113            be entered the right way - not sure if there is an alternative
114            since the '\' is a valid posix character so we can not switch
115            those safely to '/' if any are found in the middle of the prepath */
116         /* BB test paths to Windows with '/' in the midst of prepath */
117
118         if (dfsplen) {
119                 strncpy(full_path, cifs_sb->tcon->treeName, dfsplen);
120                 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
121                         int i;
122                         for (i = 0; i < dfsplen; i++) {
123                                 if (full_path[i] == '\\')
124                                         full_path[i] = '/';
125                         }
126                 }
127         }
128         strncpy(full_path + dfsplen, CIFS_SB(direntry->d_sb)->prepath, pplen);
129         return full_path;
130 }
131
132 static int cifs_posix_open(char *full_path, struct inode **pinode,
133                     struct super_block *sb, int mode, int oflags,
134                     int *poplock, __u16 *pnetfid, int xid)
135 {
136         int rc;
137         __u32 oplock;
138         FILE_UNIX_BASIC_INFO *presp_data;
139         __u32 posix_flags = 0;
140         struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
141
142         cFYI(1, ("posix open %s", full_path));
143
144         presp_data = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
145         if (presp_data == NULL)
146                 return -ENOMEM;
147
148 /* So far cifs posix extensions can only map the following flags.
149    There are other valid fmode oflags such as FMODE_LSEEK, FMODE_PREAD, but
150    so far we do not seem to need them, and we can treat them as local only */
151         if ((oflags & (FMODE_READ | FMODE_WRITE)) ==
152                 (FMODE_READ | FMODE_WRITE))
153                 posix_flags = SMB_O_RDWR;
154         else if (oflags & FMODE_READ)
155                 posix_flags = SMB_O_RDONLY;
156         else if (oflags & FMODE_WRITE)
157                 posix_flags = SMB_O_WRONLY;
158         if (oflags & O_CREAT)
159                 posix_flags |= SMB_O_CREAT;
160         if (oflags & O_EXCL)
161                 posix_flags |= SMB_O_EXCL;
162         if (oflags & O_TRUNC)
163                 posix_flags |= SMB_O_TRUNC;
164         if (oflags & O_APPEND)
165                 posix_flags |= SMB_O_APPEND;
166         if (oflags & O_SYNC)
167                 posix_flags |= SMB_O_SYNC;
168         if (oflags & O_DIRECTORY)
169                 posix_flags |= SMB_O_DIRECTORY;
170         if (oflags & O_NOFOLLOW)
171                 posix_flags |= SMB_O_NOFOLLOW;
172         if (oflags & O_DIRECT)
173                 posix_flags |= SMB_O_DIRECT;
174
175
176         rc = CIFSPOSIXCreate(xid, cifs_sb->tcon, posix_flags, mode,
177                         pnetfid, presp_data, &oplock, full_path,
178                         cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
179                                         CIFS_MOUNT_MAP_SPECIAL_CHR);
180         if (rc)
181                 goto posix_open_ret;
182
183         if (presp_data->Type == cpu_to_le32(-1))
184                 goto posix_open_ret; /* open ok, caller does qpathinfo */
185
186         /* get new inode and set it up */
187         if (!pinode)
188                 goto posix_open_ret; /* caller does not need info */
189
190         *pinode = cifs_new_inode(sb, &presp_data->UniqueId);
191
192         /* We do not need to close the file if new_inode fails since
193            the caller will retry qpathinfo as long as inode is null */
194         if (*pinode == NULL)
195                 goto posix_open_ret;
196
197         posix_fill_in_inode(*pinode, presp_data, 1);
198
199 posix_open_ret:
200         kfree(presp_data);
201         return rc;
202 }
203
204 static void setup_cifs_dentry(struct cifsTconInfo *tcon,
205                               struct dentry *direntry,
206                               struct inode *newinode)
207 {
208         if (tcon->nocase)
209                 direntry->d_op = &cifs_ci_dentry_ops;
210         else
211                 direntry->d_op = &cifs_dentry_ops;
212         d_instantiate(direntry, newinode);
213 }
214
215 /* Inode operations in similar order to how they appear in Linux file fs.h */
216
217 int
218 cifs_create(struct inode *inode, struct dentry *direntry, int mode,
219                 struct nameidata *nd)
220 {
221         int rc = -ENOENT;
222         int xid;
223         int create_options = CREATE_NOT_DIR;
224         int oplock = 0;
225         int oflags;
226         /*
227          * BB below access is probably too much for mknod to request
228          *    but we have to do query and setpathinfo so requesting
229          *    less could fail (unless we want to request getatr and setatr
230          *    permissions (only).  At least for POSIX we do not have to
231          *    request so much.
232          */
233         int desiredAccess = GENERIC_READ | GENERIC_WRITE;
234         __u16 fileHandle;
235         struct cifs_sb_info *cifs_sb;
236         struct cifsTconInfo *tcon;
237         char *full_path = NULL;
238         FILE_ALL_INFO *buf = NULL;
239         struct inode *newinode = NULL;
240         struct cifsInodeInfo *pCifsInode;
241         int disposition = FILE_OVERWRITE_IF;
242         bool write_only = false;
243
244         xid = GetXid();
245
246         cifs_sb = CIFS_SB(inode->i_sb);
247         tcon = cifs_sb->tcon;
248
249         full_path = build_path_from_dentry(direntry);
250         if (full_path == NULL) {
251                 FreeXid(xid);
252                 return -ENOMEM;
253         }
254
255         mode &= ~current->fs->umask;
256         if (oplockEnabled)
257                 oplock = REQ_OPLOCK;
258
259         if (nd && (nd->flags & LOOKUP_OPEN))
260                 oflags = nd->intent.open.flags;
261         else
262                 oflags = FMODE_READ;
263
264         if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
265             (CIFS_UNIX_POSIX_PATH_OPS_CAP &
266                         le64_to_cpu(tcon->fsUnixInfo.Capability))) {
267                 rc = cifs_posix_open(full_path, &newinode, inode->i_sb,
268                                      mode, oflags, &oplock, &fileHandle, xid);
269                 /* EIO could indicate that (posix open) operation is not
270                    supported, despite what server claimed in capability
271                    negotation.  EREMOTE indicates DFS junction, which is not
272                    handled in posix open */
273
274                 if ((rc == 0) && (newinode == NULL))
275                         goto cifs_create_get_file_info; /* query inode info */
276                 else if (rc == 0) /* success, no need to query */
277                         goto cifs_create_set_dentry;
278                 else if ((rc != -EIO) && (rc != -EREMOTE) &&
279                          (rc != -EOPNOTSUPP)) /* path not found or net err */
280                         goto cifs_create_out;
281                 /* else fallthrough to retry, using older open call, this is
282                    case where server does not support this SMB level, and
283                    falsely claims capability (also get here for DFS case
284                    which should be rare for path not covered on files) */
285         }
286
287         if (nd && (nd->flags & LOOKUP_OPEN)) {
288                 /* if the file is going to stay open, then we
289                    need to set the desired access properly */
290                 desiredAccess = 0;
291                 if (oflags & FMODE_READ)
292                         desiredAccess |= GENERIC_READ; /* is this too little? */
293                 if (oflags & FMODE_WRITE) {
294                         desiredAccess |= GENERIC_WRITE;
295                         if (!(oflags & FMODE_READ))
296                                 write_only = true;
297                 }
298
299                 if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
300                         disposition = FILE_CREATE;
301                 else if ((oflags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
302                         disposition = FILE_OVERWRITE_IF;
303                 else if ((oflags & O_CREAT) == O_CREAT)
304                         disposition = FILE_OPEN_IF;
305                 else
306                         cFYI(1, ("Create flag not set in create function"));
307         }
308
309         /* BB add processing to set equivalent of mode - e.g. via CreateX with
310            ACLs */
311
312         buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
313         if (buf == NULL) {
314                 kfree(full_path);
315                 FreeXid(xid);
316                 return -ENOMEM;
317         }
318
319         /*
320          * if we're not using unix extensions, see if we need to set
321          * ATTR_READONLY on the create call
322          */
323         if (!tcon->unix_ext && (mode & S_IWUGO) == 0)
324                 create_options |= CREATE_OPTION_READONLY;
325
326         if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS)
327                 rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
328                          desiredAccess, create_options,
329                          &fileHandle, &oplock, buf, cifs_sb->local_nls,
330                          cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
331         else
332                 rc = -EIO; /* no NT SMB support fall into legacy open below */
333
334         if (rc == -EIO) {
335                 /* old server, retry the open legacy style */
336                 rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
337                         desiredAccess, create_options,
338                         &fileHandle, &oplock, buf, cifs_sb->local_nls,
339                         cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
340         }
341         if (rc) {
342                 cFYI(1, ("cifs_create returned 0x%x", rc));
343                 goto cifs_create_out;
344         }
345
346         /* If Open reported that we actually created a file
347            then we now have to set the mode if possible */
348         if ((tcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) {
349                 struct cifs_unix_set_info_args args = {
350                                 .mode   = mode,
351                                 .ctime  = NO_CHANGE_64,
352                                 .atime  = NO_CHANGE_64,
353                                 .mtime  = NO_CHANGE_64,
354                                 .device = 0,
355                 };
356
357                 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
358                         args.uid = (__u64) current_fsuid();
359                         if (inode->i_mode & S_ISGID)
360                                 args.gid = (__u64) inode->i_gid;
361                         else
362                                 args.gid = (__u64) current_fsgid();
363                 } else {
364                         args.uid = NO_CHANGE_64;
365                         args.gid = NO_CHANGE_64;
366                 }
367                 CIFSSMBUnixSetInfo(xid, tcon, full_path, &args,
368                         cifs_sb->local_nls,
369                         cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
370         } else {
371                 /* BB implement mode setting via Windows security
372                    descriptors e.g. */
373                 /* CIFSSMBWinSetPerms(xid,tcon,path,mode,-1,-1,nls);*/
374
375                 /* Could set r/o dos attribute if mode & 0222 == 0 */
376         }
377
378 cifs_create_get_file_info:
379         /* server might mask mode so we have to query for it */
380         if (tcon->unix_ext)
381                 rc = cifs_get_inode_info_unix(&newinode, full_path,
382                                               inode->i_sb, xid);
383         else {
384                 rc = cifs_get_inode_info(&newinode, full_path, buf,
385                                          inode->i_sb, xid, &fileHandle);
386                 if (newinode) {
387                         if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
388                                 newinode->i_mode = mode;
389                         if ((oplock & CIFS_CREATE_ACTION) &&
390                             (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) {
391                                 newinode->i_uid = current_fsuid();
392                                 if (inode->i_mode & S_ISGID)
393                                         newinode->i_gid = inode->i_gid;
394                                 else
395                                         newinode->i_gid = current_fsgid();
396                         }
397                 }
398         }
399
400 cifs_create_set_dentry:
401         if (rc == 0)
402                 setup_cifs_dentry(tcon, direntry, newinode);
403         else
404                 cFYI(1, ("Create worked, get_inode_info failed rc = %d", rc));
405
406         /* nfsd case - nfs srv does not set nd */
407         if ((nd == NULL) || (!(nd->flags & LOOKUP_OPEN))) {
408                 /* mknod case - do not leave file open */
409                 CIFSSMBClose(xid, tcon, fileHandle);
410         } else if (newinode) {
411                 struct cifsFileInfo *pCifsFile =
412                         kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
413
414                 if (pCifsFile == NULL)
415                         goto cifs_create_out;
416                 pCifsFile->netfid = fileHandle;
417                 pCifsFile->pid = current->tgid;
418                 pCifsFile->pInode = newinode;
419                 pCifsFile->invalidHandle = false;
420                 pCifsFile->closePend     = false;
421                 init_MUTEX(&pCifsFile->fh_sem);
422                 mutex_init(&pCifsFile->lock_mutex);
423                 INIT_LIST_HEAD(&pCifsFile->llist);
424                 atomic_set(&pCifsFile->wrtPending, 0);
425
426                 /* set the following in open now
427                                 pCifsFile->pfile = file; */
428                 write_lock(&GlobalSMBSeslock);
429                 list_add(&pCifsFile->tlist, &tcon->openFileList);
430                 pCifsInode = CIFS_I(newinode);
431                 if (pCifsInode) {
432                         /* if readable file instance put first in list*/
433                         if (write_only) {
434                                 list_add_tail(&pCifsFile->flist,
435                                               &pCifsInode->openFileList);
436                         } else {
437                                 list_add(&pCifsFile->flist,
438                                          &pCifsInode->openFileList);
439                         }
440                         if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
441                                 pCifsInode->clientCanCacheAll = true;
442                                 pCifsInode->clientCanCacheRead = true;
443                                 cFYI(1, ("Exclusive Oplock inode %p",
444                                         newinode));
445                         } else if ((oplock & 0xF) == OPLOCK_READ)
446                                 pCifsInode->clientCanCacheRead = true;
447                 }
448                 write_unlock(&GlobalSMBSeslock);
449         }
450 cifs_create_out:
451         kfree(buf);
452         kfree(full_path);
453         FreeXid(xid);
454         return rc;
455 }
456
457 int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
458                 dev_t device_number)
459 {
460         int rc = -EPERM;
461         int xid;
462         struct cifs_sb_info *cifs_sb;
463         struct cifsTconInfo *pTcon;
464         char *full_path = NULL;
465         struct inode *newinode = NULL;
466
467         if (!old_valid_dev(device_number))
468                 return -EINVAL;
469
470         xid = GetXid();
471
472         cifs_sb = CIFS_SB(inode->i_sb);
473         pTcon = cifs_sb->tcon;
474
475         full_path = build_path_from_dentry(direntry);
476         if (full_path == NULL)
477                 rc = -ENOMEM;
478         else if (pTcon->unix_ext) {
479                 struct cifs_unix_set_info_args args = {
480                         .mode   = mode & ~current->fs->umask,
481                         .ctime  = NO_CHANGE_64,
482                         .atime  = NO_CHANGE_64,
483                         .mtime  = NO_CHANGE_64,
484                         .device = device_number,
485                 };
486                 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
487                         args.uid = (__u64) current_fsuid();
488                         args.gid = (__u64) current_fsgid();
489                 } else {
490                         args.uid = NO_CHANGE_64;
491                         args.gid = NO_CHANGE_64;
492                 }
493                 rc = CIFSSMBUnixSetInfo(xid, pTcon, full_path,
494                         &args, cifs_sb->local_nls,
495                         cifs_sb->mnt_cifs_flags &
496                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
497
498                 if (!rc) {
499                         rc = cifs_get_inode_info_unix(&newinode, full_path,
500                                                 inode->i_sb, xid);
501                         if (pTcon->nocase)
502                                 direntry->d_op = &cifs_ci_dentry_ops;
503                         else
504                                 direntry->d_op = &cifs_dentry_ops;
505                         if (rc == 0)
506                                 d_instantiate(direntry, newinode);
507                 }
508         } else {
509                 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
510                         int oplock = 0;
511                         u16 fileHandle;
512                         FILE_ALL_INFO *buf;
513
514                         cFYI(1, ("sfu compat create special file"));
515
516                         buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
517                         if (buf == NULL) {
518                                 kfree(full_path);
519                                 FreeXid(xid);
520                                 return -ENOMEM;
521                         }
522
523                         rc = CIFSSMBOpen(xid, pTcon, full_path,
524                                          FILE_CREATE, /* fail if exists */
525                                          GENERIC_WRITE /* BB would
526                                           WRITE_OWNER | WRITE_DAC be better? */,
527                                          /* Create a file and set the
528                                             file attribute to SYSTEM */
529                                          CREATE_NOT_DIR | CREATE_OPTION_SPECIAL,
530                                          &fileHandle, &oplock, buf,
531                                          cifs_sb->local_nls,
532                                          cifs_sb->mnt_cifs_flags &
533                                             CIFS_MOUNT_MAP_SPECIAL_CHR);
534
535                         /* BB FIXME - add handling for backlevel servers
536                            which need legacy open and check for all
537                            calls to SMBOpen for fallback to SMBLeagcyOpen */
538                         if (!rc) {
539                                 /* BB Do not bother to decode buf since no
540                                    local inode yet to put timestamps in,
541                                    but we can reuse it safely */
542                                 unsigned int bytes_written;
543                                 struct win_dev *pdev;
544                                 pdev = (struct win_dev *)buf;
545                                 if (S_ISCHR(mode)) {
546                                         memcpy(pdev->type, "IntxCHR", 8);
547                                         pdev->major =
548                                               cpu_to_le64(MAJOR(device_number));
549                                         pdev->minor =
550                                               cpu_to_le64(MINOR(device_number));
551                                         rc = CIFSSMBWrite(xid, pTcon,
552                                                 fileHandle,
553                                                 sizeof(struct win_dev),
554                                                 0, &bytes_written, (char *)pdev,
555                                                 NULL, 0);
556                                 } else if (S_ISBLK(mode)) {
557                                         memcpy(pdev->type, "IntxBLK", 8);
558                                         pdev->major =
559                                               cpu_to_le64(MAJOR(device_number));
560                                         pdev->minor =
561                                               cpu_to_le64(MINOR(device_number));
562                                         rc = CIFSSMBWrite(xid, pTcon,
563                                                 fileHandle,
564                                                 sizeof(struct win_dev),
565                                                 0, &bytes_written, (char *)pdev,
566                                                 NULL, 0);
567                                 } /* else if(S_ISFIFO */
568                                 CIFSSMBClose(xid, pTcon, fileHandle);
569                                 d_drop(direntry);
570                         }
571                         kfree(buf);
572                         /* add code here to set EAs */
573                 }
574         }
575
576         kfree(full_path);
577         FreeXid(xid);
578         return rc;
579 }
580
581
582 struct dentry *
583 cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
584             struct nameidata *nd)
585 {
586         int xid;
587         int rc = 0; /* to get around spurious gcc warning, set to zero here */
588         struct cifs_sb_info *cifs_sb;
589         struct cifsTconInfo *pTcon;
590         struct inode *newInode = NULL;
591         char *full_path = NULL;
592
593         xid = GetXid();
594
595         cFYI(1, ("parent inode = 0x%p name is: %s and dentry = 0x%p",
596               parent_dir_inode, direntry->d_name.name, direntry));
597
598         /* check whether path exists */
599
600         cifs_sb = CIFS_SB(parent_dir_inode->i_sb);
601         pTcon = cifs_sb->tcon;
602
603         /*
604          * Don't allow the separator character in a path component.
605          * The VFS will not allow "/", but "\" is allowed by posix.
606          */
607         if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)) {
608                 int i;
609                 for (i = 0; i < direntry->d_name.len; i++)
610                         if (direntry->d_name.name[i] == '\\') {
611                                 cFYI(1, ("Invalid file name"));
612                                 FreeXid(xid);
613                                 return ERR_PTR(-EINVAL);
614                         }
615         }
616
617         /* can not grab the rename sem here since it would
618         deadlock in the cases (beginning of sys_rename itself)
619         in which we already have the sb rename sem */
620         full_path = build_path_from_dentry(direntry);
621         if (full_path == NULL) {
622                 FreeXid(xid);
623                 return ERR_PTR(-ENOMEM);
624         }
625
626         if (direntry->d_inode != NULL) {
627                 cFYI(1, ("non-NULL inode in lookup"));
628         } else {
629                 cFYI(1, ("NULL inode in lookup"));
630         }
631         cFYI(1, ("Full path: %s inode = 0x%p", full_path, direntry->d_inode));
632
633         if (pTcon->unix_ext)
634                 rc = cifs_get_inode_info_unix(&newInode, full_path,
635                                               parent_dir_inode->i_sb, xid);
636         else
637                 rc = cifs_get_inode_info(&newInode, full_path, NULL,
638                                          parent_dir_inode->i_sb, xid, NULL);
639
640         if ((rc == 0) && (newInode != NULL)) {
641                 if (pTcon->nocase)
642                         direntry->d_op = &cifs_ci_dentry_ops;
643                 else
644                         direntry->d_op = &cifs_dentry_ops;
645                 d_add(direntry, newInode);
646
647                 /* since paths are not looked up by component - the parent
648                    directories are presumed to be good here */
649                 renew_parental_timestamps(direntry);
650
651         } else if (rc == -ENOENT) {
652                 rc = 0;
653                 direntry->d_time = jiffies;
654                 if (pTcon->nocase)
655                         direntry->d_op = &cifs_ci_dentry_ops;
656                 else
657                         direntry->d_op = &cifs_dentry_ops;
658                 d_add(direntry, NULL);
659         /*      if it was once a directory (but how can we tell?) we could do
660                 shrink_dcache_parent(direntry); */
661         } else if (rc != -EACCES) {
662                 cERROR(1, ("Unexpected lookup error %d", rc));
663                 /* We special case check for Access Denied - since that
664                 is a common return code */
665         }
666
667         kfree(full_path);
668         FreeXid(xid);
669         return ERR_PTR(rc);
670 }
671
672 static int
673 cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd)
674 {
675         int isValid = 1;
676
677         if (direntry->d_inode) {
678                 if (cifs_revalidate(direntry))
679                         return 0;
680         } else {
681                 cFYI(1, ("neg dentry 0x%p name = %s",
682                          direntry, direntry->d_name.name));
683                 if (time_after(jiffies, direntry->d_time + HZ) ||
684                         !lookupCacheEnabled) {
685                         d_drop(direntry);
686                         isValid = 0;
687                 }
688         }
689
690         return isValid;
691 }
692
693 /* static int cifs_d_delete(struct dentry *direntry)
694 {
695         int rc = 0;
696
697         cFYI(1, ("In cifs d_delete, name = %s", direntry->d_name.name));
698
699         return rc;
700 }     */
701
702 struct dentry_operations cifs_dentry_ops = {
703         .d_revalidate = cifs_d_revalidate,
704 /* d_delete:       cifs_d_delete,      */ /* not needed except for debugging */
705 };
706
707 static int cifs_ci_hash(struct dentry *dentry, struct qstr *q)
708 {
709         struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls;
710         unsigned long hash;
711         int i;
712
713         hash = init_name_hash();
714         for (i = 0; i < q->len; i++)
715                 hash = partial_name_hash(nls_tolower(codepage, q->name[i]),
716                                          hash);
717         q->hash = end_name_hash(hash);
718
719         return 0;
720 }
721
722 static int cifs_ci_compare(struct dentry *dentry, struct qstr *a,
723                            struct qstr *b)
724 {
725         struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls;
726
727         if ((a->len == b->len) &&
728             (nls_strnicmp(codepage, a->name, b->name, a->len) == 0)) {
729                 /*
730                  * To preserve case, don't let an existing negative dentry's
731                  * case take precedence.  If a is not a negative dentry, this
732                  * should have no side effects
733                  */
734                 memcpy((void *)a->name, b->name, a->len);
735                 return 0;
736         }
737         return 1;
738 }
739
740 struct dentry_operations cifs_ci_dentry_ops = {
741         .d_revalidate = cifs_d_revalidate,
742         .d_hash = cifs_ci_hash,
743         .d_compare = cifs_ci_compare,
744 };