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