Merge git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[wrt350n-kernel.git] / fs / cifs / dir.c
blobfad6aa979733f6e9c9325850bc4fee92b1b332fc
1 /*
2 * fs/cifs/dir.c
4 * vfs operations that deal with dentries
6 <<<<<<< HEAD:fs/cifs/dir.c
7 * Copyright (C) International Business Machines Corp., 2002,2007
8 =======
9 * Copyright (C) International Business Machines Corp., 2002,2008
10 >>>>>>> 264e3e889d86e552b4191d69bb60f4f3b383135a:fs/cifs/dir.c
11 * Author(s): Steve French (sfrench@us.ibm.com)
13 * This library is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU Lesser General Public License as published
15 * by the Free Software Foundation; either version 2.1 of the License, or
16 * (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
21 * the GNU Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public License
24 * along with this library; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include <linux/fs.h>
28 #include <linux/stat.h>
29 #include <linux/slab.h>
30 #include <linux/namei.h>
31 #include "cifsfs.h"
32 #include "cifspdu.h"
33 #include "cifsglob.h"
34 #include "cifsproto.h"
35 #include "cifs_debug.h"
36 #include "cifs_fs_sb.h"
38 static void
39 renew_parental_timestamps(struct dentry *direntry)
41 /* BB check if there is a way to get the kernel to do this or if we
42 really need this */
43 do {
44 direntry->d_time = jiffies;
45 direntry = direntry->d_parent;
46 } while (!IS_ROOT(direntry));
49 /* Note: caller must free return buffer */
50 char *
51 build_path_from_dentry(struct dentry *direntry)
53 struct dentry *temp;
54 int namelen;
55 int pplen;
56 char *full_path;
57 char dirsep;
59 if (direntry == NULL)
60 return NULL; /* not much we can do if dentry is freed and
61 we need to reopen the file after it was closed implicitly
62 when the server crashed */
64 dirsep = CIFS_DIR_SEP(CIFS_SB(direntry->d_sb));
65 pplen = CIFS_SB(direntry->d_sb)->prepathlen;
66 cifs_bp_rename_retry:
67 namelen = pplen;
68 for (temp = direntry; !IS_ROOT(temp);) {
69 namelen += (1 + temp->d_name.len);
70 temp = temp->d_parent;
71 if (temp == NULL) {
72 cERROR(1, ("corrupt dentry"));
73 return NULL;
77 full_path = kmalloc(namelen+1, GFP_KERNEL);
78 if (full_path == NULL)
79 return full_path;
80 full_path[namelen] = 0; /* trailing null */
81 for (temp = direntry; !IS_ROOT(temp);) {
82 namelen -= 1 + temp->d_name.len;
83 if (namelen < 0) {
84 break;
85 } else {
86 full_path[namelen] = dirsep;
87 strncpy(full_path + namelen + 1, temp->d_name.name,
88 temp->d_name.len);
89 cFYI(0, ("name: %s", full_path + namelen));
91 temp = temp->d_parent;
92 if (temp == NULL) {
93 cERROR(1, ("corrupt dentry"));
94 kfree(full_path);
95 return NULL;
98 if (namelen != pplen) {
99 cERROR(1,
100 ("did not end path lookup where expected namelen is %d",
101 namelen));
102 /* presumably this is only possible if racing with a rename
103 of one of the parent directories (we can not lock the dentries
104 above us to prevent this, but retrying should be harmless) */
105 kfree(full_path);
106 goto cifs_bp_rename_retry;
108 /* DIR_SEP already set for byte 0 / vs \ but not for
109 subsequent slashes in prepath which currently must
110 be entered the right way - not sure if there is an alternative
111 since the '\' is a valid posix character so we can not switch
112 those safely to '/' if any are found in the middle of the prepath */
113 /* BB test paths to Windows with '/' in the midst of prepath */
114 strncpy(full_path, CIFS_SB(direntry->d_sb)->prepath, pplen);
115 return full_path;
118 <<<<<<< HEAD:fs/cifs/dir.c
119 /* char * build_wildcard_path_from_dentry(struct dentry *direntry)
121 if(full_path == NULL)
122 return full_path;
124 full_path[namelen] = '\\';
125 full_path[namelen+1] = '*';
126 full_path[namelen+2] = 0;
127 BB remove above eight lines BB */
129 =======
130 >>>>>>> 264e3e889d86e552b4191d69bb60f4f3b383135a:fs/cifs/dir.c
131 /* Inode operations in similar order to how they appear in Linux file fs.h */
134 cifs_create(struct inode *inode, struct dentry *direntry, int mode,
135 struct nameidata *nd)
137 int rc = -ENOENT;
138 int xid;
139 int oplock = 0;
140 int desiredAccess = GENERIC_READ | GENERIC_WRITE;
141 __u16 fileHandle;
142 struct cifs_sb_info *cifs_sb;
143 struct cifsTconInfo *pTcon;
144 char *full_path = NULL;
145 FILE_ALL_INFO *buf = NULL;
146 struct inode *newinode = NULL;
147 struct cifsFileInfo *pCifsFile = NULL;
148 struct cifsInodeInfo *pCifsInode;
149 int disposition = FILE_OVERWRITE_IF;
150 int write_only = FALSE;
152 xid = GetXid();
154 cifs_sb = CIFS_SB(inode->i_sb);
155 pTcon = cifs_sb->tcon;
157 full_path = build_path_from_dentry(direntry);
158 if (full_path == NULL) {
159 FreeXid(xid);
160 return -ENOMEM;
163 if (nd && (nd->flags & LOOKUP_OPEN)) {
164 int oflags = nd->intent.open.flags;
166 desiredAccess = 0;
167 if (oflags & FMODE_READ)
168 desiredAccess |= GENERIC_READ;
169 if (oflags & FMODE_WRITE) {
170 desiredAccess |= GENERIC_WRITE;
171 if (!(oflags & FMODE_READ))
172 write_only = TRUE;
175 if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
176 disposition = FILE_CREATE;
177 else if ((oflags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
178 disposition = FILE_OVERWRITE_IF;
179 else if ((oflags & O_CREAT) == O_CREAT)
180 disposition = FILE_OPEN_IF;
181 <<<<<<< HEAD:fs/cifs/dir.c
182 else {
183 =======
184 else
185 >>>>>>> 264e3e889d86e552b4191d69bb60f4f3b383135a:fs/cifs/dir.c
186 cFYI(1, ("Create flag not set in create function"));
187 <<<<<<< HEAD:fs/cifs/dir.c
189 =======
190 >>>>>>> 264e3e889d86e552b4191d69bb60f4f3b383135a:fs/cifs/dir.c
193 /* BB add processing to set equivalent of mode - e.g. via CreateX with
194 ACLs */
195 if (oplockEnabled)
196 oplock = REQ_OPLOCK;
198 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
199 if (buf == NULL) {
200 kfree(full_path);
201 FreeXid(xid);
202 return -ENOMEM;
204 if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS)
205 rc = CIFSSMBOpen(xid, pTcon, full_path, disposition,
206 desiredAccess, CREATE_NOT_DIR,
207 &fileHandle, &oplock, buf, cifs_sb->local_nls,
208 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
209 else
210 rc = -EIO; /* no NT SMB support fall into legacy open below */
212 if (rc == -EIO) {
213 /* old server, retry the open legacy style */
214 rc = SMBLegacyOpen(xid, pTcon, full_path, disposition,
215 desiredAccess, CREATE_NOT_DIR,
216 &fileHandle, &oplock, buf, cifs_sb->local_nls,
217 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
219 if (rc) {
220 cFYI(1, ("cifs_create returned 0x%x", rc));
221 } else {
222 /* If Open reported that we actually created a file
223 then we now have to set the mode if possible */
224 if ((pTcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) {
225 mode &= ~current->fs->umask;
226 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
227 CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
228 (__u64)current->fsuid,
229 (__u64)current->fsgid,
230 0 /* dev */,
231 cifs_sb->local_nls,
232 cifs_sb->mnt_cifs_flags &
233 CIFS_MOUNT_MAP_SPECIAL_CHR);
234 } else {
235 CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
236 (__u64)-1,
237 (__u64)-1,
238 0 /* dev */,
239 cifs_sb->local_nls,
240 cifs_sb->mnt_cifs_flags &
241 CIFS_MOUNT_MAP_SPECIAL_CHR);
243 } else {
244 /* BB implement mode setting via Windows security
245 descriptors e.g. */
246 /* CIFSSMBWinSetPerms(xid,pTcon,path,mode,-1,-1,nls);*/
248 /* Could set r/o dos attribute if mode & 0222 == 0 */
251 /* server might mask mode so we have to query for it */
252 if (pTcon->unix_ext)
253 rc = cifs_get_inode_info_unix(&newinode, full_path,
254 inode->i_sb, xid);
255 else {
256 rc = cifs_get_inode_info(&newinode, full_path,
257 buf, inode->i_sb, xid);
258 if (newinode) {
259 newinode->i_mode = mode;
260 if ((oplock & CIFS_CREATE_ACTION) &&
261 (cifs_sb->mnt_cifs_flags &
262 CIFS_MOUNT_SET_UID)) {
263 newinode->i_uid = current->fsuid;
264 newinode->i_gid = current->fsgid;
269 if (rc != 0) {
270 cFYI(1,
271 ("Create worked but get_inode_info failed rc = %d",
272 rc));
273 } else {
274 if (pTcon->nocase)
275 direntry->d_op = &cifs_ci_dentry_ops;
276 else
277 direntry->d_op = &cifs_dentry_ops;
278 d_instantiate(direntry, newinode);
280 if ((nd == NULL /* nfsd case - nfs srv does not set nd */) ||
281 ((nd->flags & LOOKUP_OPEN) == FALSE)) {
282 /* mknod case - do not leave file open */
283 CIFSSMBClose(xid, pTcon, fileHandle);
284 } else if (newinode) {
285 pCifsFile =
286 kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
288 if (pCifsFile == NULL)
289 goto cifs_create_out;
290 pCifsFile->netfid = fileHandle;
291 pCifsFile->pid = current->tgid;
292 pCifsFile->pInode = newinode;
293 pCifsFile->invalidHandle = FALSE;
294 pCifsFile->closePend = FALSE;
295 init_MUTEX(&pCifsFile->fh_sem);
296 mutex_init(&pCifsFile->lock_mutex);
297 INIT_LIST_HEAD(&pCifsFile->llist);
298 atomic_set(&pCifsFile->wrtPending, 0);
300 /* set the following in open now
301 pCifsFile->pfile = file; */
302 write_lock(&GlobalSMBSeslock);
303 list_add(&pCifsFile->tlist, &pTcon->openFileList);
304 pCifsInode = CIFS_I(newinode);
305 if (pCifsInode) {
306 /* if readable file instance put first in list*/
307 if (write_only == TRUE) {
308 list_add_tail(&pCifsFile->flist,
309 &pCifsInode->openFileList);
310 } else {
311 list_add(&pCifsFile->flist,
312 &pCifsInode->openFileList);
314 if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
315 pCifsInode->clientCanCacheAll = TRUE;
316 pCifsInode->clientCanCacheRead = TRUE;
317 cFYI(1, ("Exclusive Oplock inode %p",
318 newinode));
319 } else if ((oplock & 0xF) == OPLOCK_READ)
320 pCifsInode->clientCanCacheRead = TRUE;
322 write_unlock(&GlobalSMBSeslock);
325 cifs_create_out:
326 kfree(buf);
327 kfree(full_path);
328 FreeXid(xid);
329 return rc;
332 int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
333 dev_t device_number)
335 int rc = -EPERM;
336 int xid;
337 struct cifs_sb_info *cifs_sb;
338 struct cifsTconInfo *pTcon;
339 char *full_path = NULL;
340 struct inode *newinode = NULL;
342 if (!old_valid_dev(device_number))
343 return -EINVAL;
345 xid = GetXid();
347 cifs_sb = CIFS_SB(inode->i_sb);
348 pTcon = cifs_sb->tcon;
350 full_path = build_path_from_dentry(direntry);
351 if (full_path == NULL)
352 rc = -ENOMEM;
353 else if (pTcon->unix_ext) {
354 mode &= ~current->fs->umask;
355 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
356 rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path,
357 mode, (__u64)current->fsuid,
358 (__u64)current->fsgid,
359 device_number, cifs_sb->local_nls,
360 cifs_sb->mnt_cifs_flags &
361 CIFS_MOUNT_MAP_SPECIAL_CHR);
362 } else {
363 rc = CIFSSMBUnixSetPerms(xid, pTcon,
364 full_path, mode, (__u64)-1, (__u64)-1,
365 device_number, cifs_sb->local_nls,
366 cifs_sb->mnt_cifs_flags &
367 CIFS_MOUNT_MAP_SPECIAL_CHR);
370 if (!rc) {
371 rc = cifs_get_inode_info_unix(&newinode, full_path,
372 inode->i_sb, xid);
373 if (pTcon->nocase)
374 direntry->d_op = &cifs_ci_dentry_ops;
375 else
376 direntry->d_op = &cifs_dentry_ops;
377 if (rc == 0)
378 d_instantiate(direntry, newinode);
380 } else {
381 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
382 int oplock = 0;
383 u16 fileHandle;
384 <<<<<<< HEAD:fs/cifs/dir.c
385 FILE_ALL_INFO * buf;
386 =======
387 FILE_ALL_INFO *buf;
388 >>>>>>> 264e3e889d86e552b4191d69bb60f4f3b383135a:fs/cifs/dir.c
390 cFYI(1, ("sfu compat create special file"));
392 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
393 if (buf == NULL) {
394 kfree(full_path);
395 FreeXid(xid);
396 return -ENOMEM;
399 rc = CIFSSMBOpen(xid, pTcon, full_path,
400 FILE_CREATE, /* fail if exists */
401 GENERIC_WRITE /* BB would
402 WRITE_OWNER | WRITE_DAC be better? */,
403 /* Create a file and set the
404 file attribute to SYSTEM */
405 CREATE_NOT_DIR | CREATE_OPTION_SPECIAL,
406 &fileHandle, &oplock, buf,
407 cifs_sb->local_nls,
408 cifs_sb->mnt_cifs_flags &
409 CIFS_MOUNT_MAP_SPECIAL_CHR);
411 /* BB FIXME - add handling for backlevel servers
412 which need legacy open and check for all
413 calls to SMBOpen for fallback to SMBLeagcyOpen */
414 if (!rc) {
415 /* BB Do not bother to decode buf since no
416 local inode yet to put timestamps in,
417 but we can reuse it safely */
418 unsigned int bytes_written;
419 struct win_dev *pdev;
420 pdev = (struct win_dev *)buf;
421 if (S_ISCHR(mode)) {
422 memcpy(pdev->type, "IntxCHR", 8);
423 pdev->major =
424 cpu_to_le64(MAJOR(device_number));
425 pdev->minor =
426 cpu_to_le64(MINOR(device_number));
427 rc = CIFSSMBWrite(xid, pTcon,
428 fileHandle,
429 sizeof(struct win_dev),
430 0, &bytes_written, (char *)pdev,
431 NULL, 0);
432 } else if (S_ISBLK(mode)) {
433 memcpy(pdev->type, "IntxBLK", 8);
434 pdev->major =
435 cpu_to_le64(MAJOR(device_number));
436 pdev->minor =
437 cpu_to_le64(MINOR(device_number));
438 rc = CIFSSMBWrite(xid, pTcon,
439 fileHandle,
440 sizeof(struct win_dev),
441 0, &bytes_written, (char *)pdev,
442 NULL, 0);
443 } /* else if(S_ISFIFO */
444 CIFSSMBClose(xid, pTcon, fileHandle);
445 d_drop(direntry);
447 kfree(buf);
448 /* add code here to set EAs */
452 kfree(full_path);
453 FreeXid(xid);
454 return rc;
458 struct dentry *
459 cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
460 struct nameidata *nd)
462 int xid;
463 int rc = 0; /* to get around spurious gcc warning, set to zero here */
464 struct cifs_sb_info *cifs_sb;
465 struct cifsTconInfo *pTcon;
466 struct inode *newInode = NULL;
467 char *full_path = NULL;
469 xid = GetXid();
471 cFYI(1, (" parent inode = 0x%p name is: %s and dentry = 0x%p",
472 parent_dir_inode, direntry->d_name.name, direntry));
474 /* check whether path exists */
476 cifs_sb = CIFS_SB(parent_dir_inode->i_sb);
477 pTcon = cifs_sb->tcon;
480 * Don't allow the separator character in a path component.
481 * The VFS will not allow "/", but "\" is allowed by posix.
483 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)) {
484 int i;
485 for (i = 0; i < direntry->d_name.len; i++)
486 if (direntry->d_name.name[i] == '\\') {
487 cFYI(1, ("Invalid file name"));
488 FreeXid(xid);
489 return ERR_PTR(-EINVAL);
493 /* can not grab the rename sem here since it would
494 deadlock in the cases (beginning of sys_rename itself)
495 in which we already have the sb rename sem */
496 full_path = build_path_from_dentry(direntry);
497 if (full_path == NULL) {
498 FreeXid(xid);
499 return ERR_PTR(-ENOMEM);
502 if (direntry->d_inode != NULL) {
503 cFYI(1, (" non-NULL inode in lookup"));
504 } else {
505 cFYI(1, (" NULL inode in lookup"));
507 cFYI(1,
508 (" Full path: %s inode = 0x%p", full_path, direntry->d_inode));
510 if (pTcon->unix_ext)
511 rc = cifs_get_inode_info_unix(&newInode, full_path,
512 parent_dir_inode->i_sb, xid);
513 else
514 rc = cifs_get_inode_info(&newInode, full_path, NULL,
515 parent_dir_inode->i_sb, xid);
517 if ((rc == 0) && (newInode != NULL)) {
518 if (pTcon->nocase)
519 direntry->d_op = &cifs_ci_dentry_ops;
520 else
521 direntry->d_op = &cifs_dentry_ops;
522 d_add(direntry, newInode);
524 /* since paths are not looked up by component - the parent
525 directories are presumed to be good here */
526 renew_parental_timestamps(direntry);
528 } else if (rc == -ENOENT) {
529 rc = 0;
530 direntry->d_time = jiffies;
531 if (pTcon->nocase)
532 direntry->d_op = &cifs_ci_dentry_ops;
533 else
534 direntry->d_op = &cifs_dentry_ops;
535 d_add(direntry, NULL);
536 /* if it was once a directory (but how can we tell?) we could do
537 shrink_dcache_parent(direntry); */
538 } else if (rc != -EACCES) {
539 cERROR(1, ("Unexpected lookup error %d", rc));
540 /* We special case check for Access Denied - since that
541 is a common return code */
544 kfree(full_path);
545 FreeXid(xid);
546 return ERR_PTR(rc);
549 static int
550 cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd)
552 int isValid = 1;
554 if (direntry->d_inode) {
555 <<<<<<< HEAD:fs/cifs/dir.c
556 if (cifs_revalidate(direntry)) {
557 =======
558 if (cifs_revalidate(direntry))
559 >>>>>>> 264e3e889d86e552b4191d69bb60f4f3b383135a:fs/cifs/dir.c
560 return 0;
561 <<<<<<< HEAD:fs/cifs/dir.c
563 =======
564 >>>>>>> 264e3e889d86e552b4191d69bb60f4f3b383135a:fs/cifs/dir.c
565 } else {
566 cFYI(1, ("neg dentry 0x%p name = %s",
567 direntry, direntry->d_name.name));
568 if (time_after(jiffies, direntry->d_time + HZ) ||
569 !lookupCacheEnabled) {
570 d_drop(direntry);
571 isValid = 0;
575 return isValid;
578 /* static int cifs_d_delete(struct dentry *direntry)
580 int rc = 0;
582 cFYI(1, ("In cifs d_delete, name = %s", direntry->d_name.name));
584 return rc;
585 } */
587 struct dentry_operations cifs_dentry_ops = {
588 .d_revalidate = cifs_d_revalidate,
589 /* d_delete: cifs_d_delete, */ /* not needed except for debugging */
592 static int cifs_ci_hash(struct dentry *dentry, struct qstr *q)
594 struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls;
595 unsigned long hash;
596 int i;
598 hash = init_name_hash();
599 for (i = 0; i < q->len; i++)
600 hash = partial_name_hash(nls_tolower(codepage, q->name[i]),
601 hash);
602 q->hash = end_name_hash(hash);
604 return 0;
607 static int cifs_ci_compare(struct dentry *dentry, struct qstr *a,
608 struct qstr *b)
610 struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls;
612 if ((a->len == b->len) &&
613 (nls_strnicmp(codepage, a->name, b->name, a->len) == 0)) {
615 * To preserve case, don't let an existing negative dentry's
616 * case take precedence. If a is not a negative dentry, this
617 * should have no side effects
619 memcpy(a->name, b->name, a->len);
620 return 0;
622 return 1;
625 struct dentry_operations cifs_ci_dentry_ops = {
626 .d_revalidate = cifs_d_revalidate,
627 .d_hash = cifs_ci_hash,
628 .d_compare = cifs_ci_compare,