From 35911f7f7d8e105ff286f7a1aa64a303d80152b7 Mon Sep 17 00:00:00 2001 From: "szager@google.com" Date: Tue, 22 May 2012 21:35:01 +0000 Subject: [PATCH] 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-d872f2087c98 --- create-ntfs-junction.c | 161 +++++++++++++++++++++++++++++++++++++++ create-ntfs-junction.exe | Bin 0 -> 8704 bytes 2 files changed, 161 insertions(+) create mode 100644 create-ntfs-junction.c create mode 100755 create-ntfs-junction.exe diff --git a/create-ntfs-junction.c b/create-ntfs-junction.c new file mode 100644 index 000000000..1b4d08ba3 --- /dev/null +++ b/create-ntfs-junction.c @@ -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 +#include + +// 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 \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; +} diff --git a/create-ntfs-junction.exe b/create-ntfs-junction.exe new file mode 100755 index 0000000000000000000000000000000000000000..12e0b7c5e3b4b2ba7680984658263a043f1d689c GIT binary patch literal 8704 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 KNU#4V