cifs: use Minshall+French symlink functions
authorStefan Metzmacher <metze@samba.org>
Thu, 5 Aug 2010 19:19:56 +0000 (21:19 +0200)
committerSteve French <sfrench@us.ibm.com>
Wed, 29 Sep 2010 19:04:31 +0000 (19:04 +0000)
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>
fs/cifs/cifs_fs_sb.h
fs/cifs/inode.c
fs/cifs/link.c
fs/cifs/readdir.c

index 9e771450c3b8eba5230ffa16c30cb95a73151868..7fde52969896b23c18fc187f76f038305cb4c27c 100644 (file)
@@ -36,6 +36,7 @@
 #define CIFS_MOUNT_NOPOSIXBRL   0x2000 /* mandatory not posix byte range lock */
 #define CIFS_MOUNT_NOSSYNC      0x4000 /* don't do slow SMBflush on every sync*/
 #define CIFS_MOUNT_FSCACHE     0x8000 /* local caching enabled */
+#define CIFS_MOUNT_MF_SYMLINKS 0x10000 /* Minshall+French Symlinks enabled */
 
 struct cifs_sb_info {
        struct cifsTconInfo *tcon;      /* primary mount */
index 93f77d438d3c8f3d6702d24486c4e0f64055796b..016975b8e6ddf280c75d953d8a3ea548033470c9 100644 (file)
@@ -332,6 +332,13 @@ int cifs_get_inode_info_unix(struct inode **pinode,
                return rc;
        }
 
+       /* check for Minshall+French symlinks */
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
+               int tmprc = CIFSCheckMFSymlink(&fattr, full_path, cifs_sb, xid);
+               if (tmprc)
+                       cFYI(1, "CIFSCheckMFSymlink: %d", tmprc);
+       }
+
        if (*pinode == NULL) {
                /* get new inode */
                cifs_fill_uniqueid(sb, &fattr);
@@ -661,6 +668,13 @@ int cifs_get_inode_info(struct inode **pinode,
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)
                cifs_sfu_mode(&fattr, full_path, cifs_sb, xid);
 
+       /* check for Minshall+French symlinks */
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
+               tmprc = CIFSCheckMFSymlink(&fattr, full_path, cifs_sb, xid);
+               if (tmprc)
+                       cFYI(1, "CIFSCheckMFSymlink: %d", tmprc);
+       }
+
        if (!*pinode) {
                *pinode = cifs_iget(sb, &fattr);
                if (!*pinode)
index 1b2a8c97199541ace5dc9aba230780d7bcf5cca4..cbf7b112287b02157240d6fe3e30b7c77482aa69 100644 (file)
@@ -407,7 +407,8 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
         * but there doesn't seem to be any harm in allowing the client to
         * read them.
         */
-       if (!(tcon->ses->capabilities & CAP_UNIX)) {
+       if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS)
+           && !(tcon->ses->capabilities & CAP_UNIX)) {
                rc = -EACCES;
                goto out;
        }
@@ -418,8 +419,21 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
 
        cFYI(1, "Full path: %s inode = 0x%p", full_path, inode);
 
-       rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, &target_path,
-                                    cifs_sb->local_nls);
+       rc = -EACCES;
+       /*
+        * First try Minshall+French Symlinks, if configured
+        * and fallback to UNIX Extensions Symlinks.
+        */
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS)
+               rc = CIFSQueryMFSymLink(xid, tcon, full_path, &target_path,
+                                       cifs_sb->local_nls,
+                                       cifs_sb->mnt_cifs_flags &
+                                               CIFS_MOUNT_MAP_SPECIAL_CHR);
+
+       if ((rc != 0) && (tcon->ses->capabilities & CAP_UNIX))
+               rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, &target_path,
+                                            cifs_sb->local_nls);
+
        kfree(full_path);
 out:
        if (rc != 0) {
@@ -459,7 +473,12 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
        cFYI(1, "symname is %s", symname);
 
        /* BB what if DFS and this volume is on different share? BB */
-       if (pTcon->unix_ext)
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS)
+               rc = CIFSCreateMFSymLink(xid, pTcon, full_path, symname,
+                                        cifs_sb->local_nls,
+                                        cifs_sb->mnt_cifs_flags &
+                                               CIFS_MOUNT_MAP_SPECIAL_CHR);
+       else if (pTcon->unix_ext)
                rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname,
                                           cifs_sb->local_nls);
        /* else
index d5e591fab4753bf48bde4e9d7883f1051d2dc280..6a8b417babab8721bb5f1b4fd4e63ab8172af3bd 100644 (file)
@@ -738,6 +738,15 @@ static int cifs_filldir(char *pfindEntry, struct file *file, filldir_t filldir,
                cifs_autodisable_serverino(cifs_sb);
        }
 
+       if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) &&
+           CIFSCouldBeMFSymlink(&fattr))
+               /*
+                * trying to get the type and mode can be slow,
+                * so just call those regular files for now, and mark
+                * for reval
+                */
+               fattr.cf_flags |= CIFS_FATTR_NEED_REVAL;
+
        ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid);
        tmp_dentry = cifs_readdir_lookup(file->f_dentry, &qstring, &fattr);