summaryrefslogtreecommitdiff
path: root/fs/cifs
diff options
context:
space:
mode:
authorSteve French <smfrench@gmail.com>2014-09-16 16:18:19 +0400
committerSteve French <smfrench@gmail.com>2014-10-17 00:20:20 +0400
commitc22870ea2deb2841402133909cfa707a2c0b12ed (patch)
tree99a15884a9be669408c166a997b55944b5504388 /fs/cifs
parent5ab97578cbb3bf9a28dec4534cb86fbc35e600bb (diff)
downloadlinux-c22870ea2deb2841402133909cfa707a2c0b12ed.tar.xz
mfsymlinks support for SMB2.1/SMB3. Part 2 query symlink
Adds support on SMB2.1 and SMB3 mounts for emulation of symlinks via the "Minshall/French" symlink format already used for cifs mounts when mfsymlinks mount option is used (and also used by Apple). http://wiki.samba.org/index.php/UNIX_Extensions#Minshall.2BFrench_symlinks This second patch adds support to query them (recognize them as symlinks and read them). Third version of patch makes minor corrections to error handling. Signed-off-by: Steve French <smfrench@gmail.com> Reviewed-by: Stefan Metzmacher <metze@samba.org>
Diffstat (limited to 'fs/cifs')
-rw-r--r--fs/cifs/link.c70
-rw-r--r--fs/cifs/smb2ops.c2
-rw-r--r--fs/cifs/smb2proto.h4
3 files changed, 75 insertions, 1 deletions
diff --git a/fs/cifs/link.c b/fs/cifs/link.c
index 1216f4f1c6c9..ce7d4bbf3120 100644
--- a/fs/cifs/link.c
+++ b/fs/cifs/link.c
@@ -28,7 +28,9 @@
#include "cifsproto.h"
#include "cifs_debug.h"
#include "cifs_fs_sb.h"
+#ifdef CONFIG_CIFS_SMB2
#include "smb2proto.h"
+#endif
/*
* M-F Symlink Functions - Begin
@@ -401,6 +403,72 @@ cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
return rc;
}
+/*
+ * SMB 2.1/SMB3 Protocol specific functions
+ */
+#ifdef CONFIG_CIFS_SMB2
+int
+smb3_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
+ struct cifs_sb_info *cifs_sb, const unsigned char *path,
+ char *pbuf, unsigned int *pbytes_read)
+{
+ int rc;
+ struct cifs_fid fid;
+ struct cifs_open_parms oparms;
+ struct cifs_io_parms io_parms;
+ int buf_type = CIFS_NO_BUFFER;
+ __le16 *utf16_path;
+ __u8 oplock = SMB2_OPLOCK_LEVEL_II;
+ struct smb2_file_all_info *pfile_info = NULL;
+
+ oparms.tcon = tcon;
+ oparms.cifs_sb = cifs_sb;
+ oparms.desired_access = GENERIC_READ;
+ oparms.create_options = CREATE_NOT_DIR;
+ if (backup_cred(cifs_sb))
+ oparms.create_options |= CREATE_OPEN_BACKUP_INTENT;
+ oparms.disposition = FILE_OPEN;
+ oparms.fid = &fid;
+ oparms.reconnect = false;
+
+ utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
+ if (utf16_path == NULL)
+ return -ENOMEM;
+
+ pfile_info = kzalloc(sizeof(struct smb2_file_all_info) + PATH_MAX * 2,
+ GFP_KERNEL);
+
+ if (pfile_info == NULL) {
+ kfree(utf16_path);
+ return -ENOMEM;
+ }
+
+ rc = SMB2_open(xid, &oparms, utf16_path, &oplock, pfile_info, NULL);
+ if (rc)
+ goto qmf_out_open_fail;
+
+ if (pfile_info->EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) {
+ /* it's not a symlink */
+ rc = -ENOENT; /* Is there a better rc to return? */
+ goto qmf_out;
+ }
+
+ io_parms.netfid = fid.netfid;
+ io_parms.pid = current->tgid;
+ io_parms.tcon = tcon;
+ io_parms.offset = 0;
+ io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE;
+ io_parms.persistent_fid = fid.persistent_fid;
+ io_parms.volatile_fid = fid.volatile_fid;
+ rc = SMB2_read(xid, &io_parms, pbytes_read, &pbuf, &buf_type);
+qmf_out:
+ SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
+qmf_out_open_fail:
+ kfree(utf16_path);
+ kfree(pfile_info);
+ return rc;
+}
+
int
smb3_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb, const unsigned char *path,
@@ -461,7 +529,7 @@ smb3_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
kfree(utf16_path);
return rc;
}
-
+#endif /* CONFIG_CIFS_SMB2 */
/*
* M-F Symlink Functions - End
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 5e35d51504fd..af446866cbe8 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -1452,6 +1452,7 @@ struct smb_version_operations smb21_operations = {
.rename = smb2_rename_path,
.create_hardlink = smb2_create_hardlink,
.query_symlink = smb2_query_symlink,
+ .query_mf_symlink = smb3_query_mf_symlink,
.create_mf_symlink = smb3_create_mf_symlink,
.open = smb2_open_file,
.set_fid = smb2_set_fid,
@@ -1532,6 +1533,7 @@ struct smb_version_operations smb30_operations = {
.rename = smb2_rename_path,
.create_hardlink = smb2_create_hardlink,
.query_symlink = smb2_query_symlink,
+ .query_mf_symlink = smb3_query_mf_symlink,
.create_mf_symlink = smb3_create_mf_symlink,
.open = smb2_open_file,
.set_fid = smb2_set_fid,
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index e144ecfaa797..79dc650c18b2 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -85,6 +85,10 @@ extern int smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
extern int smb3_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb, const unsigned char *path,
char *pbuf, unsigned int *pbytes_written);
+extern int smb3_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
+ struct cifs_sb_info *cifs_sb,
+ const unsigned char *path, char *pbuf,
+ unsigned int *pbytes_read);
extern int smb2_open_file(const unsigned int xid,
struct cifs_open_parms *oparms,
__u32 *oplock, FILE_ALL_INFO *buf);