From: Hyunchul Lee Date: Sun, 14 Jun 2026 23:49:55 +0000 (+0900) Subject: ntfs: add native_symlink mount option X-Git-Tag: v7.2-rc1~90^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=115446b06fb725ba04e0f2ae5174029d2c60cad6;p=thirdparty%2Fkernel%2Fstable.git ntfs: add native_symlink mount option Because bind-mounted subtrees of the volume may resolve to unexpected locations, change converting junctions and non-relative symbolic links into paths relative to the NTFS volume to be allowed only if the native_symlink=rel mount option is specified. Add the native_symlink= mount option to configure how absolute symbolic links and mount points (junctions) are handled. The option accepts "raw" or "rel", with "raw" being the default. Under "raw", the absolute target path (ni->target) is returned as-is without translation. Under "rel", ntfs_translate_junction() is called to rewrite the absolute path as a relative path anchored at the volume root. Signed-off-by: Hyunchul Lee Signed-off-by: Namjae Jeon --- diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c index 6b0dfc56577ba..6a7b638e523d9 100644 --- a/fs/ntfs/file.c +++ b/fs/ntfs/file.c @@ -22,6 +22,7 @@ #include "ea.h" #include "iomap.h" #include "bitmap.h" +#include "volume.h" #include @@ -688,12 +689,13 @@ static const char *ntfs_get_link(struct dentry *dentry, struct inode *inode, if (ni->reparse_tag == IO_REPARSE_TAG_MOUNT_POINT || (ni->reparse_tag == IO_REPARSE_TAG_SYMLINK && !(ni->reparse_flags & cpu_to_le32(SYMLINK_FLAG_RELATIVE)))) { - err = ntfs_translate_symlink_path(dentry, ni->target, &target); - if (err < 0) - return ERR_PTR(err); - - set_delayed_call(done, kfree_link, target); - return target; + if (NVolNativeSymlinkRel(ni->vol)) { + err = ntfs_translate_symlink_path(dentry, ni->target, &target); + if (err < 0) + return ERR_PTR(err); + set_delayed_call(done, kfree_link, target); + return target; + } } return ni->target; diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c index 07ca799a8f9a7..76595f2e30ffb 100644 --- a/fs/ntfs/inode.c +++ b/fs/ntfs/inode.c @@ -2378,6 +2378,10 @@ int ntfs_show_options(struct seq_file *sf, struct dentry *root) seq_puts(sf, ",discard"); if (NVolDisableSparse(vol)) seq_puts(sf, ",disable_sparse"); + if (NVolNativeSymlinkRel(vol)) + seq_puts(sf, ",native_symlink=rel"); + else + seq_puts(sf, ",native_symlink=raw"); if (vol->sb->s_flags & SB_POSIXACL) seq_puts(sf, ",acl"); return 0; diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c index ca882e946a22d..e032a247455c2 100644 --- a/fs/ntfs/super.c +++ b/fs/ntfs/super.c @@ -43,6 +43,17 @@ static const struct constant_table ntfs_param_enums[] = { {} }; +enum { + NATIVE_SYMLINK_RAW, + NATIVE_SYMLINK_REL, +}; + +static const struct constant_table ntfs_native_symlink_enums[] = { + { "raw", NATIVE_SYMLINK_RAW }, + { "rel", NATIVE_SYMLINK_REL }, + {} +}; + enum { Opt_uid, Opt_gid, @@ -66,6 +77,7 @@ enum { Opt_acl, Opt_discard, Opt_nocase, + Opt_native_symlink, }; static const struct fs_parameter_spec ntfs_parameters[] = { @@ -91,6 +103,7 @@ static const struct fs_parameter_spec ntfs_parameters[] = { fsparam_flag("discard", Opt_discard), fsparam_flag("sparse", Opt_sparse), fsparam_flag("nocase", Opt_nocase), + fsparam_enum("native_symlink", Opt_native_symlink, ntfs_native_symlink_enums), {} }; @@ -215,6 +228,12 @@ static int ntfs_parse_param(struct fs_context *fc, struct fs_parameter *param) else NVolClearDisableSparse(vol); break; + case Opt_native_symlink: + if (result.uint_32 == NATIVE_SYMLINK_REL) + NVolSetNativeSymlinkRel(vol); + else + NVolClearNativeSymlinkRel(vol); + break; case Opt_sparse: break; default: diff --git a/fs/ntfs/volume.h b/fs/ntfs/volume.h index 3348394dbc0d3..55298689a7bbb 100644 --- a/fs/ntfs/volume.h +++ b/fs/ntfs/volume.h @@ -177,6 +177,7 @@ struct ntfs_volume { * * NV_Discard Issue discard/TRIM commands for freed clusters. * NV_DisableSparse Disable creation of sparse regions. + * NV_NativeSymlinkRel Translate absolute Windows reparse targets (native_symlink=rel). */ enum { NV_Errors, @@ -194,6 +195,7 @@ enum { NV_CheckWindowsNames, NV_Discard, NV_DisableSparse, + NV_NativeSymlinkRel, }; /* @@ -230,6 +232,7 @@ DEFINE_NVOL_BIT_OPS(HideDotFiles) DEFINE_NVOL_BIT_OPS(CheckWindowsNames) DEFINE_NVOL_BIT_OPS(Discard) DEFINE_NVOL_BIT_OPS(DisableSparse) +DEFINE_NVOL_BIT_OPS(NativeSymlinkRel) static inline void ntfs_inc_free_clusters(struct ntfs_volume *vol, s64 nr) {