aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/cifs/cifs_fs_sb.h1
-rw-r--r--fs/cifs/inode.c14
-rw-r--r--fs/cifs/link.c27
-rw-r--r--fs/cifs/readdir.c9
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
40struct cifs_sb_info { 41struct 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);
424out: 438out:
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