There may be no need to fully understand Junction, Hard Link and Symbolic Link in NTFS
In normal scenarios, the concepts and characteristics of
hard links
, junctions
, and
symbolic links
are intertwined. Only a few words cannot
tell them clearly. However, in terms of daily use, why must we
understand 100% of their differences and similarities? Sometimes, it is
enough to remember these three concepts’ main features and differences,
plus some experience.
From the perspective of an average Windows user, this article
introduces hard links
, junctions
, and
symbolic links
in Windows file system (NTFS). And, through
direct experiments or tests, this article gives out some insights that
are less than deep and broad understanding and record some simple usage.
In the end, this article shows the same tests and conclusions on
ReFS.
All codes can be found in TestWindowsLinkBehavior.ps1, which has been integrated as an example in Zhaopudark/PSComputerManagementZp, one of my customized PowerShell Modules.
Definition
The NTFS file system supports three types of file links: hard links, junctions, and symbolic links. 1
- Hard links: A hard link is the file-system representation of a file by which more than one path references a single file in the same volume. To create a hard link, use the CreateHardLinkA function. 2
- Junctions: A junction (also called a soft link) differs from a hard link in that the storage objects it references are separate directories. A junction can also link directories located on different local volumes on the same computer. Otherwise, junctions operate identically to hard links. Junctions are implemented through reparse points. 3
- Symbolic Links: A symbolic link is a file-system object that points to another file system object. The object being pointed to is called the target. Symbolic links are transparent to users; the links appear as normal files or directories, and can be acted upon by the user or application in exactly the same manner. Symbolic links are designed to aid in migration and application compatibility with UNIX operating systems. Microsoft has implemented its symbolic links to function just like UNIX links.4
For more information about symbolic links, see Create symbolic links.
Test to Reveal Differences and Similarities
To Identify the differences and similarities of Hard links, Junctions, and Symbolic Links on Windows, I think, the best way is to test. Because:
- As normal users, not experts on Windows development, we may not know all the similarities and differences.
- As normal users, we try to identify the similarities and differences is to use rather than analyze the design philosophy and make improvements.
- As normal users, we can directly get the similarities and differences in the aspect of usage by testing on specific circumstances. That’s enough.
So, in this article, we may not know all the similarities and differences of these links. We may only concern about some occasions. And in the following sections, we will design some tests, do these tests and report the results. Key points will also be includes in conclusion.
NOTICE: If one wants to know more, even all information about these links’ differences and similarities, the following links may be help, but in this article, we do not cover so much content.
- 软连接和硬链接区别 - matengfei - 博客园 (cnblogs.com)
- Junction vs Symbolic Links - Windows (ourtechroom.com)
- windows - “directory junction” vs “directory symbolic link”? - Super User
- 硬链接和交汇点 - Win32 apps | Microsoft Learn
- 重分析点 - Win32 apps | Microsoft Learn
- 符号链接 - Win32 apps | Microsoft Learn
- 关于Windows:NTFS连接点和符号链接之间有什么区别? | 码农家园 (codenong.com)
In the following sections, we product some tests and report key results.
Preparation
We mainly tests the above links in 3 aspects, i.e, the basic attributes, the delete behavior and the Authorization behavior. Let’s elaborate some prerequisites:
Prepare a native Window System and make an extra drive
D:
. We can achieve this by Hyper-V with Window-11 Enterprise Evaluation (developer). Here is a example:Provided that we have
${Home}="C:\Users\User"
a driveD:\
with NTFS.Use
$guid = [guid]::NewGuid()
to get a GUID as the name of testing dir, see here for more about GUIDs.${Home}\${guid}
andD:\${guid}
are the working space (testing directory)Generate the following items for testing:
${Home}\${guid}\file_for_hardlink.txt
D:\${guid}\file_for_hardlink.txt
${Home}\${guid}\dir_for_local_junction
D:\${guid}\dir_for_local_junction
${Home}\${guid}\dir_for_non_local_junction
D:\${guid}\dir_for_non_local_junction
${Home}\${guid}\fire_for_local_symbiliclink.txt
D:\${guid}\fire_for_local_symbiliclink.txt
${Home}\${guid}\fire_for_non_local_symbiliclink.txt
D:\${guid}\fire_for_non_local_symbiliclink.txt
${Home}\${guid}\dir_for_local_symbiliclink
D:\${guid}\dir_for_local_symbiliclink
${Home}\${guid}\dir_for_non_local_symbiliclink
D:\${guid}\dir_for_non_local_symbiliclink
Codes:
- See function
New-AllItem
for the codes.
- See function
Then, we can generate a 14-type of links as:
Path \(\rightarrow\) | Toward | Type |
---|---|---|
${Home}\${guid}\hardlink |
${Home}\${guid}\file_for_hardlink.txt |
Hard Link \(\rightarrow\)File |
D:\${guid}\hardlink |
D:\${guid}\file_for_hardlink.txt |
Hard Link \(\rightarrow\)File |
${Home}\${guid}\local_junction |
${Home}\${guid}\dir_for_local_junction |
Junction \(\rightarrow\)Directory |
D:\${guid}\local_junction |
D:\${guid}\dir_for_local_junction |
Junction \(\rightarrow\)Directory |
D:\${guid}\non_local_junction |
${Home}\${guid}\dir_for_non_local_junction |
Junction \(\rightarrow\)Directory |
${Home}\${guid}\non_local_junction |
D:\${guid}\dir_for_non_local_junction |
Junction \(\rightarrow\)Directory |
${Home}\${guid}\local_symbiliclink-txt |
${Home}\${guid}\fire_for_local_symbiliclink.txt |
Symbolic Link \(\rightarrow\)File |
D:\${guid}\local_symbiliclink-txt |
D:\${guid}\fire_for_local_symbiliclink.txt |
Symbolic Link \(\rightarrow\)File |
D:\${guid}\non_local_symbiliclink-txt |
${Home}\${guid}\fire_for_non_local_symbiliclink.txt |
Symbolic Link \(\rightarrow\)File |
${Home}\${guid}\non_local_symbiliclink-txt
|
D:\${guid}\fire_for_non_local_symbiliclink.txt |
Symbolic Link \(\rightarrow\)File |
${Home}\${guid}\local_symbiliclink |
${Home}\${guid}\dir_for_local_symbiliclink |
Symbolic Link \(\rightarrow\)Directory |
D:\${guid}\local_symbiliclink |
D:\${guid}\dir_for_local_symbiliclink |
Symbolic Link \(\rightarrow\)Directory |
D:\${guid}\non_local_symbiliclink |
${Home}\${guid}\dir_for_non_local_symbiliclink |
Symbolic Link \(\rightarrow\)Directory |
${Home}\${guid}\non_local_symbiliclink |
D:\${guid}\dir_for_non_local_symbiliclink |
Symbolic Link \(\rightarrow\)Directory |
That is to say, we will make the 14-type of links as the table above,
covering many types that we may encounter when using. Notice, the table
above shows the interrelationship between the non-local links in the two
directories in red and
green, i.e., a link name contains
non_local
in ${Home}\${guid}
will be linked to
a corresponding directory or file in D:\${guid}
, and a link
name contains non_local
in D:\${guid}
will be
linked to a corresponding directory or file in
${Home}\${guid}
. Although this operation seems to be
troublesome, it is necessary for the rigor of following tests and
conclusions, since junction
and symbolic link
can be created across partitions.
Results
By TestWindowsLinkBehavior.ps1 with Pester, it is easy to conduct tests and collect results.
Test Basic Attributes
Targets:
- Compare item
Attributes
. - Compare item
LinkType
. - Compare item
LinkTarget
.
Codes:
- See the block ‘Context Test Basic Attributes’
Th results are collected in the following table, where -
means null or empty ('' or $null
in PowerShell)
Path | Attributes | LinkType | LinkTarget |
---|---|---|---|
${Home}\${guid}\file_for_hardlink.txt |
Archive | HardLink | - |
${Home}\${guid}\hardlink |
Archive | HardLink | - |
D:\${guid}\file_for_hardlink.txt |
Archive | HardLink | - |
D:\${guid}\hardlink |
Archive | HardLink | - |
${Home}\${guid}\dir_for_local_junction |
Directory | - | - |
${Home}\${guid}\local_junction |
Directory, ReparsePoint | Junction | ${Home}\${guid}\dir_for_local_junction |
D:\${guid}\dir_for_local_junction |
Directory | - | - |
D:\${guid}\local_junction |
Directory, ReparsePoint | Junction | D:\${guid}\dir_for_local_junction |
${Home}\${guid}\dir_for_non_local_junction |
Directory | - | - |
D:\${guid}\non_local_junction |
Directory, ReparsePoint | Junction | ${Home}\${guid}\dir_for_non_local_junction |
D:\${guid}\dir_for_non_local_junction |
Directory | - | - |
${Home}\${guid}\non_local_junction |
Directory, ReparsePoint | Junction | D:\${guid}\dir_for_non_local_junction |
${Home}\${guid}\fire_for_local_symbiliclink.txt |
Archive | - | - |
${Home}\${guid}\local_symbiliclink-txt |
Archive, ReparsePoint | SymbolicLink | ${Home}\${guid}\fire_for_local_symbiliclink.txt |
D:\${guid}\fire_for_local_symbiliclink.txt |
Archive | - | - |
D:\${guid}\local_symbiliclink-txt |
Archive, ReparsePoint | SymbolicLink | D:\${guid}\fire_for_local_symbiliclink.txt |
${Home}\${guid}\fire_for_non_local_symbiliclink.txt |
Archive | - | - |
D:\${guid}\non_local_symbiliclink-txt |
Archive, ReparsePoint | SymbolicLink | ${Home}\${guid}\fire_for_non_local_symbiliclink.txt |
D:\${guid}\fire_for_non_local_symbiliclink.txt |
Archive | - | - |
${Home}\${guid}\non_local_symbiliclink-txt |
Archive, ReparsePoint | SymbolicLink | D:\${guid}\fire_for_non_local_symbiliclink.txt |
${Home}\${guid}\dir_for_local_symbiliclink |
Directory | - | - |
${Home}\${guid}\local_symbiliclink |
Directory, ReparsePoint | SymbolicLink | ${Home}\${guid}\dir_for_local_symbiliclink |
D:\${guid}\dir_for_local_symbiliclink |
Directory | - | - |
D:\${guid}\local_symbiliclink |
Directory, ReparsePoint | SymbolicLink | D:\${guid}\dir_for_local_symbiliclink |
${Home}\${guid}\dir_for_non_local_symbiliclink |
Directory | - | - |
D:\${guid}\non_local_symbiliclink |
Directory, ReparsePoint | SymbolicLink | ${Home}\${guid}\dir_for_non_local_symbiliclink |
D:\${guid}\dir_for_non_local_symbiliclink |
Directory | - | - |
${Home}\${guid}\non_local_symbiliclink |
Directory, ReparsePoint | SymbolicLink | D:\${guid}\dir_for_non_local_symbiliclink |
Test Deletion Behavior
Targets:
- If delete the link, check whether the source exists or not.
- If delete the source, check whether the link exists or is valid.
Main methods:
- Since the targets involve two operations that will affect each other, we should delete links to check target 1 and then repeat the preparation as Preparation to restore testing status, then delete the source to check the target 2.
- We may encounter invalid links, where the link itself exists, but
the source cannot be accessed through them. Instead of defining the
meaning of an invalid link in the standard terminology, we here assume
that a link is invalid as long as it does not serve our purpose. So, for
the following tests and comparisons, we deal with directories and files
separately:
- If a file, either a link or a source file, can be opened normally
with
notepad.exe
instead ofNew Open
or throwing errors, we consider this file valid. - If a directory, either a link or a source directory, we establish a
.txt
file in it and check if the.txt
file can be opened normally withnotepad.exe
instead ofNew Open
or throwing errors, we consider this directory valid.
- If a file, either a link or a source file, can be opened normally
with
Codes:
- For target 1, see the block ‘Test Deletion Behavior1 (delete link)’
- For target 2, see the block ‘Test Deletion Behavior2 (delete source|target)’
Results for target 1: See the following table.
Link \(\rightarrow\) | Source | Check source after link deletion |
---|---|---|
${Home}\${guid}\hardlink |
${Home}\${guid}\file_for_hardlink.txt |
*1 |
D:\${guid}\hardlink |
D:\${guid}\file_for_hardlink.txt |
*1 |
${Home}\${guid}\local_junction |
${Home}\${guid}\dir_for_local_junction |
*2 |
D:\${guid}\local_junction |
D:\${guid}\dir_for_local_junction |
*2 |
D:\${guid}\non_local_junction |
${Home}\${guid}\dir_for_non_local_junction |
*2 |
${Home}\${guid}\non_local_junction |
D:\${guid}\dir_for_non_local_junction |
*2 |
${Home}\${guid}\local_symbiliclink-txt |
${Home}\${guid}\fire_for_local_symbiliclink.txt |
*3 |
D:\${guid}\local_symbiliclink-txt |
D:\${guid}\fire_for_local_symbiliclink.txt |
*3 |
D:\${guid}\non_local_symbiliclink-txt |
${Home}\${guid}\fire_for_non_local_symbiliclink.txt |
*3 |
${Home}\${guid}\non_local_symbiliclink-txt
|
D:\${guid}\fire_for_non_local_symbiliclink.txt |
*3 |
${Home}\${guid}\local_symbiliclink |
${Home}\${guid}\dir_for_local_symbiliclink |
*2 |
D:\${guid}\local_symbiliclink |
D:\${guid}\dir_for_local_symbiliclink |
*2 |
D:\${guid}\non_local_symbiliclink |
${Home}\${guid}\dir_for_non_local_symbiliclink |
*2 |
${Home}\${guid}\non_local_symbiliclink |
D:\${guid}\dir_for_non_local_symbiliclink |
*2 |
*1
: Become a normal file from a hardlink after link deletion.*2
: Maintain as a normal dir. The deletion of the link with-Recurse
does not influence the source.*3
: Maintain as a normal file.
Results for target 2: See the following table.
Link \(\rightarrow\) | Source | Check link after source deletion |
---|---|---|
${Home}\${guid}\hardlink |
${Home}\${guid}\file_for_hardlink.txt |
*1 |
D:\${guid}\hardlink |
D:\${guid}\file_for_hardlink.txt |
*1 |
${Home}\${guid}\local_junction |
${Home}\${guid}\dir_for_local_junction |
*4 |
D:\${guid}\local_junction |
D:\${guid}\dir_for_local_junction |
*4 |
D:\${guid}\non_local_junction |
${Home}\${guid}\dir_for_non_local_junction |
*4 |
${Home}\${guid}\non_local_junction |
D:\${guid}\dir_for_non_local_junction |
*4 |
${Home}\${guid}\local_symbiliclink-txt |
${Home}\${guid}\fire_for_local_symbiliclink.txt |
*5 |
D:\${guid}\local_symbiliclink-txt |
D:\${guid}\fire_for_local_symbiliclink.txt |
*5 |
D:\${guid}\non_local_symbiliclink-txt |
${Home}\${guid}\fire_for_non_local_symbiliclink.txt |
*5 |
${Home}\${guid}\non_local_symbiliclink-txt
|
D:\${guid}\fire_for_non_local_symbiliclink.txt |
*5 |
${Home}\${guid}\local_symbiliclink |
${Home}\${guid}\dir_for_local_symbiliclink |
*6 |
D:\${guid}\local_symbiliclink |
D:\${guid}\dir_for_local_symbiliclink |
*6 |
D:\${guid}\non_local_symbiliclink |
${Home}\${guid}\dir_for_non_local_symbiliclink |
*6 |
${Home}\${guid}\non_local_symbiliclink |
D:\${guid}\dir_for_non_local_symbiliclink |
*6 |
*4
: Maintain as a junction but point to a deleted path.*5
: Maintain as a symbolic link file but point to a deleted path.*6
: Maintain as a symbolic link dir but point to a deleted path
Test Authorization Behavior
Targets:
- Check if the Authorization information of a source and its link are forced to bind to be the same.
Main methods:
- Set (modify) the owner of a source, and make it effective
- Set (modify) a different owner of a link, and make it effective
- Check is the owners of the source and link are the same one.
- Logical weaknesses:
- The ownership is a part of Authorization information.
- We set a source and a link to different owners separately and they show the difference, which means the authorization information of the source and its link are not forced to bind to be the same.
- But strictly, if we set a source and a link to different owners separately and they still show the same owner, which can only means the ownership of the source and its link are forced to bind to be the same, instead of the all authorization information.
- However, there are too many authorization aspects, that we, normal users, are not usually encounter. So, in this article, we uncritically argue that inconsistent ownership information can deduce inconsistent authorization information.
- So, if we set a source and a link to different owners separately and they still show the same owner, we consider the authorization information of the source and its link are forced to bind to be the same.
- But, this method is always an opportunistic approach with pragmatism and is not a perfect solution, even though it works.
Codes:
- See the block ‘Test Authorization Behavior’
Results : See the following table.
Link \(\rightarrow\) | Source | Is authorization the same? |
---|---|---|
${Home}\${guid}\hardlink |
${Home}\${guid}\file_for_hardlink.txt |
True |
D:\${guid}\hardlink |
D:\${guid}\file_for_hardlink.txt |
True |
${Home}\${guid}\local_junction |
${Home}\${guid}\dir_for_local_junction |
False |
D:\${guid}\local_junction |
D:\${guid}\dir_for_local_junction |
False |
D:\${guid}\non_local_junction |
${Home}\${guid}\dir_for_non_local_junction |
False |
${Home}\${guid}\non_local_junction |
D:\${guid}\dir_for_non_local_junction |
False |
${Home}\${guid}\local_symbiliclink-txt |
${Home}\${guid}\fire_for_local_symbiliclink.txt |
False |
D:\${guid}\local_symbiliclink-txt |
D:\${guid}\fire_for_local_symbiliclink.txt |
False |
D:\${guid}\non_local_symbiliclink-txt |
${Home}\${guid}\fire_for_non_local_symbiliclink.txt |
False |
${Home}\${guid}\non_local_symbiliclink-txt
|
D:\${guid}\fire_for_non_local_symbiliclink.txt |
False |
${Home}\${guid}\local_symbiliclink |
${Home}\${guid}\dir_for_local_symbiliclink |
False |
D:\${guid}\local_symbiliclink |
D:\${guid}\dir_for_local_symbiliclink |
False |
D:\${guid}\non_local_symbiliclink |
${Home}\${guid}\dir_for_non_local_symbiliclink |
False |
${Home}\${guid}\non_local_symbiliclink |
D:\${guid}\dir_for_non_local_symbiliclink |
False |
Conclusion
We can use common language and get some conclusions that can be easily understood and applied by us for these links:
- When establish a
hardlink
for a file, the source and the link will all becomehardlinks
to a real file that hided and only managed by file system. So:- Removing any one of the source or the link will not remove the real file, unless removing all of them.
- Changing the authorization information of any one of the source or the link will change the real file’s authorization information since both of them represent a whole of one or more data regions in the drive.
- Consider a set of a file and its all
hardlink
s, and if the element total number of this set has been shrunk to1
, the remaining item will become a normal file, instead of maintaininghardlink
. So, to some extent, if we generate thehardlink
s of a file, there are no distinct differences between the file and itshardlink
s, i.e., the the file and itshardlink
s tend to homogenize. The expression, “itshardlink
s”, is inaccurate.
- Remove (even with
-Recurse
)Junctions
orSymbolic Links
will not influence the source. - Remove (even not
-Recurse
) the source ofJunctions
orSymbolic Links
will not influence the status of the link itself, but theLinkTarget
in these status will be an invalid path. - The links, only including
Junctions
orSymbolic Links
but excludinghardlink
, and their sources are treated as independent file system objects and can have different authorization information. Which may leads to potential security risks.
If in ReFS ?
ReFS: Resilient File System (ReFS),[7] codenamed “Protogon”,[8] is a Microsoft proprietary file system introduced with Windows Server 2012 with the intent of becoming the “next generation” file system after NTFS.5
This article is mainly about links in NTFS. But when it comes to ReFS, we have also made follow-up studies and tests.
Since ${Home}
is in C:\Users
, and recently,
as the system drive, C:\
cannot be formatted to ReFS
easily, see here, so
we only formatted drive D:\
.
We repeat all the above testing operations and report key results:
Preparation
- Drive
D:\
is formatted to ReFS instead of NTFS. As the following:
- Drive
Test Basic Attributes
- Same results to the basic attributes test in NTFS
Test Delete Behavior
- Same results to the delete behavior test in NTFS
Test Authorization Behavior
- Same results to the authorization behavior test in NTFS
Therefore, through the extensive follow-up studies, the conclusions about links in this article on NTFS still hold on ReFS
(2023, March 5). Hard links and junctions. Learn. https://learn.microsoft.com/en-us/windows/win32/fileio/hard-links-and-junctions ↩︎
(2023, March 5). Hard links and junctions. Learn. https://learn.microsoft.com/en-us/windows/win32/fileio/hard-links-and-junctions ↩︎
(2023, March 5). Hard links and junctions. Learn. https://learn.microsoft.com/en-us/windows/win32/fileio/hard-links-and-junctions ↩︎
(2023, March 5). Symbolic Links. Learn. https://learn.microsoft.com/en-us/windows/win32/fileio/symbolic-links ↩︎
(2023, May 15). ReFS - Wikipedia. En. https://en.wikipedia.org/wiki/ReFS ↩︎