Leaked source code of windows server 2003
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.

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