Click here to Skip to main content
15,868,049 members
Articles / Programming Languages / C#
Article

Manipulating NTFS Junction Points in .NET

Rate me:
Please Sign up or sign in to vote.
4.84/5 (32 votes)
19 Sep 20063 min read 172.6K   5K   59   30
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


Written By
Web Developer
United States United States
My name is Jeff Brown.

I'm a software engineer currently working at Ingenio, Inc. My main interests are programming language design, software verification, and software engineering pragmatics.

Currently released open source projects:
- MbUnit v3 (Gallio)
- Castle.Components.Scheduler
- Castle.Components.Caching
- Castle.FlexBridge
- FxCop AddIn for Visual Studio at http://fxcopaddin.tigris.org/

Comments and Discussions

 
QuestionSuggested addition to prevent recursive junction points Pin
Alonzzo227-Jul-21 21:47
Alonzzo227-Jul-21 21:47 
QuestionUse relative paths? Pin
Member 201269625-Mar-18 9:48
Member 201269625-Mar-18 9:48 
QuestionChanging created/modified date time? Pin
jez999914-Nov-17 20:37
jez999914-Nov-17 20:37 
Questionlicense Pin
orkoder9-Oct-15 1:42
orkoder9-Oct-15 1:42 
QuestionLicense? Pin
Member 112066715-Nov-14 5:47
Member 112066715-Nov-14 5:47 
Questionuse junctionpoint in order to make symbol link with file Pin
hemigueti25-Jan-13 4:59
hemigueti25-Jan-13 4:59 
QuestionAuthor / Code / Age of Information Pin
magemaster7-Nov-12 13:12
magemaster7-Nov-12 13:12 
QuestionFxCop - offtopic Pin
kiquenet.com16-Oct-12 21:46
professionalkiquenet.com16-Oct-12 21:46 
QuestionLicense? Pin
bitdisaster28-Sep-12 15:18
bitdisaster28-Sep-12 15:18 
QuestionLicence Pin
Member 94026083-Sep-12 7:06
Member 94026083-Sep-12 7:06 
QuestionLicense Pin
Member 869768717-Jul-12 2:39
Member 869768717-Jul-12 2:39 
AnswerThanks! Pin
mshrumhr2-Feb-12 2:58
mshrumhr2-Feb-12 2:58 
QuestionLicense? Pin
Gene201120-Dec-11 4:49
Gene201120-Dec-11 4:49 
BugNoticed something odd Pin
Member 841395421-Nov-11 6:08
Member 841395421-Nov-11 6:08 
GeneralMy vote of 5 Pin
Christian Rodemeyer5-Nov-11 10:07
professionalChristian Rodemeyer5-Nov-11 10:07 
GeneralTimestamps Pin
Carrrr3-Sep-09 4:47
Carrrr3-Sep-09 4:47 
GeneralYou are awesome, sir! Pin
abdurahman ibn hattab15-May-09 12:57
abdurahman ibn hattab15-May-09 12:57 
GeneralGood job!! Pin
awmeyers12-May-09 4:32
awmeyers12-May-09 4:32 
GeneralNice! Pin
Danie de Kock19-Sep-08 12:51
Danie de Kock19-Sep-08 12:51 
GeneralEnforce type semantics in parameters Pin
mrsanchez2-Jul-08 12:35
mrsanchez2-Jul-08 12:35 
GeneralGreat Pin
A Brunsk21-Apr-08 2:25
A Brunsk21-Apr-08 2:25 
GeneralCOMException 0x80070091 Pin
snorkie17-Dec-07 10:04
professionalsnorkie17-Dec-07 10:04 
GeneralPossible Change to your article Pin
snorkie30-Nov-07 5:19
professionalsnorkie30-Nov-07 5:19 
GeneralRe: Possible Change to your article Pin
Mitchster16-May-13 14:16
Mitchster16-May-13 14:16 
GeneralFramework Version Pin
snorkie8-Oct-07 1:46
professionalsnorkie8-Oct-07 1:46 
Thanks for the great article! Your didn't mention the framework version in the article anywhere. I took it home to work on this weekend. I'm set up there for the 1.1 framework and it didn't work. Seems that Microsoft.Win32.SafeHandles; doesn't exist in the 1.1 framework. Unless I'm missing something, this is a 2.0 framework and higher project.

Thanks!

Hogan

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.