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