[PATCH][WIP] query smb3 reparse tags for special files

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



WSL defines special files with various reparse tags

smbfsctl.h:#define IO_REPARSE_TAG_LX_SYMLINK    0xA000001D
smbfsctl.h:#define IO_REPARSE_TAG_LX_FIFO            0x80000024
smbfsctl.h:#define IO_REPARSE_TAG_LX_CHR             0x80000025
smbfsctl.h:#define IO_REPARSE_TAG_LX_BLK             0x80000026

These also make sense for us to use more broadly because it simplifies readdir

but ... my first attempt at querying this using infolevel 33
FileReparsePointInformation (see MS-FSCC section 2.4.35) failed ...
with Windows 10 returning STATUS_NOT_SUPPORTED when querying various
reparse points (created by WSL indirectly) including fifos, symlinks
and char devices.

I can switch approaches and try to do the smb3 fsctl to query reparse
info instead but was hoping that query info would work.  Any idea if
there is another info level that would allow me to query the tag?

In any case, here is the WIP first stage of the patch - I have to add
a second patch to add the fsctl query




-- 
Thanks,

Steve
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index b6925aeeb621..484ec2d8c5c9 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -298,6 +298,10 @@ struct smb_version_operations {
 	/* query file data from the server */
 	int (*query_file_info)(const unsigned int, struct cifs_tcon *,
 			       struct cifs_fid *, FILE_ALL_INFO *);
+	/* query reparse tag from srv to determine which type of special file */
+	int (*query_reparse_tag)(const unsigned int xid, struct cifs_tcon *tcon,
+				struct cifs_sb_info *cifs_sb, const char *path,
+				__u32 *reparse_tag);
 	/* get server index number */
 	int (*get_srv_inum)(const unsigned int, struct cifs_tcon *,
 			    struct cifs_sb_info *, const char *,
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index daec31be8571..fe20643450a1 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -916,6 +916,7 @@ cifs_get_inode_info(struct inode **inode,
 	void *smb1_backup_rsp_buf = NULL;
 	int rc = 0;
 	int tmprc = 0;
+	__u32 reparse_tag = 0;
 
 	tlink = cifs_sb_tlink(cifs_sb);
 	if (IS_ERR(tlink))
@@ -941,6 +942,16 @@ cifs_get_inode_info(struct inode **inode,
 						  full_path, tmp_data,
 						  &adjust_tz, &symlink);
 		data = tmp_data;
+
+		/*
+		 * If the file is a reparse point, it is more complicated
+		 * since we have to check if its reparse tag matches a known
+		 * special file type e.g. symlink or fifo or char etc.
+		 */
+		if ((le32_to_cpu(data->Attributes) & ATTR_REPARSE) &&
+		    (server->ops->query_reparse_tag))
+			rc = server->ops->query_reparse_tag(xid, tcon, cifs_sb,
+						full_path, &reparse_tag);
 	}
 
 	/*
diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c
index df6212e55e10..109ec166aa6a 100644
--- a/fs/cifs/smb2inode.c
+++ b/fs/cifs/smb2inode.c
@@ -503,10 +503,26 @@ move_smb2_info_to_cifs(FILE_ALL_INFO *dst, struct smb2_file_all_info *src)
 	dst->IndexNumber1 = 0; /* we don't use it */
 }
 
+/* query reparse tag from srv to determine which type of special file */
+int smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon,
+		struct cifs_sb_info *cifs_sb, const char *path, __u32 *tag)
+{
+	int rc = 0;
+	__u32 create_options = OPEN_REPARSE_POINT;
+	struct cifsFileInfo *cfile;
+
+	cifs_get_readable_path(tcon, path, &cfile);
+
+		/* TODO update below */
+	/* rc = smb2_fsctl_get_tag(xid, tcon, cifs_sb, path,... */
+
+	return rc;
+}
+
 int
 smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
 		     struct cifs_sb_info *cifs_sb, const char *full_path,
-		     FILE_ALL_INFO *data, bool *adjust_tz, bool *symlink)
+		     FILE_ALL_INFO *data, bool *adjust_tz, bool *reparse)
 {
 	int rc;
 	struct smb2_file_all_info *smb2_data;
@@ -516,7 +532,7 @@ smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
 	struct cached_fid *cfid = NULL;
 
 	*adjust_tz = false;
-	*symlink = false;
+	*reparse = false;
 
 	smb2_data = kzalloc(sizeof(struct smb2_file_all_info) + PATH_MAX * 2,
 			    GFP_KERNEL);
@@ -548,7 +564,7 @@ smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
 			      FILE_READ_ATTRIBUTES, FILE_OPEN, create_options,
 			      ACL_NO_MODE, smb2_data, SMB2_OP_QUERY_INFO, cfile);
 	if (rc == -EOPNOTSUPP) {
-		*symlink = true;
+		*reparse = true;
 		create_options |= OPEN_REPARSE_POINT;
 
 		/* Failed on a symbolic link - query a reparse point info */
@@ -570,7 +586,7 @@ smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
 int
 smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
 		     struct cifs_sb_info *cifs_sb, const char *full_path,
-		     struct smb311_posix_qinfo *data, bool *adjust_tz, bool *symlink)
+		     struct smb311_posix_qinfo *data, bool *adjust_tz, bool *reparse)
 {
 	int rc;
 	__u32 create_options = 0;
@@ -578,7 +594,7 @@ smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
 	struct smb311_posix_qinfo *smb2_data;
 
 	*adjust_tz = false;
-	*symlink = false;
+	*reparse = false;
 
 	/* BB TODO: Make struct larger when add support for parsing owner SIDs */
 	smb2_data = kzalloc(sizeof(struct smb311_posix_qinfo),
@@ -599,7 +615,7 @@ smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
 			      ACL_NO_MODE, smb2_data, SMB2_OP_POSIX_QUERY_INFO, cfile);
 	if (rc == -EOPNOTSUPP) {
 		/* BB TODO: When support for special files added to Samba re-verify this path */
-		*symlink = true;
+		*reparse = true;
 		create_options |= OPEN_REPARSE_POINT;
 
 		/* Failed on a symbolic link - query a reparse point info */
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index 171f54965703..14244d288b80 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -1691,6 +1691,11 @@ struct smb2_file_eof_info { /* encoding of request for level 10 */
 	__le64 EndOfFile; /* new end of file value */
 } __packed; /* level 20 Set */
 
+struct smb2_file_reparse_point_info {
+	__le64 IndexNumber;
+	__le32 Tag;
+} __packed;
+
 struct smb2_file_network_open_info {
 	__le64 CreationTime;
 	__le64 LastAccessTime;
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 67c50d78caa1..d4110447ee3a 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -77,6 +77,9 @@ extern void close_shroot_lease(struct cached_fid *cfid);
 extern void close_shroot_lease_locked(struct cached_fid *cfid);
 extern void move_smb2_info_to_cifs(FILE_ALL_INFO *dst,
 				   struct smb2_file_all_info *src);
+extern int smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon,
+				struct cifs_sb_info *cifs_sb, const char *path,
+				__u32 *reparse_tag);
 extern int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
 				struct cifs_sb_info *cifs_sb,
 				const char *full_path, FILE_ALL_INFO *data,

[Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux