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>
This commit is contained in:
parent
8713d01db8
commit
1b12b9c15b
|
@ -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,
|
||||||
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,
|
||||||
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)
|
||||||
* 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)
|
||||||
|
|
||||||
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)
|
||||||
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,
|
||||||
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);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue