/* $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 * UPDATE HISTORY: * 31/01/2002: Created */ #include #include #include #include #include #include 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 */