blob: d9006b04324e54de3a43cf9bedc5b8017cd52ec3 [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>
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"
33
Steve French99ee4db2007-02-27 05:35:17 +000034static void
Linus Torvalds1da177e2005-04-16 15:20:36 -070035renew_parental_timestamps(struct dentry *direntry)
36{
Steve French5fdae1f2007-06-05 18:30:44 +000037 /* BB check if there is a way to get the kernel to do this or if we
38 really need this */
Linus Torvalds1da177e2005-04-16 15:20:36 -070039 do {
40 direntry->d_time = jiffies;
41 direntry = direntry->d_parent;
Steve French5fdae1f2007-06-05 18:30:44 +000042 } while (!IS_ROOT(direntry));
Linus Torvalds1da177e2005-04-16 15:20:36 -070043}
44
45/* Note: caller must free return buffer */
46char *
47build_path_from_dentry(struct dentry *direntry)
48{
49 struct dentry *temp;
Steve French2fe87f02006-09-21 07:02:52 +000050 int namelen;
51 int pplen;
Steve French646dd532008-05-15 01:50:56 +000052 int dfsplen;
Linus Torvalds1da177e2005-04-16 15:20:36 -070053 char *full_path;
Steve French88274812006-03-09 22:21:45 +000054 char dirsep;
Steve French646dd532008-05-15 01:50:56 +000055 struct cifs_sb_info *cifs_sb;
Linus Torvalds1da177e2005-04-16 15:20:36 -070056
Steve French5fdae1f2007-06-05 18:30:44 +000057 if (direntry == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -070058 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 */
61
Steve French646dd532008-05-15 01:50:56 +000062 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -070069cifs_bp_rename_retry:
Steve French646dd532008-05-15 01:50:56 +000070 namelen = pplen + dfsplen;
Linus Torvalds1da177e2005-04-16 15:20:36 -070071 for (temp = direntry; !IS_ROOT(temp);) {
72 namelen += (1 + temp->d_name.len);
73 temp = temp->d_parent;
Steve French5fdae1f2007-06-05 18:30:44 +000074 if (temp == NULL) {
75 cERROR(1, ("corrupt dentry"));
Linus Torvalds1da177e2005-04-16 15:20:36 -070076 return NULL;
77 }
78 }
79
80 full_path = kmalloc(namelen+1, GFP_KERNEL);
Steve French5fdae1f2007-06-05 18:30:44 +000081 if (full_path == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -070082 return full_path;
83 full_path[namelen] = 0; /* trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -070084 for (temp = direntry; !IS_ROOT(temp);) {
85 namelen -= 1 + temp->d_name.len;
86 if (namelen < 0) {
87 break;
88 } else {
Steve French7f573562005-08-30 11:32:14 -070089 full_path[namelen] = dirsep;
Linus Torvalds1da177e2005-04-16 15:20:36 -070090 strncpy(full_path + namelen + 1, temp->d_name.name,
91 temp->d_name.len);
Steve French2fe87f02006-09-21 07:02:52 +000092 cFYI(0, ("name: %s", full_path + namelen));
Linus Torvalds1da177e2005-04-16 15:20:36 -070093 }
94 temp = temp->d_parent;
Steve French5fdae1f2007-06-05 18:30:44 +000095 if (temp == NULL) {
96 cERROR(1, ("corrupt dentry"));
Linus Torvalds1da177e2005-04-16 15:20:36 -070097 kfree(full_path);
98 return NULL;
99 }
100 }
Steve French646dd532008-05-15 01:50:56 +0000101 if (namelen != pplen + dfsplen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102 cERROR(1,
Steve French2fe87f02006-09-21 07:02:52 +0000103 ("did not end path lookup where expected namelen is %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 namelen));
Steve French5fdae1f2007-06-05 18:30:44 +0000105 /* presumably this is only possible if racing with a rename
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 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);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 goto cifs_bp_rename_retry;
110 }
Steve French2fe87f02006-09-21 07:02:52 +0000111 /* 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 */
Steve French646dd532008-05-15 01:50:56 +0000117
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] = '/';
125 }
126 }
127 }
128 strncpy(full_path + dfsplen, CIFS_SB(direntry->d_sb)->prepath, pplen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 return full_path;
130}
131
Steve Frencha6ce4932009-04-09 01:14:32 +0000132static void
133cifs_fill_fileinfo(struct inode *newinode, __u16 fileHandle,
134 struct cifsTconInfo *tcon, bool write_only)
135{
136 int oplock = 0;
137 struct cifsFileInfo *pCifsFile;
138 struct cifsInodeInfo *pCifsInode;
139
140 pCifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
141
142 if (pCifsFile == NULL)
143 return;
144
145 if (oplockEnabled)
146 oplock = REQ_OPLOCK;
147
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);
157
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,
170 &pCifsInode->openFileList);
171 }
172 if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
173 pCifsInode->clientCanCacheAll = true;
174 pCifsInode->clientCanCacheRead = true;
175 cFYI(1, ("Exclusive Oplock inode %p",
176 newinode));
177 } else if ((oplock & 0xF) == OPLOCK_READ)
178 pCifsInode->clientCanCacheRead = true;
179 }
180 write_unlock(&GlobalSMBSeslock);
181}
182
Steve French7fc8f4e2009-02-23 20:43:11 +0000183int cifs_posix_open(char *full_path, struct inode **pinode,
Steve Frenchc3b2a0c2009-02-20 04:32:45 +0000184 struct super_block *sb, int mode, int oflags,
185 int *poplock, __u16 *pnetfid, int xid)
186{
187 int rc;
188 __u32 oplock;
Steve Frencha6ce4932009-04-09 01:14:32 +0000189 bool write_only = false;
Steve Frenchc3b2a0c2009-02-20 04:32:45 +0000190 FILE_UNIX_BASIC_INFO *presp_data;
191 __u32 posix_flags = 0;
192 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
193
194 cFYI(1, ("posix open %s", full_path));
195
196 presp_data = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
197 if (presp_data == NULL)
198 return -ENOMEM;
199
200/* So far cifs posix extensions can only map the following flags.
201 There are other valid fmode oflags such as FMODE_LSEEK, FMODE_PREAD, but
202 so far we do not seem to need them, and we can treat them as local only */
203 if ((oflags & (FMODE_READ | FMODE_WRITE)) ==
204 (FMODE_READ | FMODE_WRITE))
205 posix_flags = SMB_O_RDWR;
206 else if (oflags & FMODE_READ)
207 posix_flags = SMB_O_RDONLY;
208 else if (oflags & FMODE_WRITE)
209 posix_flags = SMB_O_WRONLY;
210 if (oflags & O_CREAT)
211 posix_flags |= SMB_O_CREAT;
212 if (oflags & O_EXCL)
213 posix_flags |= SMB_O_EXCL;
214 if (oflags & O_TRUNC)
215 posix_flags |= SMB_O_TRUNC;
216 if (oflags & O_APPEND)
217 posix_flags |= SMB_O_APPEND;
218 if (oflags & O_SYNC)
219 posix_flags |= SMB_O_SYNC;
220 if (oflags & O_DIRECTORY)
221 posix_flags |= SMB_O_DIRECTORY;
222 if (oflags & O_NOFOLLOW)
223 posix_flags |= SMB_O_NOFOLLOW;
224 if (oflags & O_DIRECT)
225 posix_flags |= SMB_O_DIRECT;
226
Steve Frencha6ce4932009-04-09 01:14:32 +0000227 if (!(oflags & FMODE_READ))
228 write_only = true;
Steve Frenchc3b2a0c2009-02-20 04:32:45 +0000229
230 rc = CIFSPOSIXCreate(xid, cifs_sb->tcon, posix_flags, mode,
231 pnetfid, presp_data, &oplock, full_path,
232 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
233 CIFS_MOUNT_MAP_SPECIAL_CHR);
234 if (rc)
235 goto posix_open_ret;
236
237 if (presp_data->Type == cpu_to_le32(-1))
238 goto posix_open_ret; /* open ok, caller does qpathinfo */
239
240 /* get new inode and set it up */
241 if (!pinode)
242 goto posix_open_ret; /* caller does not need info */
243
Steve French85a6dac2009-04-01 05:22:00 +0000244 if (*pinode == NULL) {
245 __u64 unique_id = le64_to_cpu(presp_data->UniqueId);
246 *pinode = cifs_new_inode(sb, &unique_id);
247 }
Steve French7fc8f4e2009-02-23 20:43:11 +0000248 /* else an inode was passed in. Update its info, don't create one */
Steve Frenchc3b2a0c2009-02-20 04:32:45 +0000249
250 /* We do not need to close the file if new_inode fails since
251 the caller will retry qpathinfo as long as inode is null */
252 if (*pinode == NULL)
253 goto posix_open_ret;
254
255 posix_fill_in_inode(*pinode, presp_data, 1);
256
Steve Frencha6ce4932009-04-09 01:14:32 +0000257 cifs_fill_fileinfo(*pinode, *pnetfid, cifs_sb->tcon, write_only);
258
Steve Frenchc3b2a0c2009-02-20 04:32:45 +0000259posix_open_ret:
260 kfree(presp_data);
261 return rc;
262}
263
Steve Frenchf818dd52009-01-19 02:38:35 +0000264static void setup_cifs_dentry(struct cifsTconInfo *tcon,
265 struct dentry *direntry,
266 struct inode *newinode)
267{
268 if (tcon->nocase)
269 direntry->d_op = &cifs_ci_dentry_ops;
270 else
271 direntry->d_op = &cifs_dentry_ops;
272 d_instantiate(direntry, newinode);
273}
274
Steve French39798772006-05-31 22:40:51 +0000275/* Inode operations in similar order to how they appear in Linux file fs.h */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276
277int
278cifs_create(struct inode *inode, struct dentry *direntry, int mode,
279 struct nameidata *nd)
280{
281 int rc = -ENOENT;
282 int xid;
Jeff Layton67750fb2008-05-09 22:28:02 +0000283 int create_options = CREATE_NOT_DIR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 int oplock = 0;
Steve Frenchc3b2a0c2009-02-20 04:32:45 +0000285 int oflags;
286 /*
287 * BB below access is probably too much for mknod to request
288 * but we have to do query and setpathinfo so requesting
289 * less could fail (unless we want to request getatr and setatr
290 * permissions (only). At least for POSIX we do not have to
291 * request so much.
292 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 int desiredAccess = GENERIC_READ | GENERIC_WRITE;
294 __u16 fileHandle;
295 struct cifs_sb_info *cifs_sb;
Steve Frenchf818dd52009-01-19 02:38:35 +0000296 struct cifsTconInfo *tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 char *full_path = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000298 FILE_ALL_INFO *buf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 struct inode *newinode = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 int disposition = FILE_OVERWRITE_IF;
Steve French4b18f2a2008-04-29 00:06:05 +0000301 bool write_only = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302
303 xid = GetXid();
304
305 cifs_sb = CIFS_SB(inode->i_sb);
Steve Frenchf818dd52009-01-19 02:38:35 +0000306 tcon = cifs_sb->tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 full_path = build_path_from_dentry(direntry);
Steve French5fdae1f2007-06-05 18:30:44 +0000309 if (full_path == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 FreeXid(xid);
311 return -ENOMEM;
312 }
313
Al Viroce3b0f82009-03-29 19:08:22 -0400314 mode &= ~current_umask();
Steve Frenchc3b2a0c2009-02-20 04:32:45 +0000315 if (oplockEnabled)
316 oplock = REQ_OPLOCK;
317
318 if (nd && (nd->flags & LOOKUP_OPEN))
319 oflags = nd->intent.open.flags;
320 else
321 oflags = FMODE_READ;
322
323 if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
324 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
325 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
326 rc = cifs_posix_open(full_path, &newinode, inode->i_sb,
327 mode, oflags, &oplock, &fileHandle, xid);
328 /* EIO could indicate that (posix open) operation is not
329 supported, despite what server claimed in capability
330 negotation. EREMOTE indicates DFS junction, which is not
331 handled in posix open */
332
333 if ((rc == 0) && (newinode == NULL))
334 goto cifs_create_get_file_info; /* query inode info */
335 else if (rc == 0) /* success, no need to query */
336 goto cifs_create_set_dentry;
337 else if ((rc != -EIO) && (rc != -EREMOTE) &&
338 (rc != -EOPNOTSUPP)) /* path not found or net err */
339 goto cifs_create_out;
340 /* else fallthrough to retry, using older open call, this is
341 case where server does not support this SMB level, and
342 falsely claims capability (also get here for DFS case
343 which should be rare for path not covered on files) */
344 }
Steve Frenchf818dd52009-01-19 02:38:35 +0000345
Steve French5fdae1f2007-06-05 18:30:44 +0000346 if (nd && (nd->flags & LOOKUP_OPEN)) {
Steve Frenchc3b2a0c2009-02-20 04:32:45 +0000347 /* if the file is going to stay open, then we
348 need to set the desired access properly */
Miklos Szeredie08fc042005-09-06 15:18:26 -0700349 desiredAccess = 0;
350 if (oflags & FMODE_READ)
Steve Frenchc3b2a0c2009-02-20 04:32:45 +0000351 desiredAccess |= GENERIC_READ; /* is this too little? */
Miklos Szeredie08fc042005-09-06 15:18:26 -0700352 if (oflags & FMODE_WRITE) {
353 desiredAccess |= GENERIC_WRITE;
354 if (!(oflags & FMODE_READ))
Steve French4b18f2a2008-04-29 00:06:05 +0000355 write_only = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 }
357
Steve French5fdae1f2007-06-05 18:30:44 +0000358 if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 disposition = FILE_CREATE;
Steve French5fdae1f2007-06-05 18:30:44 +0000360 else if ((oflags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 disposition = FILE_OVERWRITE_IF;
Steve French5fdae1f2007-06-05 18:30:44 +0000362 else if ((oflags & O_CREAT) == O_CREAT)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 disposition = FILE_OPEN_IF;
Steve Frenchad7a2922008-02-07 23:25:02 +0000364 else
Steve French5fdae1f2007-06-05 18:30:44 +0000365 cFYI(1, ("Create flag not set in create function"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 }
367
Steve French5fdae1f2007-06-05 18:30:44 +0000368 /* BB add processing to set equivalent of mode - e.g. via CreateX with
369 ACLs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370
Steve French5fdae1f2007-06-05 18:30:44 +0000371 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
372 if (buf == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 kfree(full_path);
374 FreeXid(xid);
375 return -ENOMEM;
376 }
Jeff Layton67750fb2008-05-09 22:28:02 +0000377
Jeff Layton67750fb2008-05-09 22:28:02 +0000378 /*
379 * if we're not using unix extensions, see if we need to set
380 * ATTR_READONLY on the create call
381 */
Steve Frenchf818dd52009-01-19 02:38:35 +0000382 if (!tcon->unix_ext && (mode & S_IWUGO) == 0)
Jeff Layton67750fb2008-05-09 22:28:02 +0000383 create_options |= CREATE_OPTION_READONLY;
384
Steve French5fdae1f2007-06-05 18:30:44 +0000385 if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS)
Steve Frenchf818dd52009-01-19 02:38:35 +0000386 rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
Jeff Layton67750fb2008-05-09 22:28:02 +0000387 desiredAccess, create_options,
Steve French737b7582005-04-28 22:41:06 -0700388 &fileHandle, &oplock, buf, cifs_sb->local_nls,
389 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French5bafd762006-06-07 00:18:43 +0000390 else
391 rc = -EIO; /* no NT SMB support fall into legacy open below */
392
Steve French5fdae1f2007-06-05 18:30:44 +0000393 if (rc == -EIO) {
Steve Frencha9d02ad2005-08-24 23:06:05 -0700394 /* old server, retry the open legacy style */
Steve Frenchf818dd52009-01-19 02:38:35 +0000395 rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
Jeff Layton67750fb2008-05-09 22:28:02 +0000396 desiredAccess, create_options,
Steve Frencha9d02ad2005-08-24 23:06:05 -0700397 &fileHandle, &oplock, buf, cifs_sb->local_nls,
398 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French5fdae1f2007-06-05 18:30:44 +0000399 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 if (rc) {
Steve French26a21b92006-05-31 18:05:34 +0000401 cFYI(1, ("cifs_create returned 0x%x", rc));
Steve Frenchc3b2a0c2009-02-20 04:32:45 +0000402 goto cifs_create_out;
403 }
404
405 /* If Open reported that we actually created a file
406 then we now have to set the mode if possible */
407 if ((tcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) {
408 struct cifs_unix_set_info_args args = {
Jeff Layton4e1e7fb2008-08-02 07:26:12 -0400409 .mode = mode,
410 .ctime = NO_CHANGE_64,
411 .atime = NO_CHANGE_64,
412 .mtime = NO_CHANGE_64,
413 .device = 0,
Steve Frenchc3b2a0c2009-02-20 04:32:45 +0000414 };
Jeff Layton4e1e7fb2008-08-02 07:26:12 -0400415
Steve Frenchc3b2a0c2009-02-20 04:32:45 +0000416 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
417 args.uid = (__u64) current_fsuid();
418 if (inode->i_mode & S_ISGID)
419 args.gid = (__u64) inode->i_gid;
420 else
421 args.gid = (__u64) current_fsgid();
Steve French3ce53fc2007-06-08 14:55:14 +0000422 } else {
Steve Frenchc3b2a0c2009-02-20 04:32:45 +0000423 args.uid = NO_CHANGE_64;
424 args.gid = NO_CHANGE_64;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 }
Steve Frenchc3b2a0c2009-02-20 04:32:45 +0000426 CIFSSMBUnixSetInfo(xid, tcon, full_path, &args,
427 cifs_sb->local_nls,
428 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
429 } else {
430 /* BB implement mode setting via Windows security
431 descriptors e.g. */
432 /* CIFSSMBWinSetPerms(xid,tcon,path,mode,-1,-1,nls);*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433
Steve Frenchc3b2a0c2009-02-20 04:32:45 +0000434 /* Could set r/o dos attribute if mode & 0222 == 0 */
435 }
436
437cifs_create_get_file_info:
438 /* server might mask mode so we have to query for it */
439 if (tcon->unix_ext)
440 rc = cifs_get_inode_info_unix(&newinode, full_path,
441 inode->i_sb, xid);
442 else {
443 rc = cifs_get_inode_info(&newinode, full_path, buf,
444 inode->i_sb, xid, &fileHandle);
445 if (newinode) {
446 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
447 newinode->i_mode = mode;
448 if ((oplock & CIFS_CREATE_ACTION) &&
449 (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) {
450 newinode->i_uid = current_fsuid();
451 if (inode->i_mode & S_ISGID)
452 newinode->i_gid = inode->i_gid;
453 else
454 newinode->i_gid = current_fsgid();
Steve French6473a552005-11-29 20:20:10 -0800455 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 }
Steve Frenchc3b2a0c2009-02-20 04:32:45 +0000457 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458
Steve Frenchc3b2a0c2009-02-20 04:32:45 +0000459cifs_create_set_dentry:
460 if (rc == 0)
461 setup_cifs_dentry(tcon, direntry, newinode);
462 else
463 cFYI(1, ("Create worked, get_inode_info failed rc = %d", rc));
Steve Frenchf818dd52009-01-19 02:38:35 +0000464
Steve Frenchc3b2a0c2009-02-20 04:32:45 +0000465 /* nfsd case - nfs srv does not set nd */
466 if ((nd == NULL) || (!(nd->flags & LOOKUP_OPEN))) {
467 /* mknod case - do not leave file open */
468 CIFSSMBClose(xid, tcon, fileHandle);
469 } else if (newinode) {
Steve Frencha6ce4932009-04-09 01:14:32 +0000470 cifs_fill_fileinfo(newinode, fileHandle,
471 cifs_sb->tcon, write_only);
Steve French5fdae1f2007-06-05 18:30:44 +0000472 }
Steve Frenchd14537f12005-04-28 22:41:05 -0700473cifs_create_out:
474 kfree(buf);
475 kfree(full_path);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 FreeXid(xid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 return rc;
478}
479
Steve French5fdae1f2007-06-05 18:30:44 +0000480int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
481 dev_t device_number)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482{
483 int rc = -EPERM;
484 int xid;
485 struct cifs_sb_info *cifs_sb;
486 struct cifsTconInfo *pTcon;
487 char *full_path = NULL;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000488 struct inode *newinode = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489
490 if (!old_valid_dev(device_number))
491 return -EINVAL;
492
493 xid = GetXid();
494
495 cifs_sb = CIFS_SB(inode->i_sb);
496 pTcon = cifs_sb->tcon;
497
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 full_path = build_path_from_dentry(direntry);
Steve French5fdae1f2007-06-05 18:30:44 +0000499 if (full_path == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 rc = -ENOMEM;
Steve Frenchc18c8422007-07-18 23:21:09 +0000501 else if (pTcon->unix_ext) {
Jeff Layton4e1e7fb2008-08-02 07:26:12 -0400502 struct cifs_unix_set_info_args args = {
Al Viroce3b0f82009-03-29 19:08:22 -0400503 .mode = mode & ~current_umask(),
Jeff Layton4e1e7fb2008-08-02 07:26:12 -0400504 .ctime = NO_CHANGE_64,
505 .atime = NO_CHANGE_64,
506 .mtime = NO_CHANGE_64,
507 .device = device_number,
508 };
Steve French5fdae1f2007-06-05 18:30:44 +0000509 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
David Howellsa001e5b2008-11-14 10:38:47 +1100510 args.uid = (__u64) current_fsuid();
511 args.gid = (__u64) current_fsgid();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 } else {
Jeff Layton4e1e7fb2008-08-02 07:26:12 -0400513 args.uid = NO_CHANGE_64;
514 args.gid = NO_CHANGE_64;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 }
Jeff Layton4e1e7fb2008-08-02 07:26:12 -0400516 rc = CIFSSMBUnixSetInfo(xid, pTcon, full_path,
517 &args, cifs_sb->local_nls,
518 cifs_sb->mnt_cifs_flags &
519 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520
Steve French5fdae1f2007-06-05 18:30:44 +0000521 if (!rc) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 rc = cifs_get_inode_info_unix(&newinode, full_path,
Steve French5fdae1f2007-06-05 18:30:44 +0000523 inode->i_sb, xid);
Steve Frenchb92327f2005-08-22 20:09:43 -0700524 if (pTcon->nocase)
525 direntry->d_op = &cifs_ci_dentry_ops;
526 else
527 direntry->d_op = &cifs_dentry_ops;
Steve French5fdae1f2007-06-05 18:30:44 +0000528 if (rc == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 d_instantiate(direntry, newinode);
530 }
Steve Frenchd7245c22005-07-14 18:25:12 -0500531 } else {
Steve French5fdae1f2007-06-05 18:30:44 +0000532 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
Steve Frencheda3c0292005-07-21 15:20:28 -0700533 int oplock = 0;
534 u16 fileHandle;
Steve Frenchad7a2922008-02-07 23:25:02 +0000535 FILE_ALL_INFO *buf;
Steve Frenchd7245c22005-07-14 18:25:12 -0500536
Steve French5fdae1f2007-06-05 18:30:44 +0000537 cFYI(1, ("sfu compat create special file"));
Steve Frenchd7245c22005-07-14 18:25:12 -0500538
Steve French5fdae1f2007-06-05 18:30:44 +0000539 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
540 if (buf == NULL) {
Steve Frencheda3c0292005-07-21 15:20:28 -0700541 kfree(full_path);
542 FreeXid(xid);
543 return -ENOMEM;
544 }
545
546 rc = CIFSSMBOpen(xid, pTcon, full_path,
547 FILE_CREATE, /* fail if exists */
Steve French5fdae1f2007-06-05 18:30:44 +0000548 GENERIC_WRITE /* BB would
Steve Frencheda3c0292005-07-21 15:20:28 -0700549 WRITE_OWNER | WRITE_DAC be better? */,
550 /* Create a file and set the
551 file attribute to SYSTEM */
552 CREATE_NOT_DIR | CREATE_OPTION_SPECIAL,
553 &fileHandle, &oplock, buf,
554 cifs_sb->local_nls,
Steve French5fdae1f2007-06-05 18:30:44 +0000555 cifs_sb->mnt_cifs_flags &
Steve Frencheda3c0292005-07-21 15:20:28 -0700556 CIFS_MOUNT_MAP_SPECIAL_CHR);
557
Steve French5bafd762006-06-07 00:18:43 +0000558 /* BB FIXME - add handling for backlevel servers
559 which need legacy open and check for all
Steve French5fdae1f2007-06-05 18:30:44 +0000560 calls to SMBOpen for fallback to SMBLeagcyOpen */
561 if (!rc) {
Steve Frencheda3c0292005-07-21 15:20:28 -0700562 /* BB Do not bother to decode buf since no
Steve French86c96b42005-11-18 20:25:31 -0800563 local inode yet to put timestamps in,
564 but we can reuse it safely */
Steve French77159b42007-08-31 01:10:17 +0000565 unsigned int bytes_written;
Steve French86c96b42005-11-18 20:25:31 -0800566 struct win_dev *pdev;
567 pdev = (struct win_dev *)buf;
Steve French5fdae1f2007-06-05 18:30:44 +0000568 if (S_ISCHR(mode)) {
Steve French86c96b42005-11-18 20:25:31 -0800569 memcpy(pdev->type, "IntxCHR", 8);
570 pdev->major =
571 cpu_to_le64(MAJOR(device_number));
Steve French5fdae1f2007-06-05 18:30:44 +0000572 pdev->minor =
Steve French86c96b42005-11-18 20:25:31 -0800573 cpu_to_le64(MINOR(device_number));
574 rc = CIFSSMBWrite(xid, pTcon,
575 fileHandle,
576 sizeof(struct win_dev),
577 0, &bytes_written, (char *)pdev,
578 NULL, 0);
Steve French5fdae1f2007-06-05 18:30:44 +0000579 } else if (S_ISBLK(mode)) {
Steve French86c96b42005-11-18 20:25:31 -0800580 memcpy(pdev->type, "IntxBLK", 8);
581 pdev->major =
582 cpu_to_le64(MAJOR(device_number));
583 pdev->minor =
584 cpu_to_le64(MINOR(device_number));
585 rc = CIFSSMBWrite(xid, pTcon,
586 fileHandle,
587 sizeof(struct win_dev),
588 0, &bytes_written, (char *)pdev,
589 NULL, 0);
590 } /* else if(S_ISFIFO */
Steve Frencheda3c0292005-07-21 15:20:28 -0700591 CIFSSMBClose(xid, pTcon, fileHandle);
592 d_drop(direntry);
593 }
594 kfree(buf);
Steve Frenchd7245c22005-07-14 18:25:12 -0500595 /* add code here to set EAs */
596 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 }
598
Steve Frenchd14537f12005-04-28 22:41:05 -0700599 kfree(full_path);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 FreeXid(xid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 return rc;
602}
603
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604struct dentry *
Steve French5fdae1f2007-06-05 18:30:44 +0000605cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
606 struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607{
608 int xid;
609 int rc = 0; /* to get around spurious gcc warning, set to zero here */
Steve Frencha6ce4932009-04-09 01:14:32 +0000610 int oplock = 0;
611 int mode;
612 __u16 fileHandle = 0;
613 bool posix_open = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 struct cifs_sb_info *cifs_sb;
615 struct cifsTconInfo *pTcon;
616 struct inode *newInode = NULL;
617 char *full_path = NULL;
Steve Frencha6ce4932009-04-09 01:14:32 +0000618 struct file *filp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619
620 xid = GetXid();
621
Steve French61e74802008-12-03 00:57:54 +0000622 cFYI(1, ("parent inode = 0x%p name is: %s and dentry = 0x%p",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 parent_dir_inode, direntry->d_name.name, direntry));
624
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 /* check whether path exists */
626
627 cifs_sb = CIFS_SB(parent_dir_inode->i_sb);
628 pTcon = cifs_sb->tcon;
629
Steve French296034f2006-04-21 18:18:37 +0000630 /*
631 * Don't allow the separator character in a path component.
632 * The VFS will not allow "/", but "\" is allowed by posix.
633 */
634 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)) {
635 int i;
636 for (i = 0; i < direntry->d_name.len; i++)
637 if (direntry->d_name.name[i] == '\\') {
638 cFYI(1, ("Invalid file name"));
639 FreeXid(xid);
640 return ERR_PTR(-EINVAL);
641 }
642 }
643
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 /* can not grab the rename sem here since it would
645 deadlock in the cases (beginning of sys_rename itself)
646 in which we already have the sb rename sem */
647 full_path = build_path_from_dentry(direntry);
Steve French5fdae1f2007-06-05 18:30:44 +0000648 if (full_path == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 FreeXid(xid);
650 return ERR_PTR(-ENOMEM);
651 }
652
653 if (direntry->d_inode != NULL) {
Steve French61e74802008-12-03 00:57:54 +0000654 cFYI(1, ("non-NULL inode in lookup"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 } else {
Steve French61e74802008-12-03 00:57:54 +0000656 cFYI(1, ("NULL inode in lookup"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 }
Steve French61e74802008-12-03 00:57:54 +0000658 cFYI(1, ("Full path: %s inode = 0x%p", full_path, direntry->d_inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659
Steve Frencha6ce4932009-04-09 01:14:32 +0000660 if (pTcon->unix_ext) {
661 if (!(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY)) &&
662 (nd->flags & LOOKUP_OPEN)) {
663 if (!((nd->intent.open.flags & O_CREAT) &&
664 (nd->intent.open.flags & O_EXCL))) {
665 mode = nd->intent.open.create_mode &
666 ~current->fs->umask;
667 rc = cifs_posix_open(full_path, &newInode,
668 parent_dir_inode->i_sb, mode,
669 nd->intent.open.flags, &oplock,
670 &fileHandle, xid);
671 if ((rc != -EINVAL) && (rc != -EOPNOTSUPP))
672 posix_open = true;
673 }
674 }
675 if (!posix_open)
676 rc = cifs_get_inode_info_unix(&newInode, full_path,
677 parent_dir_inode->i_sb, xid);
678 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 rc = cifs_get_inode_info(&newInode, full_path, NULL,
Steve Frencha6ce4932009-04-09 01:14:32 +0000680 parent_dir_inode->i_sb, xid, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681
682 if ((rc == 0) && (newInode != NULL)) {
Steve Frenchb92327f2005-08-22 20:09:43 -0700683 if (pTcon->nocase)
684 direntry->d_op = &cifs_ci_dentry_ops;
685 else
686 direntry->d_op = &cifs_dentry_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 d_add(direntry, newInode);
Steve Frencha6ce4932009-04-09 01:14:32 +0000688 if (posix_open)
689 filp = lookup_instantiate_filp(nd, direntry, NULL);
Steve French5fdae1f2007-06-05 18:30:44 +0000690 /* since paths are not looked up by component - the parent
Steve French3abb9272005-11-28 08:16:13 -0800691 directories are presumed to be good here */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 renew_parental_timestamps(direntry);
693
694 } else if (rc == -ENOENT) {
695 rc = 0;
Steve French3abb9272005-11-28 08:16:13 -0800696 direntry->d_time = jiffies;
697 if (pTcon->nocase)
698 direntry->d_op = &cifs_ci_dentry_ops;
699 else
700 direntry->d_op = &cifs_dentry_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 d_add(direntry, NULL);
Steve French5fdae1f2007-06-05 18:30:44 +0000702 /* if it was once a directory (but how can we tell?) we could do
703 shrink_dcache_parent(direntry); */
Steve Frenched2b9172008-01-20 00:30:29 +0000704 } else if (rc != -EACCES) {
705 cERROR(1, ("Unexpected lookup error %d", rc));
706 /* We special case check for Access Denied - since that
707 is a common return code */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 }
709
Steve Frenchd14537f12005-04-28 22:41:05 -0700710 kfree(full_path);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 FreeXid(xid);
712 return ERR_PTR(rc);
713}
714
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715static int
716cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd)
717{
718 int isValid = 1;
719
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 if (direntry->d_inode) {
Steve Frenchad7a2922008-02-07 23:25:02 +0000721 if (cifs_revalidate(direntry))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 } else {
Steve French3abb9272005-11-28 08:16:13 -0800724 cFYI(1, ("neg dentry 0x%p name = %s",
725 direntry, direntry->d_name.name));
Steve French5fdae1f2007-06-05 18:30:44 +0000726 if (time_after(jiffies, direntry->d_time + HZ) ||
Steve French3abb9272005-11-28 08:16:13 -0800727 !lookupCacheEnabled) {
728 d_drop(direntry);
729 isValid = 0;
Steve French5fdae1f2007-06-05 18:30:44 +0000730 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 }
732
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 return isValid;
734}
735
736/* static int cifs_d_delete(struct dentry *direntry)
737{
738 int rc = 0;
739
740 cFYI(1, ("In cifs d_delete, name = %s", direntry->d_name.name));
741
742 return rc;
743} */
744
Al Viro4fd03e82009-02-20 05:57:07 +0000745const struct dentry_operations cifs_dentry_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 .d_revalidate = cifs_d_revalidate,
Steve French5fdae1f2007-06-05 18:30:44 +0000747/* d_delete: cifs_d_delete, */ /* not needed except for debugging */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748};
Steve Frenchb92327f2005-08-22 20:09:43 -0700749
750static int cifs_ci_hash(struct dentry *dentry, struct qstr *q)
751{
752 struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls;
753 unsigned long hash;
754 int i;
755
756 hash = init_name_hash();
757 for (i = 0; i < q->len; i++)
758 hash = partial_name_hash(nls_tolower(codepage, q->name[i]),
759 hash);
760 q->hash = end_name_hash(hash);
761
762 return 0;
763}
764
765static int cifs_ci_compare(struct dentry *dentry, struct qstr *a,
766 struct qstr *b)
767{
768 struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls;
769
770 if ((a->len == b->len) &&
771 (nls_strnicmp(codepage, a->name, b->name, a->len) == 0)) {
772 /*
773 * To preserve case, don't let an existing negative dentry's
774 * case take precedence. If a is not a negative dentry, this
775 * should have no side effects
776 */
Steve Frenchc3291632008-05-15 05:41:54 +0000777 memcpy((void *)a->name, b->name, a->len);
Steve Frenchb92327f2005-08-22 20:09:43 -0700778 return 0;
779 }
780 return 1;
781}
782
Al Viro4fd03e82009-02-20 05:57:07 +0000783const struct dentry_operations cifs_ci_dentry_ops = {
Steve Frenchb92327f2005-08-22 20:09:43 -0700784 .d_revalidate = cifs_d_revalidate,
785 .d_hash = cifs_ci_hash,
786 .d_compare = cifs_ci_compare,
787};