Windows 2000 Junction Points

By , 5 Jan 2000

If you're not interested in the way to the solution, simply skip to the section The Solution.

Background

Windows 2000 includes a new version of NTFS dubbed "Version 5".

This version of NTFS includes something called reparse points. Reparse points can, among other things, be used to implement a type of softlinks, seen in other operating systems for the last decades.

• A reparse point that points to a Volume is called Volume mount point.
• A reparse point that points to a Directory is called Junction Point.

Volume Mount Points

The first steps to try these out was by using diskmgmt.msc which is an MMC "Snap-in" replacement for the Disk Administrator in NT4.

I created a directory \mnt\s and tried to mount S: on this directory.

It worked! I now had access to my S: through \mnt\s.

OK, can I now remove the driveletter from this drive and still have it working? Yes! Finally, you don't need all those driveletters anymore (except for the boot- and system-drive). You can simply remove e.g. S: and mount the Volume under \mnt\s.

This might not seem like a big deal to some people, but it can remove a lot of clutter. It also helps a lot when moving programs from one place to another, since just about every program in the Windows world expects to never be moved from the directory it was installed in.

E.g. moving your "Program Files" directory to another drive, and linking the original "Program Files" directory to this new location.

A Volume mount point basically contains the Unicode string

"\??\Volume{ GUID }\"
and is a representation that Windows 2000 uses to identify individual Volumes.

You can list accessible Volume GUIDs by typing MountVol.

For a quick look at where these are used, start RegEdit and look in the key

HKLM\SYSTEMS\MountedDevices

Note that a Volume isn't the Media, but rather the logical "device", since a Volume can refer to a floppy drive with no media in it.

Directory Junction Points

Reading a bit more revealed that reparse points should also be able to point at another directory. Ahhh, finally, I thought.

While looking for a way to create Directory junction points, I found a reference to a tool called "linkd.exe" in the Windows help. Hunting high and low for this tool I ended up empty handed.

Perhaps the most important evolution of NTFS ever, and they didn't supply the documented tool to use it! (It's apparently supposed to appear in Windows 2000 Resource Kit)

What's even more bothering is that junction points API usage is undocumented.

The Search

Starting to work up some steam over this issue, I got going on writing a tool that could create and manipulate Directory junction points (i.e. softlinks).

Now, how do you write code with completely undocumented structures? As usual in this world, by disassembling, trial-and-error, and searching old documentation and SDKs.

The the Windows 2000 SDK documentation that mentions Reparse Points points you to the struct REPARSE_GUID_DATA_BUFFER.

typedef struct _REPARSE_GUID_DATA_BUFFER {
DWORD  ReparseTag;
WORD   ReparseDataLength;
WORD   Reserved;
GUID   ReparseGuid;
struct {
BYTE   DataBuffer[1];
} GenericReparseBuffer;
} REPARSE_GUID_DATA_BUFFER, *PREPARSE_GUID_DATA_BUFFER;

This struct is nothing more than i bit-bucket for the real data that any particular reparse point contains. In the case of Volume mount points and Junction points, it's both close to useless and completely wrong. Trying to parse the deata from a Junction Points using the ReparseGuid data member would only result in jibberish.

No help here.

There are three FSCTLs defined in WinIoCtl.h to manipulate reparse points using DeviceIoControl:

• FSCTL_SET_REPARSE_POINT
• FSCTL_GET_REPARSE_POINT
• FSCTL_DELETE_REPARSE_POINT

Looking at the definition of these, you find that all three of them has a comment // REPARSE_DATA_BUFFER. This comment is still present in the Windows 2000 SDK, but the structure definition is nowhere to be found.

At this time my cursing started to approach a level not suitable for printing, and I decided that it was a long night with a lot of coffe and disassemly ahead.

But, I had a vague memory of this structure in the VC6 header. A contents search in the include directory for REPARSE_DATA_BUFFER displayed that it indeed existed in WinNT.h from VC6.

Apparently this needed structure was removed from the Windows 2000 SDK. Go figure...

Since I've now mentioned REPARSE_DATA_BUFFER, I think it's fair to show you the definition of it.

// slightly edited for displaying purposes
struct REPARSE_DATA_BUFFER {
DWORD  ReparseTag;
WORD   ReparseDataLength;
WORD   Reserved;
struct {
WORD   SubstituteNameOffset;
WORD   SubstituteNameLength;
WORD   PrintNameOffset;
WORD   PrintNameLength;
WCHAR  PathBuffer[1];
};


Armed with this struct, and a little knowledge of how Volume mount point strings looked, I went of to write some code.

I had no success whatsoever in using the SET FSCTL. DeviceIoControl only returned an error.

Now, I could GET a Volume mount point, that are easily created with the Disk Administrator equivalent or MountVol.exe, but I couldn't SET it back!

Suddenly a thought struck me, what if the definition of the SET macro changed?!

Comparing the definitions of these macros from the new SDK with the VC6 version confirmed my suspicions. The VC6 version looks like

#define FSCTL_SET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 41,
METHOD_BUFFERED, FILE_WRITE_DATA) // REPARSE_DATA_BUFFER,
#define FSCTL_GET_REPARSE_POINT     CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42,
METHOD_BUFFERED, FILE_ANY_ACCESS) // , REPARSE_DATA_BUFFER
#define FSCTL_DELETE_REPARSE_POINT  CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 43,
METHOD_BUFFERED, FILE_WRITE_DATA) // REPARSE_DATA_BUFFER,

but in the Windows 2000 SDK, it had been changed to
// Windows 2000 SDK
#define FSCTL_SET_REPARSE_POINT     CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 41,
METHOD_BUFFERED, FILE_SPECIAL_ACCESS) // REPARSE_DATA_BUFFER,
#define FSCTL_GET_REPARSE_POINT     CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42,
METHOD_BUFFERED, FILE_ANY_ACCESS) // REPARSE_DATA_BUFFER
#define FSCTL_DELETE_REPARSE_POINT  CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 43,
METHOD_BUFFERED, FILE_SPECIAL_ACCESS) // REPARSE_DATA_BUFFER,


The new FILE_SPECIAL_ACCESS is defined as:

#define FILE_SPECIAL_ACCESS (FILE_ANY_ACCESS)

Aha, they changed the access protection for SET and DELETE! That might explain why nothing worked.

Actually, the change in access protection makes some sense. A SET or DELETE operation on a reparse point doesn't need write access to the Directory it's used on. It only needs access to the NTFS Attributes for that directory.

As a sidenote I might add the following snippet from WinIoCtl.h from the windows 2000 SDK.

// FILE_SPECIAL_ACCESS is checked
// by the NT I/O system the same as FILE_ANY_ACCESS.
// for I/O and FS controls
// that use this value.

Interesting: It mentions that

I wonder how they are supposed to do that, since both ANY and SPECIAL access are defined to be zero.

Getting Closer

Finally I could both GET and SET a Volume mount point using DeviceIoControl, and thereby get some info of how this struct should be filled in.
The Volume mount points PathBuffer in REPARSE_DATA_BUFFER is a Unicode string that looks like

"\??\Volume{9424a4a2-bbb6-11d3-a640-806d6172696f}\"

The SubstituteNameLength tells how many bytes the PathBuffer contains. By disassembling SetVolumeMountPoint from kernel32.dll, I found out that it only accepts 96 or 98 bytes as buffer length.

Strange, was my first thought. But still I tried to use the Volume GUID with an appended directory name through DeviceIoControl, in the hope that it wouldn't have the same restrictions and only get resolved during access. Right?

Wrong. Why make it orthogonal when you can make it "cumbersome"?

After many hours of trial-and-error, and even more cursing, I was about ready to give in, and admit defeat, when I got an idea. What if you instead of using a Volume GUID, look back on the CreateFile documentation?

The Solution

According to CreateFile documentation, you can enter a non-parsed path by prepending "\??\" to it. What if we used this approach and put in a "normal" full path like

"\??\C:\Program Files"

Type some code, build and test...Finally! It worked!

So, finally, to create a directory junction point, you must do the following:

1. Create a directory, or use an existing empty directory.
2. Open this directory with CreateFile, using the flags    FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT
3. Create a filled-in REPARSE_DATA_BUFFER.
4. Call
DeviceIoControl(hDir,			// HANDLE to the directory
FSCTL_SET_REPARSE_POINT,
(LPVOID)&rdb,		// REPARSE_DATA_BUFFER
dwBytesToSet,
NULL,
0,
&dwBytes,
0);

5. Done.

Well, almost. It's still that little matter of filling in this struct.

Filling in the REPARSE_DATA_BUFFER example

// quick 'n' dirty solution
wchar_t wszDestDir[] = "\\??\\C:\\Program Files\";
const int nDestBytes = lstrlenW(wszDestDir) * sizeof(wchar_t);

char szBuff[1024] = { 0 };
REPARSE_DATA_BUFFER& rdb = *(REPARSE_DATA_BUFFER*)szBuff;

rdb.ReparseTag        = IO_REPARSE_TAG_MOUNT_POINT;
rdb.ReparseDataLength = nDestBytes + 12;

const DWORD dwBytesToSet = // input buffer size to give to DeviceIoControl


Ugly or what? I especially dislike the unnamed (i.e. it doesn't have a typename) struct SymbolicLinkReparseBuffer. Both that it's unnamed, and the length of its name makes the code quite unreadable.

I copied the definition of REPARSE_DATA_BUFFER from the VC6 header file to be able to use this even with the Windows 2000 SDK. I renamed it and removed the unnamed struct. In the process, it got some member functions to make its usage a lot easier.

Summary

As I said earlier in this article, possibly one of the most sought for features (and by that, looong overdue) in NTFS is "softlinks", and they didn't have the decency to neither document it, nor to provide any API whatsoever to use it.

I mean, get real; DeviceIoControl() to create a softlink?!

To make this a bit more usable, I wrote a little library that you can use in your own creations. The included program MakeLink.exe uses this library, and it's used to create, list and delete junction points. Just start MakeLink without arguments to see its usage.

The functions that IMO were missing from Microsofts API, and got implemented by this library (though in its own C++ namespace) are:

BOOL CreateJunctionPoint(LPCTSTR szMountDir, LPCTSTR szDestDir);
BOOL DeleteJunctionPoint(LPCTSTR szMountDir);
DWORD GetJunctionPointDestination(LPCTSTR szMountDir, LPTSTR szDestBuff,
DWORD dwBuffSize /* in TCHARs */);


These should be self explaining, but in the interest of completeness, here's some documentation.

CreateJunctionPoint

This function allows you to create or overwrite an existing junction point.

• szMountDir must point to an empty directory.
• szDestDir can either contain a path in the form "C:\Program Files" or "\??\C:\Program Files".
The first form will check if the directory exists before creating/overwriting the junction point. The second form allows you to enter just about any string as the destination.

Note that using the second form, you could create a Directory junction point that points to nowhere usable (e.g. "\??\foo:bar/baz").

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Note: Strictly speaking, you can use this function as a replacement for the MountVol.exe command using the "\??\" form, but I think that Disk Admin is better suited for that purpose.

DeleteJunctionPoint

This function allows you to remove any Volume Mount Points or Directory Junction Points from the specified directory.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

GetJunctionPointDestination

This function allows you to query any directory for its reparse point destination. Note that it will only work for reparse points of the type IO_REPARSE_TAG_MOUNT_POINT, but since this includes both Volume mount points and Directory junction points, it's fit for this library.

If the GetJunctionPointDestination succeeds, the return value is the the length, in TCHARs, of the string copied to szDestDir, not including the terminating null character.

If the szDestDir buffer is too small, the return value is the size of the buffer, in TCHARs, required to hold the path.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Final notes

The code is compilable as both ANSI and Unicode. It does not use MFC, standard C++ library, or any CRT memory management functions.

Writing this library and I had a few criterias in mind:

• Make an easy API for people to use. I always use CreateFile as a comparison.
• Create as few dependencies on other libraries as possible.
• Don't use MFC. Not everybody uses MFC, and to use it for a utility (library) like this is IMO like using a sledgehammer to type on your keyboard.
• Don't depend on the standard C++ library. Not everybody uses it, and though a correct implementation is good, PJP's Microsoft implementation is not correct, since their compilers can't handle a conforming implementation. Besides that:
• Make it small.

The application MakeLink.exe is 5 632 bytes. It does however depend on MSVCRT.dll (Microsoft C Runtime Library), but I think the size criteria was met. :-)

BTW:
While browsing the new documentation, in the documentation for SetVolumeMountPoint I found the following text

... "\\?\C:\myworld\private" is seen as "C:\myworld\private".
This initially led me to believe that I've done all this work for nothing!

Trying out this API (which according to its name is to mount Volumes only), I found out that they've only mentioned it, they don't implement this behaviour in SetVolumeMountPoint. Another point of interest is that the creator of this API apparently was completely unaware of the already documented approach of creating a non-parsed file system name "\??\", and charged ahead to invent "\\?\".

Mike Nordell - Nordell Consulting

A list of licenses authors might use can be found here

 Mike Nordell Architect Sweden Member
No Biography provided

Votes of 3 or less require a comment

 Search this forum Profile popups    Spacing RelaxedCompactTight   Noise Very HighHighMediumLowVery Low   Layout Open AllThread ViewNo JavascriptPreview   Per page 102550
 First PrevNext
 some wrong on 2t disk simulator nhchmg 15 Dec '10 - 22:55
 I test on 2T Disk,a tool, 2T Disk Simulator,it simulate a 2TB disk,1024,2048,4096 bytes/secotr,this app can not work.I found this tool on http://www.2tdisk.com Sign In·View Thread·Permalink
 My vote of 5 demonkoryu 13 Oct '10 - 23:58
 Junction Link Magic: Include Option to Select Folder Level Deep james.rapula 22 Jul '10 - 13:43
 This worked wonders for our organisation when we had to restructure the share data scaling the folders into different logical drives.Few months later, I revisited the site and learnt that Version 2 had been released which further improves the functionality which provides the option to select the drives to scan!!! I’m a very happy user of the utility and will be visiting this site often to see if there are any new or updates to the utilities.   Just a small addition:   I have just one little suggestion: would it be possible to make changes to JLM in that when it scans, it only does up to 4th or 5th folder level depth? Will be much better it the depth level can be optional before the scan kicks off just after the drive selection.   Thanks James Sign In·View Thread·Permalink
 Is Link to Network Drive Possible? Jonny Hart 5 Jun '08 - 22:26
 Hello,   First of all, I use makelink a lot now to resolve building projects against different revisions of common code libraries. Without it the build file management task would be horrendous - thank you!   I have the following situation:   A PC with a legacy app deposits files on it's C drive in a place that can't be changed (we dont have the source / compiler etc). I want these files to be placed on a shared drive on a remote networked machine. I have done the following:   1) Mapped a drive on legacy PC (runs NT4) to remote machine as Z: 2) makelink c:\localfilerepository\ z:\remotefilerepository   makelink fails. both folders are empty BTW.   Am I simply asking to much of makelink?   Regargs   Jon Sign In·View Thread·Permalink
 Cab and restore a folder which is a Junction/Link in other drive kulkarniquiet 7 Mar '07 - 22:32
 I have a query about Junction/link to a folder. How to identify junction in MFC in code? Is there ant specific method? If I make write some code to cab a folder which is a link(Junction) in other drive. So when I restored it back,will the link/junction be also restored at the destination? Kindly reply. Awaiting for the same.     Best Regards, Abhijit Sign In·View Thread·Permalink
 trailing backslash--bug? larham 28 Nov '06 - 8:59
 Volume Mount Points To Device PNP smclain 23 Jun '06 - 19:07
 I enjoyed the article. I have been looking for a way to go from a VolumeMountPoint to the PNP id of the associate storage device. I have not found an interface or set of steps for doing this. Do you have any suggestions.   Thanks Sign In·View Thread·Permalink
 Longhorn provides API for symlinks LOL curlyhands 25 Mar '06 - 20:53
 Shell Extension for junctions ryltsov 10 Feb '06 - 9:52
 Directory junction points now available directly from linkd.exe Matthias Fripp 29 Sep '05 - 12:39
 With p/Invoke jonscheiding 12 Sep '05 - 6:06
 I'm attempting to write a .NET library that can accomplish this through p/Invoke. So far things are going well, I have been able to get junction point info into a REPARSE_DATA_BUFFER struct which is formulated like this:   [StructLayout (LayoutKind.Explicit)] struct REPARSE_DATA_BUFFER { [FieldOffset (0)] uint ReparseTag; [FieldOffset (4)] ushort ReparseDataLength; [FieldOffset (8)] ushort SubstituteNameOffset; [FieldOffset (10)] ushort SubstituteNameLength; [FieldOffset (12)] ushort PrintNameOffset; [FieldOffset (14)] ushort PrintNameLength; [MarshalAs ( UnmanagedType.ByValArray, SizeConst=480 )] [FieldOffset (16)] byte [] PathBuffer; }Notice that the SizeConst on PathBuffer is 480, this means that if by some chance DeviceIoControl wants to put more than 480 bytes into the buffer (this can definitely happen), it will get truncated. However, if I set the SizeConst to any greater value, DeviceIoControl fails. GetLastError returns an error code of 6, which FormatMessage translates as "Invalid access to memory location".   Does anyone know why this is? Also, does anyone happen to know what a more ideal SizeConst value would be? What is the maximum length of paths in NTFS 5?   Thanks for your time! Sign In·View Thread·Permalink
 Re: With p/Invoke Mike Nordell 14 Sep '06 - 7:20
 I want it to be known I know exactly nothing about .NET and it's runtime.   That said, I (strongly) suspect this is a function of how the virtual machine functions. You probably need to actually touch (in Win32/NT parlance that'd be to commit it) all the physical memory SizeConst says follows. If not all memory is committed, a kernel-mode check that you've provided a large enough buffer of committed memory will fail. As such a kernel-mode code can't commit the memory for you, it returns an error.   ++luck; Sign In·View Thread·Permalink
 To get Information of localization of a resource in windows Ajay Movalia 6 Nov '03 - 1:05
 hello sir, I am almost areading all the articles of you. So I am very eager to know that the resources used by the window. bcz i am from gujarat India so i want to develop the localized resource in gujarati for windows. I know that I has to write the dll and replaced it with the existing dll. But i want to know wat function it contains. and wat are the resources used by the windows.   Please help me regarding this if possible...   Ajay Movalia Sign In·View Thread·Permalink
 IsReparseTagValid macro? Jerker Bäck 30 Sep '03 - 10:25
 Definition of "IsReparseTagValid" is missing in my system: Vc7, PSDK oct 2002, WinDDK XPsp1   Maybe it's replaced by "IsReparseTagMicrosoft"?   Jerker Bäck Sign In·View Thread·Permalink
 Re: IsReparseTagValid macro? Mike Nordell 30 Sep '03 - 11:35
 No, the two are different. They both used to be defined in winnt.h (VC6), but have since apparently been removed.   You might try the following:   #define IsReparseTagMicrosoft(_tag) ((_tag) & 0x80000000 #define IO_REPARSE_TAG_VALID_VALUES (0xE000FFFF) #define IsReparseTagValid(_tag) ( \ !((_tag) & ~IO_REPARSE_TAG_VALID_VALUES) && \ ((_tag) > 1) \ )   ++luck; Sign In·View Thread·Permalink
 Re: IsReparseTagValid macro? Jerker Bäck 1 Oct '03 - 12:33
 OK, interesting... if you show 0xE000FFFF in binary format and compare it with the info in winnt.h: 0xE000FFFF => 11100000000000001111111111111111 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +-+-+-+-------------------------+-------------------------------+ |M|L|N| Reserved bits | Reparse Tag Value | +-+-+-+-------------------------+-------------------------------+ tag > IO_REPARSE_TAG_RESERVED_RANGE (>1) this macro says that the reserved bits must be zero for the tag to be valid. The "IsReparseTagMicrosoft" macro just test the M-bit. But if it's not a Microsoft tag - what is it then? The IO_REPARSE_TAG_MOUNT_POINT tag could be tested for the N-bit (the only "known" tag who set this bit).   What about mounting a shell namespace? If one clear the M-bit, set the N-bit and make up some value for the Reparse Tag Value. How to do next? The psdk says: "To ensure uniqueness of tags, Microsoft provides a mechanism to distribute new tags. For more information, see the Windows 2000 IFS Kit."   Jerker Bäck Sign In·View Thread·Permalink
 Re: IsReparseTagValid macro? Jerker Bäck 7 Nov '04 - 12:30
 OK, I looked in to this again. The following is the correct macros from ntifs.h in Windows 2003 DDK IFS-kit.   // Macro to determine whether a reparse point tag corresponds to a tag // owned by Microsoft. #define IsReparseTagMicrosoft(_tag) (((_tag) & 0x80000000))   // Macro to determine whether a reparse point tag is a name surrogate #define IsReparseTagNameSurrogate(_tag) (((_tag) & 0x20000000))   // The following constant represents the bits that are valid to use in // reparse tags. #define IO_REPARSE_TAG_VALID_VALUES (0xF000FFFF)   // Macro to determine whether a reparse tag is a valid tag. #define IsReparseTagValid(_tag) ( \ !((_tag) & ~IO_REPARSE_TAG_VALID_VALUES) && \ ((_tag) > IO_REPARSE_TAG_RESERVED_RANGE))    The "IsReparseTagMicrosoft" macro is defined in winnt.h and Mike's code will compile if "IsReparseTagValid" is substituted with this.   Jerker Sign In·View Thread·Permalink
 Another REPARSE_DATA_BUFFER Jerker Bäck 30 Sep '03 - 7:52
 The REPARSE_DATA_BUFFER has probably been moved to the Microsoft IFS kit (not for everyone!) You can find a free version of the MS IFS kit's "ntifs.h" at "Bo Brantén [ntifs.zip]" Bo has listed an another version of the structure. If this works with making junctions remains to be seen.   There is also a similar utility to "MakeLink" called "junction" made by Mark Russinovich at SysInternals [jnctnsrc.zip], source code included.   Annars: tack Micke för koden!   Jerker Bäck Sign In·View Thread·Permalink
 Multi target ? Madium 3 Jul '03 - 9:59
 Is there any way to have multi-targeting working ?I explain: we have 3 folders: A, B & CA & B has their contents. C has the content of A & B together. I'm searching a global solution: if anyone know a solution that work, even without the use of junction it's ok.I also accept, if it's more easy that C should only be acceeded by network, (or is a network share). Thanks for any help Sign In·View Thread·Permalink
 Re: Multi target ? rumburaky 31 Jul '03 - 3:52
 If the contents are only files and A,B,C are folders on the same volume, a solution could be Hard Links (see CreateHardLink in MSDN). However there are some inconvenient if you remove or add files to A and B folders, the change will not be visible in the C folder. If you only change content of the files it will all be ok. Sign In·View Thread·Permalink
 Junction Pts for C:\Program Files and C:\Documents and Settings WarrenW 8 Jun '03 - 21:06
 I'm trying to link:  "C:\Documents and Settings" to "D:\Documents and Settings""C:\Program Files" to "D:\Program Files" Since source directories have to be empty to create junction points, a user has to move all subdirectories first. However, once booted into a machine, even in safe mode as "administrator", one cannot move the contents of "Program Files" and "Documents and Settings", because files are open and being written to, etc. I attempted to boot from the Win2K CD in console/rescue mode, move the directories, and then run "junction" (the Sysinternals utility) to make the links. Unfortunately, there is a limited set of commands that can be run from console (pretty much only the DOS command set), so this won't work either. So, is there any way to accomplish this? I'd appreciate any pointers. TIA  -- .W Sign In·View Thread·Permalink
 WarrenW wrote: So, is there any way to accomplish this?   The way I do it is to always have another Window installation ready to boot at another volume. Sign In·View Thread·Permalink
 I thought about doing this, however I'm also researching creating a bootable Win2K CD. Not easy, however.   I believe such a CD could be created via PE Builder, but that is difficult to get unless you are a developer. I'm also wondering if it's possible by booting from an ERD Commander CD. ...developing...  -- .W Sign In·View Thread·Permalink
 Re: Junction Pts for C:\Program Files and C:\Documents and Settings John M. Dlugosz 22 Feb '05 - 10:01
 I set up "BartPE" specifically for this purpose. It is a clone of the unobtainable PE mentioned in another reply. You can put on it any programs you want, including this one.   But, experimenting with it I found that the drive letter used by the junction needs to match that of the normal boot-time! It uses a drive letter rather than a unique volume name. (I'm going to experiment to see if it will work with the latter).   Before that, I accomplished moving Program Files by killing off any processes that still hold files open, or forcing the handles closed. Find out who using the SysInternals tools.   In the past, I've done it by renaming the directory as a "pending move", and after rebooting, when nothing works right but I run a command shell, then create a new empty directory and create a junction. However, this last time I found that something was creating files rather than just dieing.   --John Sign In·View Thread·Permalink
 Last Visit: 31 Dec '99 - 18:00     Last Update: 25 May '13 - 11:34 Refresh 123 Next »