--- /dev/null
+/* $Id: path.c,v 1.4 2002/10/29 04:45:33 rex Exp $
+ */
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS POSIX+ Subsystem
+ * FILE: subsys/psx/lib/psxdll/misc/path.c
+ * PURPOSE: POSIX subsystem path utilities
+ * PROGRAMMER: KJK::Hyperion <noog@libero.it>
+ * UPDATE HISTORY:
+ * 31/01/2002: Created
+ */
+
+#include <ddk/ntddk.h>
+#include <errno.h>
+#include <string.h>
+#include <psx/stdlib.h>
+#include <psx/pdata.h>
+#include <psx/path.h>
+
+BOOLEAN
+__PdxPosixPathGetNextComponent_U
+(
+ IN UNICODE_STRING PathName,
+ IN OUT PUNICODE_STRING PathComponent,
+ OUT PBOOLEAN TrailingDelimiter OPTIONAL
+)
+{
+ int i, j;
+ USHORT l = PathName.Length / sizeof(WCHAR);
+
+ if(PathComponent->Buffer == 0)
+ i = 0;
+ else
+ i = ((ULONG)PathComponent->Buffer - (ULONG)PathName.Buffer + PathComponent->Length) / sizeof(WCHAR);
+
+ /* skip leading empty components */
+ while(1)
+ if(i >= l)
+ {
+ PathComponent->Length = PathComponent->MaximumLength = 0;
+ return (FALSE);
+ }
+ else if(IS_CHAR_DELIMITER_U(PathName.Buffer[i]))
+ i ++;
+ else
+ break;
+
+ if(i > l)
+ {
+ PathComponent->Length = PathComponent->MaximumLength = 0;
+ return (FALSE);
+ }
+
+ PathComponent->Buffer = &PathName.Buffer[i];
+
+ j = i + 1;
+
+ /* advance until the end of the string, or the next delimiter */
+ while(1)
+ {
+ if(j >= l)
+ {
+
+ if(TrailingDelimiter != 0)
+ *TrailingDelimiter = FALSE;
+
+ break;
+ }
+ else if (IS_CHAR_DELIMITER_U(PathName.Buffer[j]))
+ {
+
+ if(TrailingDelimiter != 0)
+ *TrailingDelimiter = TRUE;
+
+ break;
+ }
+ else
+ j ++;
+ }
+
+ PathComponent->Length = PathComponent->MaximumLength = (j - i) * sizeof(WCHAR);
+
+ return (TRUE);
+
+}
+
+BOOLEAN
+__PdxPosixPathResolve_U
+(
+ IN UNICODE_STRING PathName,
+ OUT PUNICODE_STRING ResolvedPathName,
+ IN WCHAR PathDelimiter OPTIONAL
+)
+{
+ UNICODE_STRING wstrThisComponent = {0, 0, NULL};
+ PWCHAR pwcCurPos;
+ PWCHAR pwcStartPos;
+ BOOLEAN bIsDirectory;
+
+ if(PathDelimiter == 0)
+ PathDelimiter = L'/';
+
+ /* start from the beginning of the return buffer */
+ pwcCurPos = ResolvedPathName->Buffer;
+
+ /* path begins with a delimiter (absolute path) */
+ if(IS_CHAR_DELIMITER_U(PathName.Buffer[0]))
+ {
+ /* put a delimiter in front of the return buffer */
+ *pwcCurPos = PathDelimiter;
+ /* move to next character */
+ pwcCurPos ++;
+ }
+
+ pwcStartPos = pwcCurPos;
+
+ /* repeat until the end of the path string */
+ while(__PdxPosixPathGetNextComponent_U(PathName, &wstrThisComponent, &bIsDirectory))
+ {
+ /* ".": skip */
+ if(IS_COMPONENT_DOT_U(wstrThisComponent))
+ continue;
+ /* "..": go back to the last component */
+ else if(IS_COMPONENT_DOTDOT_U(wstrThisComponent))
+ {
+ if(pwcCurPos == pwcStartPos)
+ continue;
+
+ /* skip the last (undefined) character */
+ pwcCurPos --;
+ /* down to the previous path delimiter */
+ do{ pwcCurPos --; }while(!IS_CHAR_DELIMITER_U(*pwcCurPos));
+ /* include the delimiter */
+ pwcCurPos ++;
+ }
+ else
+ {
+ /* copy this component into the return string */
+ memcpy
+ (
+ pwcCurPos,
+ wstrThisComponent.Buffer,
+ wstrThisComponent.Length
+ );
+
+ /* move the current position to the end of the string */
+ pwcCurPos = (PWCHAR)((PBYTE)pwcCurPos + wstrThisComponent.Length);
+
+ /* component had a trailing delimiter */
+ if(bIsDirectory)
+ {
+ /* append a delimiter */
+ *pwcCurPos = PathDelimiter;
+ /* on to next character */
+ pwcCurPos ++;
+ }
+ }
+ }
+
+ /* set the return string's length as the byte offset between the initial buffer
+ position and the current position */
+ ResolvedPathName->Length = ((ULONG)pwcCurPos - (ULONG)ResolvedPathName->Buffer);
+
+ return (TRUE);
+
+}
+
+BOOLEAN
+__PdxPosixPathGetNextComponent_A
+(
+ IN ANSI_STRING PathName,
+ IN OUT PANSI_STRING PathComponent,
+ OUT PBOOLEAN TrailingDelimiter OPTIONAL
+)
+{
+ int i, j;
+
+ if(PathComponent->Buffer == 0)
+ i = 0;
+ else
+ i = ((ULONG)PathComponent->Buffer - (ULONG)PathName.Buffer + PathComponent->Length);
+
+ /* skip leading empty components */
+ while(1)
+ if(i >= PathName.Length)
+ {
+ PathComponent->Length = PathComponent->MaximumLength = 0;
+ return (FALSE);
+ }
+ else if(IS_CHAR_DELIMITER_A(PathName.Buffer[i]))
+ i ++;
+ else
+ break;
+
+ if(i > PathName.Length)
+ {
+ PathComponent->Length = PathComponent->MaximumLength = 0;
+ return (FALSE);
+ }
+
+ PathComponent->Buffer = &PathName.Buffer[i];
+
+ j = i + 1;
+
+ /* advance until the end of the string, or the next delimiter */
+ while(1)
+ {
+ if(j >= PathName.Length)
+ {
+
+ if(TrailingDelimiter != 0)
+ *TrailingDelimiter = FALSE;
+
+ break;
+ }
+ else if (IS_CHAR_DELIMITER_A(PathName.Buffer[j]))
+ {
+
+ if(TrailingDelimiter != 0)
+ *TrailingDelimiter = TRUE;
+
+ break;
+ }
+ else
+ j ++;
+ }
+
+ PathComponent->Length = PathComponent->MaximumLength = j - i;
+
+ return (TRUE);
+
+}
+
+BOOLEAN
+__PdxPosixPathResolve_A
+(
+ IN ANSI_STRING PathName,
+ OUT PANSI_STRING ResolvedPathName,
+ IN CHAR PathDelimiter OPTIONAL
+)
+{
+ ANSI_STRING strThisComponent = {0, 0, NULL};
+ PCHAR pcCurPos;
+ PCHAR pcStartPos;
+ BOOLEAN bIsDirectory;
+
+ if(PathDelimiter == 0)
+ PathDelimiter = '/';
+
+ /* start from the beginning of the return buffer */
+ pcCurPos = ResolvedPathName->Buffer;
+
+ /* path begins with a delimiter (absolute path) */
+ if(IS_CHAR_DELIMITER_A(PathName.Buffer[0]))
+ {
+ /* put a delimiter in front of the return buffer */
+ *pcCurPos = PathDelimiter;
+ /* move to next character */
+ pcCurPos ++;
+ }
+
+ pcStartPos = pcCurPos;
+
+ /* repeat until the end of the path string */
+ while(__PdxPosixPathGetNextComponent_A(PathName, &strThisComponent, &bIsDirectory))
+ {
+ /* ".": skip */
+ if(IS_COMPONENT_DOT_A(strThisComponent))
+ continue;
+ /* "..": go back to the last component */
+ else if(IS_COMPONENT_DOTDOT_A(strThisComponent))
+ {
+ if(pcCurPos == pcStartPos)
+ continue;
+
+ /* skip the last (undefined) character */
+ pcCurPos --;
+ /* down to the previous path delimiter */
+ do{ pcCurPos --; }while(!IS_CHAR_DELIMITER_A(*pcCurPos));
+ /* include the delimiter */
+ pcCurPos ++;
+ }
+ else
+ {
+ /* copy this component into the return string */
+ strncpy
+ (
+ pcCurPos,
+ strThisComponent.Buffer,
+ strThisComponent.Length
+ );
+
+ /* move the current position to the end of the string */
+ pcCurPos = (PCHAR)((PBYTE)pcCurPos + strThisComponent.Length);
+
+ /* component had a trailing delimiter */
+ if(bIsDirectory)
+ {
+ /* append a delimiter */
+ *pcCurPos = PathDelimiter;
+ /* on to next character */
+ pcCurPos ++;
+ }
+ }
+ }
+
+ /* set the return string's length as the byte offset between the initial buffer
+ position and the current position */
+ ResolvedPathName->Length = ((ULONG)pcCurPos - (ULONG)ResolvedPathName->Buffer);
+
+ return (TRUE);
+
+}
+
+BOOLEAN
+__PdxPosixPathNameToNtPathName
+(
+ IN PWCHAR PosixPath,
+ OUT PUNICODE_STRING NativePath,
+ IN PUNICODE_STRING CurDir OPTIONAL,
+ IN PUNICODE_STRING RootDir OPTIONAL
+)
+{
+ UNICODE_STRING wstrPosixPath;
+ UNICODE_STRING wstrTempString;
+
+ /* parameter validation */
+ if
+ (
+ PosixPath == 0 ||
+ NativePath == 0 ||
+ NativePath->Buffer == 0 ||
+ NativePath->MaximumLength == 0 ||
+ (RootDir != 0 && RootDir->Buffer == 0)
+ )
+ {
+ errno = EINVAL;
+ return (FALSE);
+ }
+
+ RtlInitUnicodeString(&wstrPosixPath, PosixPath);
+
+ /* path is null */
+ if(0 == wstrPosixPath.Length)
+ {
+ errno = EINVAL;
+ return (FALSE);
+ }
+
+ /* first, copy the root path into the return buffer */
+ /* if no root dir passed by the caller... */
+ if(RootDir == 0)
+ /* return buffer too small */
+ if(NativePath->MaximumLength < sizeof(WCHAR))
+ {
+ errno = ENOBUFS;
+ return (FALSE);
+ }
+ /* set the first character to a backslash, and set length accordingly */
+ else
+ {
+ NativePath->Buffer[0] = L'\\';
+ NativePath->Length = sizeof(WCHAR);
+ }
+ /* ... else copy the root dir into the return buffer */
+ else
+ /* return buffer too small */
+ if(NativePath->MaximumLength < RootDir->Length)
+ {
+ errno = ENOBUFS;
+ return (FALSE);
+ }
+ /* copy the root directory into the return buffer, and set length */
+ else
+ {
+ memcpy(NativePath->Buffer, RootDir->Buffer, RootDir->Length);
+ NativePath->Length = RootDir->Length;
+ }
+
+ /* path is "/" - our work is done */
+ if(sizeof(WCHAR) == wstrPosixPath.Length && IS_CHAR_DELIMITER_U(wstrPosixPath.Buffer[0]))
+ return (TRUE);
+
+ /* temp string pointing to the tail of the return buffer */
+ wstrTempString.Length = 0;
+ wstrTempString.MaximumLength = NativePath->MaximumLength - NativePath->Length;
+ wstrTempString.Buffer = (PWCHAR)(((PBYTE)(NativePath->Buffer)) + NativePath->Length);
+
+ /* path begins with '/': absolute path. Append the resolved path to the return buffer */
+ if(IS_CHAR_DELIMITER_U(wstrPosixPath.Buffer[0]))
+ {
+ /* copy the resolved path in the return buffer */
+ __PdxPosixPathResolve_U(wstrPosixPath, &wstrTempString, L'\\');
+
+ return (TRUE);
+ }
+ else
+ {
+ UNICODE_STRING wstrAbsolutePath;
+
+ if(CurDir == 0)
+ CurDir = __PdxGetCurDir();
+
+ /* initialize the buffer for the absolute path */
+ wstrAbsolutePath.Length = 0;
+ wstrAbsolutePath.MaximumLength = 0xFFFF;
+ wstrAbsolutePath.Buffer = __malloc(0xFFFF);
+
+ /* if the current directory is not null... */
+ if(!(CurDir->Buffer == 0 || CurDir->Length == 0))
+ {
+ /* copy it into the absolute path buffer */
+ memcpy(wstrAbsolutePath.Buffer, CurDir->Buffer, CurDir->Length);
+ wstrAbsolutePath.Length += CurDir->Length;
+ }
+
+ /* not enough space to append an extra slash */
+ if((wstrAbsolutePath.MaximumLength - wstrAbsolutePath.Length) < (USHORT)sizeof(WCHAR))
+ {
+ __free(wstrAbsolutePath.Buffer);
+ NativePath->Length = 0;
+ errno = ENOBUFS;
+ return (FALSE);
+ }
+
+ /* append an extra slash */
+ wstrAbsolutePath.Buffer[wstrAbsolutePath.Length / sizeof(WCHAR)] = L'/';
+ wstrAbsolutePath.Length += sizeof(WCHAR);
+
+ /* not enough space to copy the relative path */
+ if((wstrAbsolutePath.MaximumLength - wstrAbsolutePath.Length) < wstrPosixPath.Length)
+ {
+ __free(wstrAbsolutePath.Buffer);
+ NativePath->Length = 0;
+ errno = ENOBUFS;
+ return (FALSE);
+ }
+
+ /* append the relative path to the absolute path */
+ memcpy(
+ (PWCHAR)(((PBYTE)wstrAbsolutePath.Buffer) + wstrAbsolutePath.Length),
+ wstrPosixPath.Buffer,
+ wstrPosixPath.Length
+ );
+ wstrAbsolutePath.Length += wstrPosixPath.Length;
+
+ /* resolve the path */
+ __PdxPosixPathResolve_U(wstrAbsolutePath, &wstrTempString, L'\\');
+
+ __free(wstrAbsolutePath.Buffer);
+
+ return (TRUE);
+ }
+
+ return (FALSE);
+
+}
+
+/* EOF */
+