Click here to Skip to main content
Click here to Skip to main content

Manipulating NTFS Junction Points in .NET

, 19 Sep 2006
Rate this:
Please Sign up or sign in to vote.
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:

// 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:

// 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:

// 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:

// 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

Share

About the Author

jeff.brown
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

 
QuestionLicense? PinmemberMember 112066715-Nov-14 6:47 
Questionuse junctionpoint in order to make symbol link with file Pinmemberhemigueti25-Jan-13 5:59 
QuestionAuthor / Code / Age of Information Pinmembermagemaster7-Nov-12 14:12 
QuestionFxCop - offtopic Pinmemberkiquenet.com16-Oct-12 22:46 
QuestionLicense? Pinmemberbitdisaster28-Sep-12 16:18 
QuestionLicence PinmemberMember 94026083-Sep-12 8:06 
QuestionLicense PinmemberMember 869768717-Jul-12 3:39 
AnswerThanks! Pinmembermasahiro_o2-Feb-12 3:58 
QuestionLicense? PinmemberGene201120-Dec-11 5:49 
BugNoticed something odd PinmemberMember 841395421-Nov-11 7:08 
GeneralMy vote of 5 PinmemberChristian Rodemeyer5-Nov-11 11:07 
Question2TB Virtual Disk Pinmembernhchmg27-Jun-11 21:17 
GeneralTimestamps PinmemberCarrrr3-Sep-09 5:47 
GeneralYou are awesome, sir! PinmemberAlex Gap15-May-09 13:57 
Thanks
GeneralGood job!! Pinmemberawmeyers12-May-09 5:32 
GeneralNice! Pinmemberwoelig19-Sep-08 13:51 
GeneralEnforce type semantics in parameters Pinmembermrsanchez2-Jul-08 13:35 
GeneralGreat PinmemberA Brunsk21-Apr-08 3:25 
GeneralCOMException 0x80070091 Pinmembersnorkie17-Dec-07 11:04 
GeneralPossible Change to your article Pinmembersnorkie30-Nov-07 6:19 
GeneralRe: Possible Change to your article PinmemberMitchster16-May-13 15:16 
GeneralFramework Version Pinmembersnorkie8-Oct-07 2:46 
GeneralRe: Framework Version Pinmemberjeff.brown8-Oct-07 14:07 
GeneralException thrown Pinmemberalkimiya28-Dec-06 4:31 
GeneralRe: Exception thrown Pinmemberjeff.brown28-Dec-06 10:25 
GeneralRe: Exception thrown [modified] Pinmemberc3time31-Dec-11 21:10 
GeneralThank you very much PinmemberKy Nam25-Sep-06 15:55 

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

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

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.1411023.1 | Last Updated 19 Sep 2006
Article Copyright 2006 by jeff.brown
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid