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.

310 lines
8.0 KiB

  1. #include "psxdll.h"
  2. #if DBG
  3. VOID DumpNames(PSZ, PSTRING );
  4. #endif //DBG
  5. PSTRING
  6. SetPrefix(
  7. char **Source
  8. )
  9. {
  10. static STRING SparePrefix; // pointer to this may be returned
  11. static char PrefixBuf[512];
  12. //
  13. // Test for leading slash. This tells us whether to start at the root
  14. // or at the current working directory.
  15. //
  16. if (!IS_POSIX_PATH_SEPARATOR(*Source)) {
  17. // relative pathname
  18. return &PdxDirectoryPrefix.NtCurrentWorkingDirectory;
  19. }
  20. if (!IS_POSIX_PATH_SEPARATOR(&(*Source)[1])) {
  21. // first char is slash, but second is not. Start at root.
  22. return &PdxDirectoryPrefix.PsxRoot;
  23. }
  24. if (IS_POSIX_PATH_SEPARATOR(&(*Source)[2])) {
  25. // first three chars are slashes; interpreted as single slash.
  26. return &PdxDirectoryPrefix.PsxRoot;
  27. }
  28. //
  29. // The path starts with "//something":
  30. // //X/ is \DosDevices\X:\
  31. //
  32. memset(PrefixBuf, 0, sizeof(PrefixBuf));
  33. PSX_GET_SESSION_NAME_A(PrefixBuf, DOSDEVICE_A);
  34. strncat(PrefixBuf, &(*Source)[2], 1); // get "X"
  35. strcat(PrefixBuf, ":"); // make "X:"
  36. *Source += 3;
  37. SparePrefix.Buffer = PrefixBuf;
  38. SparePrefix.Length = (USHORT)strlen(PrefixBuf);
  39. SparePrefix.MaximumLength = sizeof(PrefixBuf);
  40. return &SparePrefix;
  41. }
  42. BOOLEAN
  43. PdxCanonicalize(
  44. IN PCHAR PathName,
  45. OUT PUNICODE_STRING CanonPath_U,
  46. IN PVOID Heap
  47. )
  48. /*++
  49. Routine Description:
  50. This function accepts a POSIX pathname and converts it into a
  51. Unicode NT pathname.
  52. Arguments:
  53. PathName - Supplies the POSIX pathname to be translated.
  54. CanonPath_U - Returns the canonicalized Unicode NT pathname. On a
  55. successful call, storage is allocated and the CannonPath_U->Buffer
  56. points to the allocated storage.
  57. Heap - Supplies the heap that should be used to allocate storage from
  58. to store the canonicalized pathname.
  59. Return Value:
  60. TRUE - The pathname was successfully canonicalized. Storage was
  61. allocated, and the CanonPath_U string is initialized.
  62. FALSE - The pathname was not canonicalized. No Storage was
  63. allocated, and the CanonPath_U string is not initialized. The
  64. 'errno' variable is set appropriately in this case.
  65. --*/
  66. {
  67. ANSI_STRING AnsiCanonPath;
  68. PANSI_STRING CanonPath_A;
  69. LONG PathNameLength;
  70. char *Source, *Dest, *pch;
  71. PSTRING Prefix;
  72. ULONG UnicodeLength;
  73. NTSTATUS Status;
  74. CanonPath_A = &AnsiCanonPath;
  75. CanonPath_A->Buffer = NULL;
  76. try {
  77. PathNameLength = strlen(PathName);
  78. } except (EXCEPTION_EXECUTE_HANDLER) {
  79. PathNameLength = -1;
  80. }
  81. if (PathNameLength == -1) {
  82. errno = EFAULT;
  83. return FALSE;
  84. }
  85. if (PathNameLength == 0) {
  86. errno = ENOENT;
  87. return FALSE;
  88. }
  89. if (PathNameLength > PATH_MAX) {
  90. errno = ENAMETOOLONG;
  91. return FALSE;
  92. }
  93. Source = PathName;
  94. Prefix = SetPrefix(&Source);
  95. CanonPath_A->MaximumLength = (USHORT)(PathNameLength + Prefix->Length + 1);
  96. CanonPath_A->Buffer = RtlAllocateHeap(Heap, 0, CanonPath_A->MaximumLength);
  97. if (NULL == CanonPath_A->Buffer) {
  98. errno = ENOMEM;
  99. return FALSE;
  100. }
  101. //
  102. // Copy the prefix
  103. //
  104. RtlCopyString(CanonPath_A, Prefix);
  105. Dest = CanonPath_A->Buffer + CanonPath_A->Length;
  106. while ('\0' != *Source) switch (*Source) {
  107. case '/':
  108. // Skip adjacent /'s
  109. if (Dest[-1] != '\\') {
  110. *Dest++ = '\\';
  111. }
  112. while (IS_POSIX_PATH_SEPARATOR(Source)) {
  113. Source++;
  114. }
  115. break;
  116. case '.':
  117. //
  118. // Eat single dots as in "/./". For dot-dot back up one level.
  119. // Any other dot is just a filename character.
  120. //
  121. if (IS_POSIX_DOT(Source)) {
  122. Source++;
  123. break;
  124. }
  125. if (IS_POSIX_DOT_DOT(Source)) {
  126. UNICODE_STRING U;
  127. OBJECT_ATTRIBUTES Obj;
  128. HANDLE FileHandle;
  129. IO_STATUS_BLOCK Iosb;
  130. // back up destination string looking for a \.
  131. do {
  132. Dest--;
  133. } while (*Dest != '\\');
  134. //
  135. // Make sure the directory that we're using dot-dot
  136. // in actually exists.
  137. //
  138. if (Dest == CanonPath_A->Buffer +
  139. PdxDirectoryPrefix.PsxRoot.Length) {
  140. *(Dest + 1) = '\000';
  141. } else {
  142. *Dest = '\000';
  143. }
  144. CanonPath_A->Length = (USHORT)strlen(CanonPath_A->Buffer);
  145. Status = RtlAnsiStringToUnicodeString(&U, CanonPath_A,
  146. TRUE);
  147. if (!NT_SUCCESS(Status)) {
  148. RtlFreeHeap(Heap, 0, CanonPath_A->Buffer);
  149. errno = ENOMEM;
  150. return FALSE;
  151. }
  152. InitializeObjectAttributes(&Obj, &U, 0, NULL, 0);
  153. Status = NtOpenFile(&FileHandle, SYNCHRONIZE, &Obj,
  154. &Iosb,
  155. FILE_SHARE_READ|FILE_SHARE_WRITE|
  156. FILE_SHARE_DELETE,
  157. FILE_SYNCHRONOUS_IO_NONALERT |
  158. FILE_DIRECTORY_FILE);
  159. RtlFreeUnicodeString(&U);
  160. if (!NT_SUCCESS(Status)) {
  161. RtlFreeHeap(Heap, 0, CanonPath_A->Buffer);
  162. errno = PdxStatusToErrno(Status);
  163. return FALSE;
  164. }
  165. NtClose(FileHandle);
  166. //
  167. // Back up to previous component: "\a\b\c\" to "\a\b\".
  168. // But if we come to the root, we stay there.
  169. //
  170. do {
  171. if (Dest == CanonPath_A->Buffer +
  172. PdxDirectoryPrefix.PsxRoot.Length) {
  173. *Dest++ = '\\';
  174. break;
  175. }
  176. Dest--;
  177. } while (*Dest != '\\');
  178. // Advance source past the dot-dot
  179. Source += 2;
  180. break;
  181. }
  182. // This dot is just a filename character.
  183. //FALLTHROUGH
  184. default:
  185. //
  186. // Copy a pathname component. If the pathname component
  187. // is too long, return ENAMETOOLONG. Note that using a
  188. // constant NAME_MAX is bogus, since it could be different
  189. // for different filesystems.
  190. //
  191. pch = strchr(Source, '/');
  192. if (NULL == pch) {
  193. // this is the last component in the path.
  194. if (strlen(Source) > NAME_MAX) {
  195. errno = ENAMETOOLONG;
  196. RtlFreeHeap(Heap, 0, CanonPath_A->Buffer);
  197. return FALSE;
  198. }
  199. } else {
  200. if (pch - Source > NAME_MAX) {
  201. errno = ENAMETOOLONG;
  202. RtlFreeHeap(Heap, 0, CanonPath_A->Buffer);
  203. return FALSE;
  204. }
  205. }
  206. while (*Source != '\0' && *Source != '/') {
  207. *Dest++ = *Source++;
  208. }
  209. }
  210. //
  211. // Make sure that we never give back "/DosDevices/C:" ... the
  212. // Object Manager doesn't deal with that, we need a trailing
  213. // slash.
  214. //
  215. if (Dest == CanonPath_A->Buffer + PdxDirectoryPrefix.PsxRoot.Length) {
  216. if (Dest[-1] != '\\') {
  217. *Dest++ = '\\';
  218. }
  219. }
  220. CanonPath_A->Length = (USHORT)((ULONG_PTR)Dest - (ULONG_PTR)CanonPath_A->Buffer);
  221. CanonPath_A->Buffer[CanonPath_A->Length] = '\0';
  222. // Convert ansi pathname to unicode - use internal heap for Buffer
  223. UnicodeLength = RtlAnsiStringToUnicodeSize(CanonPath_A);
  224. CanonPath_U->MaximumLength = (USHORT)UnicodeLength;
  225. CanonPath_U->Buffer = RtlAllocateHeap(Heap, 0, UnicodeLength);
  226. if (NULL == CanonPath_U->Buffer) {
  227. RtlFreeHeap(Heap, 0, CanonPath_A->Buffer);
  228. errno = ENOMEM;
  229. return FALSE;
  230. }
  231. Status = RtlAnsiStringToUnicodeString(CanonPath_U, CanonPath_A, FALSE);
  232. ASSERT(NT_SUCCESS(Status));
  233. RtlFreeHeap(Heap, 0, CanonPath_A->Buffer);
  234. return TRUE;
  235. }
  236. #if DBG
  237. VOID
  238. DumpNames(
  239. IN PSZ PathName,
  240. IN PSTRING CanonPath_A
  241. )
  242. {
  243. USHORT i;
  244. PSZ p;
  245. KdPrint(("Input Path: \"%s\"\n",PathName));
  246. KdPrint(("Output Path: \"%Z\"\n", CanonPath_A));
  247. }
  248. #endif //DBG