smb: client: introduce ->parse_reparse_point()
authorPaulo Alcantara <pc@manguebit.com>
Tue, 21 Nov 2023 23:12:53 +0000 (20:12 -0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 20 Dec 2023 16:02:00 +0000 (17:02 +0100)
[ Upstream commit 539aad7f14dab7f947e5ab81901c0b20513a50db ]

Parse reparse point into cifs_open_info_data structure and feed it
through cifs_open_info_to_fattr().

Signed-off-by: Paulo Alcantara (SUSE) <pc@manguebit.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
fs/smb/client/cifsglob.h
fs/smb/client/inode.c
fs/smb/client/smb1ops.c
fs/smb/client/smb2ops.c

index b8d1c19..7180b57 100644 (file)
@@ -395,8 +395,7 @@ struct smb_version_operations {
                             struct cifs_tcon *tcon,
                             struct cifs_sb_info *cifs_sb,
                             const char *full_path,
-                            char **target_path,
-                            struct kvec *rsp_iov);
+                            char **target_path);
        /* open a file for non-posix mounts */
        int (*open)(const unsigned int xid, struct cifs_open_parms *oparms, __u32 *oplock,
                    void *buf);
@@ -551,6 +550,9 @@ struct smb_version_operations {
        bool (*is_status_io_timeout)(char *buf);
        /* Check for STATUS_NETWORK_NAME_DELETED */
        bool (*is_network_name_deleted)(char *buf, struct TCP_Server_Info *srv);
+       int (*parse_reparse_point)(struct cifs_sb_info *cifs_sb,
+                                  struct kvec *rsp_iov,
+                                  struct cifs_open_info_data *data);
 };
 
 struct smb_version_values {
index d6aa5e4..7a2a013 100644 (file)
@@ -457,8 +457,7 @@ static int cifs_get_unix_fattr(const unsigned char *full_path,
                        return -EOPNOTSUPP;
                rc = server->ops->query_symlink(xid, tcon,
                                                cifs_sb, full_path,
-                                               &fattr->cf_symlink_target,
-                                               NULL);
+                                               &fattr->cf_symlink_target);
                cifs_dbg(FYI, "%s: query_symlink: %d\n", __func__, rc);
        }
        return rc;
@@ -1035,22 +1034,28 @@ static int reparse_info_to_fattr(struct cifs_open_info_data *data,
                if (!rc)
                        iov = &rsp_iov;
        }
+
+       rc = -EOPNOTSUPP;
        switch ((data->reparse_tag = tag)) {
        case 0: /* SMB1 symlink */
-               iov = NULL;
-               fallthrough;
-       case IO_REPARSE_TAG_NFS:
-       case IO_REPARSE_TAG_SYMLINK:
-               if (!data->symlink_target && server->ops->query_symlink) {
+               if (server->ops->query_symlink) {
                        rc = server->ops->query_symlink(xid, tcon,
                                                        cifs_sb, full_path,
-                                                       &data->symlink_target,
-                                                       iov);
+                                                       &data->symlink_target);
                }
                break;
        case IO_REPARSE_TAG_MOUNT_POINT:
                cifs_create_junction_fattr(fattr, sb);
+               rc = 0;
                goto out;
+       default:
+               if (data->symlink_target) {
+                       rc = 0;
+               } else if (server->ops->parse_reparse_point) {
+                       rc = server->ops->parse_reparse_point(cifs_sb,
+                                                             iov, data);
+               }
+               break;
        }
 
        cifs_open_info_to_fattr(fattr, data, sb);
index 6b4d8ef..0dd5990 100644 (file)
@@ -976,32 +976,36 @@ static int cifs_query_symlink(const unsigned int xid,
                              struct cifs_tcon *tcon,
                              struct cifs_sb_info *cifs_sb,
                              const char *full_path,
-                             char **target_path,
-                             struct kvec *rsp_iov)
+                             char **target_path)
 {
-       struct reparse_data_buffer *buf;
-       TRANSACT_IOCTL_RSP *io = rsp_iov->iov_base;
-       bool unicode = !!(io->hdr.Flags2 & SMBFLG2_UNICODE);
-       u32 plen = le16_to_cpu(io->ByteCount);
        int rc;
 
        cifs_tcon_dbg(FYI, "%s: path=%s\n", __func__, full_path);
 
-       /* Check for unix extensions */
-       if (cap_unix(tcon->ses)) {
-               rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, target_path,
-                                            cifs_sb->local_nls,
-                                            cifs_remap(cifs_sb));
-               if (rc == -EREMOTE)
-                       rc = cifs_unix_dfs_readlink(xid, tcon, full_path,
-                                                   target_path,
-                                                   cifs_sb->local_nls);
-               return rc;
-       }
+       if (!cap_unix(tcon->ses))
+               return -EOPNOTSUPP;
+
+       rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, target_path,
+                                    cifs_sb->local_nls, cifs_remap(cifs_sb));
+       if (rc == -EREMOTE)
+               rc = cifs_unix_dfs_readlink(xid, tcon, full_path,
+                                           target_path, cifs_sb->local_nls);
+       return rc;
+}
+
+static int cifs_parse_reparse_point(struct cifs_sb_info *cifs_sb,
+                                   struct kvec *rsp_iov,
+                                   struct cifs_open_info_data *data)
+{
+       struct reparse_data_buffer *buf;
+       TRANSACT_IOCTL_RSP *io = rsp_iov->iov_base;
+       bool unicode = !!(io->hdr.Flags2 & SMBFLG2_UNICODE);
+       u32 plen = le16_to_cpu(io->ByteCount);
 
        buf = (struct reparse_data_buffer *)((__u8 *)&io->hdr.Protocol +
                                             le32_to_cpu(io->DataOffset));
-       return parse_reparse_point(buf, plen, cifs_sb, unicode, target_path);
+       return parse_reparse_point(buf, plen, cifs_sb, unicode,
+                                  &data->symlink_target);
 }
 
 static bool
@@ -1200,6 +1204,7 @@ struct smb_version_operations smb1_operations = {
        .rename = CIFSSMBRename,
        .create_hardlink = CIFSCreateHardLink,
        .query_symlink = cifs_query_symlink,
+       .parse_reparse_point = cifs_parse_reparse_point,
        .open = cifs_open_file,
        .set_fid = cifs_set_fid,
        .close = cifs_close_file,
index f1966ab..0390d7a 100644 (file)
@@ -2949,6 +2949,12 @@ int parse_reparse_point(struct reparse_data_buffer *buf,
                return parse_reparse_symlink(
                        (struct reparse_symlink_data_buffer *)buf,
                        plen, unicode, target_path, cifs_sb);
+       case IO_REPARSE_TAG_LX_SYMLINK:
+       case IO_REPARSE_TAG_AF_UNIX:
+       case IO_REPARSE_TAG_LX_FIFO:
+       case IO_REPARSE_TAG_LX_CHR:
+       case IO_REPARSE_TAG_LX_BLK:
+               return 0;
        default:
                cifs_dbg(VFS, "srv returned unknown symlink buffer tag:0x%08x\n",
                         le32_to_cpu(buf->ReparseTag));
@@ -2956,22 +2962,18 @@ int parse_reparse_point(struct reparse_data_buffer *buf,
        }
 }
 
-static int smb2_query_symlink(const unsigned int xid,
-                             struct cifs_tcon *tcon,
-                             struct cifs_sb_info *cifs_sb,
-                             const char *full_path,
-                             char **target_path,
-                             struct kvec *rsp_iov)
+static int smb2_parse_reparse_point(struct cifs_sb_info *cifs_sb,
+                                   struct kvec *rsp_iov,
+                                   struct cifs_open_info_data *data)
 {
        struct reparse_data_buffer *buf;
        struct smb2_ioctl_rsp *io = rsp_iov->iov_base;
        u32 plen = le32_to_cpu(io->OutputCount);
 
-       cifs_tcon_dbg(FYI, "%s: path: %s\n", __func__, full_path);
-
        buf = (struct reparse_data_buffer *)((u8 *)io +
                                             le32_to_cpu(io->OutputOffset));
-       return parse_reparse_point(buf, plen, cifs_sb, true, target_path);
+       return parse_reparse_point(buf, plen, cifs_sb,
+                                  true, &data->symlink_target);
 }
 
 static int smb2_query_reparse_point(const unsigned int xid,
@@ -5215,7 +5217,7 @@ struct smb_version_operations smb20_operations = {
        .unlink = smb2_unlink,
        .rename = smb2_rename_path,
        .create_hardlink = smb2_create_hardlink,
-       .query_symlink = smb2_query_symlink,
+       .parse_reparse_point = smb2_parse_reparse_point,
        .query_mf_symlink = smb3_query_mf_symlink,
        .create_mf_symlink = smb3_create_mf_symlink,
        .open = smb2_open_file,
@@ -5317,7 +5319,7 @@ struct smb_version_operations smb21_operations = {
        .unlink = smb2_unlink,
        .rename = smb2_rename_path,
        .create_hardlink = smb2_create_hardlink,
-       .query_symlink = smb2_query_symlink,
+       .parse_reparse_point = smb2_parse_reparse_point,
        .query_mf_symlink = smb3_query_mf_symlink,
        .create_mf_symlink = smb3_create_mf_symlink,
        .open = smb2_open_file,
@@ -5422,7 +5424,7 @@ struct smb_version_operations smb30_operations = {
        .unlink = smb2_unlink,
        .rename = smb2_rename_path,
        .create_hardlink = smb2_create_hardlink,
-       .query_symlink = smb2_query_symlink,
+       .parse_reparse_point = smb2_parse_reparse_point,
        .query_mf_symlink = smb3_query_mf_symlink,
        .create_mf_symlink = smb3_create_mf_symlink,
        .open = smb2_open_file,
@@ -5536,7 +5538,7 @@ struct smb_version_operations smb311_operations = {
        .unlink = smb2_unlink,
        .rename = smb2_rename_path,
        .create_hardlink = smb2_create_hardlink,
-       .query_symlink = smb2_query_symlink,
+       .parse_reparse_point = smb2_parse_reparse_point,
        .query_mf_symlink = smb3_query_mf_symlink,
        .create_mf_symlink = smb3_create_mf_symlink,
        .open = smb2_open_file,