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
24 #include <linux/stat.h>
25 #include <linux/slab.h>
26 #include <linux/namei.h>
30 #include "cifsproto.h"
31 #include "cifs_debug.h"
32 #include "cifs_fs_sb.h"
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
40 direntry
->d_time
= jiffies
;
41 direntry
= direntry
->d_parent
;
42 } while (!IS_ROOT(direntry
));
45 /* Note: caller must free return buffer */
47 build_path_from_dentry(struct dentry
*direntry
)
55 struct cifs_sb_info
*cifs_sb
;
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);
70 namelen
= pplen
+ dfsplen
;
71 for (temp
= direntry
; !IS_ROOT(temp
);) {
72 namelen
+= (1 + temp
->d_name
.len
);
73 temp
= temp
->d_parent
;
75 cERROR(1, ("corrupt dentry"));
80 full_path
= kmalloc(namelen
+1, GFP_KERNEL
);
81 if (full_path
== NULL
)
83 full_path
[namelen
] = 0; /* trailing null */
84 for (temp
= direntry
; !IS_ROOT(temp
);) {
85 namelen
-= 1 + temp
->d_name
.len
;
89 full_path
[namelen
] = dirsep
;
90 strncpy(full_path
+ namelen
+ 1, temp
->d_name
.name
,
92 cFYI(0, ("name: %s", full_path
+ namelen
));
94 temp
= temp
->d_parent
;
96 cERROR(1, ("corrupt dentry"));
101 if (namelen
!= pplen
+ dfsplen
) {
103 ("did not end path lookup where expected namelen is %d",
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) */
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 */
119 strncpy(full_path
, cifs_sb
->tcon
->treeName
, dfsplen
);
120 if (cifs_sb
->mnt_cifs_flags
& CIFS_MOUNT_POSIX_PATHS
) {
122 for (i
= 0; i
< dfsplen
; i
++) {
123 if (full_path
[i
] == '\\')
128 strncpy(full_path
+ dfsplen
, CIFS_SB(direntry
->d_sb
)->prepath
, pplen
);
133 cifs_fill_fileinfo(struct inode
*newinode
, __u16 fileHandle
,
134 struct cifsTconInfo
*tcon
, bool write_only
)
137 struct cifsFileInfo
*pCifsFile
;
138 struct cifsInodeInfo
*pCifsInode
;
140 pCifsFile
= kzalloc(sizeof(struct cifsFileInfo
), GFP_KERNEL
);
142 if (pCifsFile
== NULL
)
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
);
164 /* if readable file instance put first in list*/
166 list_add_tail(&pCifsFile
->flist
,
167 &pCifsInode
->openFileList
);
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
)
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
)
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
;
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
;
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
))
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
);
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 */
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 */
253 posix_fill_in_inode(*pinode
, presp_data
, 1);
255 cifs_fill_fileinfo(*pinode
, *pnetfid
, cifs_sb
->tcon
, write_only
);
262 static void setup_cifs_dentry(struct cifsTconInfo
*tcon
,
263 struct dentry
*direntry
,
264 struct inode
*newinode
)
267 direntry
->d_op
= &cifs_ci_dentry_ops
;
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
)
281 int create_options
= CREATE_NOT_DIR
;
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
291 int desiredAccess
= GENERIC_READ
| GENERIC_WRITE
;
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;
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
) {
312 mode
&= ~current_umask();
316 if (nd
&& (nd
->flags
& LOOKUP_OPEN
))
317 oflags
= nd
->intent
.open
.flags
;
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 */
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
))
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
;
363 cFYI(1, ("Create flag not set in create function"));
366 /* BB add processing to set equivalent of mode - e.g. via CreateX with
369 buf
= kmalloc(sizeof(FILE_ALL_INFO
), GFP_KERNEL
);
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
);
389 rc
= -EIO
; /* no NT SMB support fall into legacy open below */
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
);
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
= {
408 .ctime
= NO_CHANGE_64
,
409 .atime
= NO_CHANGE_64
,
410 .mtime
= NO_CHANGE_64
,
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
;
419 args
.gid
= (__u64
) current_fsgid();
421 args
.uid
= NO_CHANGE_64
;
422 args
.gid
= NO_CHANGE_64
;
424 CIFSSMBUnixSetInfo(xid
, tcon
, full_path
, &args
,
426 cifs_sb
->mnt_cifs_flags
& CIFS_MOUNT_MAP_SPECIAL_CHR
);
428 /* BB implement mode setting via Windows security
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 */
438 rc
= cifs_get_inode_info_unix(&newinode
, full_path
,
441 rc
= cifs_get_inode_info(&newinode
, full_path
, buf
,
442 inode
->i_sb
, xid
, &fileHandle
);
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
;
452 newinode
->i_gid
= current_fsgid();
457 cifs_create_set_dentry
:
459 setup_cifs_dentry(tcon
, direntry
, newinode
);
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
);
478 int cifs_mknod(struct inode
*inode
, struct dentry
*direntry
, int mode
,
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
))
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
)
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();
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
);
520 rc
= cifs_get_inode_info_unix(&newinode
, full_path
,
523 direntry
->d_op
= &cifs_ci_dentry_ops
;
525 direntry
->d_op
= &cifs_dentry_ops
;
527 d_instantiate(direntry
, newinode
);
530 if (cifs_sb
->mnt_cifs_flags
& CIFS_MOUNT_UNX_EMUL
) {
535 cFYI(1, ("sfu compat create special file"));
537 buf
= kmalloc(sizeof(FILE_ALL_INFO
), GFP_KERNEL
);
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
,
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 */
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
;
567 memcpy(pdev
->type
, "IntxCHR", 8);
569 cpu_to_le64(MAJOR(device_number
));
571 cpu_to_le64(MINOR(device_number
));
572 rc
= CIFSSMBWrite(xid
, pTcon
,
574 sizeof(struct win_dev
),
575 0, &bytes_written
, (char *)pdev
,
577 } else if (S_ISBLK(mode
)) {
578 memcpy(pdev
->type
, "IntxBLK", 8);
580 cpu_to_le64(MAJOR(device_number
));
582 cpu_to_le64(MINOR(device_number
));
583 rc
= CIFSSMBWrite(xid
, pTcon
,
585 sizeof(struct win_dev
),
586 0, &bytes_written
, (char *)pdev
,
588 } /* else if(S_ISFIFO */
589 CIFSSMBClose(xid
, pTcon
, fileHandle
);
593 /* add code here to set EAs */
603 cifs_lookup(struct inode
*parent_dir_inode
, struct dentry
*direntry
,
604 struct nameidata
*nd
)
607 int rc
= 0; /* to get around spurious gcc warning, set to zero here */
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
;
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
)) {
634 for (i
= 0; i
< direntry
->d_name
.len
; i
++)
635 if (direntry
->d_name
.name
[i
] == '\\') {
636 cFYI(1, ("Invalid file name"));
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
) {
648 return ERR_PTR(-ENOMEM
);
651 if (direntry
->d_inode
!= NULL
) {
652 cFYI(1, ("non-NULL inode in lookup"));
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
&
665 rc
= cifs_posix_open(full_path
, &newInode
,
666 parent_dir_inode
->i_sb
, mode
,
667 nd
->intent
.open
.flags
, &oplock
,
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
679 if ((rc
!= -EINVAL
) && (rc
!= -EOPNOTSUPP
))
684 rc
= cifs_get_inode_info_unix(&newInode
, full_path
,
685 parent_dir_inode
->i_sb
, xid
);
687 rc
= cifs_get_inode_info(&newInode
, full_path
, NULL
,
688 parent_dir_inode
->i_sb
, xid
, NULL
);
690 if ((rc
== 0) && (newInode
!= NULL
)) {
692 direntry
->d_op
= &cifs_ci_dentry_ops
;
694 direntry
->d_op
= &cifs_dentry_ops
;
695 d_add(direntry
, newInode
);
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
) {
704 direntry
->d_time
= jiffies
;
706 direntry
->d_op
= &cifs_ci_dentry_ops
;
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 */
724 cifs_d_revalidate(struct dentry
*direntry
, struct nameidata
*nd
)
728 if (direntry
->d_inode
) {
729 if (cifs_revalidate(direntry
))
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
) {
744 /* static int cifs_d_delete(struct dentry *direntry)
748 cFYI(1, ("In cifs d_delete, name = %s", direntry->d_name.name));
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
;
764 hash
= init_name_hash();
765 for (i
= 0; i
< q
->len
; i
++)
766 hash
= partial_name_hash(nls_tolower(codepage
, q
->name
[i
]),
768 q
->hash
= end_name_hash(hash
);
773 static int cifs_ci_compare(struct dentry
*dentry
, struct qstr
*a
,
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
);
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
,