Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(51)

Unified Diff: tools/junction/junction.c

Issue 9693033: Utility to create NTFS junctions points. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Added file system check and less funny error message. Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tools/junction/junction.c
diff --git a/tools/junction/junction.c b/tools/junction/junction.c
new file mode 100644
index 0000000000000000000000000000000000000000..555bfa56dbf441cb2367ed7c7cd0c28ab84f9c17
--- /dev/null
+++ b/tools/junction/junction.c
@@ -0,0 +1,169 @@
+// 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;
M-A Ruel 2012/05/23 00:28:09 I highly recommend converting everything to wchar_
+ 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 fs_flags = 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: junction <destination dir> <source dir>\n", stderr);
M-A Ruel 2012/05/23 00:28:09 Why fputs here but fprintf around lines 91-92?
+ 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: invalid file attributes.\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);
M-A Ruel 2012/05/23 00:28:09 Head explodes. :)
+
+ 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;
+ }
+
+ GetVolumeInformation(src_vol, NULL, 0, NULL, NULL, &fs_flags, buf, MAX_PATH);
+ if (!(fs_flags & FILE_SUPPORTS_REPARSE_POINTS)) {
+ fprintf(stderr, "File system type '%s' does not support reparse points.\n",
+ buf);
+ 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 "
nsylvain 2012/03/16 18:24:18 you should probably print the error here.
+ "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;
+}
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698