Utility to create an NTFS junction point. Previously reviewed at:
https://chromiumcodereview.appspot.com/9693033/ Review URL: https://chromiumcodereview.appspot.com/10413056 git-svn-id: svn://svn.chromium.org/chrome/trunk/tools/depot_tools@138367 0039d316-1c4b-4281-b951-d872f2087c98experimental/szager/collated-output
parent
c30dc5911b
commit
35911f7f7d
@ -0,0 +1,161 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// This is a simple utility for creating NTFS junction points on XP and later
|
||||
// versions of Windows.
|
||||
|
||||
#define _WIN32_WINNT 0x0500
|
||||
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
|
||||
// This struct definition is absent from the system header files,
|
||||
// but is described here:
|
||||
// http://msdn.microsoft.com/en-us/library/ff552012.aspx
|
||||
typedef struct _REPARSE_DATA_BUFFER {
|
||||
ULONG ReparseTag;
|
||||
USHORT ReparseDataLength;
|
||||
USHORT Reserved;
|
||||
union {
|
||||
struct {
|
||||
USHORT SubstituteNameOffset;
|
||||
USHORT SubstituteNameLength;
|
||||
USHORT PrintNameOffset;
|
||||
USHORT PrintNameLength;
|
||||
ULONG Flags;
|
||||
WCHAR PathBuffer[1];
|
||||
} SymbolicLinkReparseBuffer;
|
||||
struct {
|
||||
USHORT SubstituteNameOffset;
|
||||
USHORT SubstituteNameLength;
|
||||
USHORT PrintNameOffset;
|
||||
USHORT PrintNameLength;
|
||||
WCHAR PathBuffer[1];
|
||||
} MountPointReparseBuffer;
|
||||
struct {
|
||||
UCHAR DataBuffer[1];
|
||||
} GenericReparseBuffer;
|
||||
};
|
||||
} REPARSE_DATA_BUFFER;
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
char buf[MAX_PATH*sizeof(WCHAR) + sizeof(REPARSE_DATA_BUFFER)]={'\0'};
|
||||
char* dest_path=NULL;
|
||||
char* src_path=NULL;
|
||||
char* src_link=NULL;
|
||||
char* src_vol=NULL;
|
||||
char* dest_vol=NULL;
|
||||
HANDLE dir=NULL;
|
||||
REPARSE_DATA_BUFFER* reparse = (REPARSE_DATA_BUFFER*) buf;
|
||||
int path_len=0, data_len=0;
|
||||
DWORD ioctl_return = 0xdeadbeef;
|
||||
|
||||
// To allow this to be used as a drop-in replacement for the posix ln command,
|
||||
// allow (and ignore) extra flags.
|
||||
if (argc != 3 && (argc !=4 || *argv[1] != '-')) {
|
||||
fputs("Usage: create-ntfs-junction <destination dir> <source dir>\n", stderr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
src_path = argv[argc-2];
|
||||
path_len = strlen(src_path);
|
||||
if (src_path[path_len-1] == '\\')
|
||||
src_path[path_len-1] = '\0';
|
||||
|
||||
dest_path = argv[argc-1];
|
||||
path_len = strlen(dest_path);
|
||||
if (dest_path[path_len-1] == '\\')
|
||||
dest_path[path_len-1] = '\0';
|
||||
|
||||
if (GetFileAttributes(src_path) == INVALID_FILE_ATTRIBUTES) {
|
||||
fprintf(stderr, "%s: No such animal.\n", src_path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!GetVolumePathName(src_path, buf, MAX_PATH)) {
|
||||
fprintf(stderr, "Couldn't get volume name for '%s'.\n", src_path);
|
||||
return -1;
|
||||
}
|
||||
src_vol = _strdup(buf);
|
||||
|
||||
if (!GetVolumePathName(dest_path, buf, MAX_PATH)) {
|
||||
fprintf(stderr, "Couldn't get volume name for '%s'.\n", dest_path);
|
||||
return -1;
|
||||
}
|
||||
dest_vol = _strdup(buf);
|
||||
|
||||
if (strcmp(src_vol, dest_vol)) {
|
||||
fprintf(stderr, "Cannot create junction point across volume boundary.\n");
|
||||
fprintf(stderr, " (from volume '%s' to volume '%s')\n", src_vol, dest_vol);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// End of input sanity checks; file system modifications may now occur.
|
||||
|
||||
if (GetFileAttributes(dest_path) == INVALID_FILE_ATTRIBUTES) {
|
||||
if (!CreateDirectory(dest_path, NULL)) {
|
||||
switch(GetLastError()) {
|
||||
case ERROR_ALREADY_EXISTS:
|
||||
fprintf(stderr, "Can't create directory %s because it already exists "
|
||||
"(this should never happen).\n", dest_path);
|
||||
return -1;
|
||||
break;
|
||||
case ERROR_PATH_NOT_FOUND:
|
||||
fprintf(stderr, "Can't create directory %s because some part of the "
|
||||
"intermediate path doesn't exist.", dest_path);
|
||||
return -1;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unknown error occurred while trying to create "
|
||||
"directory %s.", dest_path);
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dir = CreateFile(dest_path,
|
||||
GENERIC_WRITE,
|
||||
0,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
|
||||
NULL);
|
||||
|
||||
strcpy_s(buf, 5, "\\??\\");
|
||||
GetFullPathName(src_path, MAX_PATH, buf+4, NULL);
|
||||
src_link = _strdup(buf);
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
path_len = MultiByteToWideChar(CP_ACP,
|
||||
0,
|
||||
src_link,
|
||||
-1,
|
||||
reparse->MountPointReparseBuffer.PathBuffer,
|
||||
MAX_PATH*sizeof(WCHAR));
|
||||
|
||||
reparse->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
|
||||
reparse->ReparseDataLength = (path_len+2)*sizeof(WCHAR) + 6;
|
||||
reparse->MountPointReparseBuffer.SubstituteNameLength =
|
||||
(path_len-1) * sizeof(WCHAR);
|
||||
reparse->MountPointReparseBuffer.PrintNameOffset =
|
||||
path_len * sizeof(WCHAR);
|
||||
data_len = reparse->ReparseDataLength + 8;
|
||||
|
||||
if (!DeviceIoControl(dir,
|
||||
FSCTL_SET_REPARSE_POINT,
|
||||
&buf,
|
||||
data_len,
|
||||
NULL,
|
||||
0,
|
||||
&ioctl_return,
|
||||
NULL)) {
|
||||
fprintf(stderr, "Junction point creation failed (ioctl_return=0x%x) (%d)\n",
|
||||
ioctl_return, GetLastError());
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Binary file not shown.
Loading…
Reference in New Issue