Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Manipulating NTFS Junction Points in .NET

4.84/5 (32 votes)
19 Sep 20063 min read 1   5K  
How to create and manipulate NTFS Junction Points (aka. symbolic links) in .NET

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:

C#
// Creates a Junction Point at 
// C:\Foo\JunctionPoint that points to the directory C:\Bar.
// Fails if there is already a file, 
// directory or Junction Point with the specified path.
JunctionPoint.Create(@"C:\Foo\JunctionPoint", @"C:\Bar", 
                    false /*don't overwrite*/)

// Creates a Junction Point at C:\Foo\JunctionPoint that points to 
// the directory C:\Bar.
// Replaces an existing Junction Point if found at the specified path.
JunctionPoint.Create(@"C:\Foo\JunctionPoint", @"C:\Bar", true /*overwrite*/)

Note: It is not possible to create Junction Points that refer to files.

Deleting a Junction Point

Use the JunctionPoint.Delete method like this:

C#
// Delete a Junction Point at C:\Foo\JunctionPoint if it exists.
// Does nothing if there is no such Junction Point.
// Fails if the specified path refers to an existing file or 
// directory rather than a Junction Point.
JunctionPoint.Delete(@"C:\Foo\JunctionPoint")

Determining existence of a Junction Point

Use the JunctionPoint.Exists method like this:

C#
// Returns true if there is a Junction Point at C:\Foo\JunctionPoint.
// Returns false if the specified path refers to an existing file 
// or directory rather than a Junction Point
// or if it refers to the vacuum of space.
bool exists = JunctionPoint.Exists(@"C:\Foo\JunctionPoint")

Getting the target of a Junction Point

Use the JunctionPoint.GetTarget method like this:

C#
// Create a Junction Point for demonstration purposes whose target is C:\Bar.
JunctionPoint.Create(@"C:\Foo\JunctionPoint", @"C:\Bar", false)

// Returns the full path of the target of the Junction Point at 
// C:\Foo\JunctionPoint.
// Fails if the specified path does not refer to a Junction Point.
string target = JunctionPoint.GetTarget(@"C:\Foo\JunctionPoint")

// target will be C:\Bar

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

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here