[PATCH 2/2] fs/ntfs3: keep PrintName not changed when creating symlink

From: Zhenyan Wang

Date: Sun Sep 27 2026 - 14:08:28 EST


When creating a symlink, ntfs3 converts all the '/' to '\' in both
PrintName and SubstituteName.

When reading this symlink, ntfs3 converts all the '\' to '/'. So if you
create a symlink to 'a\b', the result of readlink would be 'a/b'.

Fix this by converting SubstituteName only because SubstituteName is
used by NT kernel to read symlink while PrintName isn't; PrintName is
left unchanged to ensure consistency.

Signed-off-by: Zhenyan Wang <maximwang110@xxxxxxxxx>
---
fs/ntfs3/inode.c | 22 +++++++++-------------
1 file changed, 9 insertions(+), 13 deletions(-)

diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c
index 6717563..000ac34 100644
--- a/fs/ntfs3/inode.c
+++ b/fs/ntfs3/inode.c
@@ -1091,6 +1091,7 @@ ntfs_create_reparse_buffer(struct ntfs_sb_info *sbi, const char *symname,
int i, err;
struct REPARSE_DATA_BUFFER *rp;
__le16 *rp_name;
+ __le16 *sub_name;
typeof(rp->SymbolicLinkReparseBuffer) *rs;
bool is_absolute;

@@ -1118,12 +1119,6 @@ ntfs_create_reparse_buffer(struct ntfs_sb_info *sbi, const char *symname,
goto out;
}

- /* Translate Linux '/' into Windows '\'. */
- for (i = 0; i < err; i++) {
- if (rp_name[i] == cpu_to_le16('/'))
- rp_name[i] = cpu_to_le16('\\');
- }
-
rp->ReparseTag = IO_REPARSE_TAG_SYMLINK;
rp->ReparseDataLength =
cpu_to_le16(*nsize - offsetof(struct REPARSE_DATA_BUFFER,
@@ -1142,9 +1137,16 @@ ntfs_create_reparse_buffer(struct ntfs_sb_info *sbi, const char *symname,
*/
rs->Flags = cpu_to_le32(is_absolute ? 0 : SYMLINK_FLAG_RELATIVE);

- memmove(rp_name + err + (is_absolute ? 4 : 0), rp_name,
+ sub_name = rp_name + err + (is_absolute ? 4 : 0);
+ memmove(sub_name, rp_name,
sizeof(short) * err);

+ /* Translate Linux '/' into Windows '\'. */
+ for (i = 0; i < err; i++) {
+ if (sub_name[i] == cpu_to_le16('/'))
+ sub_name[i] = cpu_to_le16('\\');
+ }
+
if (is_absolute) {
/* Decorate SubstituteName. */
rp_name += err;
@@ -2031,12 +2033,6 @@ static noinline int ntfs_readlink_hlp(const struct dentry *link_de,
if (err < 0)
goto out;

- /* Translate Windows '\' into Linux '/'. */
- for (i = 0; i < err; i++) {
- if (buffer[i] == '\\')
- buffer[i] = '/';
- }
-
/* Always set last zero. */
buffer[err] = 0;

--
2.53.0