Hard Links vs. Soft Links

This article was previously published in my blog, Just Like a Magic.


This writing talks about hard links and soft links; two of the nice features of NTFS file system. 

You can divide file links into two categories:
  • Normal Links (shortcuts)
  • Symbolic Links:
    This divided into two subcategories:
    • Hard Links (for files)
    • Soft Links (for directories)

Introducing Hard Links

A hard link is a way to represent a single file (i.e. data volume) by more than one path. In other words, it is a way to create multiple directory entries for a single file. 

Consider the following example, we could have two files, e.g. D:\Documents\Bills.doc and D:\Files\Company\Invoices.doc, both files represent the same data, so when you change one file the other changes too! 

A hard link is almost like a normal link (i.e. shortcut) but there is a big difference. If you delete the source file of a shortcut, the shortcut would be broken (points to a non-existing file.) A hard link on the other hand, would be still working fine if you delete the source file as if it was just a copy.
Notice that, hard disk space is not multiplied for each hard link. Because they are share the same data volume, they share the same size. 

There is something that you should be aware of. File attributes are not updated for each of the hard links. This means that if you set a hard link (e.g. D:\Files\Company\Invoices.doc) to read-only, it is the only link that is set to this attribute. Other hard links including the source would be still read-write (unless you set them too.) 

Hard links are only supported on NTFS file system; they are not supported by Win9x versions of Windows. Besides this, hard links creation is limited to the same local disk (or network drive) of the source file. For example, you cannot create a hard link on the C: drive for a file on the drive D: or on a network share.

Introducing Soft Links

Soft links (also called junctions,) are identical to hard links except that soft links are designated for directories not files. 

For example, if you have one or more soft links to the directory D:\Tools (e.g. D:\Software and D:\Programs\Tools,) all directories (including the source) would be updated when any one of them changes. That is, if you created a new file in one directory, it is created in all directory links, and so on.
Like hard links, soft links require NTFS file system. Plus, deleting the source directory does not affect other directories, all links share the same data volume, changing attributes of one directory does not be applied to others. 

Unlike hard links, creating soft links is a special feature of Windows Vista and Windows Server 2008 (and future versions of course.) Therefore, it cannot be applied to earlier versions of Windows (like Windows XP or Windows Server 2003.)

Creating a Hard Link

Unfortunately, neither hard links nor soft links are supported by the .NET Framework. Therefore, you will need to dig into the Windows API to allow your application to consume this feature. 

You can create a hard link using a single line of code using a simple call to the Win32 function,
CreateHardLink(), that resides in the Kernel32.dll library. The definition of this function is as follows: 

BOOL CreateHardLink(
    LPCTSTR lpFileName,
    LPCTSTR lpExistingFileName,
    LPSECURITY_ATTRIBUTES lpSecurityAttributes

This function accepts three arguments;
  • lpFileName:
    The path of the new hard link to be created. Notice that, it should be resides in the location (local disk or network share) as the source file.
  • lpExistingFileName:
    The path of the source file to create the hard link from.
  • lpSecurityAttributes:
    The security descriptor for the new file. Till now, it is reserved for future use and it should not be used.
This function returns TRUE if succeeded or FALSE otherwise. 

Keeping the definition of the function in our minds, we can create its PInvoke method in C#. Simply, this is our C# PInvoke method: 

    [DllImport("Kernel32.dll", CharSet = CharSet.Unicode )]
    static extern bool CreateHardLink(
        string lpFileName,
        string lpExistingFileName,
        IntPtr lpSecurityAttributes

As you know, we have set the character encoding to Unicode because Windows NT allows Unicode file names. In addition, we have marshaled
lpSecurityAttributes as System.IntPtr to allow passing it a null value using System.IntPtr.Zero.  

Then, you simply call the function:
Change the source file to meet an existing file into your system. In addition, check that the directory of the new link exists or the call would fail. 
Take into consideration that the function creates the new file for you, it should not be found or the function would fail (as the case with soft links.)

       "D:\\Files\\Company\\Invoices.doc",    // New Link
       "D:\\Documents\\Bills.doc",            // Source

And this is another link: 

       "D:\\Important\\Work Invoices.doc",     // New Link
       "D:\\Files\\Company\\Invoices.doc",     // Source

As you see, it does not matter if you created the new link from the original file or from another link. 

Now try to change any of the links, and check the others. They are all updated at the time you commit the change (save the file, for instance.)

Creating a Soft Link

Like hard links, you can create a soft link (a junction) using a single call to a Win32 API function; it is CreateSymbolicLink() function. Again, this function is only supported by Windows Vista and Windows Server 2008 (and future versions.) 

Actually, the function
CreateSymbolicLink() can be used to create both types of symbolic links, hard and soft links. The definition of this function is as follows: 

BOOLEAN WINAPI CreateSymbolicLink(
    LPTSTR lpSymlinkFileName,
    LPTSTR lpTargetFileName,
    DWORD dwFlags

This function accepts three arguments, the first and the second are identical to the CreateHardLink() function:
  • lpSymlinkFileName:
    The path of the new link (file or directory) that resides in the same drive (local disk or network share) of the target file.
  • lpTargetFileName:
    The path of the existing source (file or directory.)
  • dwFlags:
    The type of symbolic link. It can take the following values:
    • 0x0:
      The link is a hard link (source and destination are files.)
      The link is a soft link (source and destination are directories.)
The following is the PInvoke method for our function: 

    [DllImport("Kernel32.dll", CharSet = CharSet.Unicode)]
    static extern bool CreateSymbolicLink(
        string lpSymlinkFileName,
        string lpTargetFileName,
        uint dwFlags

    const uint SYMBLOC_LINK_FLAG_FILE          = 0x0;
    const uint SYMBLOC_LINK_FLAG_DIRECTORY     = 0x1;

The following code creates two soft links for one directory:
Again, the source should be the only directory that exists in your machine or the function would fail.
        "D:\\Software",         // New Link
        "D:\\Tools",            // Source

    // Source
        "D:\\Programs\\Tools",  // New Link
        "D:\\Software",         // Source

Now try changing one directory, other links change too. Try deleting the source, nothing would be happen to the other links.