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