Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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
36static void
37renew_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 */
48char *
49build_path_from_dentry(struct dentry *direntry)
50{
51 struct dentry *temp;
52 int namelen;
53 int dfsplen;
54 char *full_path;
55 char dirsep;
56 struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
57 struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
58 unsigned seq;
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 if (tcon->Flags & SMB_SHARE_IS_IN_DFS)
67 dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1);
68 else
69 dfsplen = 0;
70cifs_bp_rename_retry:
71 namelen = dfsplen;
72 seq = read_seqbegin(&rename_lock);
73 rcu_read_lock();
74 for (temp = direntry; !IS_ROOT(temp);) {
75 namelen += (1 + temp->d_name.len);
76 temp = temp->d_parent;
77 if (temp == NULL) {
78 cERROR(1, "corrupt dentry");
79 rcu_read_unlock();
80 return NULL;
81 }
82 }
83 rcu_read_unlock();
84
85 full_path = kmalloc(namelen+1, GFP_KERNEL);
86 if (full_path == NULL)
87 return full_path;
88 full_path[namelen] = 0; /* trailing null */
89 rcu_read_lock();
90 for (temp = direntry; !IS_ROOT(temp);) {
91 spin_lock(&temp->d_lock);
92 namelen -= 1 + temp->d_name.len;
93 if (namelen < 0) {
94 spin_unlock(&temp->d_lock);
95 break;
96 } else {
97 full_path[namelen] = dirsep;
98 strncpy(full_path + namelen + 1, temp->d_name.name,
99 temp->d_name.len);
100 cFYI(0, "name: %s", full_path + namelen);
101 }
102 spin_unlock(&temp->d_lock);
103 temp = temp->d_parent;
104 if (temp == NULL) {
105 cERROR(1, "corrupt dentry");
106 rcu_read_unlock();
107 kfree(full_path);
108 return NULL;
109 }
110 }
111 rcu_read_unlock();
112 if (namelen != dfsplen || read_seqretry(&rename_lock, seq)) {
113 cERROR(1, "did not end path lookup where expected namelen is %d",
114 namelen);
115 /* presumably this is only possible if racing with a rename
116 of one of the parent directories (we can not lock the dentries
117 above us to prevent this, but retrying should be harmless) */
118 kfree(full_path);
119 goto cifs_bp_rename_retry;
120 }
121 /* DIR_SEP already set for byte 0 / vs \ but not for
122 subsequent slashes in prepath which currently must
123 be entered the right way - not sure if there is an alternative
124 since the '\' is a valid posix character so we can not switch
125 those safely to '/' if any are found in the middle of the prepath */
126 /* BB test paths to Windows with '/' in the midst of prepath */
127
128 if (dfsplen) {
129 strncpy(full_path, tcon->treeName, dfsplen);
130 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
131 int i;
132 for (i = 0; i < dfsplen; i++) {
133 if (full_path[i] == '\\')
134 full_path[i] = '/';
135 }
136 }
137 }
138 return full_path;
139}
140
141/* Inode operations in similar order to how they appear in Linux file fs.h */
142
143int
144cifs_create(struct inode *inode, struct dentry *direntry, int mode,
145 struct nameidata *nd)
146{
147 int rc = -ENOENT;
148 int xid;
149 int create_options = CREATE_NOT_DIR;
150 __u32 oplock = 0;
151 int oflags;
152 /*
153 * BB below access is probably too much for mknod to request
154 * but we have to do query and setpathinfo so requesting
155 * less could fail (unless we want to request getatr and setatr
156 * permissions (only). At least for POSIX we do not have to
157 * request so much.
158 */
159 int desiredAccess = GENERIC_READ | GENERIC_WRITE;
160 __u16 fileHandle;
161 struct cifs_sb_info *cifs_sb;
162 struct tcon_link *tlink;
163 struct cifs_tcon *tcon;
164 char *full_path = NULL;
165 FILE_ALL_INFO *buf = NULL;
166 struct inode *newinode = NULL;
167 int disposition = FILE_OVERWRITE_IF;
168
169 xid = GetXid();
170
171 cifs_sb = CIFS_SB(inode->i_sb);
172 tlink = cifs_sb_tlink(cifs_sb);
173 if (IS_ERR(tlink)) {
174 FreeXid(xid);
175 return PTR_ERR(tlink);
176 }
177 tcon = tlink_tcon(tlink);
178
179 if (oplockEnabled)
180 oplock = REQ_OPLOCK;
181
182 if (nd && (nd->flags & LOOKUP_OPEN))
183 oflags = nd->intent.open.file->f_flags;
184 else
185 oflags = O_RDONLY | O_CREAT;
186
187 full_path = build_path_from_dentry(direntry);
188 if (full_path == NULL) {
189 rc = -ENOMEM;
190 goto cifs_create_out;
191 }
192
193 if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
194 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
195 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
196 rc = cifs_posix_open(full_path, &newinode,
197 inode->i_sb, mode, oflags, &oplock, &fileHandle, xid);
198 /* EIO could indicate that (posix open) operation is not
199 supported, despite what server claimed in capability
200 negotiation. EREMOTE indicates DFS junction, which is not
201 handled in posix open */
202
203 if (rc == 0) {
204 if (newinode == NULL) /* query inode info */
205 goto cifs_create_get_file_info;
206 else /* success, no need to query */
207 goto cifs_create_set_dentry;
208 } else if ((rc != -EIO) && (rc != -EREMOTE) &&
209 (rc != -EOPNOTSUPP) && (rc != -EINVAL))
210 goto cifs_create_out;
211 /* else fallthrough to retry, using older open call, this is
212 case where server does not support this SMB level, and
213 falsely claims capability (also get here for DFS case
214 which should be rare for path not covered on files) */
215 }
216
217 if (nd && (nd->flags & LOOKUP_OPEN)) {
218 /* if the file is going to stay open, then we
219 need to set the desired access properly */
220 desiredAccess = 0;
221 if (OPEN_FMODE(oflags) & FMODE_READ)
222 desiredAccess |= GENERIC_READ; /* is this too little? */
223 if (OPEN_FMODE(oflags) & FMODE_WRITE)
224 desiredAccess |= GENERIC_WRITE;
225
226 if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
227 disposition = FILE_CREATE;
228 else if ((oflags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
229 disposition = FILE_OVERWRITE_IF;
230 else if ((oflags & O_CREAT) == O_CREAT)
231 disposition = FILE_OPEN_IF;
232 else
233 cFYI(1, "Create flag not set in create function");
234 }
235
236 /* BB add processing to set equivalent of mode - e.g. via CreateX with
237 ACLs */
238
239 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
240 if (buf == NULL) {
241 rc = -ENOMEM;
242 goto cifs_create_out;
243 }
244
245 /*
246 * if we're not using unix extensions, see if we need to set
247 * ATTR_READONLY on the create call
248 */
249 if (!tcon->unix_ext && (mode & S_IWUGO) == 0)
250 create_options |= CREATE_OPTION_READONLY;
251
252 if (tcon->ses->capabilities & CAP_NT_SMBS)
253 rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
254 desiredAccess, create_options,
255 &fileHandle, &oplock, buf, cifs_sb->local_nls,
256 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
257 else
258 rc = -EIO; /* no NT SMB support fall into legacy open below */
259
260 if (rc == -EIO) {
261 /* old server, retry the open legacy style */
262 rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
263 desiredAccess, create_options,
264 &fileHandle, &oplock, buf, cifs_sb->local_nls,
265 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
266 }
267 if (rc) {
268 cFYI(1, "cifs_create returned 0x%x", rc);
269 goto cifs_create_out;
270 }
271
272 /* If Open reported that we actually created a file
273 then we now have to set the mode if possible */
274 if ((tcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) {
275 struct cifs_unix_set_info_args args = {
276 .mode = mode,
277 .ctime = NO_CHANGE_64,
278 .atime = NO_CHANGE_64,
279 .mtime = NO_CHANGE_64,
280 .device = 0,
281 };
282
283 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
284 args.uid = (__u64) current_fsuid();
285 if (inode->i_mode & S_ISGID)
286 args.gid = (__u64) inode->i_gid;
287 else
288 args.gid = (__u64) current_fsgid();
289 } else {
290 args.uid = NO_CHANGE_64;
291 args.gid = NO_CHANGE_64;
292 }
293 CIFSSMBUnixSetFileInfo(xid, tcon, &args, fileHandle,
294 current->tgid);
295 } else {
296 /* BB implement mode setting via Windows security
297 descriptors e.g. */
298 /* CIFSSMBWinSetPerms(xid,tcon,path,mode,-1,-1,nls);*/
299
300 /* Could set r/o dos attribute if mode & 0222 == 0 */
301 }
302
303cifs_create_get_file_info:
304 /* server might mask mode so we have to query for it */
305 if (tcon->unix_ext)
306 rc = cifs_get_inode_info_unix(&newinode, full_path,
307 inode->i_sb, xid);
308 else {
309 rc = cifs_get_inode_info(&newinode, full_path, buf,
310 inode->i_sb, xid, &fileHandle);
311 if (newinode) {
312 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
313 newinode->i_mode = mode;
314 if ((oplock & CIFS_CREATE_ACTION) &&
315 (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) {
316 newinode->i_uid = current_fsuid();
317 if (inode->i_mode & S_ISGID)
318 newinode->i_gid = inode->i_gid;
319 else
320 newinode->i_gid = current_fsgid();
321 }
322 }
323 }
324
325cifs_create_set_dentry:
326 if (rc == 0)
327 d_instantiate(direntry, newinode);
328 else
329 cFYI(1, "Create worked, get_inode_info failed rc = %d", rc);
330
331 if (newinode && nd && (nd->flags & LOOKUP_OPEN)) {
332 struct cifsFileInfo *pfile_info;
333 struct file *filp;
334
335 filp = lookup_instantiate_filp(nd, direntry, generic_file_open);
336 if (IS_ERR(filp)) {
337 rc = PTR_ERR(filp);
338 CIFSSMBClose(xid, tcon, fileHandle);
339 goto cifs_create_out;
340 }
341
342 pfile_info = cifs_new_fileinfo(fileHandle, filp, tlink, oplock);
343 if (pfile_info == NULL) {
344 fput(filp);
345 CIFSSMBClose(xid, tcon, fileHandle);
346 rc = -ENOMEM;
347 }
348 } else {
349 CIFSSMBClose(xid, tcon, fileHandle);
350 }
351
352cifs_create_out:
353 kfree(buf);
354 kfree(full_path);
355 cifs_put_tlink(tlink);
356 FreeXid(xid);
357 return rc;
358}
359
360int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
361 dev_t device_number)
362{
363 int rc = -EPERM;
364 int xid;
365 struct cifs_sb_info *cifs_sb;
366 struct tcon_link *tlink;
367 struct cifs_tcon *pTcon;
368 struct cifs_io_parms io_parms;
369 char *full_path = NULL;
370 struct inode *newinode = NULL;
371 int oplock = 0;
372 u16 fileHandle;
373 FILE_ALL_INFO *buf = NULL;
374 unsigned int bytes_written;
375 struct win_dev *pdev;
376
377 if (!old_valid_dev(device_number))
378 return -EINVAL;
379
380 cifs_sb = CIFS_SB(inode->i_sb);
381 tlink = cifs_sb_tlink(cifs_sb);
382 if (IS_ERR(tlink))
383 return PTR_ERR(tlink);
384
385 pTcon = tlink_tcon(tlink);
386
387 xid = GetXid();
388
389 full_path = build_path_from_dentry(direntry);
390 if (full_path == NULL) {
391 rc = -ENOMEM;
392 goto mknod_out;
393 }
394
395 if (pTcon->unix_ext) {
396 struct cifs_unix_set_info_args args = {
397 .mode = mode & ~current_umask(),
398 .ctime = NO_CHANGE_64,
399 .atime = NO_CHANGE_64,
400 .mtime = NO_CHANGE_64,
401 .device = device_number,
402 };
403 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
404 args.uid = (__u64) current_fsuid();
405 args.gid = (__u64) current_fsgid();
406 } else {
407 args.uid = NO_CHANGE_64;
408 args.gid = NO_CHANGE_64;
409 }
410 rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, &args,
411 cifs_sb->local_nls,
412 cifs_sb->mnt_cifs_flags &
413 CIFS_MOUNT_MAP_SPECIAL_CHR);
414 if (rc)
415 goto mknod_out;
416
417 rc = cifs_get_inode_info_unix(&newinode, full_path,
418 inode->i_sb, xid);
419
420 if (rc == 0)
421 d_instantiate(direntry, newinode);
422 goto mknod_out;
423 }
424
425 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL))
426 goto mknod_out;
427
428
429 cFYI(1, "sfu compat create special file");
430
431 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
432 if (buf == NULL) {
433 kfree(full_path);
434 rc = -ENOMEM;
435 FreeXid(xid);
436 return rc;
437 }
438
439 /* FIXME: would WRITE_OWNER | WRITE_DAC be better? */
440 rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_CREATE,
441 GENERIC_WRITE, CREATE_NOT_DIR | CREATE_OPTION_SPECIAL,
442 &fileHandle, &oplock, buf, cifs_sb->local_nls,
443 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
444 if (rc)
445 goto mknod_out;
446
447 /* BB Do not bother to decode buf since no local inode yet to put
448 * timestamps in, but we can reuse it safely */
449
450 pdev = (struct win_dev *)buf;
451 io_parms.netfid = fileHandle;
452 io_parms.pid = current->tgid;
453 io_parms.tcon = pTcon;
454 io_parms.offset = 0;
455 io_parms.length = sizeof(struct win_dev);
456 if (S_ISCHR(mode)) {
457 memcpy(pdev->type, "IntxCHR", 8);
458 pdev->major =
459 cpu_to_le64(MAJOR(device_number));
460 pdev->minor =
461 cpu_to_le64(MINOR(device_number));
462 rc = CIFSSMBWrite(xid, &io_parms,
463 &bytes_written, (char *)pdev,
464 NULL, 0);
465 } else if (S_ISBLK(mode)) {
466 memcpy(pdev->type, "IntxBLK", 8);
467 pdev->major =
468 cpu_to_le64(MAJOR(device_number));
469 pdev->minor =
470 cpu_to_le64(MINOR(device_number));
471 rc = CIFSSMBWrite(xid, &io_parms,
472 &bytes_written, (char *)pdev,
473 NULL, 0);
474 } /* else if (S_ISFIFO) */
475 CIFSSMBClose(xid, pTcon, fileHandle);
476 d_drop(direntry);
477
478 /* FIXME: add code here to set EAs */
479
480mknod_out:
481 kfree(full_path);
482 kfree(buf);
483 FreeXid(xid);
484 cifs_put_tlink(tlink);
485 return rc;
486}
487
488struct dentry *
489cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
490 struct nameidata *nd)
491{
492 int xid;
493 int rc = 0; /* to get around spurious gcc warning, set to zero here */
494 __u32 oplock = 0;
495 __u16 fileHandle = 0;
496 bool posix_open = false;
497 struct cifs_sb_info *cifs_sb;
498 struct tcon_link *tlink;
499 struct cifs_tcon *pTcon;
500 struct cifsFileInfo *cfile;
501 struct inode *newInode = NULL;
502 char *full_path = NULL;
503 struct file *filp;
504
505 xid = GetXid();
506
507 cFYI(1, "parent inode = 0x%p name is: %s and dentry = 0x%p",
508 parent_dir_inode, direntry->d_name.name, direntry);
509
510 /* check whether path exists */
511
512 cifs_sb = CIFS_SB(parent_dir_inode->i_sb);
513 tlink = cifs_sb_tlink(cifs_sb);
514 if (IS_ERR(tlink)) {
515 FreeXid(xid);
516 return (struct dentry *)tlink;
517 }
518 pTcon = tlink_tcon(tlink);
519
520 /*
521 * Don't allow the separator character in a path component.
522 * The VFS will not allow "/", but "\" is allowed by posix.
523 */
524 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)) {
525 int i;
526 for (i = 0; i < direntry->d_name.len; i++)
527 if (direntry->d_name.name[i] == '\\') {
528 cFYI(1, "Invalid file name");
529 rc = -EINVAL;
530 goto lookup_out;
531 }
532 }
533
534 /*
535 * O_EXCL: optimize away the lookup, but don't hash the dentry. Let
536 * the VFS handle the create.
537 */
538 if (nd && (nd->flags & LOOKUP_EXCL)) {
539 d_instantiate(direntry, NULL);
540 rc = 0;
541 goto lookup_out;
542 }
543
544 /* can not grab the rename sem here since it would
545 deadlock in the cases (beginning of sys_rename itself)
546 in which we already have the sb rename sem */
547 full_path = build_path_from_dentry(direntry);
548 if (full_path == NULL) {
549 rc = -ENOMEM;
550 goto lookup_out;
551 }
552
553 if (direntry->d_inode != NULL) {
554 cFYI(1, "non-NULL inode in lookup");
555 } else {
556 cFYI(1, "NULL inode in lookup");
557 }
558 cFYI(1, "Full path: %s inode = 0x%p", full_path, direntry->d_inode);
559
560 /* Posix open is only called (at lookup time) for file create now.
561 * For opens (rather than creates), because we do not know if it
562 * is a file or directory yet, and current Samba no longer allows
563 * us to do posix open on dirs, we could end up wasting an open call
564 * on what turns out to be a dir. For file opens, we wait to call posix
565 * open till cifs_open. It could be added here (lookup) in the future
566 * but the performance tradeoff of the extra network request when EISDIR
567 * or EACCES is returned would have to be weighed against the 50%
568 * reduction in network traffic in the other paths.
569 */
570 if (pTcon->unix_ext) {
571 if (nd && !(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY)) &&
572 (nd->flags & LOOKUP_OPEN) && !pTcon->broken_posix_open &&
573 (nd->intent.open.file->f_flags & O_CREAT)) {
574 rc = cifs_posix_open(full_path, &newInode,
575 parent_dir_inode->i_sb,
576 nd->intent.open.create_mode,
577 nd->intent.open.file->f_flags, &oplock,
578 &fileHandle, xid);
579 /*
580 * The check below works around a bug in POSIX
581 * open in samba versions 3.3.1 and earlier where
582 * open could incorrectly fail with invalid parameter.
583 * If either that or op not supported returned, follow
584 * the normal lookup.
585 */
586 if ((rc == 0) || (rc == -ENOENT))
587 posix_open = true;
588 else if ((rc == -EINVAL) || (rc != -EOPNOTSUPP))
589 pTcon->broken_posix_open = true;
590 }
591 if (!posix_open)
592 rc = cifs_get_inode_info_unix(&newInode, full_path,
593 parent_dir_inode->i_sb, xid);
594 } else
595 rc = cifs_get_inode_info(&newInode, full_path, NULL,
596 parent_dir_inode->i_sb, xid, NULL);
597
598 if ((rc == 0) && (newInode != NULL)) {
599 d_add(direntry, newInode);
600 if (posix_open) {
601 filp = lookup_instantiate_filp(nd, direntry,
602 generic_file_open);
603 if (IS_ERR(filp)) {
604 rc = PTR_ERR(filp);
605 CIFSSMBClose(xid, pTcon, fileHandle);
606 goto lookup_out;
607 }
608
609 cfile = cifs_new_fileinfo(fileHandle, filp, tlink,
610 oplock);
611 if (cfile == NULL) {
612 fput(filp);
613 CIFSSMBClose(xid, pTcon, fileHandle);
614 rc = -ENOMEM;
615 goto lookup_out;
616 }
617 }
618 /* since paths are not looked up by component - the parent
619 directories are presumed to be good here */
620 renew_parental_timestamps(direntry);
621
622 } else if (rc == -ENOENT) {
623 rc = 0;
624 direntry->d_time = jiffies;
625 d_add(direntry, NULL);
626 /* if it was once a directory (but how can we tell?) we could do
627 shrink_dcache_parent(direntry); */
628 } else if (rc != -EACCES) {
629 cERROR(1, "Unexpected lookup error %d", rc);
630 /* We special case check for Access Denied - since that
631 is a common return code */
632 }
633
634lookup_out:
635 kfree(full_path);
636 cifs_put_tlink(tlink);
637 FreeXid(xid);
638 return ERR_PTR(rc);
639}
640
641static int
642cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd)
643{
644 if (nd->flags & LOOKUP_RCU)
645 return -ECHILD;
646
647 if (direntry->d_inode) {
648 if (cifs_revalidate_dentry(direntry))
649 return 0;
650 else
651 return 1;
652 }
653
654 /*
655 * This may be nfsd (or something), anyway, we can't see the
656 * intent of this. So, since this can be for creation, drop it.
657 */
658 if (!nd)
659 return 0;
660
661 /*
662 * Drop the negative dentry, in order to make sure to use the
663 * case sensitive name which is specified by user if this is
664 * for creation.
665 */
666 if (!(nd->flags & (LOOKUP_CONTINUE | LOOKUP_PARENT))) {
667 if (nd->flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET))
668 return 0;
669 }
670
671 if (time_after(jiffies, direntry->d_time + HZ) || !lookupCacheEnabled)
672 return 0;
673
674 return 1;
675}
676
677/* static int cifs_d_delete(struct dentry *direntry)
678{
679 int rc = 0;
680
681 cFYI(1, "In cifs d_delete, name = %s", direntry->d_name.name);
682
683 return rc;
684} */
685
686const struct dentry_operations cifs_dentry_ops = {
687 .d_revalidate = cifs_d_revalidate,
688 .d_automount = cifs_dfs_d_automount,
689/* d_delete: cifs_d_delete, */ /* not needed except for debugging */
690};
691
692static int cifs_ci_hash(const struct dentry *dentry, const struct inode *inode,
693 struct qstr *q)
694{
695 struct nls_table *codepage = CIFS_SB(dentry->d_sb)->local_nls;
696 unsigned long hash;
697 int i;
698
699 hash = init_name_hash();
700 for (i = 0; i < q->len; i++)
701 hash = partial_name_hash(nls_tolower(codepage, q->name[i]),
702 hash);
703 q->hash = end_name_hash(hash);
704
705 return 0;
706}
707
708static int cifs_ci_compare(const struct dentry *parent,
709 const struct inode *pinode,
710 const struct dentry *dentry, const struct inode *inode,
711 unsigned int len, const char *str, const struct qstr *name)
712{
713 struct nls_table *codepage = CIFS_SB(pinode->i_sb)->local_nls;
714
715 if ((name->len == len) &&
716 (nls_strnicmp(codepage, name->name, str, len) == 0))
717 return 0;
718 return 1;
719}
720
721const struct dentry_operations cifs_ci_dentry_ops = {
722 .d_revalidate = cifs_d_revalidate,
723 .d_hash = cifs_ci_hash,
724 .d_compare = cifs_ci_compare,
725 .d_automount = cifs_dfs_d_automount,
726};