Introduction
Junction Points are a little known NTFS v5+ feature roughly equivalent to UNIX symbolic links. They are supported in Windows 2000 and onwards but cannot be accessed without special tools. In particular the .NET libraries does not include any functionality for creating or querying properties of Junction Points. This article provides sample code for creating Junction Points, testing their existence, querying their target and deleting them. I hope you find it of value in your own projects.
Background
Junction Points are directories with a special attribute that indicates the target of the link. They is a special case of an NTFS feature known as a Reparse Point. A Reparse Point can roughly be thought of as a filter that is injected into the file system's name translation layer. The file system filter can transform how the name is parsed (hence the name) and redirect accesses to other resources. So Reparse Points can do much more than represent symbolic links but we're not going to worry about that today. Keep in mind this is an NTFS only feature. It will not work on other file systems. If your application relies on Junction Points in some way, you should be sure to provide alternate means of achieving the same end. Also, many applications are unaware of symbolic links. Usually that is okay but it can cause problems with tools that recursively copy or delete files because the Junction Point will simply appear to be a normal directory. For more background information about Junction Points or Reparse Points please consult the references at the end of this article.
Using the code
The source zip file includes two classes JunctionPoint
and JunctionPointTest
. The former is the one you probably care about most. The latter includes a series of tests written with the MbUnit
library. These may be ported to NUnit
easily by straightforward substitution of the namespace names. Incidentally, you'll probably want to rename the namespace to which JunctionPoint
belongs before using it in your own code. The current name reflects that of an application I am currently working on. The code makes use of Platform Invoke (PInvoke) methods to call the appropriate Win32 APIs to do the heavy lifting. To use the library you do not need to understand how these work. However, be aware that PInvokes make a Native code access security permission demand. If your application does not run with Full Trust you will likely need to ensure it acquires the necessary permissions before it tries to manipulate Junction Points.
Creating a Junction Point
Use the JunctionPoint.Create
method like this:
JunctionPoint.Create(@"C:\Foo\JunctionPoint", @"C:\Bar",
false )
JunctionPoint.Create(@"C:\Foo\JunctionPoint", @"C:\Bar", true )
Note: It is not possible to create Junction Points that refer to files.
Deleting a Junction Point
Use the JunctionPoint.Delete
method like this:
JunctionPoint.Delete(@"C:\Foo\JunctionPoint")
Determining existence of a Junction Point
Use the JunctionPoint.Exists
method like this:
bool exists = JunctionPoint.Exists(@"C:\Foo\JunctionPoint")
Getting the target of a Junction Point
Use the JunctionPoint.GetTarget
method like this:
JunctionPoint.Create(@"C:\Foo\JunctionPoint", @"C:\Bar", false)
string target = JunctionPoint.GetTarget(@"C:\Foo\JunctionPoint")
Points of Interest
I find it interesting that the .NET Framework's FileAttributes
enumeration includes the value FileAttributes.ReparsePoint
but there is no other built-in support for Reparse Points. Of course, you can delete Reparse Points as if they were ordinary directories.
Junction Points make it possible to create cyclic references in the filesystem. So be careful with them. In particular, you should never try to recursively delete the target of a Junction Point! To avoid doing that ensure that the FileAttributes
of each directory do not include the FileAttributes.ReparsePoint
flag before attempting to recursively delete it. Also beware of recursive copying.
References
This project would not have been possible without the assistance of others in the community. I consulted the following references while implementing this functionality in .NET:
- Article and C++ implementation of a Junction Point manipulation tool: Windows 2000 Junction Points by Mike Nordell.
- C implementation of a Junction Point manipulation tool: Junction Tool by SysInternals.
- PInvokes and structure declarations for Win32 API calls: PInvoke.net
- Microsoft Windows SDK documentation for Reparse Points: Reparse Points
History
- 9/19/2006: Initial post to CodeProject