#include "psxdll.h" #if DBG VOID DumpNames(PSZ, PSTRING ); #endif //DBG PSTRING SetPrefix( char **Source ) { static STRING SparePrefix; // pointer to this may be returned static char PrefixBuf[512]; // // Test for leading slash. This tells us whether to start at the root // or at the current working directory. // if (!IS_POSIX_PATH_SEPARATOR(*Source)) { // relative pathname return &PdxDirectoryPrefix.NtCurrentWorkingDirectory; } if (!IS_POSIX_PATH_SEPARATOR(&(*Source)[1])) { // first char is slash, but second is not. Start at root. return &PdxDirectoryPrefix.PsxRoot; } if (IS_POSIX_PATH_SEPARATOR(&(*Source)[2])) { // first three chars are slashes; interpreted as single slash. return &PdxDirectoryPrefix.PsxRoot; } // // The path starts with "//something": // //X/ is \DosDevices\X:\ // memset(PrefixBuf, 0, sizeof(PrefixBuf)); strcpy(PrefixBuf, "\\DosDevices\\"); strncat(PrefixBuf, &(*Source)[2], 1); // get "X" strcat(PrefixBuf, ":"); // make "X:" *Source += 3; SparePrefix.Buffer = PrefixBuf; SparePrefix.Length = strlen(PrefixBuf); SparePrefix.MaximumLength = sizeof(PrefixBuf); return &SparePrefix; } BOOLEAN PdxCanonicalize( IN PCHAR PathName, OUT PUNICODE_STRING CanonPath_U, IN PVOID Heap ) /*++ Routine Description: This function accepts a POSIX pathname and converts it into a Unicode NT pathname. Arguments: PathName - Supplies the POSIX pathname to be translated. CanonPath_U - Returns the canonicalized Unicode NT pathname. On a successful call, storage is allocated and the CannonPath_U->Buffer points to the allocated storage. Heap - Supplies the heap that should be used to allocate storage from to store the canonicalized pathname. Return Value: TRUE - The pathname was successfully canonicalized. Storage was allocated, and the CanonPath_U string is initialized. FALSE - The pathname was not canonicalized. No Storage was allocated, and the CanonPath_U string is not initialized. The 'errno' variable is set appropriately in this case. --*/ { ANSI_STRING AnsiCanonPath; PANSI_STRING CanonPath_A; LONG PathNameLength; char *Source, *Dest, *pch; PSTRING Prefix; ULONG UnicodeLength; NTSTATUS Status; CanonPath_A = &AnsiCanonPath; CanonPath_A->Buffer = NULL; try { PathNameLength = strlen(PathName); } except (EXCEPTION_EXECUTE_HANDLER) { PathNameLength = -1; } if (PathNameLength == -1) { errno = EFAULT; return FALSE; } if (PathNameLength == 0) { errno = ENOENT; return FALSE; } if (PathNameLength > PATH_MAX) { errno = ENAMETOOLONG; return FALSE; } Source = PathName; Prefix = SetPrefix(&Source); CanonPath_A->MaximumLength = (USHORT)(PathNameLength + Prefix->Length + 1); CanonPath_A->Buffer = RtlAllocateHeap(Heap, 0, CanonPath_A->MaximumLength); if (NULL == CanonPath_A->Buffer) { errno = ENOMEM; return FALSE; } // // Copy the prefix // RtlCopyString(CanonPath_A, Prefix); Dest = CanonPath_A->Buffer + CanonPath_A->Length; while ('\0' != *Source) switch (*Source) { case '/': // Skip adjacent /'s if (Dest[-1] != '\\') { *Dest++ = '\\'; } while (IS_POSIX_PATH_SEPARATOR(Source)) { Source++; } break; case '.': // // Eat single dots as in "/./". For dot-dot back up one level. // Any other dot is just a filename character. // if (IS_POSIX_DOT(Source)) { Source++; break; } if (IS_POSIX_DOT_DOT(Source)) { UNICODE_STRING U; OBJECT_ATTRIBUTES Obj; HANDLE FileHandle; IO_STATUS_BLOCK Iosb; // back up destination string looking for a \. do { Dest--; } while (*Dest != '\\'); // // Make sure the directory that we're using dot-dot // in actually exists. // if (Dest == CanonPath_A->Buffer + PdxDirectoryPrefix.PsxRoot.Length) { *(Dest + 1) = '\000'; } else { *Dest = '\000'; } CanonPath_A->Length = strlen(CanonPath_A->Buffer); Status = RtlAnsiStringToUnicodeString(&U, CanonPath_A, TRUE); if (!NT_SUCCESS(Status)) { RtlFreeHeap(Heap, 0, CanonPath_A->Buffer); errno = ENOMEM; return FALSE; } InitializeObjectAttributes(&Obj, &U, 0, NULL, 0); Status = NtOpenFile(&FileHandle, SYNCHRONIZE, &Obj, &Iosb, FILE_SHARE_READ|FILE_SHARE_WRITE| FILE_SHARE_DELETE, FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE); RtlFreeUnicodeString(&U); if (!NT_SUCCESS(Status)) { RtlFreeHeap(Heap, 0, CanonPath_A->Buffer); errno = PdxStatusToErrno(Status); return FALSE; } NtClose(FileHandle); // // Back up to previous component: "\a\b\c\" to "\a\b\". // But if we come to the root, we stay there. // do { if (Dest == CanonPath_A->Buffer + PdxDirectoryPrefix.PsxRoot.Length) { *Dest++ = '\\'; break; } Dest--; } while (*Dest != '\\'); // Advance source past the dot-dot Source += 2; break; } // This dot is just a filename character. //FALLTHROUGH default: // // Copy a pathname component. If the pathname component // is too long, return ENAMETOOLONG. Note that using a // constant NAME_MAX is bogus, since it could be different // for different filesystems. // pch = strchr(Source, '/'); if (NULL == pch) { // this is the last component in the path. if (strlen(Source) > NAME_MAX) { errno = ENAMETOOLONG; RtlFreeHeap(Heap, 0, CanonPath_A->Buffer); return FALSE; } } else { if (pch - Source > NAME_MAX) { errno = ENAMETOOLONG; RtlFreeHeap(Heap, 0, CanonPath_A->Buffer); return FALSE; } } while (*Source != '\0' && *Source != '/') { *Dest++ = *Source++; } } // // Make sure that we never give back "/DosDevices/C:" ... the // Object Manager doesn't deal with that, we need a trailing // slash. // if (Dest == CanonPath_A->Buffer + PdxDirectoryPrefix.PsxRoot.Length) { if (Dest[-1] != '\\') { *Dest++ = '\\'; } } CanonPath_A->Length = (USHORT)((ULONG)Dest - (ULONG)CanonPath_A->Buffer); CanonPath_A->Buffer[CanonPath_A->Length] = '\0'; // Convert ansi pathname to unicode - use internal heap for Buffer UnicodeLength = RtlAnsiStringToUnicodeSize(CanonPath_A); CanonPath_U->MaximumLength = (USHORT)UnicodeLength; CanonPath_U->Buffer = RtlAllocateHeap(Heap, 0, UnicodeLength); if (NULL == CanonPath_U->Buffer) { RtlFreeHeap(Heap, 0, CanonPath_A->Buffer); errno = ENOMEM; return FALSE; } Status = RtlAnsiStringToUnicodeString(CanonPath_U, CanonPath_A, FALSE); ASSERT(NT_SUCCESS(Status)); RtlFreeHeap(Heap, 0, CanonPath_A->Buffer); return TRUE; } #if DBG VOID DumpNames( IN PSZ PathName, IN PSTRING CanonPath_A ) { USHORT i; PSZ p; KdPrint(("Input Path: \"%s\"\n",PathName)); KdPrint(("Output Path: \"%Z\"\n", CanonPath_A)); } #endif //DBG