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.

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:

    Hyper-V-with-D

  • Provided that we have ${Home}="C:\Users\User" a drive D:\ with NTFS.

  • Use $guid = [guid]::NewGuid() to get a GUID as the name of testing dir, see here for more about GUIDs.

  • ${Home}\${guid} and D:\${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:

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:

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 of New 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 with notepad.exe instead of New Open or throwing errors, we consider this directory valid.

Codes:

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:

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 become hardlinks 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 hardlinks, and if the element total number of this set has been shrunk to 1, the remaining item will become a normal file, instead of maintaining hardlink. So, to some extent, if we generate the hardlinks of a file, there are no distinct differences between the file and its hardlinks, i.e., the the file and its hardlinks tend to homogenize. The expression, “its hardlinks”, is inaccurate.
  • Remove (even with -Recurse) Junctions or Symbolic Links will not influence the source.
  • Remove (even not -Recurse) the source ofJunctions or Symbolic Links will not influence the status of the link itself, but the LinkTarget in these status will be an invalid path.
  • The links, only including Junctions or Symbolic Links but excluding hardlink, 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:

Therefore, through the extensive follow-up studies, the conclusions about links in this article on NTFS still hold on ReFS


  1. (2023, March 5). Hard links and junctions. Learn. https://learn.microsoft.com/en-us/windows/win32/fileio/hard-links-and-junctions ↩︎

  2. (2023, March 5). Hard links and junctions. Learn. https://learn.microsoft.com/en-us/windows/win32/fileio/hard-links-and-junctions ↩︎

  3. (2023, March 5). Hard links and junctions. Learn. https://learn.microsoft.com/en-us/windows/win32/fileio/hard-links-and-junctions ↩︎

  4. (2023, March 5). Symbolic Links. Learn. https://learn.microsoft.com/en-us/windows/win32/fileio/symbolic-links ↩︎

  5. (2023, May 15). ReFS - Wikipedia. En. https://en.wikipedia.org/wiki/ReFS ↩︎