fs/ntfs3: correctly create symlink for relative path

[ Upstream commit b1e9d89408 ]

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>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
Rong Zhang 2025-05-07 15:35:34 +08:00 committed by Greg Kroah-Hartman
parent 3572737a76
commit 6c7fadac6c

View File

@ -1130,10 +1130,10 @@ int inode_write_data(struct inode *inode, const 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);
}
@ -1146,8 +1146,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);
@ -1162,7 +1165,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;
@ -1182,7 +1185,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;
/*
@ -1190,16 +1193,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: