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