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