mfsymlinks support for SMB2.1/SMB3. Part 2 query symlink
authorSteve French <smfrench@gmail.com>
Tue, 16 Sep 2014 12:18:19 +0000 (07:18 -0500)
committerSteve French <smfrench@gmail.com>
Thu, 16 Oct 2014 20:20:20 +0000 (15:20 -0500)
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>
fs/cifs/link.c
fs/cifs/smb2ops.c
fs/cifs/smb2proto.h

index 1216f4f1c6c9ad783f5b197d7effaffd50b80e09..ce7d4bbf3120a343b8b91e8fc57c68b587b57402 100644 (file)
@@ -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
index 5e35d51504fd086b1dd55f8198b41b992f9dc9b9..af446866cbe845d7632fc7ae9118e3230b9c3176 100644 (file)
@@ -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,
index e144ecfaa797548f9ef8cbcc28eb1a0a30ef3433..79dc650c18b26baf2e9a4ca8ac2c67df5ebdc63e 100644 (file)
@@ -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);