diff options
author | Stefan Metzmacher <metze@samba.org> | 2010-08-05 15:19:56 -0400 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2010-09-29 15:04:31 -0400 |
commit | 1b12b9c15b4371d83b729b8fc18c670e78a1479b (patch) | |
tree | f82c9b0d01cdc5e64765780403f460e9e0d8496b | |
parent | 8713d01db8bf948eb9632726f529ec4f821bb025 (diff) |
cifs: use Minshall+French symlink functions
If configured, Minshall+French Symlinks are used against
all servers. If the server supports UNIX Extensions,
we still create Minshall+French Symlinks on write,
but on read we fallback to UNIX Extension symlinks.
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Signed-off-by: Steve French <sfrench@us.ibm.com>
-rw-r--r-- | fs/cifs/cifs_fs_sb.h | 1 | ||||
-rw-r--r-- | fs/cifs/inode.c | 14 | ||||
-rw-r--r-- | fs/cifs/link.c | 27 | ||||
-rw-r--r-- | fs/cifs/readdir.c | 9 |
4 files changed, 47 insertions, 4 deletions
diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index 9e771450c3b8..7fde52969896 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h | |||
@@ -36,6 +36,7 @@ | |||
36 | #define CIFS_MOUNT_NOPOSIXBRL 0x2000 /* mandatory not posix byte range lock */ | 36 | #define CIFS_MOUNT_NOPOSIXBRL 0x2000 /* mandatory not posix byte range lock */ |
37 | #define CIFS_MOUNT_NOSSYNC 0x4000 /* don't do slow SMBflush on every sync*/ | 37 | #define CIFS_MOUNT_NOSSYNC 0x4000 /* don't do slow SMBflush on every sync*/ |
38 | #define CIFS_MOUNT_FSCACHE 0x8000 /* local caching enabled */ | 38 | #define CIFS_MOUNT_FSCACHE 0x8000 /* local caching enabled */ |
39 | #define CIFS_MOUNT_MF_SYMLINKS 0x10000 /* Minshall+French Symlinks enabled */ | ||
39 | 40 | ||
40 | struct cifs_sb_info { | 41 | struct cifs_sb_info { |
41 | struct cifsTconInfo *tcon; /* primary mount */ | 42 | struct cifsTconInfo *tcon; /* primary mount */ |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 93f77d438d3c..016975b8e6dd 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -332,6 +332,13 @@ int cifs_get_inode_info_unix(struct inode **pinode, | |||
332 | return rc; | 332 | return rc; |
333 | } | 333 | } |
334 | 334 | ||
335 | /* check for Minshall+French symlinks */ | ||
336 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) { | ||
337 | int tmprc = CIFSCheckMFSymlink(&fattr, full_path, cifs_sb, xid); | ||
338 | if (tmprc) | ||
339 | cFYI(1, "CIFSCheckMFSymlink: %d", tmprc); | ||
340 | } | ||
341 | |||
335 | if (*pinode == NULL) { | 342 | if (*pinode == NULL) { |
336 | /* get new inode */ | 343 | /* get new inode */ |
337 | cifs_fill_uniqueid(sb, &fattr); | 344 | cifs_fill_uniqueid(sb, &fattr); |
@@ -661,6 +668,13 @@ int cifs_get_inode_info(struct inode **pinode, | |||
661 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) | 668 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) |
662 | cifs_sfu_mode(&fattr, full_path, cifs_sb, xid); | 669 | cifs_sfu_mode(&fattr, full_path, cifs_sb, xid); |
663 | 670 | ||
671 | /* check for Minshall+French symlinks */ | ||
672 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) { | ||
673 | tmprc = CIFSCheckMFSymlink(&fattr, full_path, cifs_sb, xid); | ||
674 | if (tmprc) | ||
675 | cFYI(1, "CIFSCheckMFSymlink: %d", tmprc); | ||
676 | } | ||
677 | |||
664 | if (!*pinode) { | 678 | if (!*pinode) { |
665 | *pinode = cifs_iget(sb, &fattr); | 679 | *pinode = cifs_iget(sb, &fattr); |
666 | if (!*pinode) | 680 | if (!*pinode) |
diff --git a/fs/cifs/link.c b/fs/cifs/link.c index 1b2a8c971995..cbf7b112287b 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c | |||
@@ -407,7 +407,8 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd) | |||
407 | * but there doesn't seem to be any harm in allowing the client to | 407 | * but there doesn't seem to be any harm in allowing the client to |
408 | * read them. | 408 | * read them. |
409 | */ | 409 | */ |
410 | if (!(tcon->ses->capabilities & CAP_UNIX)) { | 410 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) |
411 | && !(tcon->ses->capabilities & CAP_UNIX)) { | ||
411 | rc = -EACCES; | 412 | rc = -EACCES; |
412 | goto out; | 413 | goto out; |
413 | } | 414 | } |
@@ -418,8 +419,21 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd) | |||
418 | 419 | ||
419 | cFYI(1, "Full path: %s inode = 0x%p", full_path, inode); | 420 | cFYI(1, "Full path: %s inode = 0x%p", full_path, inode); |
420 | 421 | ||
421 | rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, &target_path, | 422 | rc = -EACCES; |
422 | cifs_sb->local_nls); | 423 | /* |
424 | * First try Minshall+French Symlinks, if configured | ||
425 | * and fallback to UNIX Extensions Symlinks. | ||
426 | */ | ||
427 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) | ||
428 | rc = CIFSQueryMFSymLink(xid, tcon, full_path, &target_path, | ||
429 | cifs_sb->local_nls, | ||
430 | cifs_sb->mnt_cifs_flags & | ||
431 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
432 | |||
433 | if ((rc != 0) && (tcon->ses->capabilities & CAP_UNIX)) | ||
434 | rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, &target_path, | ||
435 | cifs_sb->local_nls); | ||
436 | |||
423 | kfree(full_path); | 437 | kfree(full_path); |
424 | out: | 438 | out: |
425 | if (rc != 0) { | 439 | if (rc != 0) { |
@@ -459,7 +473,12 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) | |||
459 | cFYI(1, "symname is %s", symname); | 473 | cFYI(1, "symname is %s", symname); |
460 | 474 | ||
461 | /* BB what if DFS and this volume is on different share? BB */ | 475 | /* BB what if DFS and this volume is on different share? BB */ |
462 | if (pTcon->unix_ext) | 476 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) |
477 | rc = CIFSCreateMFSymLink(xid, pTcon, full_path, symname, | ||
478 | cifs_sb->local_nls, | ||
479 | cifs_sb->mnt_cifs_flags & | ||
480 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
481 | else if (pTcon->unix_ext) | ||
463 | rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname, | 482 | rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname, |
464 | cifs_sb->local_nls); | 483 | cifs_sb->local_nls); |
465 | /* else | 484 | /* else |
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index d5e591fab475..6a8b417babab 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c | |||
@@ -738,6 +738,15 @@ static int cifs_filldir(char *pfindEntry, struct file *file, filldir_t filldir, | |||
738 | cifs_autodisable_serverino(cifs_sb); | 738 | cifs_autodisable_serverino(cifs_sb); |
739 | } | 739 | } |
740 | 740 | ||
741 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) && | ||
742 | CIFSCouldBeMFSymlink(&fattr)) | ||
743 | /* | ||
744 | * trying to get the type and mode can be slow, | ||
745 | * so just call those regular files for now, and mark | ||
746 | * for reval | ||
747 | */ | ||
748 | fattr.cf_flags |= CIFS_FATTR_NEED_REVAL; | ||
749 | |||
741 | ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid); | 750 | ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid); |
742 | tmp_dentry = cifs_readdir_lookup(file->f_dentry, &qstring, &fattr); | 751 | tmp_dentry = cifs_readdir_lookup(file->f_dentry, &qstring, &fattr); |
743 | 752 | ||