[2/2,SMB3] Add mfsymlinks support for SMB2.1/SMB3. Part 2 query symlink
diff mbox

Message ID CAH2r5muC3a2Cb_8t1nFJDRsyf27q2T4jbddZ2vADBhAStSm0CQ@mail.gmail.com
State New, archived
Headers show

Commit Message

Steve French Sept. 16, 2014, 6:05 a.m. UTC
Updated version of th3 final patch in series attached (which adds
query symlink support for smb2.1/smb3).  Makes minor correction to
error handling (SMB2_close call was in wrong place in some error
cases)



On Mon, Sep 15, 2014 at 6:39 PM, Steve French <smfrench@gmail.com> wrote:
>     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).
>
>     Signed-off-by: Steve French <smfrench@gmail.com>
>     CC: Stefan Metzmacher <metze@samba.org>
> ---
>  fs/cifs/link.c      | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++
>  fs/cifs/smb2ops.c   |  2 ++
>  fs/cifs/smb2proto.h |  4 ++++
>  3 files changed, 71 insertions(+)
>
> diff --git a/fs/cifs/link.c b/fs/cifs/link.c
> index 11657f6..cf1113e 100644
> --- a/fs/cifs/link.c
> +++ b/fs/cifs/link.c
> @@ -399,6 +399,71 @@ cifs_create_mf_symlink(unsigned int xid, struct
> cifs_tcon *tcon,
>      return rc;
>  }
>
> +/*
> + * SMB 2.1/SMB3 Protocol specific functions
> + */
> +
> +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) {
> +        rc = -ENOMEM;
> +        goto qmf_out;
> +    }
> +
> +    rc = SMB2_open(xid, &oparms, utf16_path, &oplock, pfile_info, NULL);
> +    if (rc)
> +        goto qmf_out;
> +
> +    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:
> +    kfree(utf16_path);
> +    kfree(pfile_info);
> +    SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
> +    return rc;
> +}
> +
>  int
>  smb3_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
>                 struct cifs_sb_info *cifs_sb, const unsigned char *path,
> diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
> index 7d3fa29..489f48b 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 e144ecf..79dc650 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);
> --
>
> --
> Thanks,
>
> Steve

Patch
diff mbox

From d4493f4e3c86aabf9c94717f87763d13ec431394 Mon Sep 17 00:00:00 2001
From: Steve French <smfrench@gmail.com>
Date: Tue, 16 Sep 2014 00:58:26 -0500
Subject: [PATCH] [SMB3] 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).  Second version of patch makes minor correction
    to error handling.

    Signed-off-by: Steve French <smfrench@gmail.com>
    CC: Stefan Metzmacher <metze@samba.org>
---
 fs/cifs/link.c      | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/cifs/smb2ops.c   |  2 ++
 fs/cifs/smb2proto.h |  4 ++++
 3 files changed, 71 insertions(+)

diff --git a/fs/cifs/link.c b/fs/cifs/link.c
index 11657f6..de3dad8 100644
--- a/fs/cifs/link.c
+++ b/fs/cifs/link.c
@@ -399,6 +399,71 @@  cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
 	return rc;
 }
 
+/*
+ * SMB 2.1/SMB3 Protocol specific functions
+ */
+
+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) {
+		rc = -ENOMEM;
+		goto qmf_out;
+	}
+
+	rc = SMB2_open(xid, &oparms, utf16_path, &oplock, pfile_info, NULL);
+	if (rc)
+		goto qmf_out;
+
+	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);
+	SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
+qmf_out:
+	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,
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 7d3fa29..489f48b 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 e144ecf..79dc650 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);
-- 
1.9.1