windows-nt/Source/XPSP1/NT/base/subsys/posix/client/dllname.c
2020-09-26 16:20:57 +08:00

311 lines
8 KiB
C

#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));
PSX_GET_SESSION_NAME_A(PrefixBuf, DOSDEVICE_A);
strncat(PrefixBuf, &(*Source)[2], 1); // get "X"
strcat(PrefixBuf, ":"); // make "X:"
*Source += 3;
SparePrefix.Buffer = PrefixBuf;
SparePrefix.Length = (USHORT)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 = (USHORT)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_PTR)Dest - (ULONG_PTR)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