diff --git a/reactos/subsys/system/usetup/console.c b/reactos/subsys/system/usetup/console.c index 1655d4c5c9f..6ff57ccee92 100644 --- a/reactos/subsys/system/usetup/console.c +++ b/reactos/subsys/system/usetup/console.c @@ -366,6 +366,57 @@ WriteConsoleOutputCharacters(LPCSTR lpCharacter, } +NTSTATUS +WriteConsoleOutputCharactersW(LPCWSTR lpCharacter, + ULONG nLength, + COORD dwWriteCoord) +{ + IO_STATUS_BLOCK IoStatusBlock; + PCHAR Buffer; + COORD *pCoord; + PCHAR pText; + NTSTATUS Status; + ULONG i; + + Buffer = RtlAllocateHeap(ProcessHeap, + 0, + nLength + sizeof(COORD)); + pCoord = (COORD *)Buffer; + pText = (PCHAR)(pCoord + 1); + + *pCoord = dwWriteCoord; + + /* FIXME: use real unicode->oem conversion */ + for (i = 0; i < nLength; i++) + pText[i] = (CHAR)lpCharacter[i]; + pText[i] = 0; + + Status = NtDeviceIoControlFile(StdOutput, + NULL, + NULL, + NULL, + &IoStatusBlock, + IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER, + NULL, + 0, + Buffer, + nLength + sizeof(COORD)); + if (Status == STATUS_PENDING) + { + NtWaitForSingleObject(StdOutput, + FALSE, + NULL); + Status = IoStatusBlock.Status; + } + + RtlFreeHeap(ProcessHeap, + 0, + Buffer); + + return(Status); +} + + NTSTATUS WriteConsoleOutputAttributes(CONST USHORT *lpAttribute, ULONG nLength, @@ -892,7 +943,7 @@ SetTextXY(SHORT x, SHORT y, PCHAR Text) VOID -SetInputTextXY(SHORT x, SHORT y, SHORT len, PCHAR Text) +SetInputTextXY(SHORT x, SHORT y, SHORT len, PWCHAR Text) { COORD coPos; ULONG Length; @@ -901,16 +952,20 @@ SetInputTextXY(SHORT x, SHORT y, SHORT len, PCHAR Text) coPos.X = x; coPos.Y = y; - Length = strlen(Text); + Length = wcslen(Text); + if (Length > len - 1) + { + Length = len - 1; + } FillConsoleOutputAttribute(0x70, len, coPos, &Written); - WriteConsoleOutputCharacters(Text, - Length, - coPos); + WriteConsoleOutputCharactersW(Text, + Length, + coPos); coPos.X += Length; FillConsoleOutputCharacter('_', diff --git a/reactos/subsys/system/usetup/console.h b/reactos/subsys/system/usetup/console.h index cecff914ecf..80fb37c4c67 100644 --- a/reactos/subsys/system/usetup/console.h +++ b/reactos/subsys/system/usetup/console.h @@ -108,7 +108,7 @@ VOID SetTextXY(SHORT x, SHORT y, PCHAR Text); VOID -SetInputTextXY(SHORT x, SHORT y, SHORT len, PCHAR Text); +SetInputTextXY(SHORT x, SHORT y, SHORT len, PWCHAR Text); VOID SetUnderlinedTextXY(SHORT x, SHORT y, PCHAR Text); diff --git a/reactos/subsys/system/usetup/drivesup.h b/reactos/subsys/system/usetup/drivesup.h index 1d86fd52346..da9a4881a82 100644 --- a/reactos/subsys/system/usetup/drivesup.h +++ b/reactos/subsys/system/usetup/drivesup.h @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* $Id: drivesup.h,v 1.2 2002/11/02 23:17:06 ekohl Exp $ +/* $Id: drivesup.h,v 1.3 2002/11/13 18:25:18 ekohl Exp $ * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS text-mode setup * FILE: subsys/system/usetup/drivesup.h @@ -38,4 +38,4 @@ GetDriveLetter(ULONG DriveNumber, #endif /* __DRIVESUP_H__ */ -/* EOF */ \ No newline at end of file +/* EOF */ diff --git a/reactos/subsys/system/usetup/filesup.c b/reactos/subsys/system/usetup/filesup.c new file mode 100644 index 00000000000..c210636d4af --- /dev/null +++ b/reactos/subsys/system/usetup/filesup.c @@ -0,0 +1,79 @@ +/* + * ReactOS kernel + * Copyright (C) 2002 ReactOS Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* $Id: filesup.c,v 1.1 2002/11/13 18:25:18 ekohl Exp $ + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS text-mode setup + * FILE: subsys/system/usetup/filesup.c + * PURPOSE: File support functions + * PROGRAMMER: Eric Kohl + */ + +/* INCLUDES *****************************************************************/ + +#include +#include + +#include "usetup.h" +#include "filesup.h" + + +/* FUNCTIONS ****************************************************************/ + + +NTSTATUS +CreateDirectory(PWCHAR DirectoryName) +{ + OBJECT_ATTRIBUTES ObjectAttributes; + IO_STATUS_BLOCK IoStatusBlock; + UNICODE_STRING PathName; + HANDLE DirectoryHandle; + NTSTATUS Status; + + RtlCreateUnicodeString(&PathName, + DirectoryName); + + ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES); + ObjectAttributes.RootDirectory = NULL; + ObjectAttributes.ObjectName = &PathName; + ObjectAttributes.Attributes = OBJ_CASE_INSENSITIVE | OBJ_INHERIT; + ObjectAttributes.SecurityDescriptor = NULL; + ObjectAttributes.SecurityQualityOfService = NULL; + + Status = NtCreateFile(&DirectoryHandle, + DIRECTORY_ALL_ACCESS, + &ObjectAttributes, + &IoStatusBlock, + NULL, + FILE_ATTRIBUTE_DIRECTORY, + 0, + FILE_CREATE, + FILE_DIRECTORY_FILE, + NULL, + 0); + if (NT_SUCCESS(Status)) + { + NtClose(DirectoryHandle); + } + + RtlFreeUnicodeString(&PathName); + + return(Status); +} + +/* EOF */ diff --git a/reactos/subsys/system/usetup/filesup.h b/reactos/subsys/system/usetup/filesup.h new file mode 100644 index 00000000000..548fad047d6 --- /dev/null +++ b/reactos/subsys/system/usetup/filesup.h @@ -0,0 +1,36 @@ +/* + * ReactOS kernel + * Copyright (C) 2002 ReactOS Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* $Id: filesup.h,v 1.1 2002/11/13 18:25:18 ekohl Exp $ + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS text-mode setup + * FILE: subsys/system/usetup/filesup.h + * PURPOSE: File support functions + * PROGRAMMER: Eric Kohl + */ + +#ifndef __FILESUP_H__ +#define __FILESUP_H__ + +NTSTATUS +CreateDirectory(PWCHAR DirectoryName); + + +#endif /* __FILESUP_H__ */ + +/* EOF */ diff --git a/reactos/subsys/system/usetup/inicache.c b/reactos/subsys/system/usetup/inicache.c new file mode 100644 index 00000000000..7bafbbe0b0f --- /dev/null +++ b/reactos/subsys/system/usetup/inicache.c @@ -0,0 +1,841 @@ +/* + * ReactOS kernel + * Copyright (C) 2002 ReactOS Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* $Id: inicache.c,v 1.1 2002/11/13 18:25:18 ekohl Exp $ + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS text-mode setup + * FILE: subsys/system/usetup/inicache.c + * PURPOSE: INI file parser that caches contents of INI file in memory + * PROGRAMMER: Royce Mitchell III + * Eric Kohl + */ + +/* INCLUDES *****************************************************************/ + +#include +#include "usetup.h" +#include "inicache.h" + + +/* PRIVATE FUNCTIONS ********************************************************/ + +static PINICACHEKEY +IniCacheFreeKey(PINICACHEKEY Key) +{ + PINICACHEKEY Next; + + if (Key == NULL) + { + return(NULL); + } + + Next = Key->Next; + if (Key->Name != NULL) + { + RtlFreeHeap(ProcessHeap, + 0, + Key->Name); + Key->Name = NULL; + } + + if (Key->Value != NULL) + { + RtlFreeHeap(ProcessHeap, + 0, + Key->Value); + Key->Value = NULL; + } + + RtlFreeHeap(ProcessHeap, + 0, + Key); + + return(Next); +} + + +static PINICACHESECTION +IniCacheFreeSection(PINICACHESECTION Section) +{ + PINICACHESECTION Next; + + if (Section == NULL) + { + return(NULL); + } + + Next = Section->Next; + while (Section->FirstKey != NULL) + { + Section->FirstKey = IniCacheFreeKey(Section->FirstKey); + } + Section->LastKey = NULL; + + if (Section->Name != NULL) + { + RtlFreeHeap(ProcessHeap, + 0, + Section->Name); + Section->Name = NULL; + } + + RtlFreeHeap(ProcessHeap, + 0, + Section); + + return(Next); +} + + +static PINICACHEKEY +IniCacheFindKey(PINICACHESECTION Section, + PWCHAR Name, + ULONG NameLength) +{ + PINICACHEKEY Key; + + Key = Section->FirstKey; + while (Key != NULL) + { + if (NameLength == wcslen(Key->Name)) + { + if (_wcsnicmp(Key->Name, Name, NameLength) == 0) + break; + } + + Key = Key->Next; + } + + return(Key); +} + + +static PINICACHEKEY +IniCacheAddKey(PINICACHESECTION Section, + PCHAR Name, + ULONG NameLength, + PCHAR Value, + ULONG ValueLength) +{ + PINICACHEKEY Key; + ULONG i; + + Key = NULL; + + if (Section == NULL || + Name == NULL || + NameLength == 0 || + Value == NULL || + ValueLength == 0) + { + DPRINT("Invalid parameter\n"); + return(NULL); + } + + Key = (PINICACHEKEY)RtlAllocateHeap(ProcessHeap, + 0, + sizeof(INICACHEKEY)); + if (Key == NULL) + { + DPRINT("RtlAllocateHeap() failed\n"); + return(NULL); + } + + RtlZeroMemory(Key, + sizeof(INICACHEKEY)); + + + Key->Name = RtlAllocateHeap(ProcessHeap, + 0, + (NameLength + 1) * sizeof(WCHAR)); + if (Key->Name == NULL) + { + DPRINT("RtlAllocateHeap() failed\n"); + RtlFreeHeap(ProcessHeap, + 0, + Key); + return(NULL); + } + + /* Copy value name */ + for (i = 0; i < NameLength; i++) + { + Key->Name[i] = (WCHAR)Name[i]; + } + Key->Name[NameLength] = 0; + + + Key->Value = RtlAllocateHeap(ProcessHeap, + 0, + (ValueLength + 1) * sizeof(WCHAR)); + if (Key->Value == NULL) + { + DPRINT("RtlAllocateHeap() failed\n"); + RtlFreeHeap(ProcessHeap, + 0, + Key->Name); + RtlFreeHeap(ProcessHeap, + 0, + Key); + return(NULL); + } + + /* Copy value data */ + for (i = 0; i < ValueLength; i++) + { + Key->Value[i] = (WCHAR)Value[i]; + } + Key->Value[ValueLength] = 0; + + + if (Section->FirstKey == NULL) + { + Section->FirstKey = Key; + Section->LastKey = Key; + } + else + { + Section->LastKey->Next = Key; + Key->Prev = Section->LastKey; + Section->LastKey = Key; + } + + return(Key); +} + + +static PINICACHESECTION +IniCacheFindSection(PINICACHE Cache, + PWCHAR Name, + ULONG NameLength) +{ + PINICACHESECTION Section = NULL; + + if (Cache == NULL || Name == NULL || NameLength == 0) + { + return(NULL); + } + + Section = Cache->FirstSection; + + /* iterate through list of sections */ + while (Section != NULL) + { + if (NameLength == wcslen(Section->Name)) + { + /* are the contents the same too? */ + if (_wcsnicmp(Section->Name, Name, NameLength) == 0) + break; + } + + /* get the next section*/ + Section = Section->Next; + } + + return(Section); +} + + +static PINICACHESECTION +IniCacheAddSection(PINICACHE Cache, + PCHAR Name, + ULONG NameLength) +{ + PINICACHESECTION Section = NULL; + ULONG i; + + if (Cache == NULL || Name == NULL || NameLength == 0) + { + DPRINT("Invalid parameter\n"); + return(NULL); + } + + Section = (PINICACHESECTION)RtlAllocateHeap(ProcessHeap, + 0, + sizeof(INICACHESECTION)); + if (Section == NULL) + { + DPRINT("RtlAllocateHeap() failed\n"); + return(NULL); + } + RtlZeroMemory(Section, + sizeof(INICACHESECTION)); + + /* Allocate and initialize section name */ + Section->Name = RtlAllocateHeap(ProcessHeap, + 0, + (NameLength + 1) * sizeof(WCHAR)); + if (Section->Name == NULL) + { + DPRINT("RtlAllocateHeap() failed\n"); + RtlFreeHeap(ProcessHeap, + 0, + Section); + return(NULL); + } + + /* Copy section name */ + for (i = 0; i < NameLength; i++) + { + Section->Name[i] = (WCHAR)Name[i]; + } + Section->Name[NameLength] = 0; + + /* Append section */ + if (Cache->FirstSection == NULL) + { + Cache->FirstSection = Section; + Cache->LastSection = Section; + } + else + { + Cache->LastSection->Next = Section; + Section->Prev = Cache->LastSection; + Cache->LastSection = Section; + } + + return(Section); +} + + +static PCHAR +IniCacheSkipWhitespace(PCHAR Ptr) +{ + while (*Ptr != 0 && isspace(*Ptr)) + Ptr++; + + return((*Ptr == 0) ? NULL : Ptr); +} + + +static PCHAR +IniCacheSkipToNextSection(PCHAR Ptr) +{ + while (*Ptr != 0 && *Ptr != '[') + { + while (*Ptr != 0 && *Ptr != L'\n') + { + Ptr++; + } + Ptr++; + } + + return((*Ptr == 0) ? NULL : Ptr); +} + + +static PCHAR +IniCacheGetSectionName(PCHAR Ptr, + PCHAR *NamePtr, + PULONG NameSize) +{ + ULONG Size = 0; + CHAR Name[256]; + + *NamePtr = NULL; + *NameSize = 0; + + /* skip whitespace */ + while (*Ptr != 0 && isspace(*Ptr)) + { + Ptr++; + } + + *NamePtr = Ptr; + + while (*Ptr != 0 && *Ptr != ']') + { + Size++; + Ptr++; + } + + Ptr++; + + while (*Ptr != 0 && *Ptr != L'\n') + { + Ptr++; + } + Ptr++; + + *NameSize = Size; + + strncpy(Name, *NamePtr, Size); + Name[Size] = 0; + + DPRINT("SectionName: '%s'\n", Name); + + return(Ptr); +} + + +static PCHAR +IniCacheGetKeyName(PCHAR Ptr, + PCHAR *NamePtr, + PULONG NameSize) +{ + ULONG Size = 0; + + *NamePtr = NULL; + *NameSize = 0; + + /* skip whitespace */ + while (*Ptr != 0 && isspace(*Ptr)) + { + Ptr++; + } + + *NamePtr = Ptr; + + while (*Ptr != 0 && !isspace(*Ptr) && *Ptr != '=') + { + Size++; + Ptr++; + } + + *NameSize = Size; + + return(Ptr); +} + + +static PCHAR +IniCacheGetKeyValue(PCHAR Ptr, + PCHAR *DataPtr, + PULONG DataSize) +{ + ULONG Size = 0; + + *DataPtr = NULL; + *DataSize = 0; + + /* skip whitespace */ + while (*Ptr != 0 && isspace(*Ptr)) + { + Ptr++; + } + + /* check and skip '=' */ + if (*Ptr != '=') + { + return(NULL); + } + Ptr++; + + /* skip whitespace */ + while (*Ptr != 0 && isspace(*Ptr)) + { + Ptr++; + } + + /* check for quoted data */ + if (*Ptr == '\"') + { + Ptr++; + *DataPtr = Ptr; + + while (*Ptr != 0 && *Ptr != '\"') + { + Ptr++; + Size++; + } + Ptr++; + } + else + { + *DataPtr = Ptr; + + while (*Ptr != 0 && !isspace(*Ptr) && *Ptr != '\n') + { + Ptr++; + Size++; + } + } + + /* Skip to next line */ + while (*Ptr != 0 && *Ptr != '\n') + { + Ptr++; + } + Ptr++; + + *DataSize = Size; + + return(Ptr); +} + + + + +/* PUBLIC FUNCTIONS *********************************************************/ + +NTSTATUS +IniCacheLoad(PINICACHE *Cache, + PUNICODE_STRING FileName) +{ + OBJECT_ATTRIBUTES ObjectAttributes; + FILE_STANDARD_INFORMATION FileInfo; + IO_STATUS_BLOCK IoStatusBlock; + HANDLE FileHandle; + NTSTATUS Status; + PCHAR FileBuffer; + ULONG FileLength; + PCHAR Ptr; + LARGE_INTEGER FileOffset; + + ULONG i; + PINICACHESECTION Section; + PINICACHEKEY Key; + + PCHAR SectionName; + ULONG SectionNameSize; + + PCHAR KeyName; + ULONG KeyNameSize; + + PCHAR KeyValue; + ULONG KeyValueSize; + + *Cache = NULL; + + /* Open ini file */ + InitializeObjectAttributes(&ObjectAttributes, + FileName, + 0, + NULL, + NULL); + + Status = NtOpenFile(&FileHandle, + GENERIC_READ | SYNCHRONIZE, + &ObjectAttributes, + &IoStatusBlock, + FILE_SHARE_READ, + FILE_NON_DIRECTORY_FILE); + if (!NT_SUCCESS(Status)) + { + DPRINT("NtOpenFile() failed (Status %lx)\n", Status); + return(Status); + } + + DPRINT("NtOpenFile() successful\n"); + + /* Query file size */ + Status = NtQueryInformationFile(FileHandle, + &IoStatusBlock, + &FileInfo, + sizeof(FILE_STANDARD_INFORMATION), + FileStandardInformation); + if (Status == STATUS_PENDING) + { + DPRINT("NtQueryInformationFile() returns STATUS_PENDING\n"); + + } + else if (!NT_SUCCESS(Status)) + { + DPRINT("NtQueryInformationFile() failed (Status %lx)\n", Status); + NtClose(FileHandle); + return(Status); + } + + FileLength = FileInfo.EndOfFile.u.LowPart; + + DPRINT("File size: %lu\n", FileLength); + + /* Allocate file buffer */ + FileBuffer = RtlAllocateHeap(ProcessHeap, + 0, + FileLength + 1); + if (FileBuffer == NULL) + { + DPRINT1("RtlAllocateHeap() failed\n"); + NtClose(FileHandle); + return(STATUS_INSUFFICIENT_RESOURCES); + } + + /* Read file */ + FileOffset.QuadPart = 0ULL; + Status = NtReadFile(FileHandle, + NULL, + NULL, + NULL, + &IoStatusBlock, + FileBuffer, + FileLength, + &FileOffset, + NULL); + + if (Status == STATUS_PENDING) + { + DPRINT("NtReadFile() returns STATUS_PENDING\n"); + + Status = IoStatusBlock.Status; + } + + /* Append string terminator */ + FileBuffer[FileLength] = 0; + + NtClose(FileHandle); + + if (!NT_SUCCESS(Status)) + { + DPRINT("NtReadFile() failed (Status %lx)\n", Status); + RtlFreeHeap(ProcessHeap, + 0, + FileBuffer); + return(Status); + } + + + /* Allocate inicache header */ + *Cache = (PINICACHE)RtlAllocateHeap(ProcessHeap, + 0, + sizeof(INICACHE)); + if (*Cache == NULL) + { + DPRINT("RtlAllocateHeap() failed\n"); + return(STATUS_INSUFFICIENT_RESOURCES); + } + + /* Initialize inicache header */ + RtlZeroMemory(*Cache, + sizeof(INICACHE)); + + /* Parse ini file */ + Section = NULL; + Ptr = FileBuffer; + while (Ptr != NULL && *Ptr != 0) + { + Ptr = IniCacheSkipWhitespace(Ptr); + if (Ptr == NULL) + continue; + + if (*Ptr == '[') + { + Section = NULL; + Ptr++; + + Ptr = IniCacheGetSectionName(Ptr, + &SectionName, + &SectionNameSize); + + Section = IniCacheAddSection(*Cache, + SectionName, + SectionNameSize); + if (Section == NULL) + { + DPRINT("IniCacheAddSection() failed\n"); + Ptr = IniCacheSkipToNextSection(Ptr); + continue; + } + } + else + { + if (Section == NULL) + { + Ptr = IniCacheSkipToNextSection(Ptr); + continue; + } + + Ptr = IniCacheGetKeyName(Ptr, + &KeyName, + &KeyNameSize); + + Ptr = IniCacheGetKeyValue(Ptr, + &KeyValue, + &KeyValueSize); + + Key = IniCacheAddKey(Section, + KeyName, + KeyNameSize, + KeyValue, + KeyValueSize); + if (Key == NULL) + { + DPRINT("IniCacheAddKey() failed\n"); + } + } + } + + /* Free file buffer */ + RtlFreeHeap(ProcessHeap, + 0, + FileBuffer); + + return(Status); +} + + +VOID +IniCacheDestroy(PINICACHE Cache) +{ + if (Cache == NULL) + { + return; + } + + while (Cache->FirstSection != NULL) + { + Cache->FirstSection = IniCacheFreeSection(Cache->FirstSection); + } + Cache->LastSection = NULL; + + RtlFreeHeap(ProcessHeap, + 0, + Cache); +} + + +PINICACHESECTION +IniCacheGetSection(PINICACHE Cache, + PWCHAR Name) +{ + PINICACHESECTION Section = NULL; + + if (Cache == NULL || Name == NULL) + { + DPRINT("Invalid parameter\n"); + return(NULL); + } + + /* iterate through list of sections */ + Section = Cache->FirstSection; + while (Section != NULL) + { + DPRINT("Comparing '%S' and '%S'\n", Section->Name, Name); + + /* Are the section names the same? */ + if (_wcsicmp(Section->Name, Name) == 0) + return(Section); + + /* Get the next section */ + Section = Section->Next; + } + + DPRINT("Section not found\n"); + + return(NULL); +} + + +NTSTATUS +IniCacheGetKey(PINICACHESECTION Section, + PWCHAR KeyName, + PWCHAR *KeyValue) +{ + PINICACHEKEY Key; + + if (Section == NULL || KeyName == NULL || KeyValue == NULL) + { + DPRINT("Invalid parameter\n"); + return(STATUS_INVALID_PARAMETER); + } + + *KeyValue = NULL; + + Key = IniCacheFindKey(Section, KeyName, wcslen(KeyName)); + if (Key == NULL) + { + return(STATUS_INVALID_PARAMETER); + } + + *KeyValue = Key->Value; + + return(STATUS_SUCCESS); +} + + +PINICACHEITERATOR +IniCacheFindFirstValue(PINICACHESECTION Section, + PWCHAR *KeyName, + PWCHAR *KeyValue) +{ + PINICACHEITERATOR Iterator; + PINICACHEKEY Key; + + if (Section == NULL || KeyName == NULL || KeyValue == NULL) + { + DPRINT("Invalid parameter\n"); + return(NULL); + } + + Key = Section->FirstKey; + if (Key == NULL) + { + DPRINT("Invalid parameter\n"); + return(NULL); + } + + *KeyName = Key->Name; + *KeyValue = Key->Value; + + Iterator = (PINICACHEITERATOR)RtlAllocateHeap(ProcessHeap, + 0, + sizeof(INICACHEITERATOR)); + if (Iterator == NULL) + { + DPRINT("RtlAllocateHeap() failed\n"); + return(NULL); + } + + Iterator->Section = Section; + Iterator->Key = Key; + + return(Iterator); +} + + +BOOLEAN +IniCacheFindNextValue(PINICACHEITERATOR Iterator, + PWCHAR *KeyName, + PWCHAR *KeyValue) +{ + PINICACHEKEY Key; + + if (Iterator == NULL || KeyName == NULL || KeyValue == NULL) + { + DPRINT("Invalid parameter\n"); + return(FALSE); + } + + Key = Iterator->Key->Next; + if (Key == NULL) + { + DPRINT("No more entries\n"); + return(FALSE); + } + + *KeyName = Key->Name; + *KeyValue = Key->Value; + + Iterator->Key = Key; + + return(TRUE); +} + + +VOID +IniCacheFindClose(PINICACHEITERATOR Iterator) +{ + if (Iterator == NULL) + return; + + RtlFreeHeap(ProcessHeap, + 0, + Iterator); +} + +/* EOF */ diff --git a/reactos/subsys/system/usetup/inicache.h b/reactos/subsys/system/usetup/inicache.h new file mode 100644 index 00000000000..4320b670144 --- /dev/null +++ b/reactos/subsys/system/usetup/inicache.h @@ -0,0 +1,104 @@ +/* + * ReactOS kernel + * Copyright (C) 2002 ReactOS Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS text-mode setup + * FILE: subsys/system/usetup/inicache.h + * PURPOSE: INI file parser that caches contents of INI file in memory + * PROGRAMMER: Royce Mitchell III + * Eric Kohl + */ + +#ifndef __INICACHE_H__ +#define __INICACHE_H__ + + +typedef struct _INICACHEKEY +{ + PWCHAR Name; + PWCHAR Value; + + struct _INICACHEKEY *Next; + struct _INICACHEKEY *Prev; +} INICACHEKEY, *PINICACHEKEY; + + +typedef struct _INICACHESECTION +{ + PWCHAR Name; + + PINICACHEKEY FirstKey; + PINICACHEKEY LastKey; + + struct _INICACHESECTION *Next; + struct _INICACHESECTION *Prev; +} INICACHESECTION, *PINICACHESECTION; + + +typedef struct _INICACHE +{ + PINICACHESECTION FirstSection; + PINICACHESECTION LastSection; +} INICACHE, *PINICACHE; + + +typedef struct _PINICACHEITERATOR +{ + PINICACHESECTION Section; + PINICACHEKEY Key; +} INICACHEITERATOR, *PINICACHEITERATOR; + + +/* FUNCTIONS ****************************************************************/ + +NTSTATUS +IniCacheLoad(PINICACHE *Cache, + PUNICODE_STRING FileName); + +VOID +IniCacheDestroy(PINICACHE Cache); + +PINICACHESECTION +IniCacheGetSection(PINICACHE Cache, + PWCHAR Name); + +NTSTATUS +IniCacheGetKey(PINICACHESECTION Section, + PWCHAR KeyName, + PWCHAR *KeyValue); + + + +PINICACHEITERATOR +IniCacheFindFirstValue(PINICACHESECTION Section, + PWCHAR *KeyName, + PWCHAR *KeyValue); + +BOOLEAN +IniCacheFindNextValue(PINICACHEITERATOR Iterator, + PWCHAR *KeyName, + PWCHAR *KeyValue); + +VOID +IniCacheFindClose(PINICACHEITERATOR Iterator); + + +#endif /* __INICACHE_H__ */ + +/* EOF */ diff --git a/reactos/subsys/system/usetup/makefile b/reactos/subsys/system/usetup/makefile index b3aefdfcf3b..bce64816289 100644 --- a/reactos/subsys/system/usetup/makefile +++ b/reactos/subsys/system/usetup/makefile @@ -1,4 +1,4 @@ -# $Id: makefile,v 1.3 2002/10/29 18:40:02 ekohl Exp $ +# $Id: makefile,v 1.4 2002/11/13 18:25:18 ekohl Exp $ PATH_TO_TOP = ../../.. @@ -12,7 +12,7 @@ TARGET_INSTALLDIR = system32 TARGET_CFLAGS = -D__NTAPP__ -TARGET_OBJECTS = $(TARGET_NAME).o console.o drivesup.o partlist.o +TARGET_OBJECTS = $(TARGET_NAME).o console.o drivesup.o filesup.o inicache.o partlist.o include $(PATH_TO_TOP)/rules.mak diff --git a/reactos/subsys/system/usetup/partlist.c b/reactos/subsys/system/usetup/partlist.c index 17bf4f277d4..e930f125853 100644 --- a/reactos/subsys/system/usetup/partlist.c +++ b/reactos/subsys/system/usetup/partlist.c @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* $Id: partlist.c,v 1.3 2002/11/02 23:17:06 ekohl Exp $ +/* $Id: partlist.c,v 1.4 2002/11/13 18:25:18 ekohl Exp $ * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS text-mode setup * FILE: subsys/system/usetup/partlist.c @@ -39,6 +39,88 @@ /* FUNCTIONS ****************************************************************/ +static VOID +AddPartitionList(ULONG DiskNumber, + PDISKENTRY DiskEntry, + DRIVE_LAYOUT_INFORMATION *LayoutBuffer) +{ + PPARTENTRY PartEntry; + ULONG i; + ULONG EntryCount; + + + /* + * FIXME: + * Determine required number of partiton entries. + * This must include entries for unused disk space. + */ + + /* Check for unpartitioned disk */ + if (LayoutBuffer->PartitionCount == 0) + { + EntryCount = 1; + } + else + { + +#if 0 + for (i = 0; i < LayoutBuffer->PartitionCount; i++) + { + + } +#endif + + EntryCount = LayoutBuffer->PartitionCount; + } + + + DiskEntry->PartArray = (PPARTENTRY)RtlAllocateHeap(ProcessHeap, + 0, + EntryCount * sizeof(PARTENTRY)); + DiskEntry->PartCount = EntryCount; + + RtlZeroMemory(DiskEntry->PartArray, + EntryCount * sizeof(PARTENTRY)); + + if (LayoutBuffer->PartitionCount == 0) + { + /* Initialize an 'Unpartitioned space' entry */ + PartEntry = &DiskEntry->PartArray[0]; + + PartEntry->Unpartitioned = TRUE; + PartEntry->PartSize = 0; /* ?? */ + + PartEntry->Used = TRUE; + } + else + { + for (i = 0; i < LayoutBuffer->PartitionCount; i++) + { + PartEntry = &DiskEntry->PartArray[i]; + + if ((LayoutBuffer->PartitionEntry[i].PartitionType != PARTITION_ENTRY_UNUSED) && + (!IsContainerPartition(LayoutBuffer->PartitionEntry[i].PartitionType))) + { + PartEntry->PartSize = LayoutBuffer->PartitionEntry[i].PartitionLength.QuadPart; + PartEntry->PartNumber = LayoutBuffer->PartitionEntry[i].PartitionNumber, + PartEntry->PartType = LayoutBuffer->PartitionEntry[i].PartitionType; + + PartEntry->DriveLetter = GetDriveLetter(DiskNumber, + LayoutBuffer->PartitionEntry[i].PartitionNumber); + + PartEntry->Unpartitioned = FALSE; + + PartEntry->Used = TRUE; + } + else + { + PartEntry->Used = FALSE; + } + } + } +} + + PPARTLIST CreatePartitionList(SHORT Left, SHORT Top, @@ -49,16 +131,15 @@ CreatePartitionList(SHORT Left, OBJECT_ATTRIBUTES ObjectAttributes; SYSTEM_DEVICE_INFORMATION Sdi; DISK_GEOMETRY DiskGeometry; + IO_STATUS_BLOCK Iosb; ULONG ReturnSize; NTSTATUS Status; - ULONG DiskCount; - IO_STATUS_BLOCK Iosb; + ULONG DiskNumber; WCHAR Buffer[MAX_PATH]; UNICODE_STRING Name; HANDLE FileHandle; DRIVE_LAYOUT_INFORMATION *LayoutBuffer; SCSI_ADDRESS ScsiAddress; - ULONG i; List = (PPARTLIST)RtlAllocateHeap(ProcessHeap, 0, sizeof(PARTLIST)); if (List == NULL) @@ -96,11 +177,11 @@ CreatePartitionList(SHORT Left, Sdi.NumberOfDisks * sizeof(DISKENTRY)); List->DiskCount = Sdi.NumberOfDisks; - for (DiskCount = 0; DiskCount < Sdi.NumberOfDisks; DiskCount++) + for (DiskNumber = 0; DiskNumber < Sdi.NumberOfDisks; DiskNumber++) { swprintf(Buffer, L"\\Device\\Harddisk%d\\Partition0", - DiskCount); + DiskNumber); RtlInitUnicodeString(&Name, Buffer); @@ -144,17 +225,17 @@ CreatePartitionList(SHORT Left, sizeof(SCSI_ADDRESS)); - List->DiskArray[DiskCount].DiskSize = + List->DiskArray[DiskNumber].DiskSize = DiskGeometry.Cylinders.QuadPart * (ULONGLONG)DiskGeometry.TracksPerCylinder * (ULONGLONG)DiskGeometry.SectorsPerTrack * (ULONGLONG)DiskGeometry.BytesPerSector; - List->DiskArray[DiskCount].DiskNumber = DiskCount; - List->DiskArray[DiskCount].Port = ScsiAddress.PortNumber; - List->DiskArray[DiskCount].Bus = ScsiAddress.PathId; - List->DiskArray[DiskCount].Id = ScsiAddress.TargetId; + List->DiskArray[DiskNumber].DiskNumber = DiskNumber; + List->DiskArray[DiskNumber].Port = ScsiAddress.PortNumber; + List->DiskArray[DiskNumber].Bus = ScsiAddress.PathId; + List->DiskArray[DiskNumber].Id = ScsiAddress.TargetId; - List->DiskArray[DiskCount].FixedDisk = TRUE; + List->DiskArray[DiskNumber].FixedDisk = TRUE; LayoutBuffer = (DRIVE_LAYOUT_INFORMATION*)RtlAllocateHeap(ProcessHeap, 0, 8192); @@ -171,31 +252,9 @@ CreatePartitionList(SHORT Left, 8192); if (NT_SUCCESS(Status)) { - - List->DiskArray[DiskCount].PartArray = (PPARTENTRY)RtlAllocateHeap(ProcessHeap, - 0, - LayoutBuffer->PartitionCount * sizeof(PARTENTRY)); - List->DiskArray[DiskCount].PartCount = LayoutBuffer->PartitionCount; - - for (i = 0; i < LayoutBuffer->PartitionCount; i++) - { - if ((LayoutBuffer->PartitionEntry[i].PartitionType != PARTITION_ENTRY_UNUSED) && - !IsContainerPartition(LayoutBuffer->PartitionEntry[i].PartitionType)) - { - List->DiskArray[DiskCount].PartArray[i].PartSize = LayoutBuffer->PartitionEntry[i].PartitionLength.QuadPart; - List->DiskArray[DiskCount].PartArray[i].PartNumber = LayoutBuffer->PartitionEntry[i].PartitionNumber, - List->DiskArray[DiskCount].PartArray[i].PartType = LayoutBuffer->PartitionEntry[i].PartitionType; - - List->DiskArray[DiskCount].PartArray[i].DriveLetter = GetDriveLetter(DiskCount, - LayoutBuffer->PartitionEntry[i].PartitionNumber); - - List->DiskArray[DiskCount].PartArray[i].Used = TRUE; - } - else - { - List->DiskArray[DiskCount].PartArray[i].Used = FALSE; - } - } + AddPartitionList(DiskNumber, + &List->DiskArray[DiskNumber], + LayoutBuffer); } RtlFreeHeap(ProcessHeap, 0, LayoutBuffer); @@ -203,9 +262,9 @@ CreatePartitionList(SHORT Left, else { /* mark removable disk entry */ - List->DiskArray[DiskCount].FixedDisk = FALSE; - List->DiskArray[DiskCount].PartCount = 0; - List->DiskArray[DiskCount].PartArray = NULL; + List->DiskArray[DiskNumber].FixedDisk = FALSE; + List->DiskArray[DiskNumber].PartCount = 0; + List->DiskArray[DiskNumber].PartArray = NULL; } } @@ -321,9 +380,8 @@ PrintPartitionData(PPARTLIST List, ULONGLONG PartSize; PCHAR Unit; - PCHAR PartType; UCHAR Attribute; - + PCHAR PartType; Width = List->Right - List->Left - 1; Height = List->Bottom - List->Top - 1; @@ -336,33 +394,38 @@ PrintPartitionData(PPARTLIST List, PartEntry = &List->DiskArray[DiskIndex].PartArray[PartIndex]; - if ((PartEntry->PartType == PARTITION_FAT_12) || - (PartEntry->PartType == PARTITION_FAT_16) || - (PartEntry->PartType == PARTITION_HUGE) || - (PartEntry->PartType == PARTITION_XINT13)) + /* Determine partition type */ + PartType = NULL; + if (PartEntry->Unpartitioned == FALSE) { - PartType = "FAT"; - } - else if ((PartEntry->PartType == PARTITION_FAT32) || - (PartEntry->PartType == PARTITION_FAT32_XINT13)) - { - PartType = "FAT32"; - } - else if (PartEntry->PartType == PARTITION_IFS) - { - PartType = "NTFS"; /* FIXME: Not quite correct! */ - } - else - { - PartType = "Unknown"; + if ((PartEntry->PartType == PARTITION_FAT_12) || + (PartEntry->PartType == PARTITION_FAT_16) || + (PartEntry->PartType == PARTITION_HUGE) || + (PartEntry->PartType == PARTITION_XINT13)) + { + PartType = "FAT"; + } + else if ((PartEntry->PartType == PARTITION_FAT32) || + (PartEntry->PartType == PARTITION_FAT32_XINT13)) + { + PartType = "FAT32"; + } + else if (PartEntry->PartType == PARTITION_IFS) + { + PartType = "NTFS"; /* FIXME: Not quite correct! */ + } } + +#if 0 if (PartEntry->PartSize >= 0x280000000ULL) /* 10 GB */ { PartSize = (PartEntry->PartSize + (1 << 29)) >> 30; Unit = "GB"; } - else if (PartEntry->PartSize >= 0xA00000ULL) /* 10 MB */ + else +#endif + if (PartEntry->PartSize >= 0xA00000ULL) /* 10 MB */ { PartSize = (PartEntry->PartSize + (1 << 19)) >> 20; Unit = "MB"; @@ -370,29 +433,58 @@ PrintPartitionData(PPARTLIST List, else { PartSize = (PartEntry->PartSize + (1 << 9)) >> 10; - Unit = "kB"; + Unit = "KB"; } - if (PartEntry->DriveLetter != (CHAR)0) + + if (PartEntry->Unpartitioned == TRUE) { sprintf(LineBuffer, - "%c: %d: nr: %d type: %x (%s) %I64u %s", + " Unpartitioned space %I64u %s", + PartSize, + Unit); + } + else if (PartEntry->DriveLetter != (CHAR)0) + { + if (PartType == NULL) + { + sprintf(LineBuffer, + "%c: Type %-3lu %I64u %s", + PartEntry->DriveLetter, + PartEntry->PartType, + PartSize, + Unit); + } + else + { + sprintf(LineBuffer, + "%c: %s %I64u %s", + PartEntry->DriveLetter, + PartType, + PartSize, + Unit); + } + +#if 0 + sprintf(LineBuffer, + "%c: %s (%d: nr: %d type: %x) %I64u %s", PartEntry->DriveLetter, + PartType, PartIndex, PartEntry->PartNumber, PartEntry->PartType, - PartType, PartSize, Unit); +#endif } else { sprintf(LineBuffer, - " %d: nr: %d type: %x (%s) %I64u %s", + "-- %s (%d: nr: %d type: %x) %I64u %s", + PartEntry->FileSystemName, PartIndex, PartEntry->PartNumber, PartEntry->PartType, - PartType, PartSize, Unit); } @@ -435,7 +527,6 @@ PrintDiskData(PPARTLIST List, ULONGLONG DiskSize; PCHAR Unit; SHORT PartIndex; - BOOL PartPrinted; DiskEntry = &List->DiskArray[DiskIndex]; @@ -448,24 +539,23 @@ PrintDiskData(PPARTLIST List, coPos.X = List->Left + 1; coPos.Y = List->Top + 1 + List->Line; +#if 0 if (DiskEntry->DiskSize >= 0x280000000ULL) /* 10 GB */ { DiskSize = (DiskEntry->DiskSize + (1 << 29)) >> 30; Unit = "GB"; } - else if (DiskEntry->DiskSize >= 0xA00000ULL) /* 10 MB */ + else +#endif { DiskSize = (DiskEntry->DiskSize + (1 << 19)) >> 20; + if (DiskSize == 0) + DiskSize = 1; Unit = "MB"; } - else - { - DiskSize = (DiskEntry->DiskSize + (1 << 9)) >> 10; - Unit = "kB"; - } sprintf(LineBuffer, - "%I64u %s Harddisk %lu (Port=%hu, Bus=%hu, Id=%hu)", + "%I64u %s Harddisk %lu (Port=%hu, Bus=%hu, Id=%hu)", DiskSize, Unit, DiskEntry->DiskNumber, @@ -494,25 +584,19 @@ PrintDiskData(PPARTLIST List, PrintEmptyLine(List); - PartPrinted = FALSE; - /* Print partition lines*/ - for (PartIndex = 0; PartIndex < List->DiskArray[DiskIndex].PartCount; PartIndex++) + for (PartIndex = 0; PartIndex < DiskEntry->PartCount; PartIndex++) { - if (List->DiskArray[DiskIndex].PartArray[PartIndex].Used == TRUE) + if (DiskEntry->PartArray[PartIndex].Used == TRUE) { PrintPartitionData(List, DiskIndex, PartIndex); - PartPrinted = TRUE; } } /* Print separator line */ - if (PartPrinted == TRUE) - { - PrintEmptyLine(List); - } + PrintEmptyLine(List); } @@ -582,7 +666,7 @@ DrawPartitionList(PPARTLIST List) coPos, &Written); - /* draw upper right corner */ + /* draw lower right corner */ coPos.X = List->Right; coPos.Y = List->Bottom; FillConsoleOutputCharacter(0xD9, // '+', diff --git a/reactos/subsys/system/usetup/partlist.h b/reactos/subsys/system/usetup/partlist.h index f20d8c8cf5c..d7e915b5198 100644 --- a/reactos/subsys/system/usetup/partlist.h +++ b/reactos/subsys/system/usetup/partlist.h @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* $Id: partlist.h,v 1.3 2002/11/02 23:17:06 ekohl Exp $ +/* $Id: partlist.h,v 1.4 2002/11/13 18:25:18 ekohl Exp $ * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS text-mode setup * FILE: subsys/system/usetup/partlist.h @@ -50,6 +50,11 @@ typedef struct _PARTENTRY ULONG PartType; CHAR DriveLetter; + CHAR VolumeLabel[17]; + CHAR FileSystemName[9]; + + BOOL Unpartitioned; + BOOL Used; } PARTENTRY, *PPARTENTRY; diff --git a/reactos/subsys/system/usetup/usetup.c b/reactos/subsys/system/usetup/usetup.c index 87d28fa37bb..0ee9b4e8d7f 100644 --- a/reactos/subsys/system/usetup/usetup.c +++ b/reactos/subsys/system/usetup/usetup.c @@ -27,9 +27,13 @@ #include #include +#include +#include + #include "usetup.h" #include "console.h" #include "partlist.h" +#include "inicache.h" @@ -56,14 +60,16 @@ HANDLE ProcessHeap; -BOOL PartDataValid = FALSE; +BOOLEAN PartDataValid; PARTDATA PartData; -CHAR InstallDir[51]; +WCHAR InstallDir[51]; UNICODE_STRING SourcePath; UNICODE_STRING SourceRootPath; +PINICACHE IniCache; + /* FUNCTIONS ****************************************************************/ @@ -88,6 +94,216 @@ PrintString(char* fmt,...) } +static VOID +PopupError(PCHAR Text, + PCHAR Status) +{ + SHORT xScreen; + SHORT yScreen; + SHORT yTop; + SHORT xLeft; + COORD coPos; + ULONG Written; + ULONG Length; + ULONG MaxLength; + ULONG Lines; + PCHAR p; + PCHAR pnext; + BOOLEAN LastLine; + SHORT Width; + SHORT Height; + + + /* Count text lines and longest line */ + MaxLength = 0; + Lines = 0; + pnext = Text; + while (TRUE) + { + p = strchr(pnext, '\n'); + if (p == NULL) + { + Length = strlen(pnext); + LastLine = TRUE; + } + else + { + Length = (ULONG)(p - pnext); + LastLine = FALSE; + } + + Lines++; + if (Length > MaxLength) + MaxLength = Length; + + if (LastLine == TRUE) + break; + + pnext = p + 1; + } + + /* Check length of status line */ + if (Status != NULL) + { + Length = strlen(Status); + if (Length > MaxLength) + MaxLength = Length; + } + + GetScreenSize(&xScreen, &yScreen); + + Width = MaxLength + 4; + Height = Lines + 2; + if (Status != NULL) + Height += 2; + + yTop = (yScreen - Height) / 2; + xLeft = (xScreen - Width) / 2; + + + /* Set screen attributes */ + coPos.X = xLeft; + for (coPos.Y = yTop; coPos.Y < yTop + Height; coPos.Y++) + { + FillConsoleOutputAttribute(0x74, + Width, + coPos, + &Written); + } + + /* draw upper left corner */ + coPos.X = xLeft; + coPos.Y = yTop; + FillConsoleOutputCharacter(0xDA, // '+', + 1, + coPos, + &Written); + + /* draw upper edge */ + coPos.X = xLeft + 1; + coPos.Y = yTop; + FillConsoleOutputCharacter(0xC4, // '-', + Width - 2, + coPos, + &Written); + + /* draw upper right corner */ + coPos.X = xLeft + Width - 1; + coPos.Y = yTop; + FillConsoleOutputCharacter(0xBF, // '+', + 1, + coPos, + &Written); + + /* Draw right edge, inner space and left edge */ + for (coPos.Y = yTop + 1; coPos.Y < yTop + Height - 1; coPos.Y++) + { + coPos.X = xLeft; + FillConsoleOutputCharacter(0xB3, // '|', + 1, + coPos, + &Written); + + coPos.X = xLeft + 1; + FillConsoleOutputCharacter(' ', + Width - 2, + coPos, + &Written); + + coPos.X = xLeft + Width - 1; + FillConsoleOutputCharacter(0xB3, // '|', + 1, + coPos, + &Written); + } + + /* draw lower left corner */ + coPos.X = xLeft; + coPos.Y = yTop + Height - 1; + FillConsoleOutputCharacter(0xC0, // '+', + 1, + coPos, + &Written); + + /* draw lower edge */ + coPos.X = xLeft + 1; + coPos.Y = yTop + Height - 1; + FillConsoleOutputCharacter(0xC4, // '-', + Width - 2, + coPos, + &Written); + + /* draw lower right corner */ + coPos.X = xLeft + Width - 1; + coPos.Y = yTop + Height - 1; + FillConsoleOutputCharacter(0xD9, // '+', + 1, + coPos, + &Written); + + /* Print message text */ + coPos.Y = yTop + 1; + pnext = Text; + while (TRUE) + { + p = strchr(pnext, '\n'); + if (p == NULL) + { + Length = strlen(pnext); + LastLine = TRUE; + } + else + { + Length = (ULONG)(p - pnext); + LastLine = FALSE; + } + + if (Length != 0) + { + coPos.X = xLeft + 2; + WriteConsoleOutputCharacters(pnext, + Length, + coPos); + } + + if (LastLine == TRUE) + break; + + coPos.Y++; + pnext = p + 1; + } + + /* Print separator line and status text */ + if (Status != NULL) + { + coPos.Y = yTop + Height - 3; + coPos.X = xLeft; + FillConsoleOutputCharacter(0xC3, // '+', + 1, + coPos, + &Written); + + coPos.X = xLeft + 1; + FillConsoleOutputCharacter(0xC4, // '-', + Width - 2, + coPos, + &Written); + + coPos.X = xLeft + Width - 1; + FillConsoleOutputCharacter(0xB4, // '+', + 1, + coPos, + &Written); + + coPos.Y++; + coPos.X = xLeft + 2; + WriteConsoleOutputCharacters(Status, + min(strlen(Status), Width - 4), + coPos); + } +} + + /* * Confirm quit setup * RETURNS @@ -97,65 +313,15 @@ PrintString(char* fmt,...) static BOOL ConfirmQuit(PINPUT_RECORD Ir) { - SHORT xScreen; - SHORT yScreen; - SHORT yTop; - SHORT xLeft; BOOL Result = FALSE; - PUSHORT pAttributes = NULL; - PUCHAR pCharacters = NULL; - COORD Pos; - GetScreenSize(&xScreen, &yScreen); - yTop = (yScreen - 10) / 2; - xLeft = (xScreen - 52) / 2; - - /* Save screen */ -#if 0 - Pos.X = 0; - Pos.Y = 0; - pAttributes = (PUSHORT)RtlAllocateHeap(ProcessHeap, - 0, - xScreen * yScreen * sizeof(USHORT)); -CHECKPOINT1; -DPRINT1("pAttributes %p\n", pAttributes); - ReadConsoleOutputAttributes(pAttributes, - xScreen * yScreen, - Pos, - NULL); -CHECKPOINT1; - pCharacters = (PUCHAR)RtlAllocateHeap(ProcessHeap, - 0, - xScreen * yScreen * sizeof(UCHAR)); -CHECKPOINT1; - ReadConsoleOutputCharacters(pCharacters, - xScreen * yScreen, - Pos, - NULL); -CHECKPOINT1; -#endif - - /* Draw popup window */ - SetTextXY(xLeft, yTop, - "+----------------------------------------------------+"); - SetTextXY(xLeft, yTop + 1, - "| ReactOS 0.0.20 is not completely installed on your |"); - SetTextXY(xLeft, yTop + 2, - "| computer. If you quit Setup now, you will need to |"); - SetTextXY(xLeft, yTop + 3, - "| run Setup again to install ReactOS. |"); - SetTextXY(xLeft, yTop + 4, - "| |"); - SetTextXY(xLeft, yTop + 5, - "| * Press ENTER to continue Setup. |"); - SetTextXY(xLeft, yTop + 6, - "| * Press F3 to quit Setup. |"); - SetTextXY(xLeft, yTop + 7, - "+----------------------------------------------------+"); - SetTextXY(xLeft, yTop + 8, - "| F3= Quit ENTER = Continue |"); - SetTextXY(xLeft, yTop + 9, - "+----------------------------------------------------+"); + PopupError("ReactOS is not completely installed on your\n" + "computer. If you quit Setup now, you will need to\n" + "run Setup again to install ReactOS.\n" + "\n" + " * Press ENTER to continue Setup.\n" + " * Press F3 to quit Setup.", + "F3= Quit ENTER = Continue"); while(TRUE) { @@ -174,34 +340,11 @@ CHECKPOINT1; } } - /* Restore screen */ -#if 0 -CHECKPOINT1; - WriteConsoleOutputAttributes(pAttributes, - xScreen * yScreen, - Pos, - NULL); -CHECKPOINT1; - - WriteConsoleOutputCharacters(pCharacters, - xScreen * yScreen, - Pos); -CHECKPOINT1; - - RtlFreeHeap(ProcessHeap, - 0, - pAttributes); - RtlFreeHeap(ProcessHeap, - 0, - pCharacters); -#endif - return(Result); } - /* * Start page * RETURNS @@ -211,6 +354,12 @@ static ULONG StartPage(PINPUT_RECORD Ir) { NTSTATUS Status; + WCHAR FileNameBuffer[MAX_PATH]; + UNICODE_STRING FileName; + + PINICACHESECTION Section; + PWCHAR Value; + SetStatusText(" Please wait..."); @@ -226,12 +375,91 @@ StartPage(PINPUT_RECORD Ir) PrintTextXY(6, 16, "SourceRootPath: '%wZ'", &SourceRootPath); } - /* - * FIXME: Open and load txtsetup.sif here. A pointer (or handle) to the - * ini data should be stored in a global variable. - * The full path to txtsetup.sif is created by appending '\txtsetup.sif' - * to the unicode string SourceRootPath. - */ + + /* Load txtsetup.sif from install media. */ + wcscpy(FileNameBuffer, SourceRootPath.Buffer); + wcscat(FileNameBuffer, L"\\install\\txtsetup.sif"); + RtlInitUnicodeString(&FileName, + FileNameBuffer); + + IniCache = NULL; + Status = IniCacheLoad(&IniCache, + &FileName); + if (!NT_SUCCESS(Status)) + { + PopupError("Setup failed to load the file TXTSETUP.SIF.\n", + "ENTER = Reboot computer"); + + while(TRUE) + { + ConInKey(Ir); + + if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */ + { + return(QUIT_PAGE); + } + } + } + + /* Open 'Version' section */ + Section = IniCacheGetSection(IniCache, + L"Version"); + if (Section == NULL) + { + PopupError("Setup found a corrupt TXTSETUP.SIF.\n", + "ENTER = Reboot computer"); + + while(TRUE) + { + ConInKey(Ir); + + if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */ + { + return(QUIT_PAGE); + } + } + } + + + /* Get pointer 'Signature' key */ + Status = IniCacheGetKey(Section, + L"Signature", + &Value); + if (!NT_SUCCESS(Status)) + { + PopupError("Setup found a corrupt TXTSETUP.SIF.\n", + "ENTER = Reboot computer"); + + while(TRUE) + { + ConInKey(Ir); + + if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */ + { + return(QUIT_PAGE); + } + } + } + + /* Check 'Signature' string */ + if (_wcsicmp(Value, L"$ReactOS$") != 0) + { + PopupError("Setup found an invalid signature in TXTSETUP.SIF.\n", + "ENTER = Reboot computer"); + + while(TRUE) + { + ConInKey(Ir); + + if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */ + { + return(QUIT_PAGE); + } + } + } + +#if 0 + PopupError("This is a test error.", "ENTER = Reboot computer"); SetStatusText(" ENTER = Continue"); @@ -246,6 +474,9 @@ StartPage(PINPUT_RECORD Ir) } return(START_PAGE); +#endif + + return(INTRO_PAGE); } @@ -607,8 +838,8 @@ InstallDirectoryPage(PINPUT_RECORD Ir) SetTextXY(6, 8, "Setup installs ReactOS files onto the selected partition. Choose a"); SetTextXY(6, 9, "directory where you want ReactOS to be installed:"); - strcpy(InstallDir, "\\reactos"); - Length = strlen(InstallDir); + wcscpy(InstallDir, L"\\reactos"); + Length = wcslen(InstallDir); SetInputTextXY(8, 11, 51, InstallDir); @@ -632,6 +863,7 @@ InstallDirectoryPage(PINPUT_RECORD Ir) } else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */ { + return(PREPARE_COPY_PAGE); } else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x08) /* BACKSPACE */ @@ -647,7 +879,7 @@ InstallDirectoryPage(PINPUT_RECORD Ir) { if (Length < 50) { - InstallDir[Length] = Ir->Event.KeyEvent.uChar.AsciiChar; + InstallDir[Length] = (WCHAR)Ir->Event.KeyEvent.uChar.AsciiChar; Length++; InstallDir[Length] = 0; SetInputTextXY(8, 11, 51, InstallDir); @@ -662,24 +894,14 @@ InstallDirectoryPage(PINPUT_RECORD Ir) static ULONG PrepareCopyPage(PINPUT_RECORD Ir) { - OBJECT_ATTRIBUTES ObjectAttributes; - IO_STATUS_BLOCK IoStatusBlock; - CHAR PathBuffer[MAX_PATH]; - UNICODE_STRING PathName; - HANDLE DirectoryHandle; - NTSTATUS Status; - PCHAR End; + WCHAR PathBuffer[MAX_PATH]; + PINICACHESECTION Section; + PINICACHEITERATOR Iterator; + PWCHAR KeyName; + PWCHAR KeyValue; ULONG Length; - ULONG i; + NTSTATUS Status; - PCHAR Dirs[]= { - "System32", - "System32\\Config", - "System32\\Drivers", - "Inf", - "Help", - "Fonts", - NULL}; SetTextXY(6, 8, "Setup prepares your computer for copying the ReactOS files. "); @@ -701,111 +923,133 @@ PrepareCopyPage(PINPUT_RECORD Ir) SetHighlightedTextXY(50, 12, "Done"); + + /* create directories */ SetInvertedTextXY(8, 14, "Create directories"); + /* Open 'Directories' section */ + Section = IniCacheGetSection(IniCache, + L"Directories"); + if (Section == NULL) + { + PopupError("Setup failed to find the 'Directories' section\n" + "in TXTSETUP.SIF.\n", + "ENTER = Reboot computer"); + + while(TRUE) + { + ConInKey(Ir); + + if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */ + { + return(QUIT_PAGE); + } + } + } + /* - * FIXME: Enumerate the ini section 'Directories' and create all "relative" directories + * FIXME: + * Install directories like '\reactos\test' are not handled yet. */ + /* Build full install directory name */ + swprintf(PathBuffer, + L"\\Device\\Harddisk%lu\\Partition%lu", + PartData.DiskNumber, + PartData.PartNumber); + if (InstallDir[0] != L'\\') + wcscat(PathBuffer, L"\\"); + wcscat(PathBuffer, InstallDir); - /* create the systemroot directory */ - sprintf(PathBuffer, - "\\Device\\Harddisk%lu\\Partition%lu", - PartData.DiskNumber, - PartData.PartNumber); - if (InstallDir[0] != '\\') - strcat(PathBuffer, "\\"); - strcat(PathBuffer, InstallDir); - - /* remove trailing backslash */ - Length = strlen(PathBuffer); + /* Remove trailing backslash */ + Length = wcslen(PathBuffer); if ((Length > 0) && (PathBuffer[Length - 1] == '\\')) PathBuffer[Length - 1] = 0; - RtlCreateUnicodeStringFromAsciiz(&PathName, - PathBuffer); + /* Create the install directory */ + Status = CreateDirectory(PathBuffer); + if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION) + { + DPRINT1("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer, Status); - ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES); - ObjectAttributes.RootDirectory = NULL; - ObjectAttributes.ObjectName = &PathName; - ObjectAttributes.Attributes = OBJ_CASE_INSENSITIVE | OBJ_INHERIT; - ObjectAttributes.SecurityDescriptor = NULL; - ObjectAttributes.SecurityQualityOfService = NULL; + PopupError("Setup could not create the install directory.", + "ENTER = Reboot computer"); - Status = NtCreateFile(&DirectoryHandle, - DIRECTORY_ALL_ACCESS, - &ObjectAttributes, - &IoStatusBlock, - NULL, - FILE_ATTRIBUTE_DIRECTORY, - 0, - FILE_CREATE, - FILE_DIRECTORY_FILE, - NULL, - 0); - if (!NT_SUCCESS(Status)) + while(TRUE) { - PrintTextXY(6, 25, "Creating directory failed: Status = 0x%08lx", Status); + ConInKey(Ir); + if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */ + { + return(QUIT_PAGE); + } } - else + } + + + /* Enumerate the directory values and create the subdirectories */ + Iterator = IniCacheFindFirstValue(Section, + &KeyName, + &KeyValue); + if (Iterator != NULL) + { + do { - PrintTextXY(6, 25, "Created directory."); - NtClose (DirectoryHandle); + if (KeyValue[0] == L'\\' && KeyValue[1] != 0) + { + DPRINT("Absolute Path: '%S'\n", KeyValue); + + swprintf(PathBuffer, + L"\\Device\\Harddisk%lu\\Partition%lu", + PartData.DiskNumber, + PartData.PartNumber); + wcscat(PathBuffer, KeyValue); + + DPRINT("FullPath: '%S'\n", PathBuffer); + } + else if (KeyValue[0] != L'\\') + { + DPRINT("RelativePath: '%S'\n", KeyValue); + swprintf(PathBuffer, + L"\\Device\\Harddisk%lu\\Partition%lu", + PartData.DiskNumber, + PartData.PartNumber); + + if (InstallDir[0] != L'\\') + wcscat(PathBuffer, L"\\"); + wcscat(PathBuffer, InstallDir); + wcscat(PathBuffer, L"\\"); + wcscat(PathBuffer, KeyValue); + + DPRINT("FullPath: '%S'\n", PathBuffer); + + Status = CreateDirectory(PathBuffer); + if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION) + { + DPRINT1("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer, Status); + + PopupError("Setup could not create install directories.", + "ENTER = Reboot computer"); + + while(TRUE) + { + ConInKey(Ir); + + if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */ + { + IniCacheFindClose(Iterator); + return(QUIT_PAGE); + } + } + } + } } + while (IniCacheFindNextValue(Iterator, &KeyName, &KeyValue)); - - RtlFreeUnicodeString(&PathName); - - - /* create the subdirectories */ - - /* append backslash and init end pointer */ - strcat(PathBuffer, "\\"); - Length = strlen(PathBuffer); - End = &PathBuffer[Length]; - - for (i = 0; Dirs[i] != NULL; i++) - { - strcpy(End, Dirs[i]); - - - RtlCreateUnicodeStringFromAsciiz(&PathName, - PathBuffer); - - - ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES); - ObjectAttributes.RootDirectory = NULL; - ObjectAttributes.ObjectName = &PathName; - ObjectAttributes.Attributes = OBJ_CASE_INSENSITIVE | OBJ_INHERIT; - ObjectAttributes.SecurityDescriptor = NULL; - ObjectAttributes.SecurityQualityOfService = NULL; - - Status = NtCreateFile(&DirectoryHandle, - DIRECTORY_ALL_ACCESS, - &ObjectAttributes, - &IoStatusBlock, - NULL, - FILE_ATTRIBUTE_DIRECTORY, - 0, - FILE_CREATE, - FILE_DIRECTORY_FILE, - NULL, - 0); - if (!NT_SUCCESS(Status)) - { - PrintTextXY(6, 25, "Creating directory failed: Status = 0x%08lx", Status); - } - else - { - PrintTextXY(6, 25, "Created directory."); - NtClose (DirectoryHandle); - } - - RtlFreeUnicodeString(&PathName); - } + IniCacheFindClose(Iterator); + } SetTextXY(8, 14, "Create directories"); @@ -1066,12 +1310,14 @@ NtProcessStartup(PPEB Peb) 0,0,0,0,0); } + PartDataValid = FALSE; + Page = START_PAGE; while (Page != REBOOT_PAGE) { ClearScreen(); - SetUnderlinedTextXY(4, 3, " ReactOS 0.0.20 Setup "); + SetUnderlinedTextXY(4, 3, " ReactOS " KERNEL_VERSION_STR " Setup "); switch (Page) {