Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

520 lines
13 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. curdir.c
  5. Abstract:
  6. Current directory support
  7. Author:
  8. Mark Lucovsky (markl) 10-Oct-1990
  9. Revision History:
  10. --*/
  11. #include "basedll.h"
  12. BOOL
  13. CheckForSameCurdir(
  14. PUNICODE_STRING PathName
  15. )
  16. {
  17. PCURDIR CurDir;
  18. UNICODE_STRING CurrentDir;
  19. BOOL rv;
  20. CurDir = &(NtCurrentPeb()->ProcessParameters->CurrentDirectory);
  21. if (CurDir->DosPath.Length > 6 ) {
  22. if ( (CurDir->DosPath.Length-2) != PathName->Length ) {
  23. return FALSE;
  24. }
  25. }
  26. else {
  27. if ( CurDir->DosPath.Length != PathName->Length ) {
  28. return FALSE;
  29. }
  30. }
  31. RtlAcquirePebLock();
  32. CurrentDir = CurDir->DosPath;
  33. if ( CurrentDir.Length > 6 ) {
  34. CurrentDir.Length -= 2;
  35. }
  36. rv = FALSE;
  37. if ( RtlEqualUnicodeString(&CurrentDir,PathName,TRUE) ) {
  38. rv = TRUE;
  39. }
  40. RtlReleasePebLock();
  41. return rv;
  42. }
  43. DWORD
  44. APIENTRY
  45. GetFullPathNameA(
  46. LPCSTR lpFileName,
  47. DWORD nBufferLength,
  48. LPSTR lpBuffer,
  49. LPSTR *lpFilePart
  50. )
  51. /*++
  52. Routine Description:
  53. ANSI thunk to GetFullPathNameW
  54. --*/
  55. {
  56. NTSTATUS Status;
  57. ULONG UnicodeLength;
  58. UNICODE_STRING UnicodeString;
  59. UNICODE_STRING UnicodeResult;
  60. ANSI_STRING AnsiResult;
  61. PWSTR Ubuff;
  62. PWSTR FilePart;
  63. PWSTR *FilePartPtr;
  64. INT PrefixLength = 0;
  65. if ( ARGUMENT_PRESENT(lpFilePart) ) {
  66. FilePartPtr = &FilePart;
  67. } else {
  68. FilePartPtr = NULL;
  69. }
  70. if (!Basep8BitStringToDynamicUnicodeString( &UnicodeString, lpFileName )) {
  71. return 0;
  72. }
  73. Ubuff = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), (MAX_PATH<<1) + sizeof(UNICODE_NULL));
  74. if ( !Ubuff ) {
  75. RtlFreeUnicodeString(&UnicodeString);
  76. BaseSetLastNTError(STATUS_NO_MEMORY);
  77. return 0;
  78. }
  79. UnicodeLength = RtlGetFullPathName_U(
  80. UnicodeString.Buffer,
  81. (MAX_PATH<<1),
  82. Ubuff,
  83. FilePartPtr
  84. );
  85. //
  86. // UnicodeLength contains the byte count of unicode string.
  87. // Original code does "UnicodeLength / sizeof(WCHAR)" to get
  88. // the size of corresponding ansi string.
  89. // This is correct in SBCS environment. However in DBCS environment,
  90. // it's definitely WRONG.
  91. //
  92. if ( UnicodeLength <= MAX_PATH * sizeof (WCHAR) ) {
  93. Status = RtlUnicodeToMultiByteSize(&UnicodeLength, Ubuff, UnicodeLength);
  94. //
  95. // At this point, UnicodeLength variable contains
  96. // Ansi based byte length.
  97. //
  98. if ( NT_SUCCESS(Status) ) {
  99. if ( UnicodeLength && ARGUMENT_PRESENT(lpFilePart) && FilePart != NULL ) {
  100. INT UnicodePrefixLength;
  101. UnicodePrefixLength = (INT)(FilePart - Ubuff) * sizeof(WCHAR);
  102. Status = RtlUnicodeToMultiByteSize( &PrefixLength,
  103. Ubuff,
  104. UnicodePrefixLength );
  105. //
  106. // At this point, PrefixLength variable contains
  107. // Ansi based byte length.
  108. //
  109. if ( !NT_SUCCESS(Status) ) {
  110. BaseSetLastNTError(Status);
  111. UnicodeLength = 0;
  112. }
  113. }
  114. } else {
  115. BaseSetLastNTError(Status);
  116. UnicodeLength = 0;
  117. }
  118. } else {
  119. //
  120. // we exceed the MAX_PATH limit. we should log the error and
  121. // return zero. however US code returns the byte count of
  122. // buffer required and doesn't log any error.
  123. //
  124. UnicodeLength = 0;
  125. }
  126. if ( UnicodeLength && UnicodeLength < nBufferLength ) {
  127. RtlInitUnicodeString(&UnicodeResult,Ubuff);
  128. Status = BasepUnicodeStringTo8BitString(&AnsiResult,&UnicodeResult,TRUE);
  129. if ( NT_SUCCESS(Status) ) {
  130. RtlMoveMemory(lpBuffer,AnsiResult.Buffer,UnicodeLength+1);
  131. RtlFreeAnsiString(&AnsiResult);
  132. if ( ARGUMENT_PRESENT(lpFilePart) ) {
  133. if ( FilePart == NULL ) {
  134. *lpFilePart = NULL;
  135. } else {
  136. *lpFilePart = lpBuffer + PrefixLength;
  137. }
  138. }
  139. } else {
  140. BaseSetLastNTError(Status);
  141. UnicodeLength = 0;
  142. }
  143. } else {
  144. if ( UnicodeLength ) {
  145. UnicodeLength++;
  146. }
  147. }
  148. RtlFreeUnicodeString(&UnicodeString);
  149. RtlFreeHeap(RtlProcessHeap(), 0,Ubuff);
  150. return (DWORD)UnicodeLength;
  151. }
  152. DWORD
  153. APIENTRY
  154. GetFullPathNameW(
  155. LPCWSTR lpFileName,
  156. DWORD nBufferLength,
  157. LPWSTR lpBuffer,
  158. LPWSTR *lpFilePart
  159. )
  160. /*++
  161. Routine Description:
  162. This function is used to return the fully qualified path name
  163. corresponding to the specified file name.
  164. This function is used to return a fully qualified pathname
  165. corresponding to the specified filename. It does this by merging
  166. the current drive and directory together with the specified file
  167. name. In addition to this, it calculates the address of the file
  168. name portion of the fully qualified pathname.
  169. Arguments:
  170. lpFileName - Supplies the file name of the file whose fully
  171. qualified pathname is to be returned.
  172. nBufferLength - Supplies the length in bytes of the buffer that is
  173. to receive the fully qualified path.
  174. lpBuffer - Returns the fully qualified pathname corresponding to the
  175. specified file.
  176. lpFilePart - Returns the address of the last component of the fully
  177. qualified pathname.
  178. Return Value:
  179. The return value is the length of the string copied to lpBuffer, not
  180. including the terminating null character. If the return value is
  181. greater than nBufferLength, the return value is the size of the buffer
  182. required to hold the pathname. The return value is zero if the
  183. function failed.
  184. --*/
  185. {
  186. return (DWORD) RtlGetFullPathName_U(
  187. lpFileName,
  188. nBufferLength*2,
  189. lpBuffer,
  190. lpFilePart
  191. )/2;
  192. }
  193. DWORD
  194. APIENTRY
  195. GetCurrentDirectoryA(
  196. DWORD nBufferLength,
  197. LPSTR lpBuffer
  198. )
  199. /*++
  200. Routine Description:
  201. ANSI thunk to GetCurrentDirectoryW
  202. --*/
  203. {
  204. PUNICODE_STRING Unicode;
  205. ANSI_STRING AnsiString;
  206. NTSTATUS Status;
  207. DWORD ReturnValue;
  208. ULONG cbAnsiString;
  209. if ( nBufferLength > MAXUSHORT ) {
  210. nBufferLength = MAXUSHORT-2;
  211. }
  212. Unicode = &NtCurrentTeb()->StaticUnicodeString;
  213. Unicode->Length = (USHORT)RtlGetCurrentDirectory_U(
  214. Unicode->MaximumLength,
  215. Unicode->Buffer
  216. );
  217. //
  218. // Unicode->Length contains the byte count of unicode string.
  219. // Original code does "UnicodeLength / sizeof(WCHAR)" to
  220. // get the size of corresponding ansi string.
  221. // This is correct in SBCS environment. However in DBCS
  222. // environment, it's definitely WRONG.
  223. //
  224. Status = RtlUnicodeToMultiByteSize( &cbAnsiString, Unicode->Buffer, Unicode->Length );
  225. if ( !NT_SUCCESS(Status) ) {
  226. BaseSetLastNTError(Status);
  227. ReturnValue = 0;
  228. }
  229. else {
  230. if ( nBufferLength > (DWORD)(cbAnsiString ) ) {
  231. AnsiString.Buffer = lpBuffer;
  232. AnsiString.MaximumLength = (USHORT)(nBufferLength+1);
  233. Status = BasepUnicodeStringTo8BitString(&AnsiString,Unicode,FALSE);
  234. if ( !NT_SUCCESS(Status) ) {
  235. BaseSetLastNTError(Status);
  236. ReturnValue = 0;
  237. }
  238. else {
  239. ReturnValue = AnsiString.Length;
  240. }
  241. }
  242. else {
  243. // The return value is the size of the buffer required to hold the
  244. // pathname (including the terminating null character).
  245. ReturnValue = cbAnsiString + 1;
  246. }
  247. }
  248. return ReturnValue;
  249. }
  250. DWORD
  251. APIENTRY
  252. GetCurrentDirectoryW(
  253. DWORD nBufferLength,
  254. LPWSTR lpBuffer
  255. )
  256. /*++
  257. Routine Description:
  258. The current directory for a process can be retreived using
  259. GetCurrentDirectory.
  260. Arguments:
  261. nBufferLength - Supplies the length in bytes of the buffer that is to
  262. receive the current directory string.
  263. lpBuffer - Returns the current directory string for the current
  264. process. The string is a null terminated string and specifies
  265. the absolute path to the current directory.
  266. Return Value:
  267. The return value is the length of the string copied to lpBuffer, not
  268. including the terminating null character. If the return value is
  269. greater than nBufferLength, the return value is the size of the buffer
  270. required to hold the pathname. The return value is zero if the
  271. function failed.
  272. --*/
  273. {
  274. return (DWORD)RtlGetCurrentDirectory_U(nBufferLength*2,lpBuffer)/2;
  275. }
  276. BOOL
  277. APIENTRY
  278. SetCurrentDirectoryA(
  279. LPCSTR lpPathName
  280. )
  281. /*++
  282. Routine Description:
  283. ANSI thunk to SetCurrentDirectoryW
  284. --*/
  285. {
  286. NTSTATUS Status;
  287. PUNICODE_STRING Unicode;
  288. BOOL rv;
  289. Unicode = Basep8BitStringToStaticUnicodeString( lpPathName );
  290. if (Unicode == NULL) {
  291. return FALSE;
  292. }
  293. if ( !CheckForSameCurdir(Unicode) ) {
  294. Status = RtlSetCurrentDirectory_U(Unicode);
  295. if ( !NT_SUCCESS(Status) ) {
  296. //
  297. // claris works 5.0 has a bug where it doesn't strip leading/trailing
  298. // quotes properly. It ends up calling SetCurrentDirectoryA with a
  299. // leading quote, and WinExec with a trailing quote. This error path
  300. // logic will compensate for the leading quote problem
  301. //
  302. if ( Unicode->Buffer[0] == L'"' && Unicode->Length > 2 ) {
  303. Unicode = Basep8BitStringToStaticUnicodeString( lpPathName+1 );
  304. if (Unicode == NULL) {
  305. return FALSE;
  306. }
  307. Status = RtlSetCurrentDirectory_U(Unicode);
  308. if ( !NT_SUCCESS(Status) ) {
  309. BaseSetLastNTError(Status);
  310. rv = FALSE;
  311. }
  312. else {
  313. rv = TRUE;
  314. }
  315. }
  316. else {
  317. BaseSetLastNTError(Status);
  318. rv = FALSE;
  319. }
  320. } else {
  321. rv = TRUE;
  322. }
  323. } else {
  324. rv = TRUE;
  325. }
  326. return rv;
  327. }
  328. BOOL
  329. APIENTRY
  330. SetCurrentDirectoryW(
  331. LPCWSTR lpPathName
  332. )
  333. /*++
  334. Routine Description:
  335. The current directory for a process is changed using
  336. SetCurrentDirectory.
  337. Each process has a single current directory. A current directory is
  338. made up of type parts.
  339. - A disk designator either which is either a drive letter followed
  340. by a colon, or a UNC servername/sharename "\\servername\sharename".
  341. - A directory on the disk designator.
  342. For APIs that manipulate files, the file names may be relative to
  343. the current directory. A filename is relative to the entire current
  344. directory if it does not begin with a disk designator or a path name
  345. separator. If the file name begins with a path name separator, then
  346. it is relative to the disk designator of the current directory. If
  347. a file name begins with a disk designator, than it is a fully
  348. qualified absolute path name.
  349. The value of lpPathName supplies the current directory. The value
  350. of lpPathName, may be a relative path name as described above, or a
  351. fully qualified absolute path name. In either case, the fully
  352. qualified absolute path name of the specified directory is
  353. calculated and is stored as the current directory.
  354. Arguments:
  355. lpPathName - Supplies the pathname of the directory that is to be
  356. made the current directory.
  357. Return Value:
  358. TRUE - The operation was successful.
  359. FALSE/NULL - The operation failed. Extended error status is available
  360. using GetLastError.
  361. --*/
  362. {
  363. NTSTATUS Status;
  364. UNICODE_STRING UnicodeString;
  365. BOOL rv;
  366. RtlInitUnicodeString(&UnicodeString,lpPathName);
  367. if ( !CheckForSameCurdir(&UnicodeString) ) {
  368. Status = RtlSetCurrentDirectory_U(&UnicodeString);
  369. if ( !NT_SUCCESS(Status) ) {
  370. BaseSetLastNTError(Status);
  371. rv = FALSE;
  372. }
  373. else {
  374. rv = TRUE;
  375. }
  376. }
  377. else {
  378. rv = TRUE;
  379. }
  380. return rv;
  381. }
  382. DWORD
  383. APIENTRY
  384. GetLogicalDrives(
  385. VOID
  386. )
  387. {
  388. NTSTATUS Status;
  389. PROCESS_DEVICEMAP_INFORMATION ProcessDeviceMapInfo;
  390. Status = NtQueryInformationProcess( NtCurrentProcess(),
  391. ProcessDeviceMap,
  392. &ProcessDeviceMapInfo.Query,
  393. sizeof( ProcessDeviceMapInfo.Query ),
  394. NULL
  395. );
  396. if (NT_SUCCESS (Status)) {
  397. if (ProcessDeviceMapInfo.Query.DriveMap == 0) {
  398. SetLastError(NO_ERROR);
  399. }
  400. return ProcessDeviceMapInfo.Query.DriveMap;
  401. } else {
  402. BaseSetLastNTError(Status);
  403. return 0;
  404. }
  405. }