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
)
31 if (ErrCode
== ERROR_SUCCESS
)
35 /* Retrieve the message string without appending extra newlines */
36 dwLength
= FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
|
37 FORMAT_MESSAGE_IGNORE_INSERTS
| FORMAT_MESSAGE_MAX_WIDTH_MASK
,
43 if (pMsgBuf
/* && dwLength */)
45 ConResPrintf(StdErr
, IDS_FAILED_WITH_ERRORCODE
,
51 ULONG
QuerySubstedDrive(IN WCHAR DriveLetter
,
52 IN OUT PWSTR
* TargetPath OPTIONAL
,
55 ULONG Result
= ERROR_INVALID_DRIVE
;
56 WCHAR Drive
[] = L
"A:";
57 DWORD dwSize
, CharCount
= 0;
58 PWSTR lpTargetPath
= NULL
, tmp
;
60 Drive
[0] = DriveLetter
;
62 /* Check whether the user has given a pointer to a target path buffer */
65 /* No, therefore use a local buffer */
67 lpTargetPath
= (PWSTR
)HeapAlloc(GetProcessHeap(), 0, dwSize
* sizeof(WCHAR
));
69 return ERROR_NOT_ENOUGH_MEMORY
;
73 /* Just use the user-given pointer to a buffer; Size should point to a valid ULONG */
75 return ERROR_INVALID_PARAMETER
;
77 lpTargetPath
= *TargetPath
;
82 /* Try querying DOS device information */
83 CharCount
= QueryDosDeviceW(Drive
, lpTargetPath
, dwSize
);
85 Result
= GetLastError();
87 if (!CharCount
&& (Result
== ERROR_INSUFFICIENT_BUFFER
))
89 /* Reallocate the buffer with double size */
91 tmp
= (PWSTR
)HeapReAlloc(GetProcessHeap(), 0, lpTargetPath
, dwSize
* sizeof(WCHAR
));
94 /* Memory problem, bail out */
96 Result
= ERROR_NOT_ENOUGH_MEMORY
;
108 if ( wcsncmp(lpTargetPath
, L
"\\??\\", 4) == 0 &&
109 ( (lpTargetPath
[4] >= L
'A' && lpTargetPath
[4] <= L
'Z') ||
110 (lpTargetPath
[4] >= L
'a' && lpTargetPath
[4] <= L
'z') ) )
112 /* The drive exists and is SUBSTed */
113 Result
= ERROR_IS_SUBSTED
;
118 /* The drive exists but is not SUBSTed */
119 Result
= ERROR_INVALID_DRIVE
;
126 /* Free the local buffer */
127 HeapFree(GetProcessHeap(), 0, lpTargetPath
);
131 /* Update the user-given pointers */
132 *TargetPath
= lpTargetPath
;
139 VOID
DumpSubstedDrives(VOID
)
142 PWSTR lpTargetPath
= NULL
;
147 lpTargetPath
= (PWSTR
)HeapAlloc(GetProcessHeap(), 0, dwSize
* sizeof(WCHAR
));
153 DriveLetter
= L
'A' + i
;
154 if (QuerySubstedDrive(DriveLetter
, &lpTargetPath
, &dwSize
) == ERROR_IS_SUBSTED
)
156 ConPrintf(StdOut
, L
"%c:\\: => %s\n", DriveLetter
, lpTargetPath
+ 4);
162 HeapFree(GetProcessHeap(), 0, lpTargetPath
);
165 INT
DeleteSubst(IN PWSTR Drive
)
169 if ((wcslen(Drive
) != 2) || (Drive
[1] != L
':'))
171 dwResult
= ERROR_INVALID_PARAMETER
;
175 if (QuerySubstedDrive(Drive
[0], NULL
, NULL
) != ERROR_IS_SUBSTED
)
177 dwResult
= ERROR_INVALID_PARAMETER
;
181 if (!DefineDosDeviceW(DDD_REMOVE_DEFINITION
, Drive
, NULL
))
182 dwResult
= GetLastError();
184 dwResult
= ERROR_SUCCESS
;
192 // case ERROR_INVALID_DRIVE:
193 case ERROR_INVALID_PARAMETER
:
195 ConResPrintf(StdErr
, IDS_INVALID_PARAMETER2
, Drive
);
199 case ERROR_ACCESS_DENIED
:
201 ConResPrintf(StdErr
, IDS_ACCESS_DENIED
, Drive
);
207 PrintError(GetLastError());
215 INT
AddSubst(IN PWSTR Drive
, IN PWSTR Path
)
217 DWORD dwResult
, dwPathAttr
;
219 if ((wcslen(Drive
) != 2) || (Drive
[1] != L
':'))
221 dwResult
= ERROR_INVALID_PARAMETER
;
226 * Even if DefineDosDevice allows to map files to drive letters (yes yes!!)
227 * it is not the purpose of SUBST to allow that. Therefore check whether
228 * the given path exists and really is a path to a directory, and if not,
229 * just fail with an error.
231 dwPathAttr
= GetFileAttributesW(Path
);
232 if ( (dwPathAttr
== INVALID_FILE_ATTRIBUTES
) ||
233 !(dwPathAttr
& FILE_ATTRIBUTE_DIRECTORY
) )
235 dwResult
= ERROR_PATH_NOT_FOUND
;
240 * QuerySubstedDrive (via QueryDosDevice) returns ERROR_FILE_NOT_FOUND only
241 * if there is no already existing drive mapping. For all other results
242 * (existing drive, be it already subst'ed or not, or other errors...)
243 * no attempt at defining a drive mapping should be done.
245 dwResult
= QuerySubstedDrive(Drive
[0], NULL
, NULL
);
246 if (dwResult
!= ERROR_FILE_NOT_FOUND
)
249 if (!DefineDosDeviceW(0, Drive
, Path
))
250 dwResult
= GetLastError();
252 dwResult
= ERROR_SUCCESS
;
260 case ERROR_INVALID_DRIVE
:
261 case ERROR_INVALID_PARAMETER
:
263 ConResPrintf(StdErr
, IDS_INVALID_PARAMETER2
, Drive
);
267 case ERROR_IS_SUBSTED
:
269 ConResPrintf(StdErr
, IDS_DRIVE_ALREADY_SUBSTED
);
273 case ERROR_FILE_NOT_FOUND
:
274 case ERROR_PATH_NOT_FOUND
:
276 ConResPrintf(StdErr
, IDS_PATH_NOT_FOUND
, Path
);
280 case ERROR_ACCESS_DENIED
:
282 ConResPrintf(StdErr
, IDS_ACCESS_DENIED
, Path
);
288 PrintError(GetLastError());
296 int wmain(int argc
, WCHAR
* argv
[])
300 /* Initialize the Console Standard Streams */
303 for (i
= 0; i
< argc
; i
++)
305 if (!_wcsicmp(argv
[i
], L
"/?"))
307 ConResPrintf(StdOut
, IDS_USAGE
);
316 ConResPrintf(StdErr
, IDS_INVALID_PARAMETER
, argv
[1]);
325 ConResPrintf(StdErr
, IDS_INCORRECT_PARAMETER_COUNT
, argv
[3]);
329 if (!_wcsicmp(argv
[1], L
"/D"))
330 return DeleteSubst(argv
[2]);
331 if (!_wcsicmp(argv
[2], L
"/D"))
332 return DeleteSubst(argv
[1]);
333 return AddSubst(argv
[1], argv
[2]);