[CIFS] Allow raw ntlmssp code to be enabled with sec=ntlmssp
[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>
27#include "cifsfs.h"
28#include "cifspdu.h"
29#include "cifsglob.h"
30#include "cifsproto.h"
31#include "cifs_debug.h"
32#include "cifs_fs_sb.h"
33
99ee4dbd 34static void
1da177e4
LT
35renew_parental_timestamps(struct dentry *direntry)
36{
5fdae1f6
SF
37 /* BB check if there is a way to get the kernel to do this or if we
38 really need this */
1da177e4
LT
39 do {
40 direntry->d_time = jiffies;
41 direntry = direntry->d_parent;
5fdae1f6 42 } while (!IS_ROOT(direntry));
1da177e4
LT
43}
44
45/* Note: caller must free return buffer */
46char *
47build_path_from_dentry(struct dentry *direntry)
48{
49 struct dentry *temp;
2fe87f02
SF
50 int namelen;
51 int pplen;
646dd539 52 int dfsplen;
1da177e4 53 char *full_path;
88274815 54 char dirsep;
646dd539 55 struct cifs_sb_info *cifs_sb;
1da177e4 56
5fdae1f6 57 if (direntry == NULL)
1da177e4
LT
58 return NULL; /* not much we can do if dentry is freed and
59 we need to reopen the file after it was closed implicitly
60 when the server crashed */
61
646dd539
SF
62 cifs_sb = CIFS_SB(direntry->d_sb);
63 dirsep = CIFS_DIR_SEP(cifs_sb);
64 pplen = cifs_sb->prepathlen;
65 if (cifs_sb->tcon && (cifs_sb->tcon->Flags & SMB_SHARE_IS_IN_DFS))
66 dfsplen = strnlen(cifs_sb->tcon->treeName, MAX_TREE_SIZE + 1);
67 else
68 dfsplen = 0;
1da177e4 69cifs_bp_rename_retry:
646dd539 70 namelen = pplen + dfsplen;
1da177e4
LT
71 for (temp = direntry; !IS_ROOT(temp);) {
72 namelen += (1 + temp->d_name.len);
73 temp = temp->d_parent;
5fdae1f6
SF
74 if (temp == NULL) {
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);
2fe87f02 92 cFYI(0, ("name: %s", full_path + namelen));
1da177e4
LT
93 }
94 temp = temp->d_parent;
5fdae1f6
SF
95 if (temp == NULL) {
96 cERROR(1, ("corrupt dentry"));
1da177e4
LT
97 kfree(full_path);
98 return NULL;
99 }
100 }
646dd539 101 if (namelen != pplen + dfsplen) {
1da177e4 102 cERROR(1,
2fe87f02 103 ("did not end path lookup where expected namelen is %d",
1da177e4 104 namelen));
5fdae1f6 105 /* presumably this is only possible if racing with a rename
1da177e4
LT
106 of one of the parent directories (we can not lock the dentries
107 above us to prevent this, but retrying should be harmless) */
108 kfree(full_path);
1da177e4
LT
109 goto cifs_bp_rename_retry;
110 }
2fe87f02
SF
111 /* DIR_SEP already set for byte 0 / vs \ but not for
112 subsequent slashes in prepath which currently must
113 be entered the right way - not sure if there is an alternative
114 since the '\' is a valid posix character so we can not switch
115 those safely to '/' if any are found in the middle of the prepath */
116 /* BB test paths to Windows with '/' in the midst of prepath */
646dd539
SF
117
118 if (dfsplen) {
119 strncpy(full_path, cifs_sb->tcon->treeName, dfsplen);
120 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
121 int i;
122 for (i = 0; i < dfsplen; i++) {
123 if (full_path[i] == '\\')
124 full_path[i] = '/';
125 }
126 }
127 }
128 strncpy(full_path + dfsplen, CIFS_SB(direntry->d_sb)->prepath, pplen);
1da177e4
LT
129 return full_path;
130}
131
a6ce4932
SF
132static void
133cifs_fill_fileinfo(struct inode *newinode, __u16 fileHandle,
134 struct cifsTconInfo *tcon, bool write_only)
135{
136 int oplock = 0;
137 struct cifsFileInfo *pCifsFile;
138 struct cifsInodeInfo *pCifsInode;
139
140 pCifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
141
142 if (pCifsFile == NULL)
143 return;
144
145 if (oplockEnabled)
146 oplock = REQ_OPLOCK;
147
148 pCifsFile->netfid = fileHandle;
149 pCifsFile->pid = current->tgid;
150 pCifsFile->pInode = newinode;
151 pCifsFile->invalidHandle = false;
bc8cd439 152 pCifsFile->closePend = false;
a6ce4932
SF
153 mutex_init(&pCifsFile->fh_mutex);
154 mutex_init(&pCifsFile->lock_mutex);
155 INIT_LIST_HEAD(&pCifsFile->llist);
156 atomic_set(&pCifsFile->wrtPending, 0);
157
158 /* set the following in open now
159 pCifsFile->pfile = file; */
160 write_lock(&GlobalSMBSeslock);
161 list_add(&pCifsFile->tlist, &tcon->openFileList);
162 pCifsInode = CIFS_I(newinode);
163 if (pCifsInode) {
164 /* if readable file instance put first in list*/
bc8cd439 165 if (write_only)
a6ce4932
SF
166 list_add_tail(&pCifsFile->flist,
167 &pCifsInode->openFileList);
bc8cd439
SF
168 else
169 list_add(&pCifsFile->flist, &pCifsInode->openFileList);
170
a6ce4932
SF
171 if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
172 pCifsInode->clientCanCacheAll = true;
173 pCifsInode->clientCanCacheRead = true;
bc8cd439 174 cFYI(1, ("Exclusive Oplock inode %p", newinode));
a6ce4932 175 } else if ((oplock & 0xF) == OPLOCK_READ)
bc8cd439 176 pCifsInode->clientCanCacheRead = true;
a6ce4932
SF
177 }
178 write_unlock(&GlobalSMBSeslock);
179}
180
7fc8f4e9 181int cifs_posix_open(char *full_path, struct inode **pinode,
c3b2a0c6
SF
182 struct super_block *sb, int mode, int oflags,
183 int *poplock, __u16 *pnetfid, int xid)
184{
185 int rc;
186 __u32 oplock;
a6ce4932 187 bool write_only = false;
c3b2a0c6
SF
188 FILE_UNIX_BASIC_INFO *presp_data;
189 __u32 posix_flags = 0;
190 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
191
192 cFYI(1, ("posix open %s", full_path));
193
194 presp_data = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
195 if (presp_data == NULL)
196 return -ENOMEM;
197
198/* So far cifs posix extensions can only map the following flags.
199 There are other valid fmode oflags such as FMODE_LSEEK, FMODE_PREAD, but
200 so far we do not seem to need them, and we can treat them as local only */
201 if ((oflags & (FMODE_READ | FMODE_WRITE)) ==
202 (FMODE_READ | FMODE_WRITE))
203 posix_flags = SMB_O_RDWR;
204 else if (oflags & FMODE_READ)
205 posix_flags = SMB_O_RDONLY;
206 else if (oflags & FMODE_WRITE)
207 posix_flags = SMB_O_WRONLY;
208 if (oflags & O_CREAT)
209 posix_flags |= SMB_O_CREAT;
210 if (oflags & O_EXCL)
211 posix_flags |= SMB_O_EXCL;
212 if (oflags & O_TRUNC)
213 posix_flags |= SMB_O_TRUNC;
214 if (oflags & O_APPEND)
215 posix_flags |= SMB_O_APPEND;
216 if (oflags & O_SYNC)
217 posix_flags |= SMB_O_SYNC;
218 if (oflags & O_DIRECTORY)
219 posix_flags |= SMB_O_DIRECTORY;
220 if (oflags & O_NOFOLLOW)
221 posix_flags |= SMB_O_NOFOLLOW;
222 if (oflags & O_DIRECT)
223 posix_flags |= SMB_O_DIRECT;
224
a6ce4932
SF
225 if (!(oflags & FMODE_READ))
226 write_only = true;
c3b2a0c6
SF
227
228 rc = CIFSPOSIXCreate(xid, cifs_sb->tcon, posix_flags, mode,
229 pnetfid, presp_data, &oplock, full_path,
230 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
231 CIFS_MOUNT_MAP_SPECIAL_CHR);
232 if (rc)
233 goto posix_open_ret;
234
235 if (presp_data->Type == cpu_to_le32(-1))
236 goto posix_open_ret; /* open ok, caller does qpathinfo */
237
238 /* get new inode and set it up */
239 if (!pinode)
240 goto posix_open_ret; /* caller does not need info */
241
85a6dac5
SF
242 if (*pinode == NULL) {
243 __u64 unique_id = le64_to_cpu(presp_data->UniqueId);
244 *pinode = cifs_new_inode(sb, &unique_id);
245 }
7fc8f4e9 246 /* else an inode was passed in. Update its info, don't create one */
c3b2a0c6
SF
247
248 /* We do not need to close the file if new_inode fails since
249 the caller will retry qpathinfo as long as inode is null */
250 if (*pinode == NULL)
251 goto posix_open_ret;
252
253 posix_fill_in_inode(*pinode, presp_data, 1);
254
a6ce4932
SF
255 cifs_fill_fileinfo(*pinode, *pnetfid, cifs_sb->tcon, write_only);
256
c3b2a0c6
SF
257posix_open_ret:
258 kfree(presp_data);
259 return rc;
260}
261
f818dd55
SF
262static void setup_cifs_dentry(struct cifsTconInfo *tcon,
263 struct dentry *direntry,
264 struct inode *newinode)
265{
266 if (tcon->nocase)
267 direntry->d_op = &cifs_ci_dentry_ops;
268 else
269 direntry->d_op = &cifs_dentry_ops;
270 d_instantiate(direntry, newinode);
271}
272
3979877e 273/* Inode operations in similar order to how they appear in Linux file fs.h */
1da177e4
LT
274
275int
276cifs_create(struct inode *inode, struct dentry *direntry, int mode,
277 struct nameidata *nd)
278{
279 int rc = -ENOENT;
280 int xid;
67750fb9 281 int create_options = CREATE_NOT_DIR;
1da177e4 282 int oplock = 0;
c3b2a0c6
SF
283 int oflags;
284 /*
285 * BB below access is probably too much for mknod to request
286 * but we have to do query and setpathinfo so requesting
287 * less could fail (unless we want to request getatr and setatr
288 * permissions (only). At least for POSIX we do not have to
289 * request so much.
290 */
1da177e4
LT
291 int desiredAccess = GENERIC_READ | GENERIC_WRITE;
292 __u16 fileHandle;
293 struct cifs_sb_info *cifs_sb;
f818dd55 294 struct cifsTconInfo *tcon;
1da177e4 295 char *full_path = NULL;
fb8c4b14 296 FILE_ALL_INFO *buf = NULL;
1da177e4 297 struct inode *newinode = NULL;
1da177e4 298 int disposition = FILE_OVERWRITE_IF;
4b18f2a9 299 bool write_only = false;
1da177e4
LT
300
301 xid = GetXid();
302
303 cifs_sb = CIFS_SB(inode->i_sb);
f818dd55 304 tcon = cifs_sb->tcon;
1da177e4 305
1da177e4 306 full_path = build_path_from_dentry(direntry);
5fdae1f6 307 if (full_path == NULL) {
1da177e4
LT
308 FreeXid(xid);
309 return -ENOMEM;
310 }
311
ce3b0f8d 312 mode &= ~current_umask();
c3b2a0c6
SF
313 if (oplockEnabled)
314 oplock = REQ_OPLOCK;
f818dd55 315
c3b2a0c6
SF
316 if (nd && (nd->flags & LOOKUP_OPEN))
317 oflags = nd->intent.open.flags;
318 else
319 oflags = FMODE_READ;
320
321 if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
322 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
323 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
324 rc = cifs_posix_open(full_path, &newinode, inode->i_sb,
325 mode, oflags, &oplock, &fileHandle, xid);
326 /* EIO could indicate that (posix open) operation is not
327 supported, despite what server claimed in capability
328 negotation. EREMOTE indicates DFS junction, which is not
329 handled in posix open */
330
331 if ((rc == 0) && (newinode == NULL))
332 goto cifs_create_get_file_info; /* query inode info */
333 else if (rc == 0) /* success, no need to query */
334 goto cifs_create_set_dentry;
335 else if ((rc != -EIO) && (rc != -EREMOTE) &&
336 (rc != -EOPNOTSUPP)) /* path not found or net err */
337 goto cifs_create_out;
338 /* else fallthrough to retry, using older open call, this is
339 case where server does not support this SMB level, and
340 falsely claims capability (also get here for DFS case
341 which should be rare for path not covered on files) */
342 }
e08fc045 343
c3b2a0c6
SF
344 if (nd && (nd->flags & LOOKUP_OPEN)) {
345 /* if the file is going to stay open, then we
346 need to set the desired access properly */
e08fc045
MS
347 desiredAccess = 0;
348 if (oflags & FMODE_READ)
c3b2a0c6 349 desiredAccess |= GENERIC_READ; /* is this too little? */
e08fc045
MS
350 if (oflags & FMODE_WRITE) {
351 desiredAccess |= GENERIC_WRITE;
352 if (!(oflags & FMODE_READ))
4b18f2a9 353 write_only = true;
1da177e4
LT
354 }
355
5fdae1f6 356 if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
1da177e4 357 disposition = FILE_CREATE;
5fdae1f6 358 else if ((oflags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
1da177e4 359 disposition = FILE_OVERWRITE_IF;
5fdae1f6 360 else if ((oflags & O_CREAT) == O_CREAT)
1da177e4 361 disposition = FILE_OPEN_IF;
ad7a2926 362 else
5fdae1f6 363 cFYI(1, ("Create flag not set in create function"));
1da177e4
LT
364 }
365
5fdae1f6
SF
366 /* BB add processing to set equivalent of mode - e.g. via CreateX with
367 ACLs */
1da177e4 368
5fdae1f6
SF
369 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
370 if (buf == NULL) {
1da177e4
LT
371 kfree(full_path);
372 FreeXid(xid);
373 return -ENOMEM;
374 }
67750fb9 375
67750fb9
JL
376 /*
377 * if we're not using unix extensions, see if we need to set
378 * ATTR_READONLY on the create call
379 */
f818dd55 380 if (!tcon->unix_ext && (mode & S_IWUGO) == 0)
67750fb9
JL
381 create_options |= CREATE_OPTION_READONLY;
382
5fdae1f6 383 if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS)
f818dd55 384 rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
67750fb9 385 desiredAccess, create_options,
737b758c
SF
386 &fileHandle, &oplock, buf, cifs_sb->local_nls,
387 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
5bafd765
SF
388 else
389 rc = -EIO; /* no NT SMB support fall into legacy open below */
390
5fdae1f6 391 if (rc == -EIO) {
a9d02ad4 392 /* old server, retry the open legacy style */
f818dd55 393 rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
67750fb9 394 desiredAccess, create_options,
a9d02ad4
SF
395 &fileHandle, &oplock, buf, cifs_sb->local_nls,
396 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
5fdae1f6 397 }
1da177e4 398 if (rc) {
26a21b98 399 cFYI(1, ("cifs_create returned 0x%x", rc));
c3b2a0c6
SF
400 goto cifs_create_out;
401 }
402
403 /* If Open reported that we actually created a file
404 then we now have to set the mode if possible */
405 if ((tcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) {
406 struct cifs_unix_set_info_args args = {
4e1e7fb9
JL
407 .mode = mode,
408 .ctime = NO_CHANGE_64,
409 .atime = NO_CHANGE_64,
410 .mtime = NO_CHANGE_64,
411 .device = 0,
c3b2a0c6
SF
412 };
413
414 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
415 args.uid = (__u64) current_fsuid();
416 if (inode->i_mode & S_ISGID)
417 args.gid = (__u64) inode->i_gid;
418 else
419 args.gid = (__u64) current_fsgid();
3ce53fc4 420 } else {
c3b2a0c6
SF
421 args.uid = NO_CHANGE_64;
422 args.gid = NO_CHANGE_64;
1da177e4 423 }
c3b2a0c6
SF
424 CIFSSMBUnixSetInfo(xid, tcon, full_path, &args,
425 cifs_sb->local_nls,
426 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
427 } else {
428 /* BB implement mode setting via Windows security
429 descriptors e.g. */
430 /* CIFSSMBWinSetPerms(xid,tcon,path,mode,-1,-1,nls);*/
431
432 /* Could set r/o dos attribute if mode & 0222 == 0 */
433 }
1da177e4 434
c3b2a0c6
SF
435cifs_create_get_file_info:
436 /* server might mask mode so we have to query for it */
437 if (tcon->unix_ext)
438 rc = cifs_get_inode_info_unix(&newinode, full_path,
439 inode->i_sb, xid);
440 else {
441 rc = cifs_get_inode_info(&newinode, full_path, buf,
442 inode->i_sb, xid, &fileHandle);
443 if (newinode) {
444 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
445 newinode->i_mode = mode;
446 if ((oplock & CIFS_CREATE_ACTION) &&
447 (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) {
448 newinode->i_uid = current_fsuid();
449 if (inode->i_mode & S_ISGID)
450 newinode->i_gid = inode->i_gid;
451 else
452 newinode->i_gid = current_fsgid();
6473a559 453 }
1da177e4 454 }
c3b2a0c6 455 }
1da177e4 456
c3b2a0c6
SF
457cifs_create_set_dentry:
458 if (rc == 0)
459 setup_cifs_dentry(tcon, direntry, newinode);
460 else
461 cFYI(1, ("Create worked, get_inode_info failed rc = %d", rc));
462
463 /* nfsd case - nfs srv does not set nd */
464 if ((nd == NULL) || (!(nd->flags & LOOKUP_OPEN))) {
465 /* mknod case - do not leave file open */
466 CIFSSMBClose(xid, tcon, fileHandle);
467 } else if (newinode) {
a6ce4932
SF
468 cifs_fill_fileinfo(newinode, fileHandle,
469 cifs_sb->tcon, write_only);
5fdae1f6 470 }
d14537f1
SF
471cifs_create_out:
472 kfree(buf);
473 kfree(full_path);
1da177e4 474 FreeXid(xid);
1da177e4
LT
475 return rc;
476}
477
5fdae1f6
SF
478int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
479 dev_t device_number)
1da177e4
LT
480{
481 int rc = -EPERM;
482 int xid;
483 struct cifs_sb_info *cifs_sb;
484 struct cifsTconInfo *pTcon;
485 char *full_path = NULL;
fb8c4b14 486 struct inode *newinode = NULL;
1da177e4
LT
487
488 if (!old_valid_dev(device_number))
489 return -EINVAL;
490
491 xid = GetXid();
492
493 cifs_sb = CIFS_SB(inode->i_sb);
494 pTcon = cifs_sb->tcon;
495
1da177e4 496 full_path = build_path_from_dentry(direntry);
5fdae1f6 497 if (full_path == NULL)
1da177e4 498 rc = -ENOMEM;
c18c842b 499 else if (pTcon->unix_ext) {
4e1e7fb9 500 struct cifs_unix_set_info_args args = {
ce3b0f8d 501 .mode = mode & ~current_umask(),
4e1e7fb9
JL
502 .ctime = NO_CHANGE_64,
503 .atime = NO_CHANGE_64,
504 .mtime = NO_CHANGE_64,
505 .device = device_number,
506 };
5fdae1f6 507 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
a001e5b5
DH
508 args.uid = (__u64) current_fsuid();
509 args.gid = (__u64) current_fsgid();
1da177e4 510 } else {
4e1e7fb9
JL
511 args.uid = NO_CHANGE_64;
512 args.gid = NO_CHANGE_64;
1da177e4 513 }
4e1e7fb9
JL
514 rc = CIFSSMBUnixSetInfo(xid, pTcon, full_path,
515 &args, cifs_sb->local_nls,
516 cifs_sb->mnt_cifs_flags &
517 CIFS_MOUNT_MAP_SPECIAL_CHR);
1da177e4 518
5fdae1f6 519 if (!rc) {
1da177e4 520 rc = cifs_get_inode_info_unix(&newinode, full_path,
5fdae1f6 521 inode->i_sb, xid);
b92327fe
SF
522 if (pTcon->nocase)
523 direntry->d_op = &cifs_ci_dentry_ops;
524 else
525 direntry->d_op = &cifs_dentry_ops;
5fdae1f6 526 if (rc == 0)
1da177e4
LT
527 d_instantiate(direntry, newinode);
528 }
d7245c2c 529 } else {
5fdae1f6 530 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
eda3c029
SF
531 int oplock = 0;
532 u16 fileHandle;
ad7a2926 533 FILE_ALL_INFO *buf;
d7245c2c 534
5fdae1f6 535 cFYI(1, ("sfu compat create special file"));
d7245c2c 536
5fdae1f6
SF
537 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
538 if (buf == NULL) {
eda3c029
SF
539 kfree(full_path);
540 FreeXid(xid);
541 return -ENOMEM;
542 }
543
544 rc = CIFSSMBOpen(xid, pTcon, full_path,
545 FILE_CREATE, /* fail if exists */
5fdae1f6 546 GENERIC_WRITE /* BB would
eda3c029
SF
547 WRITE_OWNER | WRITE_DAC be better? */,
548 /* Create a file and set the
549 file attribute to SYSTEM */
550 CREATE_NOT_DIR | CREATE_OPTION_SPECIAL,
551 &fileHandle, &oplock, buf,
552 cifs_sb->local_nls,
5fdae1f6 553 cifs_sb->mnt_cifs_flags &
eda3c029
SF
554 CIFS_MOUNT_MAP_SPECIAL_CHR);
555
5bafd765
SF
556 /* BB FIXME - add handling for backlevel servers
557 which need legacy open and check for all
5fdae1f6
SF
558 calls to SMBOpen for fallback to SMBLeagcyOpen */
559 if (!rc) {
eda3c029 560 /* BB Do not bother to decode buf since no
86c96b4b
SF
561 local inode yet to put timestamps in,
562 but we can reuse it safely */
77159b4d 563 unsigned int bytes_written;
86c96b4b
SF
564 struct win_dev *pdev;
565 pdev = (struct win_dev *)buf;
5fdae1f6 566 if (S_ISCHR(mode)) {
86c96b4b
SF
567 memcpy(pdev->type, "IntxCHR", 8);
568 pdev->major =
569 cpu_to_le64(MAJOR(device_number));
5fdae1f6 570 pdev->minor =
86c96b4b
SF
571 cpu_to_le64(MINOR(device_number));
572 rc = CIFSSMBWrite(xid, pTcon,
573 fileHandle,
574 sizeof(struct win_dev),
575 0, &bytes_written, (char *)pdev,
576 NULL, 0);
5fdae1f6 577 } else if (S_ISBLK(mode)) {
86c96b4b
SF
578 memcpy(pdev->type, "IntxBLK", 8);
579 pdev->major =
580 cpu_to_le64(MAJOR(device_number));
581 pdev->minor =
582 cpu_to_le64(MINOR(device_number));
583 rc = CIFSSMBWrite(xid, pTcon,
584 fileHandle,
585 sizeof(struct win_dev),
586 0, &bytes_written, (char *)pdev,
587 NULL, 0);
588 } /* else if(S_ISFIFO */
eda3c029
SF
589 CIFSSMBClose(xid, pTcon, fileHandle);
590 d_drop(direntry);
591 }
592 kfree(buf);
d7245c2c
SF
593 /* add code here to set EAs */
594 }
1da177e4
LT
595 }
596
d14537f1 597 kfree(full_path);
1da177e4 598 FreeXid(xid);
1da177e4
LT
599 return rc;
600}
601
1da177e4 602struct dentry *
5fdae1f6
SF
603cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
604 struct nameidata *nd)
1da177e4
LT
605{
606 int xid;
607 int rc = 0; /* to get around spurious gcc warning, set to zero here */
a6ce4932
SF
608 int oplock = 0;
609 int mode;
610 __u16 fileHandle = 0;
611 bool posix_open = false;
1da177e4
LT
612 struct cifs_sb_info *cifs_sb;
613 struct cifsTconInfo *pTcon;
614 struct inode *newInode = NULL;
615 char *full_path = NULL;
a6ce4932 616 struct file *filp;
1da177e4
LT
617
618 xid = GetXid();
619
61e74801 620 cFYI(1, ("parent inode = 0x%p name is: %s and dentry = 0x%p",
1da177e4
LT
621 parent_dir_inode, direntry->d_name.name, direntry));
622
1da177e4
LT
623 /* check whether path exists */
624
625 cifs_sb = CIFS_SB(parent_dir_inode->i_sb);
626 pTcon = cifs_sb->tcon;
627
296034f7
SF
628 /*
629 * Don't allow the separator character in a path component.
630 * The VFS will not allow "/", but "\" is allowed by posix.
631 */
632 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)) {
633 int i;
634 for (i = 0; i < direntry->d_name.len; i++)
635 if (direntry->d_name.name[i] == '\\') {
636 cFYI(1, ("Invalid file name"));
637 FreeXid(xid);
638 return ERR_PTR(-EINVAL);
639 }
640 }
641
1da177e4
LT
642 /* can not grab the rename sem here since it would
643 deadlock in the cases (beginning of sys_rename itself)
644 in which we already have the sb rename sem */
645 full_path = build_path_from_dentry(direntry);
5fdae1f6 646 if (full_path == NULL) {
1da177e4
LT
647 FreeXid(xid);
648 return ERR_PTR(-ENOMEM);
649 }
650
651 if (direntry->d_inode != NULL) {
61e74801 652 cFYI(1, ("non-NULL inode in lookup"));
1da177e4 653 } else {
61e74801 654 cFYI(1, ("NULL inode in lookup"));
1da177e4 655 }
61e74801 656 cFYI(1, ("Full path: %s inode = 0x%p", full_path, direntry->d_inode));
1da177e4 657
a6ce4932
SF
658 if (pTcon->unix_ext) {
659 if (!(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY)) &&
660 (nd->flags & LOOKUP_OPEN)) {
661 if (!((nd->intent.open.flags & O_CREAT) &&
662 (nd->intent.open.flags & O_EXCL))) {
663 mode = nd->intent.open.create_mode &
88dd47ff 664 ~current_umask();
a6ce4932
SF
665 rc = cifs_posix_open(full_path, &newInode,
666 parent_dir_inode->i_sb, mode,
667 nd->intent.open.flags, &oplock,
668 &fileHandle, xid);
bc8cd439
SF
669 /*
670 * This code works around a bug in
671 * samba posix open in samba versions 3.3.1
672 * and earlier where create works
673 * but open fails with invalid parameter.
674 * If either of these error codes are
675 * returned, follow the normal lookup.
676 * Otherwise, the error during posix open
677 * is handled.
678 */
a6ce4932
SF
679 if ((rc != -EINVAL) && (rc != -EOPNOTSUPP))
680 posix_open = true;
681 }
682 }
683 if (!posix_open)
684 rc = cifs_get_inode_info_unix(&newInode, full_path,
685 parent_dir_inode->i_sb, xid);
686 } else
1da177e4 687 rc = cifs_get_inode_info(&newInode, full_path, NULL,
a6ce4932 688 parent_dir_inode->i_sb, xid, NULL);
1da177e4
LT
689
690 if ((rc == 0) && (newInode != NULL)) {
b92327fe
SF
691 if (pTcon->nocase)
692 direntry->d_op = &cifs_ci_dentry_ops;
693 else
694 direntry->d_op = &cifs_dentry_ops;
1da177e4 695 d_add(direntry, newInode);
a6ce4932
SF
696 if (posix_open)
697 filp = lookup_instantiate_filp(nd, direntry, NULL);
5fdae1f6 698 /* since paths are not looked up by component - the parent
3abb9272 699 directories are presumed to be good here */
1da177e4
LT
700 renew_parental_timestamps(direntry);
701
702 } else if (rc == -ENOENT) {
703 rc = 0;
3abb9272
SF
704 direntry->d_time = jiffies;
705 if (pTcon->nocase)
706 direntry->d_op = &cifs_ci_dentry_ops;
707 else
708 direntry->d_op = &cifs_dentry_ops;
1da177e4 709 d_add(direntry, NULL);
5fdae1f6
SF
710 /* if it was once a directory (but how can we tell?) we could do
711 shrink_dcache_parent(direntry); */
ed2b9170
SF
712 } else if (rc != -EACCES) {
713 cERROR(1, ("Unexpected lookup error %d", rc));
714 /* We special case check for Access Denied - since that
715 is a common return code */
1da177e4
LT
716 }
717
d14537f1 718 kfree(full_path);
1da177e4
LT
719 FreeXid(xid);
720 return ERR_PTR(rc);
721}
722
1da177e4
LT
723static int
724cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd)
725{
726 int isValid = 1;
727
1da177e4 728 if (direntry->d_inode) {
ad7a2926 729 if (cifs_revalidate(direntry))
1da177e4 730 return 0;
1da177e4 731 } else {
3abb9272
SF
732 cFYI(1, ("neg dentry 0x%p name = %s",
733 direntry, direntry->d_name.name));
5fdae1f6 734 if (time_after(jiffies, direntry->d_time + HZ) ||
3abb9272
SF
735 !lookupCacheEnabled) {
736 d_drop(direntry);
737 isValid = 0;
5fdae1f6 738 }
1da177e4
LT
739 }
740
1da177e4
LT
741 return isValid;
742}
743
744/* static int cifs_d_delete(struct dentry *direntry)
745{
746 int rc = 0;
747
748 cFYI(1, ("In cifs d_delete, name = %s", direntry->d_name.name));
749
750 return rc;
751} */
752
4fd03e84 753const struct dentry_operations cifs_dentry_ops = {
1da177e4 754 .d_revalidate = cifs_d_revalidate,
5fdae1f6 755/* d_delete: cifs_d_delete, */ /* not needed except for debugging */
1da177e4 756};
b92327fe
SF
757
758static int cifs_ci_hash(struct dentry *dentry, struct qstr *q)
759{
760 struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls;
761 unsigned long hash;
762 int i;
763
764 hash = init_name_hash();
765 for (i = 0; i < q->len; i++)
766 hash = partial_name_hash(nls_tolower(codepage, q->name[i]),
767 hash);
768 q->hash = end_name_hash(hash);
769
770 return 0;
771}
772
773static int cifs_ci_compare(struct dentry *dentry, struct qstr *a,
774 struct qstr *b)
775{
776 struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls;
777
778 if ((a->len == b->len) &&
779 (nls_strnicmp(codepage, a->name, b->name, a->len) == 0)) {
780 /*
781 * To preserve case, don't let an existing negative dentry's
782 * case take precedence. If a is not a negative dentry, this
783 * should have no side effects
784 */
c3291637 785 memcpy((void *)a->name, b->name, a->len);
b92327fe
SF
786 return 0;
787 }
788 return 1;
789}
790
4fd03e84 791const struct dentry_operations cifs_ci_dentry_ops = {
b92327fe
SF
792 .d_revalidate = cifs_d_revalidate,
793 .d_hash = cifs_ci_hash,
794 .d_compare = cifs_ci_compare,
795};