Chromium Code Reviews| OLD | NEW | 
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 // | |
| 5 // This is a simple utility for creating NTFS junction points on XP and later | |
| 6 // versions of Windows. | |
| 7 | |
| 8 #define _WIN32_WINNT 0x0500 | |
| 9 | |
| 10 #include <stdio.h> | |
| 11 #include <windows.h> | |
| 12 | |
| 13 // This struct definition is absent from the system header files, | |
| 14 // but is described here: | |
| 15 // http://msdn.microsoft.com/en-us/library/ff552012.aspx | |
| 16 typedef struct _REPARSE_DATA_BUFFER { | |
| 17 ULONG ReparseTag; | |
| 18 USHORT ReparseDataLength; | |
| 19 USHORT Reserved; | |
| 20 union { | |
| 21 struct { | |
| 22 USHORT SubstituteNameOffset; | |
| 23 USHORT SubstituteNameLength; | |
| 24 USHORT PrintNameOffset; | |
| 25 USHORT PrintNameLength; | |
| 26 ULONG Flags; | |
| 27 WCHAR PathBuffer[1]; | |
| 28 } SymbolicLinkReparseBuffer; | |
| 29 struct { | |
| 30 USHORT SubstituteNameOffset; | |
| 31 USHORT SubstituteNameLength; | |
| 32 USHORT PrintNameOffset; | |
| 33 USHORT PrintNameLength; | |
| 34 WCHAR PathBuffer[1]; | |
| 35 } MountPointReparseBuffer; | |
| 36 struct { | |
| 37 UCHAR DataBuffer[1]; | |
| 38 } GenericReparseBuffer; | |
| 39 }; | |
| 40 } REPARSE_DATA_BUFFER; | |
| 41 | |
| 42 int main (int argc, char *argv[]) | |
| 
 
cmp
2012/03/14 17:43:38
no space after main
 
szager
2012/03/14 19:04:04
Done.
 
 | |
| 43 { | |
| 44 char buf[MAX_PATH*sizeof(WCHAR) + sizeof(REPARSE_DATA_BUFFER)]={'\0'}; | |
| 45 char* dest_path=NULL; | |
| 
 
cmp
2012/03/14 17:43:38
spaces around = here and below
 
szager
2012/03/14 19:04:04
Done.
 
 | |
| 46 char* src_path=NULL; | |
| 47 char* src_link=NULL; | |
| 48 char* src_vol=NULL; | |
| 49 char* dest_vol=NULL; | |
| 50 HANDLE dir=NULL; | |
| 51 REPARSE_DATA_BUFFER* reparse = (REPARSE_DATA_BUFFER*) buf; | |
| 52 int path_len=0, data_len=0; | |
| 53 DWORD ioctl_return = 0xdeadbeef; | |
| 54 | |
| 55 // To allow this to be used as a drop-in replacement for the posix ln command, | |
| 56 // allow (and ignore) extra flags. | |
| 57 if (argc != 3 && (argc !=4 || *argv[1] != '-')) { | |
| 58 fputs("Usage: junction <destination dir> <source dir>\n", stderr); | |
| 59 return -1; | |
| 60 } | |
| 61 | |
| 62 src_path = argv[argc-2]; | |
| 63 path_len = strlen(src_path); | |
| 64 if (src_path[path_len-1] == '\\') | |
| 65 src_path[path_len-1] = '\0'; | |
| 66 | |
| 67 dest_path = argv[argc-1]; | |
| 68 path_len = strlen(dest_path); | |
| 69 if (dest_path[path_len-1] == '\\') | |
| 70 dest_path[path_len-1] = '\0'; | |
| 71 | |
| 72 if (GetFileAttributes(src_path) == INVALID_FILE_ATTRIBUTES) { | |
| 
 
cmp
2012/03/14 17:45:11
This code seems to assume that it's running on a N
 
szager
2012/03/14 19:04:04
Added this check below.
 
 | |
| 73 fprintf(stderr, "%s: No such animal.\n", src_path); | |
| 
 
cmp
2012/03/14 17:43:38
:)  Any objection to changing this to "Invalid fil
 
szager
2012/03/14 19:04:04
Done.
 
 | |
| 74 return -1; | |
| 75 } | |
| 76 | |
| 77 if (!GetVolumePathName(src_path, buf, MAX_PATH)) { | |
| 78 fprintf(stderr, "Couldn't get volume name for '%s'.\n", src_path); | |
| 79 return -1; | |
| 80 } | |
| 81 src_vol = _strdup(buf); | |
| 82 | |
| 83 if (!GetVolumePathName(dest_path, buf, MAX_PATH)) { | |
| 84 fprintf(stderr, "Couldn't get volume name for '%s'.\n", dest_path); | |
| 85 return -1; | |
| 86 } | |
| 87 dest_vol = _strdup(buf); | |
| 88 | |
| 89 if (strcmp(src_vol, dest_vol)) { | |
| 90 fprintf(stderr, "Cannot create junction point across volume boundary.\n"); | |
| 91 fprintf(stderr, " (from volume '%s' to volume '%s')\n", src_vol, dest_vol); | |
| 92 return -1; | |
| 93 } | |
| 94 | |
| 95 // End of input sanity checks; file system modifications may now occur. | |
| 96 | |
| 97 if (GetFileAttributes(dest_path) == INVALID_FILE_ATTRIBUTES) { | |
| 98 if (!CreateDirectory(dest_path, NULL)) { | |
| 99 switch(GetLastError()) { | |
| 100 case ERROR_ALREADY_EXISTS: | |
| 
 
cmp
2012/03/14 17:43:38
Is there a way to check for the next 2 cases befor
 
szager
2012/03/14 19:04:04
There's no ordering implied in a case statement, o
 
cmp
2012/03/14 19:10:10
I mean what if you moved the tests for these condi
 
 | |
| 101 fprintf(stderr, "Can't create directory %s because it already exists " | |
| 102 "(this should never happen).\n", dest_path); | |
| 103 return -1; | |
| 104 break; | |
| 105 case ERROR_PATH_NOT_FOUND: | |
| 106 fprintf(stderr, "Can't create directory %s because some part of the " | |
| 107 "intermediate path doesn't exist.", dest_path); | |
| 108 return -1; | |
| 109 break; | |
| 110 default: | |
| 111 fprintf(stderr, "Unknown error occurred while trying to create " | |
| 112 "directory %s.", dest_path); | |
| 113 return -1; | |
| 114 break; | |
| 115 } | |
| 116 } | |
| 117 } | |
| 118 | |
| 119 dir = CreateFile(dest_path, | |
| 120 GENERIC_WRITE, | |
| 121 0, | |
| 122 NULL, | |
| 123 OPEN_EXISTING, | |
| 124 FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, | |
| 125 NULL); | |
| 126 | |
| 127 strcpy_s(buf, 5, "\\??\\"); | |
| 128 GetFullPathName(src_path, MAX_PATH, buf+4, NULL); | |
| 129 src_link = _strdup(buf); | |
| 130 | |
| 131 memset(buf, 0, sizeof(buf)); | |
| 132 path_len = MultiByteToWideChar(CP_ACP, | |
| 133 0, | |
| 134 src_link, | |
| 135 -1, | |
| 136 reparse->MountPointReparseBuffer.PathBuffer, | |
| 137 MAX_PATH*sizeof(WCHAR)); | |
| 138 | |
| 139 reparse->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; | |
| 140 reparse->ReparseDataLength = (path_len+2)*sizeof(WCHAR) + 6; | |
| 141 reparse->MountPointReparseBuffer.SubstituteNameLength = | |
| 142 (path_len-1) * sizeof(WCHAR); | |
| 143 reparse->MountPointReparseBuffer.PrintNameOffset = | |
| 144 path_len * sizeof(WCHAR); | |
| 145 data_len = reparse->ReparseDataLength + 8; | |
| 146 | |
| 147 if (!DeviceIoControl(dir, | |
| 148 FSCTL_SET_REPARSE_POINT, | |
| 149 &buf, | |
| 150 data_len, | |
| 151 NULL, | |
| 152 0, | |
| 153 &ioctl_return, | |
| 154 NULL)) { | |
| 155 fprintf(stderr, "Junction point creation failed (ioctl_return=0x%x) (%d)\n", | |
| 156 ioctl_return, GetLastError()); | |
| 157 return 1; | |
| 
 
cmp
2012/03/14 17:43:38
In the other error conditions you return -1, but y
 
szager
2012/03/14 19:04:04
I usually use -1 to indicate that the program exit
 
cmp
2012/03/14 19:10:10
Ok, I'm sold. :)
 
 | |
| 158 } | |
| 159 | |
| 160 return 0; | |
| 161 } | |
| OLD | NEW |