summaryrefslogtreecommitdiff
path: root/fs/smb/client/link.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/smb/client/link.c')
-rw-r--r--fs/smb/client/link.c67
1 files changed, 52 insertions, 15 deletions
diff --git a/fs/smb/client/link.c b/fs/smb/client/link.c
index d86da949a919..769752ad2c5c 100644
--- a/fs/smb/client/link.c
+++ b/fs/smb/client/link.c
@@ -18,6 +18,7 @@
#include "cifs_unicode.h"
#include "smb2proto.h"
#include "cifs_ioctl.h"
+#include "fs_context.h"
/*
* M-F Symlink Functions - Begin
@@ -257,7 +258,7 @@ cifs_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
struct cifs_open_parms oparms;
struct cifs_io_parms io_parms = {0};
int buf_type = CIFS_NO_BUFFER;
- FILE_ALL_INFO file_info;
+ struct cifs_open_info_data query_data;
oparms = (struct cifs_open_parms) {
.tcon = tcon,
@@ -269,11 +270,11 @@ cifs_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
.fid = &fid,
};
- rc = CIFS_open(xid, &oparms, &oplock, &file_info);
+ rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, &query_data);
if (rc)
return rc;
- if (file_info.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) {
+ if (query_data.fi.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) {
rc = -ENOENT;
/* it's not a symlink */
goto out;
@@ -312,7 +313,7 @@ cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
.fid = &fid,
};
- rc = CIFS_open(xid, &oparms, &oplock, NULL);
+ rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, NULL);
if (rc)
return rc;
@@ -588,6 +589,7 @@ cifs_symlink(struct mnt_idmap *idmap, struct inode *inode,
tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink)) {
rc = PTR_ERR(tlink);
+ /* BB could be clearer if skipped put_tlink on error here, but harmless */
goto symlink_exit;
}
pTcon = tlink_tcon(tlink);
@@ -603,19 +605,54 @@ cifs_symlink(struct mnt_idmap *idmap, struct inode *inode,
cifs_dbg(FYI, "symname is %s\n", symname);
/* BB what if DFS and this volume is on different share? BB */
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
- rc = create_mf_symlink(xid, pTcon, cifs_sb, full_path, symname);
+ rc = -EOPNOTSUPP;
+ switch (get_cifs_symlink_type(cifs_sb)) {
+ case CIFS_SYMLINK_TYPE_DEFAULT:
+ /* should not happen, get_cifs_symlink_type() resolves the default */
+ break;
+
+ case CIFS_SYMLINK_TYPE_NONE:
+ break;
+
+ case CIFS_SYMLINK_TYPE_UNIX:
#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
- } else if (pTcon->unix_ext) {
- rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname,
- cifs_sb->local_nls,
- cifs_remap(cifs_sb));
+ if (pTcon->unix_ext) {
+ rc = CIFSUnixCreateSymLink(xid, pTcon, full_path,
+ symname,
+ cifs_sb->local_nls,
+ cifs_remap(cifs_sb));
+ }
#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
- } else if (server->ops->create_reparse_symlink) {
- rc = server->ops->create_reparse_symlink(xid, inode, direntry,
- pTcon, full_path,
- symname);
- goto symlink_exit;
+ break;
+
+ case CIFS_SYMLINK_TYPE_MFSYMLINKS:
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
+ rc = create_mf_symlink(xid, pTcon, cifs_sb,
+ full_path, symname);
+ }
+ break;
+
+ case CIFS_SYMLINK_TYPE_SFU:
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
+ rc = __cifs_sfu_make_node(xid, inode, direntry, pTcon,
+ full_path, S_IFLNK,
+ 0, symname);
+ }
+ break;
+
+ case CIFS_SYMLINK_TYPE_NATIVE:
+ case CIFS_SYMLINK_TYPE_NFS:
+ case CIFS_SYMLINK_TYPE_WSL:
+ if (server->ops->create_reparse_symlink &&
+ (le32_to_cpu(pTcon->fsAttrInfo.Attributes) & FILE_SUPPORTS_REPARSE_POINTS)) {
+ rc = server->ops->create_reparse_symlink(xid, inode,
+ direntry,
+ pTcon,
+ full_path,
+ symname);
+ goto symlink_exit;
+ }
+ break;
}
if (rc == 0) {