[CIFS] Add support for posix open during lookup
[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 "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 void
133 cifs_fill_fileinfo(struct inode *newinode, __u16 fileHandle,
134                         struct cifsTconInfo *tcon, bool write_only)
135 {
136         int oplock = 0;
137         struct cifsFileInfo *pCifsFile;
138         struct cifsInodeInfo *pCifsInode;
139
140         pCifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
141
142         if (pCifsFile == NULL)
143                 return;
144
145         if (oplockEnabled)
146                 oplock = REQ_OPLOCK;
147
148         pCifsFile->netfid = fileHandle;
149         pCifsFile->pid = current->tgid;
150         pCifsFile->pInode = newinode;
151         pCifsFile->invalidHandle = false;
152         pCifsFile->closePend     = false;
153         mutex_init(&pCifsFile->fh_mutex);
154         mutex_init(&pCifsFile->lock_mutex);
155         INIT_LIST_HEAD(&pCifsFile->llist);
156         atomic_set(&pCifsFile->wrtPending, 0);
157
158         /* set the following in open now
159                         pCifsFile->pfile = file; */
160         write_lock(&GlobalSMBSeslock);
161         list_add(&pCifsFile->tlist, &tcon->openFileList);
162         pCifsInode = CIFS_I(newinode);
163         if (pCifsInode) {
164                 /* if readable file instance put first in list*/
165                 if (write_only) {
166                         list_add_tail(&pCifsFile->flist,
167                                       &pCifsInode->openFileList);
168                 } else {
169                         list_add(&pCifsFile->flist,
170                                  &pCifsInode->openFileList);
171                 }
172                 if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
173                         pCifsInode->clientCanCacheAll = true;
174                         pCifsInode->clientCanCacheRead = true;
175                         cFYI(1, ("Exclusive Oplock inode %p",
176                                 newinode));
177                 } else if ((oplock & 0xF) == OPLOCK_READ)
178                         pCifsInode->clientCanCacheRead = true;
179         }
180         write_unlock(&GlobalSMBSeslock);
181 }
182
183 int cifs_posix_open(char *full_path, struct inode **pinode,
184                     struct super_block *sb, int mode, int oflags,
185                     int *poplock, __u16 *pnetfid, int xid)
186 {
187         int rc;
188         __u32 oplock;
189         bool write_only = false;
190         FILE_UNIX_BASIC_INFO *presp_data;
191         __u32 posix_flags = 0;
192         struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
193
194         cFYI(1, ("posix open %s", full_path));
195
196         presp_data = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
197         if (presp_data == NULL)
198                 return -ENOMEM;
199
200 /* So far cifs posix extensions can only map the following flags.
201    There are other valid fmode oflags such as FMODE_LSEEK, FMODE_PREAD, but
202    so far we do not seem to need them, and we can treat them as local only */
203         if ((oflags & (FMODE_READ | FMODE_WRITE)) ==
204                 (FMODE_READ | FMODE_WRITE))
205                 posix_flags = SMB_O_RDWR;
206         else if (oflags & FMODE_READ)
207                 posix_flags = SMB_O_RDONLY;
208         else if (oflags & FMODE_WRITE)
209                 posix_flags = SMB_O_WRONLY;
210         if (oflags & O_CREAT)
211                 posix_flags |= SMB_O_CREAT;
212         if (oflags & O_EXCL)
213                 posix_flags |= SMB_O_EXCL;
214         if (oflags & O_TRUNC)
215                 posix_flags |= SMB_O_TRUNC;
216         if (oflags & O_APPEND)
217                 posix_flags |= SMB_O_APPEND;
218         if (oflags & O_SYNC)
219                 posix_flags |= SMB_O_SYNC;
220         if (oflags & O_DIRECTORY)
221                 posix_flags |= SMB_O_DIRECTORY;
222         if (oflags & O_NOFOLLOW)
223                 posix_flags |= SMB_O_NOFOLLOW;
224         if (oflags & O_DIRECT)
225                 posix_flags |= SMB_O_DIRECT;
226
227         if (!(oflags & FMODE_READ))
228                 write_only = true;
229
230         rc = CIFSPOSIXCreate(xid, cifs_sb->tcon, posix_flags, mode,
231                         pnetfid, presp_data, &oplock, full_path,
232                         cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
233                                         CIFS_MOUNT_MAP_SPECIAL_CHR);
234         if (rc)
235                 goto posix_open_ret;
236
237         if (presp_data->Type == cpu_to_le32(-1))
238                 goto posix_open_ret; /* open ok, caller does qpathinfo */
239
240         /* get new inode and set it up */
241         if (!pinode)
242                 goto posix_open_ret; /* caller does not need info */
243
244         if (*pinode == NULL) {
245                 __u64 unique_id = le64_to_cpu(presp_data->UniqueId);
246                 *pinode = cifs_new_inode(sb, &unique_id);
247         }
248         /* else an inode was passed in. Update its info, don't create one */
249
250         /* We do not need to close the file if new_inode fails since
251            the caller will retry qpathinfo as long as inode is null */
252         if (*pinode == NULL)
253                 goto posix_open_ret;
254
255         posix_fill_in_inode(*pinode, presp_data, 1);
256
257         cifs_fill_fileinfo(*pinode, *pnetfid, cifs_sb->tcon, write_only);
258
259 posix_open_ret:
260         kfree(presp_data);
261         return rc;
262 }
263
264 static void setup_cifs_dentry(struct cifsTconInfo *tcon,
265                               struct dentry *direntry,
266                               struct inode *newinode)
267 {
268         if (tcon->nocase)
269                 direntry->d_op = &cifs_ci_dentry_ops;
270         else
271                 direntry->d_op = &cifs_dentry_ops;
272         d_instantiate(direntry, newinode);
273 }
274
275 /* Inode operations in similar order to how they appear in Linux file fs.h */
276
277 int
278 cifs_create(struct inode *inode, struct dentry *direntry, int mode,
279                 struct nameidata *nd)
280 {
281         int rc = -ENOENT;
282         int xid;
283         int create_options = CREATE_NOT_DIR;
284         int oplock = 0;
285         int oflags;
286         /*
287          * BB below access is probably too much for mknod to request
288          *    but we have to do query and setpathinfo so requesting
289          *    less could fail (unless we want to request getatr and setatr
290          *    permissions (only).  At least for POSIX we do not have to
291          *    request so much.
292          */
293         int desiredAccess = GENERIC_READ | GENERIC_WRITE;
294         __u16 fileHandle;
295         struct cifs_sb_info *cifs_sb;
296         struct cifsTconInfo *tcon;
297         char *full_path = NULL;
298         FILE_ALL_INFO *buf = NULL;
299         struct inode *newinode = NULL;
300         int disposition = FILE_OVERWRITE_IF;
301         bool write_only = false;
302
303         xid = GetXid();
304
305         cifs_sb = CIFS_SB(inode->i_sb);
306         tcon = cifs_sb->tcon;
307
308         full_path = build_path_from_dentry(direntry);
309         if (full_path == NULL) {
310                 FreeXid(xid);
311                 return -ENOMEM;
312         }
313
314         mode &= ~current_umask();
315         if (oplockEnabled)
316                 oplock = REQ_OPLOCK;
317
318         if (nd && (nd->flags & LOOKUP_OPEN))
319                 oflags = nd->intent.open.flags;
320         else
321                 oflags = FMODE_READ;
322
323         if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
324             (CIFS_UNIX_POSIX_PATH_OPS_CAP &
325                         le64_to_cpu(tcon->fsUnixInfo.Capability))) {
326                 rc = cifs_posix_open(full_path, &newinode, inode->i_sb,
327                                      mode, oflags, &oplock, &fileHandle, xid);
328                 /* EIO could indicate that (posix open) operation is not
329                    supported, despite what server claimed in capability
330                    negotation.  EREMOTE indicates DFS junction, which is not
331                    handled in posix open */
332
333                 if ((rc == 0) && (newinode == NULL))
334                         goto cifs_create_get_file_info; /* query inode info */
335                 else if (rc == 0) /* success, no need to query */
336                         goto cifs_create_set_dentry;
337                 else if ((rc != -EIO) && (rc != -EREMOTE) &&
338                          (rc != -EOPNOTSUPP)) /* path not found or net err */
339                         goto cifs_create_out;
340                 /* else fallthrough to retry, using older open call, this is
341                    case where server does not support this SMB level, and
342                    falsely claims capability (also get here for DFS case
343                    which should be rare for path not covered on files) */
344         }
345
346         if (nd && (nd->flags & LOOKUP_OPEN)) {
347                 /* if the file is going to stay open, then we
348                    need to set the desired access properly */
349                 desiredAccess = 0;
350                 if (oflags & FMODE_READ)
351                         desiredAccess |= GENERIC_READ; /* is this too little? */
352                 if (oflags & FMODE_WRITE) {
353                         desiredAccess |= GENERIC_WRITE;
354                         if (!(oflags & FMODE_READ))
355                                 write_only = true;
356                 }
357
358                 if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
359                         disposition = FILE_CREATE;
360                 else if ((oflags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
361                         disposition = FILE_OVERWRITE_IF;
362                 else if ((oflags & O_CREAT) == O_CREAT)
363                         disposition = FILE_OPEN_IF;
364                 else
365                         cFYI(1, ("Create flag not set in create function"));
366         }
367
368         /* BB add processing to set equivalent of mode - e.g. via CreateX with
369            ACLs */
370
371         buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
372         if (buf == NULL) {
373                 kfree(full_path);
374                 FreeXid(xid);
375                 return -ENOMEM;
376         }
377
378         /*
379          * if we're not using unix extensions, see if we need to set
380          * ATTR_READONLY on the create call
381          */
382         if (!tcon->unix_ext && (mode & S_IWUGO) == 0)
383                 create_options |= CREATE_OPTION_READONLY;
384
385         if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS)
386                 rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
387                          desiredAccess, create_options,
388                          &fileHandle, &oplock, buf, cifs_sb->local_nls,
389                          cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
390         else
391                 rc = -EIO; /* no NT SMB support fall into legacy open below */
392
393         if (rc == -EIO) {
394                 /* old server, retry the open legacy style */
395                 rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
396                         desiredAccess, create_options,
397                         &fileHandle, &oplock, buf, cifs_sb->local_nls,
398                         cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
399         }
400         if (rc) {
401                 cFYI(1, ("cifs_create returned 0x%x", rc));
402                 goto cifs_create_out;
403         }
404
405         /* If Open reported that we actually created a file
406            then we now have to set the mode if possible */
407         if ((tcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) {
408                 struct cifs_unix_set_info_args args = {
409                                 .mode   = mode,
410                                 .ctime  = NO_CHANGE_64,
411                                 .atime  = NO_CHANGE_64,
412                                 .mtime  = NO_CHANGE_64,
413                                 .device = 0,
414                 };
415
416                 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
417                         args.uid = (__u64) current_fsuid();
418                         if (inode->i_mode & S_ISGID)
419                                 args.gid = (__u64) inode->i_gid;
420                         else
421                                 args.gid = (__u64) current_fsgid();
422                 } else {
423                         args.uid = NO_CHANGE_64;
424                         args.gid = NO_CHANGE_64;
425                 }
426                 CIFSSMBUnixSetInfo(xid, tcon, full_path, &args,
427                         cifs_sb->local_nls,
428                         cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
429         } else {
430                 /* BB implement mode setting via Windows security
431                    descriptors e.g. */
432                 /* CIFSSMBWinSetPerms(xid,tcon,path,mode,-1,-1,nls);*/
433
434                 /* Could set r/o dos attribute if mode & 0222 == 0 */
435         }
436
437 cifs_create_get_file_info:
438         /* server might mask mode so we have to query for it */
439         if (tcon->unix_ext)
440                 rc = cifs_get_inode_info_unix(&newinode, full_path,
441                                               inode->i_sb, xid);
442         else {
443                 rc = cifs_get_inode_info(&newinode, full_path, buf,
444                                          inode->i_sb, xid, &fileHandle);
445                 if (newinode) {
446                         if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
447                                 newinode->i_mode = mode;
448                         if ((oplock & CIFS_CREATE_ACTION) &&
449                             (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) {
450                                 newinode->i_uid = current_fsuid();
451                                 if (inode->i_mode & S_ISGID)
452                                         newinode->i_gid = inode->i_gid;
453                                 else
454                                         newinode->i_gid = current_fsgid();
455                         }
456                 }
457         }
458
459 cifs_create_set_dentry:
460         if (rc == 0)
461                 setup_cifs_dentry(tcon, direntry, newinode);
462         else
463                 cFYI(1, ("Create worked, get_inode_info failed rc = %d", rc));
464
465         /* nfsd case - nfs srv does not set nd */
466         if ((nd == NULL) || (!(nd->flags & LOOKUP_OPEN))) {
467                 /* mknod case - do not leave file open */
468                 CIFSSMBClose(xid, tcon, fileHandle);
469         } else if (newinode) {
470                         cifs_fill_fileinfo(newinode, fileHandle,
471                                         cifs_sb->tcon, write_only);
472         }
473 cifs_create_out:
474         kfree(buf);
475         kfree(full_path);
476         FreeXid(xid);
477         return rc;
478 }
479
480 int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
481                 dev_t device_number)
482 {
483         int rc = -EPERM;
484         int xid;
485         struct cifs_sb_info *cifs_sb;
486         struct cifsTconInfo *pTcon;
487         char *full_path = NULL;
488         struct inode *newinode = NULL;
489
490         if (!old_valid_dev(device_number))
491                 return -EINVAL;
492
493         xid = GetXid();
494
495         cifs_sb = CIFS_SB(inode->i_sb);
496         pTcon = cifs_sb->tcon;
497
498         full_path = build_path_from_dentry(direntry);
499         if (full_path == NULL)
500                 rc = -ENOMEM;
501         else if (pTcon->unix_ext) {
502                 struct cifs_unix_set_info_args args = {
503                         .mode   = mode & ~current_umask(),
504                         .ctime  = NO_CHANGE_64,
505                         .atime  = NO_CHANGE_64,
506                         .mtime  = NO_CHANGE_64,
507                         .device = device_number,
508                 };
509                 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
510                         args.uid = (__u64) current_fsuid();
511                         args.gid = (__u64) current_fsgid();
512                 } else {
513                         args.uid = NO_CHANGE_64;
514                         args.gid = NO_CHANGE_64;
515                 }
516                 rc = CIFSSMBUnixSetInfo(xid, pTcon, full_path,
517                         &args, cifs_sb->local_nls,
518                         cifs_sb->mnt_cifs_flags &
519                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
520
521                 if (!rc) {
522                         rc = cifs_get_inode_info_unix(&newinode, full_path,
523                                                 inode->i_sb, xid);
524                         if (pTcon->nocase)
525                                 direntry->d_op = &cifs_ci_dentry_ops;
526                         else
527                                 direntry->d_op = &cifs_dentry_ops;
528                         if (rc == 0)
529                                 d_instantiate(direntry, newinode);
530                 }
531         } else {
532                 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
533                         int oplock = 0;
534                         u16 fileHandle;
535                         FILE_ALL_INFO *buf;
536
537                         cFYI(1, ("sfu compat create special file"));
538
539                         buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
540                         if (buf == NULL) {
541                                 kfree(full_path);
542                                 FreeXid(xid);
543                                 return -ENOMEM;
544                         }
545
546                         rc = CIFSSMBOpen(xid, pTcon, full_path,
547                                          FILE_CREATE, /* fail if exists */
548                                          GENERIC_WRITE /* BB would
549                                           WRITE_OWNER | WRITE_DAC be better? */,
550                                          /* Create a file and set the
551                                             file attribute to SYSTEM */
552                                          CREATE_NOT_DIR | CREATE_OPTION_SPECIAL,
553                                          &fileHandle, &oplock, buf,
554                                          cifs_sb->local_nls,
555                                          cifs_sb->mnt_cifs_flags &
556                                             CIFS_MOUNT_MAP_SPECIAL_CHR);
557
558                         /* BB FIXME - add handling for backlevel servers
559                            which need legacy open and check for all
560                            calls to SMBOpen for fallback to SMBLeagcyOpen */
561                         if (!rc) {
562                                 /* BB Do not bother to decode buf since no
563                                    local inode yet to put timestamps in,
564                                    but we can reuse it safely */
565                                 unsigned int bytes_written;
566                                 struct win_dev *pdev;
567                                 pdev = (struct win_dev *)buf;
568                                 if (S_ISCHR(mode)) {
569                                         memcpy(pdev->type, "IntxCHR", 8);
570                                         pdev->major =
571                                               cpu_to_le64(MAJOR(device_number));
572                                         pdev->minor =
573                                               cpu_to_le64(MINOR(device_number));
574                                         rc = CIFSSMBWrite(xid, pTcon,
575                                                 fileHandle,
576                                                 sizeof(struct win_dev),
577                                                 0, &bytes_written, (char *)pdev,
578                                                 NULL, 0);
579                                 } else if (S_ISBLK(mode)) {
580                                         memcpy(pdev->type, "IntxBLK", 8);
581                                         pdev->major =
582                                               cpu_to_le64(MAJOR(device_number));
583                                         pdev->minor =
584                                               cpu_to_le64(MINOR(device_number));
585                                         rc = CIFSSMBWrite(xid, pTcon,
586                                                 fileHandle,
587                                                 sizeof(struct win_dev),
588                                                 0, &bytes_written, (char *)pdev,
589                                                 NULL, 0);
590                                 } /* else if(S_ISFIFO */
591                                 CIFSSMBClose(xid, pTcon, fileHandle);
592                                 d_drop(direntry);
593                         }
594                         kfree(buf);
595                         /* add code here to set EAs */
596                 }
597         }
598
599         kfree(full_path);
600         FreeXid(xid);
601         return rc;
602 }
603
604 struct dentry *
605 cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
606             struct nameidata *nd)
607 {
608         int xid;
609         int rc = 0; /* to get around spurious gcc warning, set to zero here */
610         int oplock = 0;
611         int mode;
612         __u16 fileHandle = 0;
613         bool posix_open = false;
614         struct cifs_sb_info *cifs_sb;
615         struct cifsTconInfo *pTcon;
616         struct inode *newInode = NULL;
617         char *full_path = NULL;
618         struct file *filp;
619
620         xid = GetXid();
621
622         cFYI(1, ("parent inode = 0x%p name is: %s and dentry = 0x%p",
623               parent_dir_inode, direntry->d_name.name, direntry));
624
625         /* check whether path exists */
626
627         cifs_sb = CIFS_SB(parent_dir_inode->i_sb);
628         pTcon = cifs_sb->tcon;
629
630         /*
631          * Don't allow the separator character in a path component.
632          * The VFS will not allow "/", but "\" is allowed by posix.
633          */
634         if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)) {
635                 int i;
636                 for (i = 0; i < direntry->d_name.len; i++)
637                         if (direntry->d_name.name[i] == '\\') {
638                                 cFYI(1, ("Invalid file name"));
639                                 FreeXid(xid);
640                                 return ERR_PTR(-EINVAL);
641                         }
642         }
643
644         /* can not grab the rename sem here since it would
645         deadlock in the cases (beginning of sys_rename itself)
646         in which we already have the sb rename sem */
647         full_path = build_path_from_dentry(direntry);
648         if (full_path == NULL) {
649                 FreeXid(xid);
650                 return ERR_PTR(-ENOMEM);
651         }
652
653         if (direntry->d_inode != NULL) {
654                 cFYI(1, ("non-NULL inode in lookup"));
655         } else {
656                 cFYI(1, ("NULL inode in lookup"));
657         }
658         cFYI(1, ("Full path: %s inode = 0x%p", full_path, direntry->d_inode));
659
660         if (pTcon->unix_ext) {
661                 if (!(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY)) &&
662                                 (nd->flags & LOOKUP_OPEN)) {
663                         if (!((nd->intent.open.flags & O_CREAT) &&
664                                         (nd->intent.open.flags & O_EXCL))) {
665                                 mode = nd->intent.open.create_mode &
666                                                 ~current->fs->umask;
667                                 rc = cifs_posix_open(full_path, &newInode,
668                                         parent_dir_inode->i_sb, mode,
669                                         nd->intent.open.flags, &oplock,
670                                         &fileHandle, xid);
671                                 if ((rc != -EINVAL) && (rc != -EOPNOTSUPP))
672                                         posix_open = true;
673                         }
674                 }
675                 if (!posix_open)
676                         rc = cifs_get_inode_info_unix(&newInode, full_path,
677                                                 parent_dir_inode->i_sb, xid);
678         } else
679                 rc = cifs_get_inode_info(&newInode, full_path, NULL,
680                                 parent_dir_inode->i_sb, xid, NULL);
681
682         if ((rc == 0) && (newInode != NULL)) {
683                 if (pTcon->nocase)
684                         direntry->d_op = &cifs_ci_dentry_ops;
685                 else
686                         direntry->d_op = &cifs_dentry_ops;
687                 d_add(direntry, newInode);
688                 if (posix_open)
689                         filp = lookup_instantiate_filp(nd, direntry, NULL);
690                 /* since paths are not looked up by component - the parent
691                    directories are presumed to be good here */
692                 renew_parental_timestamps(direntry);
693
694         } else if (rc == -ENOENT) {
695                 rc = 0;
696                 direntry->d_time = jiffies;
697                 if (pTcon->nocase)
698                         direntry->d_op = &cifs_ci_dentry_ops;
699                 else
700                         direntry->d_op = &cifs_dentry_ops;
701                 d_add(direntry, NULL);
702         /*      if it was once a directory (but how can we tell?) we could do
703                 shrink_dcache_parent(direntry); */
704         } else if (rc != -EACCES) {
705                 cERROR(1, ("Unexpected lookup error %d", rc));
706                 /* We special case check for Access Denied - since that
707                 is a common return code */
708         }
709
710         kfree(full_path);
711         FreeXid(xid);
712         return ERR_PTR(rc);
713 }
714
715 static int
716 cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd)
717 {
718         int isValid = 1;
719
720         if (direntry->d_inode) {
721                 if (cifs_revalidate(direntry))
722                         return 0;
723         } else {
724                 cFYI(1, ("neg dentry 0x%p name = %s",
725                          direntry, direntry->d_name.name));
726                 if (time_after(jiffies, direntry->d_time + HZ) ||
727                         !lookupCacheEnabled) {
728                         d_drop(direntry);
729                         isValid = 0;
730                 }
731         }
732
733         return isValid;
734 }
735
736 /* static int cifs_d_delete(struct dentry *direntry)
737 {
738         int rc = 0;
739
740         cFYI(1, ("In cifs d_delete, name = %s", direntry->d_name.name));
741
742         return rc;
743 }     */
744
745 const struct dentry_operations cifs_dentry_ops = {
746         .d_revalidate = cifs_d_revalidate,
747 /* d_delete:       cifs_d_delete,      */ /* not needed except for debugging */
748 };
749
750 static int cifs_ci_hash(struct dentry *dentry, struct qstr *q)
751 {
752         struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls;
753         unsigned long hash;
754         int i;
755
756         hash = init_name_hash();
757         for (i = 0; i < q->len; i++)
758                 hash = partial_name_hash(nls_tolower(codepage, q->name[i]),
759                                          hash);
760         q->hash = end_name_hash(hash);
761
762         return 0;
763 }
764
765 static int cifs_ci_compare(struct dentry *dentry, struct qstr *a,
766                            struct qstr *b)
767 {
768         struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls;
769
770         if ((a->len == b->len) &&
771             (nls_strnicmp(codepage, a->name, b->name, a->len) == 0)) {
772                 /*
773                  * To preserve case, don't let an existing negative dentry's
774                  * case take precedence.  If a is not a negative dentry, this
775                  * should have no side effects
776                  */
777                 memcpy((void *)a->name, b->name, a->len);
778                 return 0;
779         }
780         return 1;
781 }
782
783 const struct dentry_operations cifs_ci_dentry_ops = {
784         .d_revalidate = cifs_d_revalidate,
785         .d_hash = cifs_ci_hash,
786         .d_compare = cifs_ci_compare,
787 };