ReactOS  0.4.14-dev-384-g5b37caa
mklink.c
Go to the documentation of this file.
1 /*
2  * MKLINK.C - mklink internal command.
3  */
4 
5 #include "precomp.h"
6 
7 #ifdef INCLUDE_CMD_MKLINK
8 
9 /* There is no API for creating junctions, so we must do it the hard way */
11 {
12  /* Structure for reparse point daya when ReparseTag is one of
13  * the tags defined by Microsoft. Copied from MinGW winnt.h */
14  typedef struct _REPARSE_DATA_BUFFER
15  {
18  WORD Reserved;
19  _ANONYMOUS_UNION union
20  {
21  struct
22  {
27  ULONG Flags;
28  WCHAR PathBuffer[1];
30  struct
31  {
36  WCHAR PathBuffer[1];
38  struct
39  {
40  BYTE DataBuffer[1];
44 
45  HMODULE hNTDLL = GetModuleHandle(_T("NTDLL"));
47  = (BOOLEAN (WINAPI *)(PCWSTR, PUNICODE_STRING, PCWSTR *, CURDIR *))GetProcAddress(hNTDLL, "RtlDosPathNameToNtPathName_U");
49  = (VOID (WINAPI *)(PUNICODE_STRING))GetProcAddress(hNTDLL, "RtlFreeUnicodeString");
50 
51  TCHAR TargetFullPath[MAX_PATH];
52 #ifdef UNICODE
53  #define TargetFullPathW TargetFullPath
54 #else
55  WCHAR TargetFullPathW[MAX_PATH];
56 #endif
57  UNICODE_STRING TargetNTPath;
58  HANDLE hJunction;
59 
60  /* The data for this kind of reparse point has two strings:
61  * The first ("SubstituteName") is the full target path in NT format,
62  * the second ("PrintName") is the full target path in Win32 format.
63  * Both of these must be wide-character strings. */
66  !GetFullPathName(TargetName, MAX_PATH, TargetFullPath, NULL) ||
67 #ifndef UNICODE
68  !MultiByteToWideChar(CP_ACP, 0, TargetFullPath, -1, TargetFullPathW, -1) ||
69 #endif
70  !RtlDosPathNameToNtPathName_U(TargetFullPathW, &TargetNTPath, NULL, NULL))
71  {
72  return FALSE;
73  }
74 
75  /* We have both the names we need, so time to create the junction.
76  * Start with an empty directory */
77  if (!CreateDirectory(LinkName, NULL))
78  {
79  RtlFreeUnicodeString(&TargetNTPath);
80  return FALSE;
81  }
82 
83  /* Open the directory we just created */
84  hJunction = CreateFile(LinkName, GENERIC_WRITE, 0, NULL,
86  if (hJunction != INVALID_HANDLE_VALUE)
87  {
88  /* Allocate a buffer large enough to hold both strings, including trailing NULs */
89  SIZE_T TargetLen = wcslen(TargetFullPathW) * sizeof(WCHAR);
90  DWORD DataSize = (DWORD)(FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer)
91  + TargetNTPath.Length + sizeof(WCHAR)
92  + TargetLen + sizeof(WCHAR));
94 
95  /* Fill it out and use it to turn the directory into a reparse point */
96  Data->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
97  Data->ReparseDataLength = (WORD)(DataSize - FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer));
98  Data->Reserved = 0;
99  Data->MountPointReparseBuffer.SubstituteNameOffset = 0;
100  Data->MountPointReparseBuffer.SubstituteNameLength = TargetNTPath.Length;
101  wcscpy(Data->MountPointReparseBuffer.PathBuffer,
102  TargetNTPath.Buffer);
103  Data->MountPointReparseBuffer.PrintNameOffset = TargetNTPath.Length + sizeof(WCHAR);
104  Data->MountPointReparseBuffer.PrintNameLength = (USHORT)TargetLen;
105  wcscpy((WCHAR *)((BYTE *)Data->MountPointReparseBuffer.PathBuffer
106  + Data->MountPointReparseBuffer.PrintNameOffset),
107  TargetFullPathW);
109  Data, DataSize, NULL, 0, &DataSize, NULL))
110  {
111  /* Success */
112  CloseHandle(hJunction);
113  RtlFreeUnicodeString(&TargetNTPath);
114  return TRUE;
115  }
116  CloseHandle(hJunction);
117  }
118  RemoveDirectory(LinkName);
119  RtlFreeUnicodeString(&TargetNTPath);
120  return FALSE;
121 }
122 
123 INT
125 {
126  HMODULE hKernel32 = GetModuleHandle(_T("KERNEL32"));
127  DWORD Flags = 0;
128  enum { SYMBOLIC, HARD, JUNCTION } LinkType = SYMBOLIC;
129  INT NumFiles = 0;
130  LPTSTR Name[2];
131  INT argc, i;
132  LPTSTR *arg;
133 
134  if (!_tcsncmp(param, _T("/?"), 2))
135  {
137  return 0;
138  }
139 
140  arg = split(param, &argc, FALSE, FALSE);
141  for (i = 0; i < argc; i++)
142  {
143  if (arg[i][0] == _T('/'))
144  {
145  if (!_tcsicmp(arg[i], _T("/D")))
146  Flags |= 1; /* SYMBOLIC_LINK_FLAG_DIRECTORY */
147  else if (!_tcsicmp(arg[i], _T("/H")))
148  LinkType = HARD;
149  else if (!_tcsicmp(arg[i], _T("/J")))
150  LinkType = JUNCTION;
151  else
152  {
154  freep(arg);
155  return 1;
156  }
157  }
158  else
159  {
160  if (NumFiles == 2)
161  {
163  freep(arg);
164  return 1;
165  }
166  Name[NumFiles++] = arg[i];
167  }
168  }
169  freep(arg);
170 
171  if (NumFiles != 2)
172  {
174  return 1;
175  }
176 
177  nErrorLevel = 0;
178 
179  if (LinkType == SYMBOLIC)
180  {
181  /* CreateSymbolicLink doesn't exist in old versions of Windows,
182  * so load dynamically */
184 #ifdef UNICODE
185  = (BOOL (WINAPI *)(LPCTSTR, LPCTSTR, DWORD))GetProcAddress(hKernel32, "CreateSymbolicLinkW");
186 #else
187  = (BOOL (WINAPI *)(LPCTSTR, LPCTSTR, DWORD))GetProcAddress(hKernel32, "CreateSymbolicLinkA");
188 #endif
190  {
192  return 0;
193  }
194  }
195  else if (LinkType == HARD)
196  {
197  /* CreateHardLink doesn't exist in old versions of Windows,
198  * so load dynamically */
199  BOOL (WINAPI *CreateHardLink)(LPCTSTR, LPCTSTR, LPSECURITY_ATTRIBUTES)
200 #ifdef UNICODE
201  = (BOOL (WINAPI *)(LPCTSTR, LPCTSTR, LPSECURITY_ATTRIBUTES))GetProcAddress(hKernel32, "CreateHardLinkW");
202 #else
203  = (BOOL (WINAPI *)(LPCTSTR, LPCTSTR, LPSECURITY_ATTRIBUTES))GetProcAddress(hKernel32, "CreateHardLinkA");
204 #endif
205  if (CreateHardLink && CreateHardLink(Name[0], Name[1], NULL))
206  {
208  return 0;
209  }
210  }
211  else
212  {
213  if (CreateJunction(Name[0], Name[1]))
214  {
216  return 0;
217  }
218  }
219 
220  ErrorMessage(GetLastError(), _T("MKLINK"));
221  return 1;
222 }
223 
224 #endif /* INCLUDE_CMD_MKLINK */
INT nErrorLevel
Definition: cmd.c:157
static int argc
Definition: ServiceArgs.c:12
wchar_t UNICODE
Definition: ms-dtyp.idl:111
const uint16_t * PCWSTR
Definition: typedefs.h:55
#define TRUE
Definition: types.h:120
const CHAR * LPCTSTR
Definition: xmlstorage.h:193
#define CloseHandle
Definition: compat.h:406
struct _SECURITY_ATTRIBUTES * LPSECURITY_ATTRIBUTES
#define _tcsicmp
Definition: xmlstorage.h:205
#define STRING_MKLINK_CREATED_JUNCTION
Definition: resource.h:237
#define _ANONYMOUS_UNION
Definition: ntbasedef.h:30
#define CP_ACP
Definition: compat.h:99
static VOID ErrorMessage(DWORD dwErrorCode, LPWSTR szFormat,...)
Definition: attrib.c:51
#define RemoveDirectory
Definition: winbase.h:3719
#define INVALID_HANDLE_VALUE
Definition: compat.h:399
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1059
void * arg
Definition: msvc.h:12
#define BOOL
Definition: nt_native.h:43
#define DWORD
Definition: nt_native.h:44
USHORT PrintNameOffset
Definition: shellext.h:173
int32_t INT
Definition: typedefs.h:56
CHAR * LPTSTR
Definition: xmlstorage.h:192
#define IO_REPARSE_TAG_MOUNT_POINT
Definition: iotypes.h:6875
WCHAR PathBuffer[1]
Definition: shellext.h:176
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
unsigned int BOOL
Definition: ntddk_ex.h:94
VOID error_req_param_missing(VOID)
Definition: error.c:108
#define GENERIC_WRITE
Definition: nt_native.h:90
USHORT SubstituteNameLength
Definition: shellext.h:172
unsigned char BOOLEAN
static VOID freep(LPSTR *p)
Definition: cmdcons.c:98
UCHAR DataBuffer[1]
Definition: shellext.h:188
smooth NULL
Definition: ftsmooth.c:416
#define OPEN_EXISTING
Definition: compat.h:434
char TCHAR
Definition: xmlstorage.h:189
#define _T(x)
Definition: vfdio.h:22
__wchar_t WCHAR
Definition: xmlstorage.h:180
struct _REPARSE_DATA_BUFFER::@308::@311 MountPointReparseBuffer
GLfloat param
Definition: glext.h:5796
#define MAX_PATH
Definition: compat.h:26
#define WINAPI
Definition: msvc.h:8
static LPSTR * split(LPSTR s, LPINT args)
Definition: cmdcons.c:163
unsigned short WORD
Definition: ntddk_ex.h:93
#define ConOutResPrintf(uID,...)
Definition: console.h:48
unsigned long DWORD
Definition: ntddk_ex.h:95
NTSYSAPI VOID NTAPI RtlFreeUnicodeString(PUNICODE_STRING UnicodeString)
VOID error_invalid_switch(TCHAR)
Definition: error.c:70
_CRTIMP wchar_t *__cdecl wcscpy(_Out_writes_z_(_String_length_(_Source)+1) wchar_t *_Dest, _In_z_ const wchar_t *_Source)
USHORT ReparseDataLength
Definition: shellext.h:166
#define VOID
Definition: acefi.h:82
unsigned char BYTE
Definition: mem.h:68
#define GetFullPathName
Definition: winbase.h:3645
WCHAR TargetName[256]
Definition: arping.c:27
struct _REPARSE_DATA_BUFFER::@308::@310 SymbolicLinkReparseBuffer
VOID error_too_many_parameters(LPTSTR)
Definition: error.c:77
struct _REPARSE_DATA_BUFFER REPARSE_DATA_BUFFER
struct _REPARSE_DATA_BUFFER::@308::@312 GenericReparseBuffer
ULONG_PTR SIZE_T
Definition: typedefs.h:78
static LPWSTR CreateSymbolicLink(IN LPGUID InterfaceGuid, IN LPCWSTR ReferenceString, IN struct DeviceInfo *devInfo)
Definition: interface.c:295
BOOL WINAPI DeviceIoControl(IN HANDLE hDevice, IN DWORD dwIoControlCode, IN LPVOID lpInBuffer OPTIONAL, IN DWORD nInBufferSize OPTIONAL, OUT LPVOID lpOutBuffer OPTIONAL, IN DWORD nOutBufferSize OPTIONAL, OUT LPDWORD lpBytesReturned OPTIONAL, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: deviceio.c:136
#define GetModuleHandle
Definition: winbase.h:3651
IN OUT PVCB OUT PDIRENT OUT PBCB IN BOOLEAN CreateFile
Definition: fatprocs.h:904
unsigned short USHORT
Definition: pedump.c:61
#define STRING_MKLINK_CREATED_SYMBOLIC
Definition: resource.h:235
#define STRING_MKLINK_HELP
Definition: resource.h:84
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:254
UNICODE_STRING * PUNICODE_STRING
Definition: env_spec_w32.h:373
#define MultiByteToWideChar
Definition: compat.h:100
#define ConOutResPuts(uID)
Definition: console.h:36
_ANONYMOUS_UNION union _REPARSE_DATA_BUFFER::@3725 DUMMYUNIONNAME
#define BOOLEAN
Definition: pedump.c:73
#define FILE_FLAG_BACKUP_SEMANTICS
Definition: disk.h:41
USHORT SubstituteNameOffset
Definition: shellext.h:171
unsigned int ULONG
Definition: retypes.h:1
#define GetProcAddress(x, y)
Definition: compat.h:418
#define FSCTL_SET_REPARSE_POINT
Definition: winioctl.h:98
#define STRING_MKLINK_CREATED_HARD
Definition: resource.h:236
int _tcsncmp(const _TCHAR *s1, const _TCHAR *s2, size_t n)
Definition: tcsncmp.h:9
size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
_In_ NDIS_STATUS _In_ ULONG _In_ USHORT _In_opt_ PVOID _In_ ULONG DataSize
Definition: ndis.h:4751
USHORT PrintNameLength
Definition: shellext.h:174
struct _REPARSE_DATA_BUFFER * PREPARSE_DATA_BUFFER
NTSYSAPI BOOLEAN NTAPI RtlDosPathNameToNtPathName_U(_In_opt_z_ PCWSTR DosPathName, _Out_ PUNICODE_STRING NtPathName, _Out_opt_ PCWSTR *NtFileNamePart, _Out_opt_ PRTL_RELATIVE_NAME_U DirectoryInfo)