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