Commit 1b12b9c1 authored by Stefan Metzmacher's avatar Stefan Metzmacher Committed by Steve French

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: default avatarStefan Metzmacher <metze@samba.org>
Signed-off-by: default avatarSteve French <sfrench@us.ibm.com>
parent 8713d01d
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#define CIFS_MOUNT_NOPOSIXBRL 0x2000 /* mandatory not posix byte range lock */ #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_NOSSYNC 0x4000 /* don't do slow SMBflush on every sync*/
#define CIFS_MOUNT_FSCACHE 0x8000 /* local caching enabled */ #define CIFS_MOUNT_FSCACHE 0x8000 /* local caching enabled */
#define CIFS_MOUNT_MF_SYMLINKS 0x10000 /* Minshall+French Symlinks enabled */
struct cifs_sb_info { struct cifs_sb_info {
struct cifsTconInfo *tcon; /* primary mount */ struct cifsTconInfo *tcon; /* primary mount */
......
...@@ -332,6 +332,13 @@ int cifs_get_inode_info_unix(struct inode **pinode, ...@@ -332,6 +332,13 @@ int cifs_get_inode_info_unix(struct inode **pinode,
return rc; 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) { if (*pinode == NULL) {
/* get new inode */ /* get new inode */
cifs_fill_uniqueid(sb, &fattr); cifs_fill_uniqueid(sb, &fattr);
...@@ -661,6 +668,13 @@ int cifs_get_inode_info(struct inode **pinode, ...@@ -661,6 +668,13 @@ int cifs_get_inode_info(struct inode **pinode,
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)
cifs_sfu_mode(&fattr, full_path, cifs_sb, xid); 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) { if (!*pinode) {
*pinode = cifs_iget(sb, &fattr); *pinode = cifs_iget(sb, &fattr);
if (!*pinode) if (!*pinode)
......
...@@ -407,7 +407,8 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd) ...@@ -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 * but there doesn't seem to be any harm in allowing the client to
* read them. * 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; rc = -EACCES;
goto out; goto out;
} }
...@@ -418,8 +419,21 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd) ...@@ -418,8 +419,21 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
cFYI(1, "Full path: %s inode = 0x%p", full_path, inode); cFYI(1, "Full path: %s inode = 0x%p", full_path, inode);
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, rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, &target_path,
cifs_sb->local_nls); cifs_sb->local_nls);
kfree(full_path); kfree(full_path);
out: out:
if (rc != 0) { if (rc != 0) {
...@@ -459,7 +473,12 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) ...@@ -459,7 +473,12 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
cFYI(1, "symname is %s", symname); cFYI(1, "symname is %s", symname);
/* BB what if DFS and this volume is on different share? BB */ /* 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, rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname,
cifs_sb->local_nls); cifs_sb->local_nls);
/* else /* else
......
...@@ -738,6 +738,15 @@ static int cifs_filldir(char *pfindEntry, struct file *file, filldir_t filldir, ...@@ -738,6 +738,15 @@ static int cifs_filldir(char *pfindEntry, struct file *file, filldir_t filldir,
cifs_autodisable_serverino(cifs_sb); 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); ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid);
tmp_dentry = cifs_readdir_lookup(file->f_dentry, &qstring, &fattr); tmp_dentry = cifs_readdir_lookup(file->f_dentry, &qstring, &fattr);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment