blob: 36cf3e2ec252ab40e1740e2dba1b5a6071b8fa10 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/dir.c
3 *
4 * vfs operations that deal with dentries
Steve French5fdae1f2007-06-05 18:30:44 +00005 *
Steve Frenchc3b2a0c2009-02-20 04:32:45 +00006 * Copyright (C) International Business Machines Corp., 2002,2009
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 * 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>
Jeff Layton3bc303c2009-09-21 06:47:50 -040027#include <linux/mount.h>
Jeff Layton6ca9f3b2010-06-16 13:40:16 -040028#include <linux/file.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#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
Steve French99ee4db2007-02-27 05:35:17 +000036static void
Linus Torvalds1da177e2005-04-16 15:20:36 -070037renew_parental_timestamps(struct dentry *direntry)
38{
Steve French5fdae1f2007-06-05 18:30:44 +000039 /* BB check if there is a way to get the kernel to do this or if we
40 really need this */
Linus Torvalds1da177e2005-04-16 15:20:36 -070041 do {
42 direntry->d_time = jiffies;
43 direntry = direntry->d_parent;
Steve French5fdae1f2007-06-05 18:30:44 +000044 } while (!IS_ROOT(direntry));
Linus Torvalds1da177e2005-04-16 15:20:36 -070045}
46
47/* Note: caller must free return buffer */
48char *
49build_path_from_dentry(struct dentry *direntry)
50{
51 struct dentry *temp;
Steve French2fe87f02006-09-21 07:02:52 +000052 int namelen;
53 int pplen;
Steve French646dd532008-05-15 01:50:56 +000054 int dfsplen;
Linus Torvalds1da177e2005-04-16 15:20:36 -070055 char *full_path;
Steve French88274812006-03-09 22:21:45 +000056 char dirsep;
Jeff Layton0d424ad2010-09-20 16:01:35 -070057 struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
58 struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -070059
Steve French5fdae1f2007-06-05 18:30:44 +000060 if (direntry == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -070061 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
Steve French646dd532008-05-15 01:50:56 +000065 dirsep = CIFS_DIR_SEP(cifs_sb);
66 pplen = cifs_sb->prepathlen;
Jeff Layton0d424ad2010-09-20 16:01:35 -070067 if (tcon->Flags & SMB_SHARE_IS_IN_DFS)
68 dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1);
Steve French646dd532008-05-15 01:50:56 +000069 else
70 dfsplen = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070071cifs_bp_rename_retry:
Steve French646dd532008-05-15 01:50:56 +000072 namelen = pplen + dfsplen;
Linus Torvalds1da177e2005-04-16 15:20:36 -070073 for (temp = direntry; !IS_ROOT(temp);) {
74 namelen += (1 + temp->d_name.len);
75 temp = temp->d_parent;
Steve French5fdae1f2007-06-05 18:30:44 +000076 if (temp == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +000077 cERROR(1, "corrupt dentry");
Linus Torvalds1da177e2005-04-16 15:20:36 -070078 return NULL;
79 }
80 }
81
82 full_path = kmalloc(namelen+1, GFP_KERNEL);
Steve French5fdae1f2007-06-05 18:30:44 +000083 if (full_path == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -070084 return full_path;
85 full_path[namelen] = 0; /* trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -070086 for (temp = direntry; !IS_ROOT(temp);) {
87 namelen -= 1 + temp->d_name.len;
88 if (namelen < 0) {
89 break;
90 } else {
Steve French7f573562005-08-30 11:32:14 -070091 full_path[namelen] = dirsep;
Linus Torvalds1da177e2005-04-16 15:20:36 -070092 strncpy(full_path + namelen + 1, temp->d_name.name,
93 temp->d_name.len);
Joe Perchesb6b38f72010-04-21 03:50:45 +000094 cFYI(0, "name: %s", full_path + namelen);
Linus Torvalds1da177e2005-04-16 15:20:36 -070095 }
96 temp = temp->d_parent;
Steve French5fdae1f2007-06-05 18:30:44 +000097 if (temp == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +000098 cERROR(1, "corrupt dentry");
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 kfree(full_path);
100 return NULL;
101 }
102 }
Steve French646dd532008-05-15 01:50:56 +0000103 if (namelen != pplen + dfsplen) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000104 cERROR(1, "did not end path lookup where expected namelen is %d",
105 namelen);
Steve French5fdae1f2007-06-05 18:30:44 +0000106 /* presumably this is only possible if racing with a rename
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 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);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110 goto cifs_bp_rename_retry;
111 }
Steve French2fe87f02006-09-21 07:02:52 +0000112 /* 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 */
Steve French646dd532008-05-15 01:50:56 +0000118
119 if (dfsplen) {
Jeff Layton0d424ad2010-09-20 16:01:35 -0700120 strncpy(full_path, tcon->treeName, dfsplen);
Steve French646dd532008-05-15 01:50:56 +0000121 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);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130 return full_path;
131}
132
Jeff Layton086f68b2009-09-21 14:08:18 -0400133struct cifsFileInfo *
Jeff Laytonabfe1ee2010-10-15 15:33:58 -0400134cifs_new_fileinfo(__u16 fileHandle, struct file *file,
Jeff Laytonf6a53462010-10-15 15:33:57 -0400135 struct tcon_link *tlink, __u32 oplock)
Steve Frencha6ce4932009-04-09 01:14:32 +0000136{
Jeff Laytona5e18bc2010-10-11 15:07:18 -0400137 struct dentry *dentry = file->f_path.dentry;
Jeff Laytonabfe1ee2010-10-15 15:33:58 -0400138 struct inode *inode = dentry->d_inode;
139 struct cifsInodeInfo *pCifsInode = CIFS_I(inode);
Steve Frencha6ce4932009-04-09 01:14:32 +0000140 struct cifsFileInfo *pCifsFile;
Steve Frencha6ce4932009-04-09 01:14:32 +0000141
142 pCifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
Steve Frencha6ce4932009-04-09 01:14:32 +0000143 if (pCifsFile == NULL)
Jeff Layton086f68b2009-09-21 14:08:18 -0400144 return pCifsFile;
Steve Frencha6ce4932009-04-09 01:14:32 +0000145
Steve Frencha6ce4932009-04-09 01:14:32 +0000146 pCifsFile->netfid = fileHandle;
147 pCifsFile->pid = current->tgid;
Jeff Layton6508d902010-09-29 19:51:11 -0400148 pCifsFile->uid = current_fsuid();
Jeff Laytona5e18bc2010-10-11 15:07:18 -0400149 pCifsFile->dentry = dget(dentry);
Jeff Layton086f68b2009-09-21 14:08:18 -0400150 pCifsFile->pfile = file;
Steve Frencha6ce4932009-04-09 01:14:32 +0000151 pCifsFile->invalidHandle = false;
Steve Frenchbc8cd432009-04-12 18:18:40 +0000152 pCifsFile->closePend = false;
Jeff Layton13cfb732010-09-29 19:51:11 -0400153 pCifsFile->tlink = cifs_get_tlink(tlink);
Steve Frencha6ce4932009-04-09 01:14:32 +0000154 mutex_init(&pCifsFile->fh_mutex);
155 mutex_init(&pCifsFile->lock_mutex);
156 INIT_LIST_HEAD(&pCifsFile->llist);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -0400157 atomic_set(&pCifsFile->count, 1);
Tejun Heo9b646972010-07-20 22:09:02 +0200158 INIT_WORK(&pCifsFile->oplock_break, cifs_oplock_break);
Steve Frencha6ce4932009-04-09 01:14:32 +0000159
Steve Frencha6ce4932009-04-09 01:14:32 +0000160 write_lock(&GlobalSMBSeslock);
Jeff Layton13cfb732010-09-29 19:51:11 -0400161 list_add(&pCifsFile->tlist, &(tlink_tcon(tlink)->openFileList));
Jeff Laytonabfe1ee2010-10-15 15:33:58 -0400162 /* 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);
Steve Frencha6ce4932009-04-09 01:14:32 +0000167 write_unlock(&GlobalSMBSeslock);
Jeff Layton086f68b2009-09-21 14:08:18 -0400168
Jeff Laytonabfe1ee2010-10-15 15:33:58 -0400169 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
Jeff Layton6ca9f3b2010-06-16 13:40:16 -0400176 file->private_data = pCifsFile;
177
Jeff Layton086f68b2009-09-21 14:08:18 -0400178 return pCifsFile;
Steve Frencha6ce4932009-04-09 01:14:32 +0000179}
180
Steve Frenchf818dd52009-01-19 02:38:35 +0000181static 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
Steve French39798772006-05-31 22:40:51 +0000192/* Inode operations in similar order to how they appear in Linux file fs.h */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193
194int
195cifs_create(struct inode *inode, struct dentry *direntry, int mode,
196 struct nameidata *nd)
197{
198 int rc = -ENOENT;
199 int xid;
Jeff Layton67750fb2008-05-09 22:28:02 +0000200 int create_options = CREATE_NOT_DIR;
Jeff Layton590a3fe2009-09-12 11:54:28 -0400201 __u32 oplock = 0;
Steve Frenchc3b2a0c2009-02-20 04:32:45 +0000202 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 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 int desiredAccess = GENERIC_READ | GENERIC_WRITE;
211 __u16 fileHandle;
212 struct cifs_sb_info *cifs_sb;
Jeff Layton7ffec372010-09-29 19:51:11 -0400213 struct tcon_link *tlink;
Steve Frenchf818dd52009-01-19 02:38:35 +0000214 struct cifsTconInfo *tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 char *full_path = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000216 FILE_ALL_INFO *buf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 struct inode *newinode = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 int disposition = FILE_OVERWRITE_IF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219
220 xid = GetXid();
221
222 cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -0400223 tlink = cifs_sb_tlink(cifs_sb);
224 if (IS_ERR(tlink)) {
225 FreeXid(xid);
226 return PTR_ERR(tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 }
Jeff Layton7ffec372010-09-29 19:51:11 -0400228 tcon = tlink_tcon(tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229
Steve Frenchc3b2a0c2009-02-20 04:32:45 +0000230 if (oplockEnabled)
231 oplock = REQ_OPLOCK;
232
233 if (nd && (nd->flags & LOOKUP_OPEN))
Jeff Layton608712f2010-10-15 15:33:56 -0400234 oflags = nd->intent.open.file->f_flags;
Steve Frenchc3b2a0c2009-02-20 04:32:45 +0000235 else
Jeff Layton608712f2010-10-15 15:33:56 -0400236 oflags = O_RDONLY | O_CREAT;
Steve Frenchc3b2a0c2009-02-20 04:32:45 +0000237
Jeff Layton7ffec372010-09-29 19:51:11 -0400238 full_path = build_path_from_dentry(direntry);
239 if (full_path == NULL) {
240 rc = -ENOMEM;
241 goto cifs_create_out;
242 }
243
Steve Frenchc3b2a0c2009-02-20 04:32:45 +0000244 if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
245 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
246 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
Steve Frenchfa588e02010-04-22 19:21:55 +0000247 rc = cifs_posix_open(full_path, &newinode,
Steve Frenchfa588e02010-04-22 19:21:55 +0000248 inode->i_sb, mode, oflags, &oplock, &fileHandle, xid);
Steve Frenchc3b2a0c2009-02-20 04:32:45 +0000249 /* 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
Steve French90e4ee52009-05-08 03:04:30 +0000254 if (rc == 0) {
Steve French90e4ee52009-05-08 03:04:30 +0000255 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) &&
Steve French703a3b82009-05-21 22:21:53 +0000260 (rc != -EOPNOTSUPP) && (rc != -EINVAL))
Steve Frenchc3b2a0c2009-02-20 04:32:45 +0000261 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 }
Steve Frenchf818dd52009-01-19 02:38:35 +0000267
Steve French5fdae1f2007-06-05 18:30:44 +0000268 if (nd && (nd->flags & LOOKUP_OPEN)) {
Steve Frenchc3b2a0c2009-02-20 04:32:45 +0000269 /* if the file is going to stay open, then we
270 need to set the desired access properly */
Miklos Szeredie08fc042005-09-06 15:18:26 -0700271 desiredAccess = 0;
Jeff Layton608712f2010-10-15 15:33:56 -0400272 if (OPEN_FMODE(oflags) & FMODE_READ)
Steve Frenchc3b2a0c2009-02-20 04:32:45 +0000273 desiredAccess |= GENERIC_READ; /* is this too little? */
Jeff Layton608712f2010-10-15 15:33:56 -0400274 if (OPEN_FMODE(oflags) & FMODE_WRITE)
Miklos Szeredie08fc042005-09-06 15:18:26 -0700275 desiredAccess |= GENERIC_WRITE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276
Steve French5fdae1f2007-06-05 18:30:44 +0000277 if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 disposition = FILE_CREATE;
Steve French5fdae1f2007-06-05 18:30:44 +0000279 else if ((oflags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 disposition = FILE_OVERWRITE_IF;
Steve French5fdae1f2007-06-05 18:30:44 +0000281 else if ((oflags & O_CREAT) == O_CREAT)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 disposition = FILE_OPEN_IF;
Steve Frenchad7a2922008-02-07 23:25:02 +0000283 else
Joe Perchesb6b38f72010-04-21 03:50:45 +0000284 cFYI(1, "Create flag not set in create function");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 }
286
Steve French5fdae1f2007-06-05 18:30:44 +0000287 /* BB add processing to set equivalent of mode - e.g. via CreateX with
288 ACLs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289
Steve French5fdae1f2007-06-05 18:30:44 +0000290 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
291 if (buf == NULL) {
Jeff Layton232341b2010-08-05 13:58:38 -0400292 rc = -ENOMEM;
293 goto cifs_create_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 }
Jeff Layton67750fb2008-05-09 22:28:02 +0000295
Jeff Layton67750fb2008-05-09 22:28:02 +0000296 /*
297 * if we're not using unix extensions, see if we need to set
298 * ATTR_READONLY on the create call
299 */
Steve Frenchf818dd52009-01-19 02:38:35 +0000300 if (!tcon->unix_ext && (mode & S_IWUGO) == 0)
Jeff Layton67750fb2008-05-09 22:28:02 +0000301 create_options |= CREATE_OPTION_READONLY;
302
Jeff Laytona6e8a842010-09-20 16:01:33 -0700303 if (tcon->ses->capabilities & CAP_NT_SMBS)
Steve Frenchf818dd52009-01-19 02:38:35 +0000304 rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
Jeff Layton67750fb2008-05-09 22:28:02 +0000305 desiredAccess, create_options,
Steve French737b7582005-04-28 22:41:06 -0700306 &fileHandle, &oplock, buf, cifs_sb->local_nls,
307 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French5bafd762006-06-07 00:18:43 +0000308 else
309 rc = -EIO; /* no NT SMB support fall into legacy open below */
310
Steve French5fdae1f2007-06-05 18:30:44 +0000311 if (rc == -EIO) {
Steve Frencha9d02ad2005-08-24 23:06:05 -0700312 /* old server, retry the open legacy style */
Steve Frenchf818dd52009-01-19 02:38:35 +0000313 rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
Jeff Layton67750fb2008-05-09 22:28:02 +0000314 desiredAccess, create_options,
Steve Frencha9d02ad2005-08-24 23:06:05 -0700315 &fileHandle, &oplock, buf, cifs_sb->local_nls,
316 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French5fdae1f2007-06-05 18:30:44 +0000317 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000319 cFYI(1, "cifs_create returned 0x%x", rc);
Steve Frenchc3b2a0c2009-02-20 04:32:45 +0000320 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 = {
Jeff Layton4e1e7fb2008-08-02 07:26:12 -0400327 .mode = mode,
328 .ctime = NO_CHANGE_64,
329 .atime = NO_CHANGE_64,
330 .mtime = NO_CHANGE_64,
331 .device = 0,
Steve Frenchc3b2a0c2009-02-20 04:32:45 +0000332 };
Jeff Layton4e1e7fb2008-08-02 07:26:12 -0400333
Steve Frenchc3b2a0c2009-02-20 04:32:45 +0000334 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();
Steve French3ce53fc2007-06-08 14:55:14 +0000340 } else {
Steve Frenchc3b2a0c2009-02-20 04:32:45 +0000341 args.uid = NO_CHANGE_64;
342 args.gid = NO_CHANGE_64;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 }
Jeff Layton01ea95e2009-07-09 20:02:49 -0400344 CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
345 cifs_sb->local_nls,
346 cifs_sb->mnt_cifs_flags &
347 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve Frenchc3b2a0c2009-02-20 04:32:45 +0000348 } else {
349 /* BB implement mode setting via Windows security
350 descriptors e.g. */
351 /* CIFSSMBWinSetPerms(xid,tcon,path,mode,-1,-1,nls);*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352
Steve Frenchc3b2a0c2009-02-20 04:32:45 +0000353 /* Could set r/o dos attribute if mode & 0222 == 0 */
354 }
355
356cifs_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();
Steve French6473a552005-11-29 20:20:10 -0800374 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 }
Steve Frenchc3b2a0c2009-02-20 04:32:45 +0000376 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377
Steve Frenchc3b2a0c2009-02-20 04:32:45 +0000378cifs_create_set_dentry:
379 if (rc == 0)
380 setup_cifs_dentry(tcon, direntry, newinode);
381 else
Joe Perchesb6b38f72010-04-21 03:50:45 +0000382 cFYI(1, "Create worked, get_inode_info failed rc = %d", rc);
Steve Frenchf818dd52009-01-19 02:38:35 +0000383
Jeff Layton2422f6762010-06-16 13:40:16 -0400384 if (newinode && nd && (nd->flags & LOOKUP_OPEN)) {
Suresh Jayaramanfdb36032010-05-11 09:46:46 +0530385 struct cifsFileInfo *pfile_info;
Jeff Layton6ca9f3b2010-06-16 13:40:16 -0400386 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
Jeff Laytonabfe1ee2010-10-15 15:33:58 -0400395 pfile_info = cifs_new_fileinfo(fileHandle, filp, tlink, oplock);
Jeff Layton6ca9f3b2010-06-16 13:40:16 -0400396 if (pfile_info == NULL) {
397 fput(filp);
398 CIFSSMBClose(xid, tcon, fileHandle);
Suresh Jayaramanfdb36032010-05-11 09:46:46 +0530399 rc = -ENOMEM;
Jeff Layton6ca9f3b2010-06-16 13:40:16 -0400400 }
Jeff Layton2422f6762010-06-16 13:40:16 -0400401 } else {
402 CIFSSMBClose(xid, tcon, fileHandle);
Steve French5fdae1f2007-06-05 18:30:44 +0000403 }
Jeff Layton2422f6762010-06-16 13:40:16 -0400404
Steve Frenchd14537f12005-04-28 22:41:05 -0700405cifs_create_out:
406 kfree(buf);
407 kfree(full_path);
Jeff Layton7ffec372010-09-29 19:51:11 -0400408 cifs_put_tlink(tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 FreeXid(xid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 return rc;
411}
412
Steve French5fdae1f2007-06-05 18:30:44 +0000413int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
414 dev_t device_number)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415{
416 int rc = -EPERM;
417 int xid;
418 struct cifs_sb_info *cifs_sb;
Jeff Layton7ffec372010-09-29 19:51:11 -0400419 struct tcon_link *tlink;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 struct cifsTconInfo *pTcon;
421 char *full_path = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000422 struct inode *newinode = NULL;
Jeff Layton5d9ac7f2010-08-05 13:58:22 -0400423 int oplock = 0;
424 u16 fileHandle;
425 FILE_ALL_INFO *buf = NULL;
426 unsigned int bytes_written;
427 struct win_dev *pdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428
429 if (!old_valid_dev(device_number))
430 return -EINVAL;
431
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -0400433 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();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 full_path = build_path_from_dentry(direntry);
Jeff Layton5d9ac7f2010-08-05 13:58:22 -0400442 if (full_path == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 rc = -ENOMEM;
Jeff Layton5d9ac7f2010-08-05 13:58:22 -0400444 goto mknod_out;
445 }
446
447 if (pTcon->unix_ext) {
Jeff Layton4e1e7fb2008-08-02 07:26:12 -0400448 struct cifs_unix_set_info_args args = {
Al Viroce3b0f82009-03-29 19:08:22 -0400449 .mode = mode & ~current_umask(),
Jeff Layton4e1e7fb2008-08-02 07:26:12 -0400450 .ctime = NO_CHANGE_64,
451 .atime = NO_CHANGE_64,
452 .mtime = NO_CHANGE_64,
453 .device = device_number,
454 };
Steve French5fdae1f2007-06-05 18:30:44 +0000455 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
David Howellsa001e5b2008-11-14 10:38:47 +1100456 args.uid = (__u64) current_fsuid();
457 args.gid = (__u64) current_fsgid();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 } else {
Jeff Layton4e1e7fb2008-08-02 07:26:12 -0400459 args.uid = NO_CHANGE_64;
460 args.gid = NO_CHANGE_64;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 }
Jeff Layton01ea95e2009-07-09 20:02:49 -0400462 rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, &args,
463 cifs_sb->local_nls,
464 cifs_sb->mnt_cifs_flags &
465 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jeff Layton5d9ac7f2010-08-05 13:58:22 -0400466 if (rc)
467 goto mknod_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468
Jeff Layton5d9ac7f2010-08-05 13:58:22 -0400469 rc = cifs_get_inode_info_unix(&newinode, full_path,
Steve French5fdae1f2007-06-05 18:30:44 +0000470 inode->i_sb, xid);
Jeff Layton5d9ac7f2010-08-05 13:58:22 -0400471 if (pTcon->nocase)
472 direntry->d_op = &cifs_ci_dentry_ops;
473 else
474 direntry->d_op = &cifs_dentry_ops;
Steve Frenchd7245c22005-07-14 18:25:12 -0500475
Jeff Layton5d9ac7f2010-08-05 13:58:22 -0400476 if (rc == 0)
477 d_instantiate(direntry, newinode);
478 goto mknod_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 }
480
Jeff Layton5d9ac7f2010-08-05 13:58:22 -0400481 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
535mknod_out:
Steve Frenchd14537f12005-04-28 22:41:05 -0700536 kfree(full_path);
Jeff Layton5d9ac7f2010-08-05 13:58:22 -0400537 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 FreeXid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -0400539 cifs_put_tlink(tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 return rc;
541}
542
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543struct dentry *
Steve French5fdae1f2007-06-05 18:30:44 +0000544cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
545 struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546{
547 int xid;
548 int rc = 0; /* to get around spurious gcc warning, set to zero here */
Jeff Layton590a3fe2009-09-12 11:54:28 -0400549 __u32 oplock = 0;
Steve Frencha6ce4932009-04-09 01:14:32 +0000550 __u16 fileHandle = 0;
551 bool posix_open = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 struct cifs_sb_info *cifs_sb;
Jeff Layton7ffec372010-09-29 19:51:11 -0400553 struct tcon_link *tlink;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 struct cifsTconInfo *pTcon;
Jeff Layton2422f6762010-06-16 13:40:16 -0400555 struct cifsFileInfo *cfile;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 struct inode *newInode = NULL;
557 char *full_path = NULL;
Steve Frencha6ce4932009-04-09 01:14:32 +0000558 struct file *filp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559
560 xid = GetXid();
561
Joe Perchesb6b38f72010-04-21 03:50:45 +0000562 cFYI(1, "parent inode = 0x%p name is: %s and dentry = 0x%p",
563 parent_dir_inode, direntry->d_name.name, direntry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 /* check whether path exists */
566
567 cifs_sb = CIFS_SB(parent_dir_inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -0400568 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);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574
Steve French296034f2006-04-21 18:18:37 +0000575 /*
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] == '\\') {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000583 cFYI(1, "Invalid file name");
Jeff Layton7ffec372010-09-29 19:51:11 -0400584 rc = -EINVAL;
585 goto lookup_out;
Steve French296034f2006-04-21 18:18:37 +0000586 }
587 }
588
Jeff Layton5ddf1e02009-07-05 11:01:02 -0400589 /*
590 * O_EXCL: optimize away the lookup, but don't hash the dentry. Let
591 * the VFS handle the create.
592 */
Steve French8e6c0332009-11-24 22:17:59 +0000593 if (nd && (nd->flags & LOOKUP_EXCL)) {
Jeff Layton5ddf1e02009-07-05 11:01:02 -0400594 d_instantiate(direntry, NULL);
Jeff Layton7ffec372010-09-29 19:51:11 -0400595 rc = 0;
596 goto lookup_out;
Jeff Layton5ddf1e02009-07-05 11:01:02 -0400597 }
598
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 /* 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);
Steve French5fdae1f2007-06-05 18:30:44 +0000603 if (full_path == NULL) {
Jeff Layton7ffec372010-09-29 19:51:11 -0400604 rc = -ENOMEM;
605 goto lookup_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 }
607
608 if (direntry->d_inode != NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000609 cFYI(1, "non-NULL inode in lookup");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 } else {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000611 cFYI(1, "NULL inode in lookup");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 }
Joe Perchesb6b38f72010-04-21 03:50:45 +0000613 cFYI(1, "Full path: %s inode = 0x%p", full_path, direntry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614
Steve French8db14ca2009-05-23 18:57:25 +0000615 /* 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 */
Steve Frencha6ce4932009-04-09 01:14:32 +0000625 if (pTcon->unix_ext) {
Steve French8e6c0332009-11-24 22:17:59 +0000626 if (nd && !(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY)) &&
Steve French8db14ca2009-05-23 18:57:25 +0000627 (nd->flags & LOOKUP_OPEN) && !pTcon->broken_posix_open &&
Jeff Layton608712f2010-10-15 15:33:56 -0400628 (nd->intent.open.file->f_flags & O_CREAT)) {
Jeff Layton2422f6762010-06-16 13:40:16 -0400629 rc = cifs_posix_open(full_path, &newInode,
Steve Frenchfa588e02010-04-22 19:21:55 +0000630 parent_dir_inode->i_sb,
Steve French703a3b82009-05-21 22:21:53 +0000631 nd->intent.open.create_mode,
Jeff Layton608712f2010-10-15 15:33:56 -0400632 nd->intent.open.file->f_flags, &oplock,
Steve Frencha6ce4932009-04-09 01:14:32 +0000633 &fileHandle, xid);
Steve French8db14ca2009-05-23 18:57:25 +0000634 /*
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;
Steve Frencha6ce4932009-04-09 01:14:32 +0000645 }
646 if (!posix_open)
647 rc = cifs_get_inode_info_unix(&newInode, full_path,
648 parent_dir_inode->i_sb, xid);
649 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 rc = cifs_get_inode_info(&newInode, full_path, NULL,
Steve Frencha6ce4932009-04-09 01:14:32 +0000651 parent_dir_inode->i_sb, xid, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652
653 if ((rc == 0) && (newInode != NULL)) {
Steve Frenchb92327f2005-08-22 20:09:43 -0700654 if (pTcon->nocase)
655 direntry->d_op = &cifs_ci_dentry_ops;
656 else
657 direntry->d_op = &cifs_dentry_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 d_add(direntry, newInode);
Jeff Layton2422f6762010-06-16 13:40:16 -0400659 if (posix_open) {
Jeff Layton6ca9f3b2010-06-16 13:40:16 -0400660 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
Jeff Laytonabfe1ee2010-10-15 15:33:58 -0400668 cfile = cifs_new_fileinfo(fileHandle, filp, tlink,
669 oplock);
Jeff Layton2422f6762010-06-16 13:40:16 -0400670 if (cfile == NULL) {
Jeff Layton6ca9f3b2010-06-16 13:40:16 -0400671 fput(filp);
Jeff Layton2422f6762010-06-16 13:40:16 -0400672 CIFSSMBClose(xid, pTcon, fileHandle);
673 rc = -ENOMEM;
674 goto lookup_out;
675 }
Jeff Layton2422f6762010-06-16 13:40:16 -0400676 }
Steve French5fdae1f2007-06-05 18:30:44 +0000677 /* since paths are not looked up by component - the parent
Steve French3abb9272005-11-28 08:16:13 -0800678 directories are presumed to be good here */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 renew_parental_timestamps(direntry);
680
681 } else if (rc == -ENOENT) {
682 rc = 0;
Steve French3abb9272005-11-28 08:16:13 -0800683 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 d_add(direntry, NULL);
Steve French5fdae1f2007-06-05 18:30:44 +0000689 /* if it was once a directory (but how can we tell?) we could do
690 shrink_dcache_parent(direntry); */
Steve Frenched2b9172008-01-20 00:30:29 +0000691 } else if (rc != -EACCES) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000692 cERROR(1, "Unexpected lookup error %d", rc);
Steve Frenched2b9172008-01-20 00:30:29 +0000693 /* We special case check for Access Denied - since that
694 is a common return code */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 }
696
Jeff Layton2422f6762010-06-16 13:40:16 -0400697lookup_out:
Steve Frenchd14537f12005-04-28 22:41:05 -0700698 kfree(full_path);
Jeff Layton7ffec372010-09-29 19:51:11 -0400699 cifs_put_tlink(tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 FreeXid(xid);
701 return ERR_PTR(rc);
702}
703
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704static int
705cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd)
706{
707 int isValid = 1;
708
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 if (direntry->d_inode) {
Jeff Laytondf2cf172010-02-12 07:44:16 -0500710 if (cifs_revalidate_dentry(direntry))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 } else {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000713 cFYI(1, "neg dentry 0x%p name = %s",
714 direntry, direntry->d_name.name);
Steve French5fdae1f2007-06-05 18:30:44 +0000715 if (time_after(jiffies, direntry->d_time + HZ) ||
Steve French3abb9272005-11-28 08:16:13 -0800716 !lookupCacheEnabled) {
717 d_drop(direntry);
718 isValid = 0;
Steve French5fdae1f2007-06-05 18:30:44 +0000719 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 }
721
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 return isValid;
723}
724
725/* static int cifs_d_delete(struct dentry *direntry)
726{
727 int rc = 0;
728
Joe Perchesb6b38f72010-04-21 03:50:45 +0000729 cFYI(1, "In cifs d_delete, name = %s", direntry->d_name.name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730
731 return rc;
732} */
733
Al Viro4fd03e82009-02-20 05:57:07 +0000734const struct dentry_operations cifs_dentry_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 .d_revalidate = cifs_d_revalidate,
Steve French5fdae1f2007-06-05 18:30:44 +0000736/* d_delete: cifs_d_delete, */ /* not needed except for debugging */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737};
Steve Frenchb92327f2005-08-22 20:09:43 -0700738
739static 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
754static 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 */
Steve Frenchc3291632008-05-15 05:41:54 +0000766 memcpy((void *)a->name, b->name, a->len);
Steve Frenchb92327f2005-08-22 20:09:43 -0700767 return 0;
768 }
769 return 1;
770}
771
Al Viro4fd03e82009-02-20 05:57:07 +0000772const struct dentry_operations cifs_ci_dentry_ops = {
Steve Frenchb92327f2005-08-22 20:09:43 -0700773 .d_revalidate = cifs_d_revalidate,
774 .d_hash = cifs_ci_hash,
775 .d_compare = cifs_ci_compare,
776};