]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
fs/ntfs3: correctly create symlink for relative path
authorRong Zhang <ulin0208@gmail.com>
Wed, 7 May 2025 07:35:34 +0000 (15:35 +0800)
committerKonstantin Komarov <almaz.alexandrovich@paragon-software.com>
Mon, 23 Jun 2025 17:23:02 +0000 (19:23 +0200)
After applying this patch, could correctly create symlink:

ln -s "relative/path/to/file" symlink

Signed-off-by: Rong Zhang <ulin0208@gmail.com>
[almaz.alexandrovich@paragon-software.com: added cpu_to_le32 macro to
rs->Flags assignment]
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
fs/ntfs3/inode.c

index 0a653ee7fe089d1f9b2eed47d8ace60f96359207..8bfe354776544b4f7f96a0fbc07fe7ffac81da05 100644 (file)
@@ -1062,10 +1062,10 @@ int inode_read_data(struct inode *inode, void *data, size_t bytes)
  * Number of bytes for REPARSE_DATA_BUFFER(IO_REPARSE_TAG_SYMLINK)
  * for unicode string of @uni_len length.
  */
-static inline u32 ntfs_reparse_bytes(u32 uni_len)
+static inline u32 ntfs_reparse_bytes(u32 uni_len, bool is_absolute)
 {
        /* Header + unicode string + decorated unicode string. */
-       return sizeof(short) * (2 * uni_len + 4) +
+       return sizeof(short) * (2 * uni_len + (is_absolute ? 4 : 0)) +
               offsetof(struct REPARSE_DATA_BUFFER,
                        SymbolicLinkReparseBuffer.PathBuffer);
 }
@@ -1078,8 +1078,11 @@ ntfs_create_reparse_buffer(struct ntfs_sb_info *sbi, const char *symname,
        struct REPARSE_DATA_BUFFER *rp;
        __le16 *rp_name;
        typeof(rp->SymbolicLinkReparseBuffer) *rs;
+       bool is_absolute;
 
-       rp = kzalloc(ntfs_reparse_bytes(2 * size + 2), GFP_NOFS);
+       is_absolute = (strlen(symname) > 1 && symname[1] == ':');
+
+       rp = kzalloc(ntfs_reparse_bytes(2 * size + 2, is_absolute), GFP_NOFS);
        if (!rp)
                return ERR_PTR(-ENOMEM);
 
@@ -1094,7 +1097,7 @@ ntfs_create_reparse_buffer(struct ntfs_sb_info *sbi, const char *symname,
                goto out;
 
        /* err = the length of unicode name of symlink. */
-       *nsize = ntfs_reparse_bytes(err);
+       *nsize = ntfs_reparse_bytes(err, is_absolute);
 
        if (*nsize > sbi->reparse.max_size) {
                err = -EFBIG;
@@ -1114,7 +1117,7 @@ ntfs_create_reparse_buffer(struct ntfs_sb_info *sbi, const char *symname,
 
        /* PrintName + SubstituteName. */
        rs->SubstituteNameOffset = cpu_to_le16(sizeof(short) * err);
-       rs->SubstituteNameLength = cpu_to_le16(sizeof(short) * err + 8);
+       rs->SubstituteNameLength = cpu_to_le16(sizeof(short) * err + (is_absolute ? 8 : 0));
        rs->PrintNameLength = rs->SubstituteNameOffset;
 
        /*
@@ -1122,16 +1125,18 @@ ntfs_create_reparse_buffer(struct ntfs_sb_info *sbi, const char *symname,
         * parse this path.
         * 0-absolute path 1- relative path (SYMLINK_FLAG_RELATIVE).
         */
-       rs->Flags = 0;
+       rs->Flags = cpu_to_le32(is_absolute ? 0 : SYMLINK_FLAG_RELATIVE);
 
-       memmove(rp_name + err + 4, rp_name, sizeof(short) * err);
+       memmove(rp_name + err + (is_absolute ? 4 : 0), rp_name, sizeof(short) * err);
 
-       /* Decorate SubstituteName. */
-       rp_name += err;
-       rp_name[0] = cpu_to_le16('\\');
-       rp_name[1] = cpu_to_le16('?');
-       rp_name[2] = cpu_to_le16('?');
-       rp_name[3] = cpu_to_le16('\\');
+       if (is_absolute) {
+               /* Decorate SubstituteName. */
+               rp_name += err;
+               rp_name[0] = cpu_to_le16('\\');
+               rp_name[1] = cpu_to_le16('?');
+               rp_name[2] = cpu_to_le16('?');
+               rp_name[3] = cpu_to_le16('\\');
+       }
 
        return rp;
 out: