2 * PROJECT: ReactOS Subst Command
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/system/subst/subst.c
5 * PURPOSE: Maps a path with a drive letter
6 * PROGRAMMERS: Sam Arun Raj
11 /* INCLUDES *****************************************************************/
15 #define WIN32_NO_STATUS
23 /* FUNCTIONS ****************************************************************/
25 VOID
PrintError(IN DWORD ErrCode
)
27 // DWORD dwLength = 0;
31 if (ErrCode
== ERROR_SUCCESS
)
35 /* Retrieve the message string without appending extra newlines */
37 FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
|
38 FORMAT_MESSAGE_IGNORE_INSERTS
| FORMAT_MESSAGE_MAX_WIDTH_MASK
,
44 if (pMsgBuf
/* && dwLength */)
46 ConResPrintf(StdErr
, IDS_FAILED_WITH_ERRORCODE
,
52 ULONG
QuerySubstedDrive(IN WCHAR DriveLetter
,
53 IN OUT PWSTR
* TargetPath OPTIONAL
,
56 ULONG Result
= ERROR_INVALID_DRIVE
;
57 WCHAR Drive
[] = L
"A:";
58 DWORD dwSize
, CharCount
= 0;
59 PWSTR lpTargetPath
= NULL
, tmp
;
61 Drive
[0] = DriveLetter
;
63 /* Check whether the user has given a pointer to a target path buffer */
66 /* No, therefore use a local buffer */
68 lpTargetPath
= (PWSTR
)HeapAlloc(GetProcessHeap(), 0, dwSize
* sizeof(WCHAR
));
70 return ERROR_NOT_ENOUGH_MEMORY
;
74 /* Just use the user-given pointer to a buffer; Size should point to a valid ULONG */
76 return ERROR_INVALID_PARAMETER
;
78 lpTargetPath
= *TargetPath
;
83 /* Try querying DOS device information */
84 CharCount
= QueryDosDeviceW(Drive
, lpTargetPath
, dwSize
);
86 Result
= GetLastError();
88 if (!CharCount
&& (Result
== ERROR_INSUFFICIENT_BUFFER
))
90 /* Reallocate the buffer with double size */
92 tmp
= (PWSTR
)HeapReAlloc(GetProcessHeap(), 0, lpTargetPath
, dwSize
* sizeof(WCHAR
));
95 /* Memory problem, bail out */
97 Result
= ERROR_NOT_ENOUGH_MEMORY
;
109 if ( wcsncmp(lpTargetPath
, L
"\\??\\", 4) == 0 &&
110 ( (lpTargetPath
[4] >= L
'A' && lpTargetPath
[4] <= L
'Z') ||
111 (lpTargetPath
[4] >= L
'a' && lpTargetPath
[4] <= L
'z') ) )
113 /* The drive exists and is SUBSTed */
114 Result
= ERROR_IS_SUBSTED
;
119 /* The drive exists but is not SUBSTed */
120 Result
= ERROR_INVALID_DRIVE
;
127 /* Free the local buffer */
128 HeapFree(GetProcessHeap(), 0, lpTargetPath
);
132 /* Update the user-given pointers */
133 *TargetPath
= lpTargetPath
;
140 VOID
DumpSubstedDrives(VOID
)
143 PWSTR lpTargetPath
= NULL
;
148 lpTargetPath
= (PWSTR
)HeapAlloc(GetProcessHeap(), 0, dwSize
* sizeof(WCHAR
));
154 DriveLetter
= L
'A' + i
;
155 if (QuerySubstedDrive(DriveLetter
, &lpTargetPath
, &dwSize
) == ERROR_IS_SUBSTED
)
157 ConPrintf(StdOut
, L
"%c:\\: => %s\n", DriveLetter
, lpTargetPath
+ 4);
163 HeapFree(GetProcessHeap(), 0, lpTargetPath
);
166 INT
DeleteSubst(IN PWSTR Drive
)
170 if ((wcslen(Drive
) != 2) || (Drive
[1] != L
':'))
172 dwResult
= ERROR_INVALID_PARAMETER
;
176 if (QuerySubstedDrive(Drive
[0], NULL
, NULL
) != ERROR_IS_SUBSTED
)
178 dwResult
= ERROR_INVALID_PARAMETER
;
182 if (!DefineDosDeviceW(DDD_REMOVE_DEFINITION
, Drive
, NULL
))
183 dwResult
= GetLastError();
185 dwResult
= ERROR_SUCCESS
;
193 // case ERROR_INVALID_DRIVE:
194 case ERROR_INVALID_PARAMETER
:
196 ConResPrintf(StdErr
, IDS_INVALID_PARAMETER2
, Drive
);
200 case ERROR_ACCESS_DENIED
:
202 ConResPrintf(StdErr
, IDS_ACCESS_DENIED
, Drive
);
208 PrintError(GetLastError());
216 INT
AddSubst(IN PWSTR Drive
, IN PWSTR Path
)
218 DWORD dwResult
, dwPathAttr
;
220 if ((wcslen(Drive
) != 2) || (Drive
[1] != L
':'))
222 dwResult
= ERROR_INVALID_PARAMETER
;
227 * Even if DefineDosDevice allows to map files to drive letters (yes yes!!)
228 * it is not the purpose of SUBST to allow that. Therefore check whether
229 * the given path exists and really is a path to a directory, and if not,
230 * just fail with an error.
232 dwPathAttr
= GetFileAttributesW(Path
);
233 if ( (dwPathAttr
== INVALID_FILE_ATTRIBUTES
) ||
234 !(dwPathAttr
& FILE_ATTRIBUTE_DIRECTORY
) )
236 dwResult
= ERROR_PATH_NOT_FOUND
;
241 * QuerySubstedDrive (via QueryDosDevice) returns ERROR_FILE_NOT_FOUND only
242 * if there is no already existing drive mapping. For all other results
243 * (existing drive, be it already subst'ed or not, or other errors...)
244 * no attempt at defining a drive mapping should be done.
246 dwResult
= QuerySubstedDrive(Drive
[0], NULL
, NULL
);
247 if (dwResult
!= ERROR_FILE_NOT_FOUND
)
250 if (!DefineDosDeviceW(0, Drive
, Path
))
251 dwResult
= GetLastError();
253 dwResult
= ERROR_SUCCESS
;
261 case ERROR_INVALID_DRIVE
:
262 case ERROR_INVALID_PARAMETER
:
264 ConResPrintf(StdErr
, IDS_INVALID_PARAMETER2
, Drive
);
268 case ERROR_IS_SUBSTED
:
270 ConResPuts(StdErr
, IDS_DRIVE_ALREADY_SUBSTED
);
274 case ERROR_FILE_NOT_FOUND
:
275 case ERROR_PATH_NOT_FOUND
:
277 ConResPrintf(StdErr
, IDS_PATH_NOT_FOUND
, Path
);
281 case ERROR_ACCESS_DENIED
:
283 ConResPrintf(StdErr
, IDS_ACCESS_DENIED
, Path
);
289 PrintError(GetLastError());
297 int wmain(int argc
, WCHAR
* argv
[])
301 /* Initialize the Console Standard Streams */
304 for (i
= 0; i
< argc
; i
++)
306 if (!_wcsicmp(argv
[i
], L
"/?"))
308 ConResPuts(StdOut
, IDS_USAGE
);
317 ConResPrintf(StdErr
, IDS_INVALID_PARAMETER
, argv
[1]);
326 ConResPrintf(StdErr
, IDS_INCORRECT_PARAMETER_COUNT
, argv
[3]);
330 if (!_wcsicmp(argv
[1], L
"/D"))
331 return DeleteSubst(argv
[2]);
332 if (!_wcsicmp(argv
[2], L
"/D"))
333 return DeleteSubst(argv
[1]);
334 return AddSubst(argv
[1], argv
[2]);