aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/fs/smb/client/reparse.c
diff options
context:
space:
mode:
authorPali Rohár <pali@kernel.org>2024-10-11 11:20:56 +0200
committerSteve French <stfrench@microsoft.com>2025-01-29 17:35:32 -0600
commit660618dde2b4c372132a6be62f11ab68a0a1571a (patch)
tree610a746e53bdd628603bac5c51b741dc539fe1cb /fs/smb/client/reparse.c
parentcifs: Fix creating and resolving absolute NT-style symlinks (diff)
downloadwireguard-linux-660618dde2b4c372132a6be62f11ab68a0a1571a.tar.xz
wireguard-linux-660618dde2b4c372132a6be62f11ab68a0a1571a.zip
cifs: Add mount option -o symlink= for choosing symlink create type
Currently Linux CIFS client creates a new symlink of the first flavor which is allowed by mount options, parsed in this order: -o (no)mfsymlinks, -o (no)sfu, -o (no)unix (+ its aliases) and -o reparse=[type]. Introduce a new mount option -o symlink= for explicitly choosing a symlink flavor. Possible options are: -o symlink=default - The default behavior, like before this change. -o symlink=none - Disallow creating a new symlinks -o symlink=native - Create as native SMB symlink reparse point -o symlink=unix - Create via SMB1 unix extension command -o symlink=mfsymlinks - Create as regular file of mfsymlinks format -o symlink=sfu - Create as regular system file of SFU format -o symlink=nfs - Create as NFS reparse point -o symlink=wsl - Create as WSL reparse point So for example specifying -o sfu,mfsymlinks,symlink=native will allow to parse symlinks also of SFU and mfsymlinks types (which are disabled by default unless mount option is explicitly specified), but new symlinks will be created under native SMB type (which parsing is always enabled). Signed-off-by: Pali Rohár <pali@kernel.org> Signed-off-by: Steve French <stfrench@microsoft.com>
Diffstat (limited to 'fs/smb/client/reparse.c')
-rw-r--r--fs/smb/client/reparse.c52
1 files changed, 42 insertions, 10 deletions
diff --git a/fs/smb/client/reparse.c b/fs/smb/client/reparse.c
index 344371dd895c..24a5f563df26 100644
--- a/fs/smb/client/reparse.c
+++ b/fs/smb/client/reparse.c
@@ -14,6 +14,20 @@
#include "fs_context.h"
#include "reparse.h"
+static int mknod_nfs(unsigned int xid, struct inode *inode,
+ struct dentry *dentry, struct cifs_tcon *tcon,
+ const char *full_path, umode_t mode, dev_t dev,
+ const char *symname);
+
+static int mknod_wsl(unsigned int xid, struct inode *inode,
+ struct dentry *dentry, struct cifs_tcon *tcon,
+ const char *full_path, umode_t mode, dev_t dev,
+ const char *symname);
+
+static int create_native_symlink(const unsigned int xid, struct inode *inode,
+ struct dentry *dentry, struct cifs_tcon *tcon,
+ const char *full_path, const char *symname);
+
static int detect_directory_symlink_target(struct cifs_sb_info *cifs_sb,
const unsigned int xid,
const char *full_path,
@@ -24,6 +38,22 @@ int smb2_create_reparse_symlink(const unsigned int xid, struct inode *inode,
struct dentry *dentry, struct cifs_tcon *tcon,
const char *full_path, const char *symname)
{
+ switch (get_cifs_symlink_type(CIFS_SB(inode->i_sb))) {
+ case CIFS_SYMLINK_TYPE_NATIVE:
+ return create_native_symlink(xid, inode, dentry, tcon, full_path, symname);
+ case CIFS_SYMLINK_TYPE_NFS:
+ return mknod_nfs(xid, inode, dentry, tcon, full_path, S_IFLNK, 0, symname);
+ case CIFS_SYMLINK_TYPE_WSL:
+ return mknod_wsl(xid, inode, dentry, tcon, full_path, S_IFLNK, 0, symname);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int create_native_symlink(const unsigned int xid, struct inode *inode,
+ struct dentry *dentry, struct cifs_tcon *tcon,
+ const char *full_path, const char *symname)
+{
struct reparse_symlink_data_buffer *buf = NULL;
struct cifs_open_info_data data = {};
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
@@ -366,6 +396,7 @@ static int nfs_set_reparse_buf(struct reparse_nfs_data_buffer *buf,
case NFS_SPECFILE_SOCK:
dlen = 0;
break;
+ case NFS_SPECFILE_LNK: /* TODO: add support for NFS symlinks */
default:
return -EOPNOTSUPP;
}
@@ -384,7 +415,8 @@ static int nfs_set_reparse_buf(struct reparse_nfs_data_buffer *buf,
static int mknod_nfs(unsigned int xid, struct inode *inode,
struct dentry *dentry, struct cifs_tcon *tcon,
- const char *full_path, umode_t mode, dev_t dev)
+ const char *full_path, umode_t mode, dev_t dev,
+ const char *symname)
{
struct cifs_open_info_data data;
struct reparse_nfs_data_buffer *p;
@@ -424,6 +456,7 @@ static int wsl_set_reparse_buf(struct reparse_data_buffer *buf,
case IO_REPARSE_TAG_LX_FIFO:
case IO_REPARSE_TAG_AF_UNIX:
break;
+ case IO_REPARSE_TAG_LX_SYMLINK: /* TODO: add support for WSL symlinks */
default:
return -EOPNOTSUPP;
}
@@ -521,7 +554,8 @@ static int wsl_set_xattrs(struct inode *inode, umode_t _mode,
static int mknod_wsl(unsigned int xid, struct inode *inode,
struct dentry *dentry, struct cifs_tcon *tcon,
- const char *full_path, umode_t mode, dev_t dev)
+ const char *full_path, umode_t mode, dev_t dev,
+ const char *symname)
{
struct cifs_open_info_data data;
struct reparse_data_buffer buf;
@@ -566,17 +600,15 @@ int smb2_mknod_reparse(unsigned int xid, struct inode *inode,
const char *full_path, umode_t mode, dev_t dev)
{
struct smb3_fs_context *ctx = CIFS_SB(inode->i_sb)->ctx;
- int rc = -EOPNOTSUPP;
switch (ctx->reparse_type) {
case CIFS_REPARSE_TYPE_NFS:
- rc = mknod_nfs(xid, inode, dentry, tcon, full_path, mode, dev);
- break;
+ return mknod_nfs(xid, inode, dentry, tcon, full_path, mode, dev, NULL);
case CIFS_REPARSE_TYPE_WSL:
- rc = mknod_wsl(xid, inode, dentry, tcon, full_path, mode, dev);
- break;
+ return mknod_wsl(xid, inode, dentry, tcon, full_path, mode, dev, NULL);
+ default:
+ return -EOPNOTSUPP;
}
- return rc;
}
/* See MS-FSCC 2.1.2.6 for the 'NFS' style reparse tags */
@@ -849,7 +881,7 @@ out:
return rc;
}
-static int parse_reparse_symlink(struct reparse_symlink_data_buffer *sym,
+static int parse_reparse_native_symlink(struct reparse_symlink_data_buffer *sym,
u32 plen,
struct cifs_sb_info *cifs_sb,
const char *full_path,
@@ -936,7 +968,7 @@ int parse_reparse_point(struct reparse_data_buffer *buf,
return parse_reparse_nfs((struct reparse_nfs_data_buffer *)buf,
cifs_sb, data);
case IO_REPARSE_TAG_SYMLINK:
- return parse_reparse_symlink(
+ return parse_reparse_native_symlink(
(struct reparse_symlink_data_buffer *)buf,
plen, cifs_sb, full_path, data);
case IO_REPARSE_TAG_LX_SYMLINK: