From e611b132f9b8abe35b362e5870b74bce94a1e58e Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 16 May 2020 20:51:50 -0700 Subject: initial commit --- private/ntos/arcinst/almisc.c | 1565 +++++++++++++++++ private/ntos/arcinst/alpha/mk.inc | 16 + private/ntos/arcinst/alpha/sources | 12 + private/ntos/arcinst/arcinst.c | 234 +++ private/ntos/arcinst/arcinst.h | 827 +++++++++ private/ntos/arcinst/fdengine.c | 3394 ++++++++++++++++++++++++++++++++++++ private/ntos/arcinst/fmtexp.c | 942 ++++++++++ private/ntos/arcinst/jzcrap.c | 52 + private/ntos/arcinst/low.c | 1186 +++++++++++++ private/ntos/arcinst/makefile | 1 + private/ntos/arcinst/makefile.inc | 1 + private/ntos/arcinst/memory.c | 1184 +++++++++++++ private/ntos/arcinst/mips/mk.inc | 16 + private/ntos/arcinst/mips/sources | 12 + private/ntos/arcinst/nlsboot.c | 711 ++++++++ private/ntos/arcinst/partit.c | 727 ++++++++ private/ntos/arcinst/precomp.h | 1 + private/ntos/arcinst/sources | 16 + 18 files changed, 10897 insertions(+) create mode 100644 private/ntos/arcinst/almisc.c create mode 100644 private/ntos/arcinst/alpha/mk.inc create mode 100644 private/ntos/arcinst/alpha/sources create mode 100644 private/ntos/arcinst/arcinst.c create mode 100644 private/ntos/arcinst/arcinst.h create mode 100644 private/ntos/arcinst/fdengine.c create mode 100644 private/ntos/arcinst/fmtexp.c create mode 100644 private/ntos/arcinst/jzcrap.c create mode 100644 private/ntos/arcinst/low.c create mode 100644 private/ntos/arcinst/makefile create mode 100644 private/ntos/arcinst/makefile.inc create mode 100644 private/ntos/arcinst/memory.c create mode 100644 private/ntos/arcinst/mips/mk.inc create mode 100644 private/ntos/arcinst/mips/sources create mode 100644 private/ntos/arcinst/nlsboot.c create mode 100644 private/ntos/arcinst/partit.c create mode 100644 private/ntos/arcinst/precomp.h create mode 100644 private/ntos/arcinst/sources (limited to 'private/ntos/arcinst') diff --git a/private/ntos/arcinst/almisc.c b/private/ntos/arcinst/almisc.c new file mode 100644 index 000000000..3ac86b1d7 --- /dev/null +++ b/private/ntos/arcinst/almisc.c @@ -0,0 +1,1565 @@ +#include "precomp.h" +#pragma hdrstop + + +// +// Internal function definitions +// + +ARC_STATUS +AlpFreeComponents( + IN PCHAR *EnvVarComponents + ); + +BOOLEAN +AlpMatchComponent( + IN PCHAR Value1, + IN PCHAR Value2 + ); + +// +// Function implementations +// + + +ARC_STATUS +AlGetEnvVarComponents ( + IN PCHAR EnvValue, + OUT PCHAR **EnvVarComponents, + OUT PULONG PNumComponents + ) + +/*++ + +Routine Description: + + This routine takes an environment variable string and turns it into + the constituent value strings: + + Example EnvValue = "Value1;Value2;Value3" is turned into: + + "Value1", "Value2", "Value3" + + The following are valid value strings: + + 1. " " :one null value is found + 2. ";;;; " :five null values are found + 3. " ;Value1 ; Value2;Value3;;;;;;; ;" :12 value strings are found, + :9 of which are null + + If an invalid component (contains embedded white space) is found in the + string then this routine attempts to resynch to the next value, no error + is returned, and a the first part of the invalid value is returned for the + bad component. + + 1. " Value1;Bad Value2; Value3" : 2 value strings are found + + The value strings returned suppress all whitespace before and after the + value. + + +Arguments: + + EnvValue: ptr to zero terminated environment value string + + EnvVarComponents: ptr to a PCHAR * variable to receive the buffer of + ptrs to the constituent value strings. + + PNumComponents: ptr to a ULONG to receive the number of value strings found + +Return Value: + + The function returns the following error codes: + EACCES if EnvValue is NULL + ENOMEM if the memory allocation fails + + + The function returns the following success codes: + ESUCCESS. + + When the function returns ESUCCESS: + - *PNumComponent field gets the number of value strings found + - if the number is non zero the *EnvVarComponents field gets the + ptr to the buffer containing ptrs to value strings + +--*/ + + +{ + PCHAR pchStart, pchEnd, pchNext; + PCHAR pchComponents[MAX_COMPONENTS + 1]; + ULONG NumComponents, i; + PCHAR pch; + ULONG size; + + // + // Validate the EnvValue + // + if (EnvValue == NULL) { + return (EACCES); + } + + // + // Initialise the ptr array with nulls + // + for (i = 0; i < (MAX_COMPONENTS+1); i++) { + pchComponents[i] = NULL; + } + + // + // Initialise ptrs to search components + // + pchStart = EnvValue; + NumComponents = 0; + + + // + // search till either pchStart reaches the end or till max components + // is reached, the below has been programmed from a dfsa. + // + while (*pchStart && NumComponents < MAX_COMPONENTS) { + + // + // STATE 1: find the beginning of next variable value + // + while (*pchStart!=0 && isspace(*pchStart)) { + pchStart++; + } + + + if (*pchStart == 0) { + break; + } + + // + // STATE 2: In the midst of a value + // + pchEnd = pchStart; + while (*pchEnd!=0 && !isspace(*pchEnd) && *pchEnd!=';') { + pchEnd++; + } + + // + // STATE 3: spit out the value found + // + + size = pchEnd - pchStart; + if ((pch = AlAllocateHeap(size+1)) == NULL) { + AlpFreeComponents(pchComponents); + return (ENOMEM); + } + strncpy (pch, pchStart, size); + pch[size]=0; + pchComponents[NumComponents++]=pch; + + // + // STATE 4: variable value end has been reached, find the beginning + // of the next value + // + if ((pchNext = strchr(pchEnd, ';')) == NULL) { + break; // out of the big while loop because we are done + } + + // + // Advance beyond the semicolon. + // + + pchNext++; + + // + // reinitialise to begin STATE 1 + // + pchStart = pchNext; + + } // end while. + + // + // Get memory to hold an environment pointer and return that + // + + if ( NumComponents!=0 ) { + PCHAR *pch; + + if ((pch = (PCHAR *)AlAllocateHeap((NumComponents+1)*sizeof(PCHAR))) == NULL) { + AlpFreeComponents(pchComponents); + return (ENOMEM); + } + + // + // the last one is NULL because we initialised the array with NULLs + // + + for ( i = 0; i <= NumComponents; i++) { + pch[i] = pchComponents[i]; + } + + + *EnvVarComponents = pch; + } + + // + // Update the number of elements field and return success + // + *PNumComponents = NumComponents; + return (ESUCCESS); +} + + +ARC_STATUS +AlFreeEnvVarComponents ( + IN PCHAR *EnvVarComponents + ) +/*++ + +Routine Description: + + This routine frees up all the components in the ptr array and frees + up the storage for the ptr array itself too + +Arguments: + + EnvVarComponents: the ptr to the PCHAR * Buffer + +Return Value: + + ESUCCESS if freeing successful + EACCES if memory ptr invalid + + + +--*/ + + +{ + ARC_STATUS Status; + + // + // if the pointer is NULL just return success + // + if (EnvVarComponents == NULL) { + return (ESUCCESS); + } + + // + // free all the components first, if error in freeing return + // + Status = AlpFreeComponents(EnvVarComponents); + if (Status != ESUCCESS) { + return Status; + } + + // + // free the component holder too + // + if( AlDeallocateHeap(EnvVarComponents) != NULL) { + return (EACCES); + } + else { + return (ESUCCESS); + } + +} + + +ARC_STATUS +AlpFreeComponents( + IN PCHAR *EnvVarComponents + ) + +/*++ + +Routine Description: + + This routine frees up only the components in the ptr array, but doesn't + free the ptr array storage itself. + +Arguments: + + EnvVarComponents: the ptr to the PCHAR * Buffer + +Return Value: + + ESUCCESS if freeing successful + EACCES if memory ptr invalid + +--*/ + +{ + + // + // get all the components and free them + // + while (*EnvVarComponents != NULL) { + if(AlDeallocateHeap(*EnvVarComponents++) != NULL) { + return(EACCES); + } + } + + return(ESUCCESS); +} + + +BOOLEAN +AlpMatchComponent( + IN PCHAR Value1, + IN PCHAR Value2 + ) + +/*++ + +Routine Description: + + This routine compares two components to see if they are equal. This is + essentially comparing strings except that leading zeros are stripped from + key values. + +Arguments: + + Value1 - Supplies a pointer to the first value to match. + + Value2 - Supplies a pointer to the second value to match. + + +Return Value: + + If the components match, TRUE is returned, otherwise FALSE is returned. + +--*/ + +{ + while ((*Value1 != 0) && (*Value2 != 0)) { + if (tolower(*Value1) != tolower(*Value2)) { + return FALSE; + } + + if (*Value1 == '(') { + do { + *Value1++; + } while (*Value1 == '0'); + } else { + *Value1++; + } + + if (*Value2 == '(') { + do { + *Value2++; + } while (*Value2 == '0'); + } else { + *Value2++; + } + } + + if ((*Value1 == 0) && (*Value2 == 0)) { + return TRUE; + } + + return FALSE; +} + + +BOOLEAN +AlFindNextMatchComponent( + IN PCHAR EnvValue, + IN PCHAR MatchValue, + IN ULONG StartComponent, + OUT PULONG MatchComponent OPTIONAL + ) + +/*++ + +Routine Description: + + This routine compares each component of EnvValue, starting with + StartComponent, until a match is found or there are no more components. + +Arguments: + + EnvValue - Supplies a pointer to the environment variable value. + + MatchValue - Supplies a pointer to the value to match. + + StartComponent - Supplies the component number to start the match. + + MatchComponent - Supplies an optional pointer to a variable to receive + the number of the component that matched. + +Return Value: + + If a match is found, TRUE is returned, otherwise FALSE is returned. + +--*/ + +{ + ARC_STATUS Status; + PCHAR *EnvVarComponents; + ULONG NumComponents; + ULONG Index; + BOOLEAN Match; + + + Status = AlGetEnvVarComponents(EnvValue, &EnvVarComponents, &NumComponents); + + if (Status != ESUCCESS) { + return FALSE; + } + + Match = FALSE; + for (Index = StartComponent ; Index < NumComponents ; Index++ ) { + if (AlpMatchComponent(EnvVarComponents[Index], MatchValue)) { + Match = TRUE; + break; + } + } + + if (ARGUMENT_PRESENT(MatchComponent)) { + *MatchComponent = Index; + } + + AlFreeEnvVarComponents(EnvVarComponents); + return Match; +} + + +ARC_STATUS +AlAddSystemPartition( + IN PCHAR NewSystemPartition + ) + +/*++ + +Routine Description: + + This routine adds a system partition to the SystemPartition environment + variable, and updates the Osloader, OsloadPartition, OsloadFilename, + and OsloadOptions variables. + +Arguments: + + SystemPartition - Supplies a pointer to the pathname of the system + partition to add. + +Return Value: + + If the system partition was successfully added, ESUCCESS is returned, + otherwise an error code is returned. + + BUGBUG - This program is simplistic and doesn't attempt to make sure all + the variables are consistent. It also doesn't fail gracefully. + +--*/ + +{ + ARC_STATUS Status; + PCHAR SystemPartition; + CHAR TempValue[MAXIMUM_ENVIRONMENT_VALUE]; + //PCHAR Osloader; + //PCHAR OsloadPartition; + //PCHAR OsloadFilename; + //PCHAR OsloadOptions; + + // + // Get the system partition environment variable. + // + + SystemPartition = ArcGetEnvironmentVariable("SystemPartition"); + + // + // If the variable doesn't exist, add it and exit. + // + + if (SystemPartition == NULL) { + if(strlen(NewSystemPartition) < MAXIMUM_ENVIRONMENT_VALUE) { + Status = ArcSetEnvironmentVariable("SystemPartition", + NewSystemPartition); + } else { + Status = E2BIG; + } + return Status; + } + + // + // If the variable exists, add the new partition to the end. + // + if(strlen(SystemPartition)+strlen(NewSystemPartition)+2 > MAXIMUM_ENVIRONMENT_VALUE) { + return(E2BIG); + } + + strcpy(TempValue, SystemPartition); + strcat(TempValue, ";"); + strcat(TempValue, NewSystemPartition); + Status = ArcSetEnvironmentVariable("SystemPartition", + TempValue); + + if (Status != ESUCCESS) { + return Status; + } + +#if 0 + // + // Add semicolons to the end of each of the associated variables. + // If they don't exist add them. + // + + // + // Get the Osloader environment variable and add a semicolon to the end. + // + + Osloader = ArcGetEnvironmentVariable("Osloader"); + if (Osloader == NULL) { + *TempValue = 0; + } else { + strcpy(TempValue, Osloader); + } + strcat(TempValue, ";"); + Status = ArcSetEnvironmentVariable("Osloader",TempValue); + + if (Status != ESUCCESS) { + return Status; + } + + // + // Get the OsloadPartition environment variable and add a semicolon to the end. + // + + OsloadPartition = ArcGetEnvironmentVariable("OsloadPartition"); + if (OsloadPartition == NULL) { + *TempValue = 0; + } else { + strcpy(TempValue, OsloadPartition); + } + strcat(TempValue, ";"); + Status = ArcSetEnvironmentVariable("OsloadPartition",TempValue); + + if (Status != ESUCCESS) { + return Status; + } + + // + // Get the OsloadFilename environment variable and add a semicolon to the end. + // + + OsloadFilename = ArcGetEnvironmentVariable("OsloadFilename"); + if (OsloadFilename == NULL) { + *TempValue = 0; + } else { + strcpy(TempValue, OsloadFilename); + } + strcat(TempValue, ";"); + Status = ArcSetEnvironmentVariable("OsloadFilename",TempValue); + + if (Status != ESUCCESS) { + return Status; + } + + // + // Get the OsloadOptions environment variable and add a semicolon to the end. + // + + OsloadOptions = ArcGetEnvironmentVariable("OsloadOptions"); + if (OsloadOptions == NULL) { + *TempValue = 0; + } else { + strcpy(TempValue, OsloadOptions); + } + strcat(TempValue, ";"); + Status = ArcSetEnvironmentVariable("OsloadOptions",TempValue); +#endif + return Status; +} + + +typedef struct _tagMENUITEM { + PCHAR Text; + ULONG AssociatedData; +} MENUITEM,*PMENUITEM; + +typedef struct _tagMENUCOOKIE { + ULONG ItemCount; + PMENUITEM Items; +} MENUCOOKIE,*PMENUCOOKIE; + + +// indent for menus, status, etc. + +char MARGIN[] = " "; +char MSGMARGIN[] = " "; + +// special constants used when fetching keystrokes + +#define KEY_UP 1 +#define KEY_DOWN 2 + + +VOID +MarkLine( + ULONG Line, + BOOLEAN Selected, + PCHAR String + ); + +BOOLEAN +CommonMenuDisplay( + PMENUCOOKIE Menu, + BOOLEAN StaticMenu, + PCHAR Items[], + ULONG ItemCount, + BOOLEAN PrintOnly, + ULONG AssociatedDataOfDefaultChoice, + ULONG *AssociatedDataOfChoice, + PCHAR MenuName, + ULONG Row + ); + +char +GetChar( + VOID + ); + + +BOOLEAN +AlInitializeMenuPackage( + VOID + ) +{ + return(TRUE); +} + + +ULONG +AlGetMenuNumberItems( + PVOID MenuID + ) +{ + return(((PMENUCOOKIE)MenuID)->ItemCount); +} + + +ULONG +AlGetMenuAssociatedData( + PVOID MenuID, + ULONG n + ) +{ + return(((PMENUCOOKIE)MenuID)->Items[n].AssociatedData); +} + +BOOLEAN +AlNewMenu( + PVOID *MenuID + ) +{ + PMENUCOOKIE p; + + if(!(p = AlAllocateHeap(sizeof(MENUCOOKIE)))) { + return(FALSE); + } + p->ItemCount = 0; + p->Items = NULL; + *MenuID = p; + return(TRUE); +} + + +VOID +AlFreeMenu( + PVOID MenuID + ) +{ + PMENUCOOKIE p = MenuID; + ULONG i; + + for(i=0; iItemCount; i++) { + if(p->Items[i].Text != NULL) { + AlDeallocateHeap(p->Items[i].Text); + } + } + if(p->Items) { + AlDeallocateHeap(p->Items); + } + AlDeallocateHeap(p); +} + + +BOOLEAN +AlAddMenuItem( + PVOID MenuID, + PCHAR Text, + ULONG AssociatedData, + ULONG Attributes // unused + ) +{ + PMENUCOOKIE Menu = MenuID; + PMENUITEM p; + + DBG_UNREFERENCED_PARAMETER(Attributes); + + if(!Menu->ItemCount) { + if((Menu->Items = AlAllocateHeap(sizeof(MENUITEM))) == NULL) { + return(FALSE); + } + Menu->ItemCount = 1; + p = Menu->Items; + } else { + if((p = AlReallocateHeap(Menu->Items,sizeof(MENUITEM)*(Menu->ItemCount+1))) == NULL) { + return(FALSE); + } + Menu->Items = p; + p = &Menu->Items[Menu->ItemCount++]; + } + + if((p->Text = AlAllocateHeap(strlen(Text)+1)) == NULL) { + return(FALSE); + } + strcpy(p->Text,Text); + p->AssociatedData = AssociatedData; + return(TRUE); +} + + +BOOLEAN +AlAddMenuItems( + PVOID MenuID, + PCHAR Text[], + ULONG ItemCount + ) +{ + ULONG base,i; + + base = AlGetMenuNumberItems(MenuID); + + for(i=0; iItemCount, + PrintOnly, + AssociatedDataOfDefaultChoice, + AssociatedDataOfChoice, + MenuName, + Row + ) + ); +} + + +BOOLEAN +AlDisplayStaticMenu( + PCHAR Items[], + ULONG ItemCount, + ULONG DefaultChoice, + ULONG Row, + ULONG *IndexOfChoice + ) +{ + return(CommonMenuDisplay(NULL, + TRUE, + Items, + ItemCount, + FALSE, + DefaultChoice, + IndexOfChoice, + NULL, + Row + ) + ); +} + + + +BOOLEAN +CommonMenuDisplay( + PMENUCOOKIE Menu, + BOOLEAN StaticMenu, + PCHAR Items[], + ULONG ItemCount, + BOOLEAN PrintOnly, + ULONG AssociatedDataOfDefaultChoice, + ULONG *AssociatedDataOfChoice, + PCHAR MenuName, + ULONG Row + ) +{ +// ULONG x; + ULONG i,MenuBaseLine,Selection; + char c; + PCHAR String; + + AlSetPosition(Row,0); + AlPrint("%cJ",ASCI_CSI); // clear to end of screen. + MenuBaseLine = Row; + + AlSetScreenColor(7,4); // white on blue + +// if(MenuName) { +// AlPrint("%s%s\r\n%s",MARGIN,MenuName,MARGIN); +// x = strlen(MenuName); +// for(i=0; iItems[i].Text); + } + + if(PrintOnly) { + + char dummy; + AlPrint("\r\nPress any key to continue."); + AlGetString(&dummy,0); + + } else { + +// AlPrint("\r\n%sMake Selection using arrow keys and return,\r\n%sor escape to cancel",MARGIN,MARGIN); + + Selection = 0; + if(StaticMenu) { + Selection = AssociatedDataOfDefaultChoice; + } else { + for(i=0; iItems[i].AssociatedData == AssociatedDataOfDefaultChoice) { + Selection = i; + break; + } + } + } + + String = StaticMenu ? Items[Selection] : Menu->Items[Selection].Text; + MarkLine(MenuBaseLine+Selection,TRUE, String); + + while(((c = GetChar()) != ASCI_ESC) && (c != ASCI_LF) && (c != ASCI_CR)) { + + String = StaticMenu ? Items[Selection] : Menu->Items[Selection].Text; + MarkLine(MenuBaseLine+Selection,FALSE,String); + + if(c == KEY_UP) { + if(!Selection--) { + Selection = ItemCount - 1; + } + } else if(c == KEY_DOWN) { + if(++Selection == ItemCount) { + Selection = 0; + } + } + + String = StaticMenu ? Items[Selection] : Menu->Items[Selection].Text; + MarkLine(MenuBaseLine+Selection,TRUE,String); + } + + // set cursor to a free place on the screen. + AlSetPosition(MenuBaseLine + ItemCount + 4,0); + + if(c == ASCI_ESC) { + return(FALSE); + } + + *AssociatedDataOfChoice = StaticMenu ? Selection : Menu->Items[Selection].AssociatedData; + } + return(TRUE); +} + + + +VOID +MarkLine( + ULONG Line, + BOOLEAN Selected, + PCHAR String + ) +{ + AlSetPosition(Line,sizeof(MARGIN)); + if (Selected) { + AlSetScreenAttributes(1,0,1); // hi intensity, Reverse Video + } + AlPrint("%s\r\n", String); + AlSetScreenAttributes(1,0,0); // hi intensity +} + + + +char +GetChar( + VOID + ) +{ + UCHAR c; + ULONG count; + + ArcRead(ARC_CONSOLE_INPUT,&c,1,&count); + switch(c) { +// case ASCI_ESC: +// ArcRead(ARC_CONSOLE_INPUT,&c,1,&count); +// if(c != '[') { +// break; +// } + case ASCI_CSI: + ArcRead(ARC_CONSOLE_INPUT,&c,1,&count); + switch(c) { + case 'A': + case 'D': + return(KEY_UP); + case 'B': + case 'C': + return(KEY_DOWN); + } + default: + return(c); + } +} + + + +VOID +AlWaitKey( + PCHAR Prompt + ) +{ + char buff[1]; + + AlPrint(MSGMARGIN); + AlPrint(Prompt ? Prompt : "Press any key to continue..."); + AlGetString(buff,0); +} + + +VOID +vAlStatusMsg( + IN ULONG Row, + IN BOOLEAN Error, + IN PCHAR FormatString, + IN va_list ArgumentList + ) +{ + char text[256]; + ULONG Length,Count; + + AlSetPosition(Row,0); + AlPrint(MSGMARGIN); + Length = vsprintf(text,FormatString,ArgumentList); + if(Error) { + AlSetScreenColor(1,4); // red on blue + } else { + AlSetScreenColor(3,4); // yellow on blue + } + AlSetScreenAttributes(1,0,0); // hi intensity + ArcWrite(ARC_CONSOLE_OUTPUT,text,Length,&Count); + AlPrint("\r\n"); + AlSetScreenColor(7,4); // white on blue + AlSetScreenAttributes(1,0,0); // hi intensity +} + + +VOID +AlStatusMsg( + IN ULONG TopRow, + IN ULONG BottomRow, + IN BOOLEAN Error, + IN PCHAR FormatString, + ... + ) +{ + va_list ArgList; + + va_start(ArgList,FormatString); + vAlStatusMsg(TopRow,Error,FormatString,ArgList); + + AlWaitKey(NULL); + AlClearStatusArea(TopRow,BottomRow); +} + + +VOID +AlStatusMsgNoWait( + IN ULONG TopRow, + IN ULONG BottomRow, + IN BOOLEAN Error, + IN PCHAR FormatString, + ... + ) +{ + va_list ArgList; + + AlClearStatusArea(TopRow,BottomRow); + va_start(ArgList,FormatString); + vAlStatusMsg(TopRow,Error,FormatString,ArgList); +} + + +VOID +AlClearStatusArea( + IN ULONG TopRow, + IN ULONG BottomRow + ) +{ + ULONG i; + + for(i=BottomRow; i>=TopRow; --i) { + AlSetPosition(i,0); + AlClearLine(); + } +} + + +ARC_STATUS +AlGetMenuSelection( + + IN PCHAR szTitle, + IN PCHAR *rgszSelections, + IN ULONG crgsz, + IN ULONG crow, + IN ULONG irgszDefault, + OUT PULONG pirgsz, + OUT PCHAR *pszSelection + ) +/*++ + +Routine Description: + + This routine takes an array of strings, turns them into a menu + and gets a selection. If ESC hit then ESUCCESS is returned with + the *pszSelection NULL. + + crgsz is assume to be 1 or greater. + + +Arguments: + + szTitle - Pointer to menu title to pass to AlDisplayMenu + prgszSelection - pointer to an array of strings for menu + crgsz - count of strings + irgszDefault - index in rgszSelection to use as default selection + +Return Value: + + irgsz - index to selection + pszSelection - pointer int rgszSelection for selection. Note that + this is not a dup and should not be freed seperately + then rgszSelections. + + Note: if ARC_STATUS == ESUCCESS and pszSelection == NULL then the + menu was successfully displayed but the user hit ESC to select + nothing from the menu. + +--*/ + + +{ + + PVOID hdMenuId; + + *pszSelection = NULL; + if (!AlNewMenu(&hdMenuId)) { + + return( ENOMEM ); + + } + + // + // BUGBUG for now 1 selection will also build a menu, in the + // future once this is working we should just return that selection + // + + if (!AlAddMenuItems(hdMenuId, rgszSelections, crgsz)) { + + AlFreeMenu(hdMenuId); + return( ENOMEM ); + + } + + if (!AlDisplayMenu(hdMenuId, + FALSE, + irgszDefault, + pirgsz, + crow, + szTitle)) { + + // + // User did not pick a system partition. return NULL + // can caller should abort + // + AlFreeMenu(hdMenuId); + return( ESUCCESS ); + + } + + AlFreeMenu(hdMenuId); + *pszSelection = rgszSelections[*pirgsz]; + return( ESUCCESS ); + +} + +PCHAR +AlStrDup( + + IN PCHAR szString + ) + +/*++ + +Routine Description: + + This routine makes a copy of the passed in string. I do not use + the CRT strdup since it uses malloc. + +Arguments: + + szString - pointer of string to dup. + +Return Value: + + pointer to dup'd string. NULL if could not allocate + +--*/ +{ + + PCHAR szT; + + if (szT = AlAllocateHeap(strlen(szString) + 1)) { + + strcpy(szT, szString); + return(szT); + + } + return( NULL ); + +} + + +PCHAR +AlCombinePaths ( + + IN PCHAR szPath1, + IN PCHAR szPath2 + ) + +/*++ + +Routine Description: + + This routine combines to strings. It allocate a new string + to hold both strings. + +Arguments: + + pointer to combined path. NULL if failed to allocate. + +Return Value: + + +--*/ +{ + + PCHAR szT; + + if (szT = AlAllocateHeap(strlen(szPath1) + strlen(szPath2) + 1)) { + + strcpy(szT, szPath1); + strcat(szT, szPath2); + return( szT ); + + } else { + + return ( NULL ); + + } + +} + +VOID +AlFreeArray ( + + IN BOOLEAN fFreeArray, + IN PCHAR *rgsz, + IN ULONG csz + ) +/*++ + +Routine Description: + + This routine iterates through an array of pointers to strings freeing + each string and finally the array itself. + +Arguments: + + fFreeArray - flag wither to free the array itself. + rgsz - pointer to array of strings. + csz - size of array. + +Return Value: + + +--*/ + +{ + + ULONG irgsz; + + if (!csz) { + + return; + + } + + for( irgsz = 0; irgsz < csz; irgsz++ ) { + + if (rgsz[irgsz]) { + + AlDeallocateHeap(rgsz[irgsz]); + + } else { + + break; + + } + + } + if (fFreeArray) { + AlDeallocateHeap( rgsz ); + } + +} + +ARC_STATUS +AlGetBase ( + IN PCHAR szPath, + OUT PCHAR *pszBase + ) + +/*++ + +Routine Description: + + + This routine strips the filename off a path. + +Arguments: + + szPath - path to strip. + +Return Value: + + pszBaseh - pointer to buffer holding new base. (this is a copy) + +--*/ + +{ + + PCHAR szPathT; + + // + // Make local copy of szArcInstPath so we can alter it + // + *pszBase = AlStrDup(szPath); + if ( *pszBase == NULL ) { + + return( ENOMEM ); + } + + // + // The start of the path part should be either a \ or a ) where + // ) is the end of the arc name + // + if ((szPathT = strrchr(*pszBase,'\\')) == 0) { + if ((szPathT = strrchr(*pszBase, ')')) == 0) { + + AlDeallocateHeap(*pszBase); + return( EBADSYNTAX ); + } + } + + + // + // Cut filename out + // + // szPath points to either ')' or '\' so need to move over that + // onto actual name + // + *(szPathT + 1) = 0; + return( ESUCCESS ); + + +} + +// +// Define static data. +// + + +PCHAR AdapterTypes[AdapterMaximum + 1] = {"eisa","scsi", "multi", NULL}; + +PCHAR ControllerTypes[ControllerMaximum + 1] = {"cdrom", "disk", NULL}; + +PCHAR PeripheralTypes[PeripheralMaximum + 1] = {"rdisk", "fdisk", NULL}; + + + +PCHAR +AlGetNextArcNamToken ( + IN PCHAR TokenString, + OUT PCHAR OutputToken, + OUT PULONG UnitNumber + ) + +/*++ + +Routine Description: + + This routine scans the specified token string for the next token and + unit number. The token format is: + + name[(unit)] + +Arguments: + + TokenString - Supplies a pointer to a zero terminated token string. + + OutputToken - Supplies a pointer to a variable that receives the next + token. + + UnitNumber - Supplies a pointer to a variable that receives the unit + number. + +Return Value: + + If another token exists in the token string, then a pointer to the + start of the next token is returned. Otherwise, a value of NULL is + returned. + +--*/ + +{ + + // + // If there are more characters in the token string, then parse the + // next token. Otherwise, return a value of NULL. + // + + if (*TokenString == '\0') { + return NULL; + + } else { + while ((*TokenString != '\0') && (*TokenString != '(')) { + *OutputToken++ = *TokenString++; + } + + *OutputToken = '\0'; + + // + // If a unit number is specified, then convert it to binary. + // Otherwise, default the unit number to zero. + // + + *UnitNumber = 0; + if (*TokenString == '(') { + TokenString += 1; + while ((*TokenString != '\0') && (*TokenString != ')')) { + *UnitNumber = (*UnitNumber * 10) + (*TokenString++ - '0'); + } + + if (*TokenString == ')') { + TokenString += 1; + } + } + } + + return TokenString; +} + + +ULONG +AlMatchArcNamToken ( + IN PCHAR TokenValue, + IN TOKEN_TYPE TokenType + ) + +/*++ + +Routine Description: + + This routine attempts to match a token with an array of possible + values. + +Arguments: + + TokenValue - Supplies a pointer to a zero terminated token value. + + TokenType - Indicates which type of token we are dealing with + (AdapterType/ControllerType/PeripheralType) + +Return Value: + + If the token type is invalid, INVALID_TOKEN_TYPE is returned. + + If a token match is not located, then a value INVALID_TOKEN_VALUE + is returned. + + If a token match is located, then the ENUM value of the token is + returned. + +--*/ + +{ + + ULONG Index; + PCHAR MatchString; + PCHAR TokenString; + PCHAR *TokenArray; + BOOLEAN Found; + + // + // Depending on token type choose the appropriate token string array + // + switch (TokenType) { + case AdapterType: + TokenArray = AdapterTypes; + break; + + case ControllerType: + TokenArray = ControllerTypes; + break; + + case PeripheralType: + TokenArray = PeripheralTypes; + break; + + default: + return ((ULONG)INVALID_TOKEN_TYPE); + } + + // + // Scan the match array until either a match is found or all of + // the match strings have been scanned. + // + // BUGBUG** The code below can be easily implemented using _strcmpi. + // + + Index = 0; + Found = FALSE; + while (TokenArray[Index] != NULL) { + MatchString = TokenArray[Index]; + TokenString = TokenValue; + while ((*MatchString != '\0') && (*TokenString != '\0')) { + if (toupper(*MatchString) != toupper(*TokenString)) { + break; + } + + MatchString += 1; + TokenString += 1; + } + + if ((*MatchString == '\0') && (*TokenString == '\0')) { + Found = TRUE; + break; + } + + Index += 1; + } + + return (Found ? Index : INVALID_TOKEN_VALUE); +} + +ULONG +AlPrint ( + PCHAR Format, + ... + ) + +{ + + va_list arglist; + UCHAR Buffer[256]; + ULONG Count; + ULONG Length; + + // + // Format the output into a buffer and then print it. + // + + va_start(arglist, Format); + Length = vsprintf(Buffer, Format, arglist); + ArcWrite( ARC_CONSOLE_OUTPUT, Buffer, Length, &Count); + va_end(arglist); + return 0; +} + + +BOOLEAN +AlGetString( + OUT PCHAR String, + IN ULONG StringLength + ) + +/*++ + +Routine Description: + + This routine reads a string from standardin until a + carriage return or escape is found or StringLength is reached. + +Arguments: + + String - Supplies a pointer to where the string will be stored. + + StringLength - Supplies the Max Length to read. + +Return Value: + + FALSE if user pressed esc, TRUE otherwise. + +--*/ + +{ + CHAR c; + ULONG Count; + PCHAR Buffer; + + Buffer = String; + while (ArcRead(ARC_CONSOLE_INPUT,&c,1,&Count)==ESUCCESS) { + if(c == ASCI_ESC) { + return(FALSE); + } + if ((c=='\r') || (c=='\n') || ((ULONG)(Buffer-String) == StringLength)) { + *Buffer='\0'; + ArcWrite(ARC_CONSOLE_OUTPUT,"\r\n",2,&Count); + return(TRUE); + } + // + // Check for backspace; + // + if (c=='\b') { + if (((ULONG)Buffer > (ULONG)String)) { + Buffer--; + ArcWrite(ARC_CONSOLE_OUTPUT,"\b \b",3,&Count); + } + } else { + // + // If it's a printable char store it and display it. + // + if (isprint(c)) { + *Buffer++ = c; + ArcWrite(ARC_CONSOLE_OUTPUT,&c,1,&Count); + } + } + } +} diff --git a/private/ntos/arcinst/alpha/mk.inc b/private/ntos/arcinst/alpha/mk.inc new file mode 100644 index 000000000..f85c9a0ea --- /dev/null +++ b/private/ntos/arcinst/alpha/mk.inc @@ -0,0 +1,16 @@ +obj\alpha\arcinst.exe: obj\alpha\arcinst.lib makefile.inc + link -out:obj\alpha\arcinst.exe @<< +-machine:alpha +-align:0x100 +-rom +-fixed +-map:obj\alpha\arcinst.map +-debug:notmapped +-debugtype:coff +-ignore:4001 +-base:0x80600000,0x80614000 +-entry:main +obj\alpha\arcinst.lib +\nt\public\sdk\lib\alpha\libcntpr.lib +< +#include +#include +#include +#include +#include +#include +#include +#include + +// +// Define special character values. +// +#define ASCI_NUL 0x00 +#define ASCI_BEL 0x07 +#define ASCI_BS 0x08 +#define ASCI_HT 0x09 +#define ASCI_LF 0x0A +#define ASCI_VT 0x0B +#define ASCI_FF 0x0C +#define ASCI_CR 0x0D +#define ASCI_CSI 0x9B +#define ASCI_ESC 0x1B +#define ASCI_SYSRQ 0x80 + +// +// Locally defined error codes +// +#define EBADSYNTAX EMAXIMUM + +#define MAX_COMPONENTS 20 + +ARC_STATUS +AlGetEnvVarComponents ( + IN PCHAR EnvValue, + OUT PCHAR **EnvVarComponents, + OUT PULONG PNumComponents + ); + +ARC_STATUS +AlFreeEnvVarComponents ( + IN PCHAR *EnvVarComponents + ); + +BOOLEAN +AlFindNextMatchComponent( + IN PCHAR EnvValue, + IN PCHAR MatchValue, + IN ULONG StartComponent, + OUT PULONG MatchComponent OPTIONAL + ); + +ARC_STATUS +AlAddSystemPartition( + IN PCHAR NewSystemPartition + ); + +ARC_STATUS +AlMemoryInitialize ( + ULONG StackPages, + ULONG HeapPages + ); + +PVOID +AlAllocateHeap ( + IN ULONG Size + ); + +PVOID +AlDeallocateHeap ( + IN PVOID HeapAddress + ); + +PVOID +AlReallocateHeap ( + IN PVOID HeapAddress, + IN ULONG NewSize + ); + +BOOLEAN +AlValidateHeap( + IN BOOLEAN DumpHeap + ); + +BOOLEAN +AlInitializeMenuPackage( + VOID + ); + +BOOLEAN +AlNewMenu( + PVOID *MenuID + ); + +VOID +AlFreeMenu( + PVOID MenuID + ); + +BOOLEAN // fails if OOM +AlAddMenuItem( + PVOID MenuID, + PCHAR Text, + ULONG AssociatedData, + ULONG Attributes // currently unused + ); + +BOOLEAN // fails if OOM +AlAddMenuItems( + PVOID MenuID, + PCHAR Text[], // NOTE: associated data for each item is its + ULONG ItemCount // index in the array. + ); + +BOOLEAN // FALSE if user escaped +AlDisplayMenu( + PVOID MenuID, + BOOLEAN PrintOnly, + ULONG AssociatedDataOfDefaultChoice, + ULONG *AssociatedDataOfChoice, + ULONG Row, + PCHAR MenuName // may be NULL + ); + +ULONG +AlGetMenuNumberItems( + PVOID MenuID + ); + +ULONG +AlGetMenuAssociatedData( + PVOID MenuID, + ULONG n + ); + +ARC_STATUS +AlGetMenuSelection( + IN PCHAR szTitle, + IN PCHAR *rgszSelections, + IN ULONG crgsz, + IN ULONG crow, + IN ULONG irgszDefault, + OUT PULONG pirgsz, + OUT PCHAR *pszSelection + ); + +VOID +AlWaitKey( + PCHAR Prompt // uses default if NULL + ); + +VOID +vAlStatusMsg( + IN ULONG Row, + IN BOOLEAN Error, + IN PCHAR FormatString, + IN va_list ArgumentList + ); + +VOID +AlStatusMsg( + IN ULONG TopRow, + IN ULONG BottomRow, + IN BOOLEAN Error, + IN PCHAR FormatString, + ... + ); + +VOID +AlStatusMsgNoWait( + IN ULONG TopRow, + IN ULONG BottomRow, + IN BOOLEAN Error, + IN PCHAR FormatString, + ... + ); + +VOID +AlClearStatusArea( + IN ULONG TopRow, + IN ULONG BottomRow + ); + +PCHAR +AlStrDup( + IN PCHAR szString + ); + +PCHAR +AlCombinePaths ( + IN PCHAR szPath1, + IN PCHAR szPath2 + ); + +VOID +AlFreeArray ( + IN BOOLEAN fFreeArray, + IN PCHAR *rgsz, + IN ULONG csz + ); + +ARC_STATUS +AlGetBase ( + IN PCHAR szPath, + OUT PCHAR *pszBase + ); + +// +// Define types of adapters that can be booted from. +// +typedef enum _ADAPTER_TYPES { + AdapterEisa, + AdapterScsi, + AdapterMulti, + AdapterMaximum +} ADAPTER_TYPES; + +// +// Define type of controllers that can be booted from. +// +typedef enum _CONTROLLER_TYPES { + ControllerDisk, + ControllerCdrom, + ControllerMaximum +} CONTROLLER_TYPES; + +// +// Define type of peripheral that can be booted from. +// +typedef enum _PERIPHERAL_TYPES { + PeripheralRigidDisk, + PeripheralFloppyDisk, + PeripheralMaximum +} PERIPHERAL_TYPES; + +// +// Define type of token we are referring to +// +typedef enum _TOKEN_TYPES { + AdaptType, + ControllerType, + PeripheralType +} TOKEN_TYPES; + +// +// Define error codes +// +#define INVALID_TOKEN_TYPE ~0L +#define INVALID_TOKEN_VALUE ~1L + +// +// token string is searched for next name(unit) +// +PCHAR +AlGetNextArcNameToken ( + IN PCHAR TokenString, + OUT PCHAR OutputToken, + OUT PULONG UnitNumber + ); + +// +// If invalid tokentype or tokenvalue passed in the error codes defined +// above are returned, else the enumeration of the token type is returned +// +ULONG +AlMatchArcNameToken ( + IN PCHAR TokenValue, + IN TOKEN_TYPES TokenType + ); + +ARC_STATUS +FdiskInitialize( + VOID + ); + +VOID +FdiskCleanUp( + VOID + ); + +VOID +ConfigureSystemPartitions( + VOID + ); + +VOID +ConfigureOSPartitions( + VOID + ); + +ULONG +AlPrint ( + PCHAR Format, + ... + ); + +extern char MSGMARGIN[]; + +#define AlClearScreen() \ + AlPrint("%c2J", ASCI_CSI) + +#define AlClearLine() \ + AlPrint("%c2K", ASCI_CSI) + +#define AlSetScreenColor(FgColor, BgColor) \ + AlPrint("%c3%dm", ASCI_CSI, (UCHAR)FgColor); \ + AlPrint("%c4%dm", ASCI_CSI, (UCHAR)BgColor) + +#define AlSetScreenAttributes( HighIntensity, Underscored, ReverseVideo ) \ + AlPrint("%c0m", ASCI_CSI); \ + if (HighIntensity) { \ + AlPrint("%c1m", ASCI_CSI); \ + } \ + if (Underscored) { \ + AlPrint("%c4m", ASCI_CSI); \ + } \ + if (ReverseVideo) { \ + AlPrint("%c7m", ASCI_CSI); \ + } + +#define AlSetPosition( Row, Column ) \ + AlPrint("%c%d;%dH", ASCI_CSI, Row, Column) + +BOOLEAN // false if user escaped. +AlGetString( + OUT PCHAR String, + IN ULONG StringLength + ); + +#define AllocateMemory(size) AlAllocateHeap(size) +#define ReallocateMemory(block,size) AlReallocateHeap(block,size) +#define FreeMemory(block) AlDeallocateHeap(block) + +#define OK_STATUS ESUCCESS +#define RETURN_OUT_OF_MEMORY return(ENOMEM) + +#define LOWPART(x) ((x).LowPart) + +#define ONE_MEG (1024*1024) + +ULONG +SIZEMB( + IN LARGE_INTEGER ByteCount + ); + +#define ENTRIES_PER_BOOTSECTOR 4 + +/* + This structure is used to hold the information returned by the + get drive geometry call. +*/ +typedef struct _tagDISKGEOM { + LARGE_INTEGER Cylinders; + ULONG Heads; + ULONG SectorsPerTrack; + ULONG BytesPerSector; + // These two are not part of drive geometry info, but calculated from it. + ULONG BytesPerCylinder; + ULONG BytesPerTrack; +} DISKGEOM,*PDISKGEOM; + + +/* + These structures are used in doubly-linked per disk lists that + describe the layout of the disk. + + Free spaces are indicated by entries with a SysID of 0 (note that + these entries don't actually appear anywhere on-disk!) + + The partition number is the number the system will assign to + the partition in naming it. For free spaces, this is the number + that the system WOULD assign to it if it was a partition. + The number is good only for one transaction (create or delete), + after which partitions must be renumbered. + +*/ + +typedef struct _tagPARTITION { + struct _tagPARTITION *Next; + struct _tagPARTITION *Prev; + LARGE_INTEGER Offset; + LARGE_INTEGER Length; + ULONG Disk; + ULONG OriginalPartitionNumber; + ULONG PartitionNumber; + ULONG PersistentData; + BOOLEAN Update; + BOOLEAN Active; + BOOLEAN Recognized; + UCHAR SysID; +} PARTITION,*PPARTITION; + +typedef struct _tagREGION_DATA { + PPARTITION Partition; + LARGE_INTEGER AlignedRegionOffset; + LARGE_INTEGER AlignedRegionSize; +} REGION_DATA,*PREGION_DATA; + + +#if DBG + +#define ASRT(x) if(!(x)) { char c; ULONG n; \ + AlPrint("\r\nAssertion failure in %s, line %u\r\n",__FILE__,__LINE__);\ + AlPrint("Press return to exit\r\n"); \ + ArcRead(ARC_CONSOLE_INPUT,&c,1,&n); \ + ArcEnterInteractiveMode(); \ + } + +#else + +#define ASRT(x) + +#endif + +ARC_STATUS +FmtIsFatPartition( + IN ULONG PartitionId, + IN ULONG SectorSize, + OUT PBOOLEAN IsFatPartition + ); + +ARC_STATUS +FmtIsFat( + IN PCHAR PartitionPath, + OUT PBOOLEAN IsFatPartition + ); + +ARC_STATUS +FmtFatFormat( + IN PCHAR PartitionPath, + IN ULONG HiddenSectorCount + ); + +ARC_STATUS +FmtQueryFatPartitionList( + OUT PCHAR** FatPartitionList, + OUT PULONG ListLength + ); + +ARC_STATUS +FmtFreeFatPartitionList( + IN OUT PCHAR* FatPartitionList, + IN ULONG ListLength + ); + +ARC_STATUS +LowOpenDisk( + IN PCHAR DevicePath, + OUT PULONG DiskId + ); + +ARC_STATUS +LowCloseDisk( + IN ULONG DiskId + ); + +ARC_STATUS +LowGetDriveGeometry( + IN PCHAR DevicePath, + OUT PULONG TotalSectorCount, + OUT PULONG SectorSize, + OUT PULONG SectorsPerTrack, + OUT PULONG Heads + ); + +ARC_STATUS +LowGetPartitionGeometry( + IN PCHAR PartitionPath, + OUT PULONG TotalSectorCount, + OUT PULONG SectorSize, + OUT PULONG SectorsPerTrack, + OUT PULONG Heads + ); + +ARC_STATUS +LowReadSectors( + IN ULONG VolumeId, + IN ULONG SectorSize, + IN ULONG StartingSector, + IN ULONG NumberOfSectors, + OUT PVOID Buffer + ); + +ARC_STATUS +LowWriteSectors( + IN ULONG VolumeId, + IN ULONG SectorSize, + IN ULONG StartingSector, + IN ULONG NumberOfSectors, + IN PVOID Buffer + ); + +ARC_STATUS +LowQueryPathFromComponent( + IN PCONFIGURATION_COMPONENT Component, + OUT PCHAR* Path + ); + +ARC_STATUS +LowQueryComponentList( + IN CONFIGURATION_CLASS* ConfigClass OPTIONAL, + IN CONFIGURATION_TYPE* ConfigType OPTIONAL, + OUT PCONFIGURATION_COMPONENT** ComponentList, + OUT PULONG ListLength + ); + +ARC_STATUS +LowQueryPathList( + IN CONFIGURATION_CLASS* ConfigClass OPTIONAL, + IN CONFIGURATION_TYPE* ConfigType OPTIONAL, + OUT PCHAR** PathList, + OUT PULONG ListLength + ); + +ARC_STATUS +LowFreePathList( + IN PCHAR* PathList, + IN ULONG ListLength + ); + +ARC_STATUS +LowQueryFdiskPathList( + OUT PCHAR** PathList, + OUT PULONG ListLength + ); + +ARC_STATUS +LowFreeFdiskPathList( + IN OUT PCHAR* PathList, + IN ULONG ListLength + ); + +ARC_STATUS +LowGetDiskLayout( + IN PCHAR Path, + OUT PDRIVE_LAYOUT_INFORMATION *DriveLayout + ); + +ARC_STATUS +LowSetDiskLayout( + IN PCHAR Path, + IN PDRIVE_LAYOUT_INFORMATION DriveLayout + ); + +typedef enum { REGION_PRIMARY, + REGION_EXTENDED, + REGION_LOGICAL + } REGION_TYPE; + +enum { + SYSID_UNUSED = 0, + SYSID_EXTENDED = 5, + SYSID_BIGFAT = 6, + SYSID_IFS = 7 + }; + +typedef struct _tagREGION_DESCRIPTOR { + ULONG PersistentData; + ULONG Disk; + ULONG SizeMB; + ULONG PartitionNumber; + ULONG OriginalPartitionNumber; + REGION_TYPE RegionType; + BOOLEAN Active; + BOOLEAN Recognized; + UCHAR SysID; + PVOID Reserved; +} REGION_DESCRIPTOR,*PREGION_DESCRIPTOR; + +ULONG +GetDiskCount( + VOID + ); + +PCHAR +GetDiskName( + ULONG Disk + ); + +ULONG +DiskSizeMB( + IN ULONG Disk + ); + +ARC_STATUS +GetDiskRegions( + IN ULONG Disk, + IN BOOLEAN WantUsedRegions, + IN BOOLEAN WantFreeRegions, + IN BOOLEAN WantPrimaryRegions, + IN BOOLEAN WantLogicalRegions, + OUT PREGION_DESCRIPTOR *Region, + OUT ULONG *RegionCount + ); + +#define GetAllDiskRegions(disk,regions,count) \ + GetDiskRegions(disk,TRUE,TRUE,TRUE,TRUE,regions,count) + +#define GetFreeDiskRegions(disk,regions,count) \ + GetDiskRegions(disk,FALSE,TRUE,TRUE,TRUE,regions,count) + +#define GetUsedDiskRegions(disk,regions,count) \ + GetDiskRegions(disk,TRUE,FALSE,TRUE,TRUE,regions,count) + +#define GetPrimaryDiskRegions(disk,regions,count) \ + GetDiskRegions(disk,TRUE,TRUE,TRUE,FALSE,regions,count) + +#define GetLogicalDiskRegions(disk,regions,count) \ + GetDiskRegions(disk,TRUE,TRUE,FALSE,TRUE,regions,count) + +#define GetUsedPrimaryDiskRegions(disk,regions,count) \ + GetDiskRegions(disk,TRUE,FALSE,TRUE,FALSE,regions,count) + +#define GetUsedLogicalDiskRegions(disk,regions,count) \ + GetDiskRegions(disk,TRUE,FALSE,FALSE,TRUE,regions,count) + +#define GetFreePrimaryDiskRegions(disk,regions,count) \ + GetDiskRegions(disk,FALSE,TRUE,TRUE,FALSE,regions,count) + +#define GetFreeLogicalDiskRegions(disk,regions,count) \ + GetDiskRegions(disk,FALSE,TRUE,FALSE,TRUE,regions,count) + +VOID +FreeRegionArray( + IN PREGION_DESCRIPTOR Region, + IN ULONG RegionCount + ); + +ARC_STATUS +IsAnyCreationAllowed( + IN ULONG Disk, + IN BOOLEAN AllowMultiplePrimaries, + OUT PBOOLEAN AnyAllowed, + OUT PBOOLEAN PrimaryAllowed, + OUT PBOOLEAN ExtendedAllowed, + OUT PBOOLEAN LogicalAllowed + ); + +ARC_STATUS +IsCreationOfPrimaryAllowed( + IN ULONG Disk, + IN BOOLEAN AllowMultiplePrimaries, + OUT PBOOLEAN Allowed + ); + +ARC_STATUS +IsCreationOfExtendedAllowed( + IN ULONG Disk, + OUT PBOOLEAN Allowed + ); + +ARC_STATUS +IsCreationOfLogicalAllowed( + IN ULONG Disk, + OUT PBOOLEAN Allowed + ); + +ARC_STATUS +DoesAnyPartitionExist( + IN ULONG Disk, + OUT PBOOLEAN AnyExists, + OUT PBOOLEAN PrimaryExists, + OUT PBOOLEAN ExtendedExists, + OUT PBOOLEAN LogicalExists + ); + +ARC_STATUS +DoesAnyPrimaryExist( + IN ULONG Disk, + OUT PBOOLEAN Exists + ); + +ARC_STATUS +DoesExtendedExist( + IN ULONG Disk, + OUT PBOOLEAN Exists + ); + +ARC_STATUS +DoesAnyLogicalExist( + IN ULONG Disk, + OUT PBOOLEAN Exists + ); + +BOOLEAN +IsExtended( + IN UCHAR SysID + ); + +VOID +SetPartitionActiveFlag( + IN PREGION_DESCRIPTOR Region, + IN UCHAR value + ); + +ARC_STATUS +CreatePartition( + IN PREGION_DESCRIPTOR Region, + IN ULONG CreationSizeMB, + IN REGION_TYPE Type + ); + +ARC_STATUS +CreatePartitionEx( + IN PREGION_DESCRIPTOR Region, + IN LARGE_INTEGER MinimumSize, + IN ULONG CreationSizeMB, + IN REGION_TYPE Type, + IN UCHAR SysId + ); + +ARC_STATUS +DeletePartition( + IN PREGION_DESCRIPTOR Region + ); + +ULONG +GetHiddenSectorCount( + ULONG Disk, + ULONG Partition + ); + +VOID +SetSysID( + IN ULONG Disk, + IN ULONG Partition, + IN UCHAR SysID + ); + +VOID +SetSysID2( + IN PREGION_DESCRIPTOR Region, + IN UCHAR SysID + ); + +PCHAR +GetSysIDName( + UCHAR SysID + ); + +ARC_STATUS +CommitPartitionChanges( + IN ULONG Disk + ); + +BOOLEAN +HavePartitionsBeenChanged( + IN ULONG Disk + ); + +VOID +FdMarkDiskDirty( + IN ULONG Disk + ); + +VOID +FdSetPersistentData( + IN PREGION_DESCRIPTOR Region, + IN ULONG Data + ); + +ULONG +FdGetMinimumSizeMB( + IN ULONG Disk + ); + +ULONG +FdGetMaximumSizeMB( + IN PREGION_DESCRIPTOR Region, + IN REGION_TYPE CreationType + ); + +LARGE_INTEGER +FdGetExactSize( + IN PREGION_DESCRIPTOR Region, + IN BOOLEAN ForExtended + ); + +LARGE_INTEGER +FdGetExactOffset( + IN PREGION_DESCRIPTOR Region + ); + +BOOLEAN +FdCrosses1024Cylinder( + IN PREGION_DESCRIPTOR Region, + IN ULONG CreationSizeMB, + IN REGION_TYPE RegionType + ); + +ULONG +FdGetDiskSignature( + IN ULONG Disk + ); + +VOID +FdSetDiskSignature( + IN ULONG Disk, + IN ULONG Signature + ); + +BOOLEAN +IsDiskOffLine( + IN ULONG Disk + ); + + + +typedef enum _BOOT_VARIABLES { + LoadIdentifierVariable, + SystemPartitionVariable, + OsLoaderVariable, + OsLoadPartitionVariable, + OsLoadFilenameVariable, + OsLoadOptionsVariable, + MaximumBootVariable +} BOOT_VARIABLE; + +extern PCHAR BootString[]; + +VOID +JzDeleteVariableSegment ( + PCHAR VariableName, + ULONG Selection + ); + +#define MAXIMUM_ENVIRONMENT_VALUE 256 diff --git a/private/ntos/arcinst/fdengine.c b/private/ntos/arcinst/fdengine.c new file mode 100644 index 000000000..7644f222f --- /dev/null +++ b/private/ntos/arcinst/fdengine.c @@ -0,0 +1,3394 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + fdengine.c + +Abstract: + + This module contains the disk partitioning engine. The code + in this module can be compiled for either the NT platform + or the ARC platform (-DARC). + +Author: + + Ted Miller (tedm) Nov-1991 + +Revision History: + +--*/ + +#include "precomp.h" +#pragma hdrstop + +#define ARCDBG + +// Attached disk devices. + +ULONG CountOfDisks; +PCHAR *DiskNames; + +// Information about attached disks. + +DISKGEOM *DiskGeometryArray; + +PPARTITION *PrimaryPartitions, + *LogicalVolumes; + +// +// Array keeping track of whether each disk is off line. +// +PBOOLEAN OffLine; + +// Keeps track of whether changes have been made +// to each disk's partition structure. + +BOOLEAN *ChangesMade; + + +// +// Value used to indicate that the partition entry has changed but in a non- +// destructive way (ie, made active/inactive). +// +#define CHANGED_DONT_ZAP ((BOOLEAN)(5)) + +// forward declarations + + +ARC_STATUS +OpenDisks( + VOID + ); + +VOID +CloseDisks( + VOID + ); + +ARC_STATUS +GetGeometry( + VOID + ); + +BOOLEAN +CheckIfDiskIsOffLine( + IN ULONG Disk + ); + +ARC_STATUS +InitializePartitionLists( + VOID + ); + +ARC_STATUS +GetRegions( + IN ULONG Disk, + IN PPARTITION p, + IN BOOLEAN WantUsedRegions, + IN BOOLEAN WantFreeRegions, + IN BOOLEAN WantLogicalRegions, + OUT PREGION_DESCRIPTOR *Region, + OUT ULONG *RegionCount, + IN REGION_TYPE RegionType + ); + +BOOLEAN +AddRegionEntry( + IN OUT PREGION_DESCRIPTOR *Regions, + IN OUT ULONG *RegionCount, + IN ULONG SizeMB, + IN REGION_TYPE RegionType, + IN PPARTITION Partition, + IN LARGE_INTEGER AlignedRegionOffset, + IN LARGE_INTEGER AlignedRegionSize + ); + +VOID +AddPartitionToLinkedList( + IN PARTITION **Head, + IN PARTITION *p + ); + +BOOLEAN +IsInLinkedList( + IN PPARTITION p, + IN PPARTITION List + ); + +BOOLEAN +IsInLogicalList( + IN ULONG Disk, + IN PPARTITION p + ); + +BOOLEAN +IsInPartitionList( + IN ULONG Disk, + IN PPARTITION p + ); + +LARGE_INTEGER +AlignTowardsDiskStart( + IN ULONG Disk, + IN LARGE_INTEGER Offset + ); + +LARGE_INTEGER +AlignTowardsDiskEnd( + IN ULONG Disk, + IN LARGE_INTEGER Offset + ); + +VOID +FreeLinkedPartitionList( + IN PARTITION **q + ); + +VOID +MergeFreePartitions( + IN PPARTITION p + ); + +VOID +RenumberPartitions( + ULONG Disk + ); + +VOID +FreePartitionInfoLinkedLists( + IN PARTITION **ListHeadArray + ); + +LARGE_INTEGER +DiskLengthBytes( + IN ULONG Disk + ); + +PPARTITION +AllocatePartitionStructure( + IN ULONG Disk, + IN LARGE_INTEGER Offset, + IN LARGE_INTEGER Length, + IN UCHAR SysID, + IN BOOLEAN Update, + IN BOOLEAN Active, + IN BOOLEAN Recognized + ); + + + +ARC_STATUS +FdiskInitialize( + VOID + ) + +/*++ + +Routine Description: + + This routine initializes the partitioning engine, including allocating + arrays, determining attached disk devices, and reading their + partition tables. + +Arguments: + + None. + +Return Value: + + OK_STATUS or error code. + +--*/ + +{ + ARC_STATUS status; + ULONG i; + + + if((status = LowQueryFdiskPathList(&DiskNames,&CountOfDisks)) != OK_STATUS) { + return(status); + } + +#if 0 +#ifdef ARCDBG + AlPrint("Disk count = %u\r\n",CountOfDisks); + for(i=0; iReserved)->Partition; + + if((UCHAR)p->Active != value) { + + // + // Unfortuneately, the Update flag becomes the RewritePartition flag + // at commit time. This causes us to zap the boot sector. To avoid + // this, we use a spacial non-boolean value that can be checked for + // at commit time and that will cause us NOT to zap the bootsector + // even though RewritePartition will be TRUE. + // + + p->Active = value; + if(!p->Update) { + p->Update = CHANGED_DONT_ZAP; + } + ChangesMade[p->Disk] = TRUE; + } +} +#endif + + +VOID +DetermineCreateSizeAndOffset( + IN PREGION_DESCRIPTOR Region, + IN LARGE_INTEGER MinimumSize, + IN ULONG CreationSizeMB, + IN REGION_TYPE Type, + OUT PLARGE_INTEGER CreationStart, + OUT PLARGE_INTEGER CreationSize + ) + +/*++ + +Routine Description: + + Determine the actual offset and size of the partition, given the + size in megabytes. + +Arguments: + + Region - a region descriptor returned by GetDiskRegions(). Must + be an unused region. + + MinimumSize - if non-0, this is the minimum size that the partition + or logical drive can be. + + CreationSizeMB - If MinimumSize is 0, size of partition to create, in MB. + + Type - REGION_PRIMARY, REGION_EXTENDED, or REGION_LOGICAL, for + creating a primary partition, extended partition, or + logical volume, respectively. + + CreationStart - receives the offset where the partition should be placed. + + CreationSize - receives the exact size for the partition. + +Return Value: + + None. + +--*/ + +{ + PREGION_DATA CreateData = Region->Reserved; + LARGE_INTEGER CSize,CStart; + LARGE_INTEGER Mod; + ULONG bpc = DiskGeometryArray[Region->Disk].BytesPerCylinder; + ULONG bpt = DiskGeometryArray[Region->Disk].BytesPerTrack; + + ASRT(Region->SysID == SYSID_UNUSED); + + // + // If we are creating a partition at offset 0, adjust the aligned region + // offset and the aligned region size, because no partition can actually + // start at offset 0. + // + + if(CreateData->AlignedRegionOffset.QuadPart == 0) { + + LARGE_INTEGER Delta; + + if(Type == REGION_EXTENDED) { + + Delta.QuadPart = bpc; + + } else { + + ASRT(Type == REGION_PRIMARY); + Delta.QuadPart = bpt; + } + + CreateData->AlignedRegionOffset = Delta; + CreateData->AlignedRegionSize.QuadPart = (CreateData->AlignedRegionSize.QuadPart - Delta.QuadPart); + } + + CStart = CreateData->AlignedRegionOffset; + if(MinimumSize.QuadPart == 0) { + CSize.QuadPart = UInt32x32To64(CreationSizeMB,ONE_MEG); + } else { + CSize = MinimumSize; + if(Type == REGION_LOGICAL) { + CSize.QuadPart = CSize.QuadPart + bpt; + } + } + + // + // Decide whether to align the ending cylinder up or down. + // If the offset of end of the partition is more than half way into the + // final cylinder, align towrds the disk end. Otherwise align toward + // the disk start. + // + + Mod.QuadPart = (CStart.QuadPart + CSize.QuadPart) % bpc; + + if(Mod.QuadPart != 0) { + + if((MinimumSize.QuadPart != 0) || (Mod.QuadPart > bpc/2)) { + CSize.QuadPart = (CSize.QuadPart + (bpc - Mod.QuadPart)); + } else { + CSize.QuadPart = (CSize.QuadPart - Mod.QuadPart); // snap downwards tp cyl boundary + } + } + + if(CSize.QuadPart > CreateData->AlignedRegionSize.QuadPart) { + + // + // Space available in the free space isn't large enough to accomodate + // the request in its entirety; just use the entire free space. + // + + CSize = CreateData->AlignedRegionSize; + } + + ASRT(CStart.QuadPart != 0); + ASRT(CSize.QuadPart != 0); + + *CreationStart = CStart; + *CreationSize = CSize; +} + + +ARC_STATUS +CreatePartitionEx( + IN PREGION_DESCRIPTOR Region, + IN LARGE_INTEGER MinimumSize, + IN ULONG CreationSizeMB, + IN REGION_TYPE Type, + IN UCHAR SysId + ) + +/*++ + +Routine Description: + + This routine creates a partition from a free region on the disk. The + partition is always created at the beginning of the free space, and any + left over space at the end is kept on the free space list. + +Arguments: + + Region - a region descriptor returned by GetDiskRegions(). Must + be an unused region. + + CreationSizeMB - size of partition to create, in MB. + + Type - REGION_PRIMARY, REGION_EXTENDED, or REGION_LOGICAL, for + creating a primary partition, extended pasrtition, or + logical volume, respectively. + + SysId - system ID byte to be assigned to the partition + +Return Value: + + OK_STATUS or error code. + +--*/ + +{ + PPARTITION p1,p2,p3; + PREGION_DATA CreateData = Region->Reserved; + LARGE_INTEGER CreationStart,CreationSize,LeftOver; + PPARTITION *PartitionList; + + ASRT(Region->SysID == SYSID_UNUSED); + + DetermineCreateSizeAndOffset( Region, + MinimumSize, + CreationSizeMB, + Type, + &CreationStart, + &CreationSize + ); + + // + // now we've got the start and size of the partition to be created. + // If there's left-over at the beginning of the free space (after + // alignment), make a new PARTITION structure. + + p1 = NULL; + LeftOver.QuadPart = (CreationStart.QuadPart - CreateData->Partition->Offset.QuadPart); + + if(LeftOver.QuadPart > 0) { + + p1 = AllocatePartitionStructure(Region->Disk, + CreateData->Partition->Offset, + LeftOver, + SYSID_UNUSED, + FALSE, + FALSE, + FALSE + ); + if(p1 == NULL) { + RETURN_OUT_OF_MEMORY; + } + } + + // make a new partition structure for space being left free as + // a result of this creation. + + p2 = NULL; + LeftOver.QuadPart = (CreateData->Partition->Offset.QuadPart + CreateData->Partition->Length.QuadPart) - + (CreationStart.QuadPart + CreationSize.QuadPart); + + if(LeftOver.QuadPart != 0) { + + LARGE_INTEGER TmpResult; + + TmpResult.QuadPart = CreationStart.QuadPart + CreationSize.QuadPart; + p2 = AllocatePartitionStructure(Region->Disk, + TmpResult, + LeftOver, + SYSID_UNUSED, + FALSE, + FALSE, + FALSE + ); + if(p2 == NULL) { + RETURN_OUT_OF_MEMORY; + } + } + + // adjust the free partition's fields. + + CreateData->Partition->Offset = CreationStart; + CreateData->Partition->Length = CreationSize; + CreateData->Partition->SysID = SysId; + CreateData->Partition->Update = TRUE; + CreateData->Partition->Recognized = TRUE; + + // if we just created an extended partition, show the whole thing + // as one free logical region. + + if(Type == REGION_EXTENDED) { + + ASRT(LogicalVolumes[Region->Disk] == NULL); + + p3 = AllocatePartitionStructure(Region->Disk, + CreationStart, + CreationSize, + SYSID_UNUSED, + FALSE, + FALSE, + FALSE + ); + if(p3 == NULL) { + RETURN_OUT_OF_MEMORY; + } + AddPartitionToLinkedList(&LogicalVolumes[Region->Disk],p3); + } + + PartitionList = (Type == REGION_LOGICAL) + ? &LogicalVolumes[Region->Disk] + : &PrimaryPartitions[Region->Disk]; + + if(p1) { + AddPartitionToLinkedList(PartitionList,p1); + } + if(p2) { + AddPartitionToLinkedList(PartitionList,p2); + } + + MergeFreePartitions(*PartitionList); + RenumberPartitions(Region->Disk); + + ChangesMade[Region->Disk] = TRUE; + + return(OK_STATUS); +} + + +ARC_STATUS +CreatePartition( + IN PREGION_DESCRIPTOR Region, + IN ULONG CreationSizeMB, + IN REGION_TYPE Type + ) +{ + LARGE_INTEGER LargeZero; + + LargeZero.QuadPart = 0; + return(CreatePartitionEx(Region, + LargeZero, + CreationSizeMB, + Type, + (UCHAR)((Type == REGION_EXTENDED) ? SYSID_EXTENDED + : SYSID_BIGFAT + ) + ) + ); +} + + + +ARC_STATUS +DeletePartition( + IN PREGION_DESCRIPTOR Region + ) + +/*++ + +Routine Description: + + This routine deletes a partition, returning its space to the + free space on the disk. If deleting the extended partition, + all logical volumes within it are also deleted. + +Arguments: + + Region - a region descriptor returned by GetDiskRegions(). Must + be a used region. + +Return Value: + + OK_STATUS or error code. + +--*/ + +{ + PREGION_DATA RegionData = Region->Reserved; + PPARTITION *PartitionList; + + ASRT( IsInPartitionList(Region->Disk,RegionData->Partition) + || IsInLogicalList (Region->Disk,RegionData->Partition) + ); + + if(IsExtended(Region->SysID)) { + + ASRT(IsInPartitionList(Region->Disk,RegionData->Partition)); + + // Deleting extended partition. Also delete all logical volumes. + + FreeLinkedPartitionList(&LogicalVolumes[Region->Disk]); + } + + RegionData->Partition->SysID = SYSID_UNUSED; + RegionData->Partition->Update = TRUE; + RegionData->Partition->Active = FALSE; + RegionData->Partition->OriginalPartitionNumber = 0; + + PartitionList = (Region->RegionType == REGION_LOGICAL) + ? &LogicalVolumes[Region->Disk] + : &PrimaryPartitions[Region->Disk]; + + MergeFreePartitions(*PartitionList); + RenumberPartitions(Region->Disk); + + ChangesMade[Region->Disk] = TRUE; + + return(OK_STATUS); +} + + +ARC_STATUS +GetDiskRegions( + IN ULONG Disk, + IN BOOLEAN WantUsedRegions, + IN BOOLEAN WantFreeRegions, + IN BOOLEAN WantPrimaryRegions, + IN BOOLEAN WantLogicalRegions, + OUT PREGION_DESCRIPTOR *Region, + OUT ULONG *RegionCount + ) + +/*++ + +Routine Description: + + This routine returns an array of region descriptors to the caller. + A region desscriptor describes a space on the disk, either used + or free. The caller can control which type of regions are returned. + + The caller must free the returned array via FreeRegionArray(). + +Arguments: + + Disk - index of disk whose regions are to be returned + + WantUsedRegions - whether to return used disk regions + + WantFreeRegions - whether to return free disk regions + + WantPrimaryRegions - whether to return regions not in the + extended partition + + WantLogicalRegions - whether to return regions within the + extended partition + + Region - where to put a pointer to the array of regions + + RegionCount - where to put the number of items in the returned + Region array + +Return Value: + + OK_STATUS or error code. + +--*/ + +{ + *Region = AllocateMemory(0); + *RegionCount = 0; + + if(WantPrimaryRegions) { + return(GetRegions(Disk, + PrimaryPartitions[Disk], + WantUsedRegions, + WantFreeRegions, + WantLogicalRegions, + Region, + RegionCount, + REGION_PRIMARY + ) + ); + } else if(WantLogicalRegions) { + return(GetRegions(Disk, + LogicalVolumes[Disk], + WantUsedRegions, + WantFreeRegions, + FALSE, + Region, + RegionCount, + REGION_LOGICAL + ) + ); + } + return(OK_STATUS); +} + + +// workers for GetDiskRegions + +ARC_STATUS +GetRegions( + IN ULONG Disk, + IN PPARTITION p, + IN BOOLEAN WantUsedRegions, + IN BOOLEAN WantFreeRegions, + IN BOOLEAN WantLogicalRegions, + OUT PREGION_DESCRIPTOR *Region, + OUT ULONG *RegionCount, + IN REGION_TYPE RegionType + ) +{ + ARC_STATUS status; + LARGE_INTEGER AlignedOffset,AlignedSize; + ULONG SizeMB; + + while(p) { + + if(p->SysID == SYSID_UNUSED) { + + if(WantFreeRegions) { + + LARGE_INTEGER Result1, Result2; + + AlignedOffset = AlignTowardsDiskEnd(p->Disk,p->Offset); + + Result2.QuadPart = p->Offset.QuadPart + p->Length.QuadPart; + Result1 = AlignTowardsDiskStart(p->Disk,Result2); + AlignedSize.QuadPart = Result1.QuadPart - AlignedOffset.QuadPart; + + SizeMB = SIZEMB(AlignedSize); + + + // + // Show the space free if it is greater than 1 meg, AND + // it is not a space starting at the beginning of the disk + // and of length <= 1 cylinder. + // This prevents the user from seeing the first cylinder + // of the disk as free (could otherwise happen with an + // extended partition starting on cylinder 1 and cylinders + // of 1 megabyte or larger). + // + + if( (AlignedSize.QuadPart > 0) + && SizeMB + && ( (p->Offset.QuadPart != 0) + || ( p->Length.QuadPart > + DiskGeometryArray[p->Disk].BytesPerCylinder ) + ) + ) + { + if(!AddRegionEntry(Region, + RegionCount, + SizeMB, + RegionType, + p, + AlignedOffset, + AlignedSize + )) + { + RETURN_OUT_OF_MEMORY; + } + } + } + } else { + + if(WantUsedRegions) { + + AlignedOffset = p->Offset; + AlignedSize = p->Length; + SizeMB = SIZEMB(AlignedSize); + + if(!AddRegionEntry(Region, + RegionCount, + SizeMB, + RegionType, + p, + AlignedOffset, + AlignedSize + )) + { + RETURN_OUT_OF_MEMORY; + } + } + + if(IsExtended(p->SysID) && WantLogicalRegions) { + status = GetRegions(Disk, + LogicalVolumes[Disk], + WantUsedRegions, + WantFreeRegions, + FALSE, + Region, + RegionCount, + REGION_LOGICAL + ); + if(status != OK_STATUS) { + return(status); + } + } + } + p = p->Next; + } + return(OK_STATUS); +} + + +BOOLEAN +AddRegionEntry( + OUT PREGION_DESCRIPTOR *Regions, + OUT ULONG *RegionCount, + IN ULONG SizeMB, + IN REGION_TYPE RegionType, + IN PPARTITION Partition, + IN LARGE_INTEGER AlignedRegionOffset, + IN LARGE_INTEGER AlignedRegionSize + ) +{ + PREGION_DESCRIPTOR p; + PREGION_DATA data; + + p = ReallocateMemory(*Regions,((*RegionCount) + 1) * sizeof(REGION_DESCRIPTOR)); + if(p == NULL) { + return(FALSE); + } else { + *Regions = p; + (*RegionCount)++; + } + + p = &(*Regions)[(*RegionCount)-1]; + + if(!(p->Reserved = AllocateMemory(sizeof(REGION_DATA)))) { + return(FALSE); + } + + p->Disk = Partition->Disk; + p->SysID = Partition->SysID; + p->SizeMB = SizeMB; + p->Active = Partition->Active; + p->Recognized = Partition->Recognized; + p->PartitionNumber = Partition->PartitionNumber; + p->OriginalPartitionNumber = Partition->OriginalPartitionNumber; + p->RegionType = RegionType; + p->PersistentData = Partition->PersistentData; + + data = p->Reserved; + + data->Partition = Partition; + data->AlignedRegionOffset = AlignedRegionOffset; + data->AlignedRegionSize = AlignedRegionSize; + + return(TRUE); +} + + +VOID +FreeRegionArray( + IN PREGION_DESCRIPTOR Region, + IN ULONG RegionCount + ) + +/*++ + +Routine Description: + + This routine frees a region array returned by GetDiskRegions(). + +Arguments: + + Region - pointer to the array of regions to be freed + + RegionCount - number of items in the Region array + +Return Value: + + None. + +--*/ + +{ + ULONG i; + + for(i=0; iOffset.QuadPart < cur->Offset.QuadPart) { + p->Next = cur; + cur->Prev = p; + *Head = p; + return; + } + + prev = *Head; + cur = cur->Next; + + while(cur) { + if(p->Offset.QuadPart < cur->Offset.QuadPart) { + + p->Next = cur; + p->Prev = prev; + prev->Next = p; + cur->Prev = p; + return; + } + prev = cur; + cur = cur->Next; + } + + prev->Next = p; + p->Prev = prev; + return; +} + + +BOOLEAN +IsInLinkedList( + IN PPARTITION p, + IN PPARTITION List + ) + +/*++ + +Routine Description: + + This routine determines whether a PARTITION element is in + a given linked list of PARTITION elements. + +Arguments: + + p - pointer to element to be checked for + + List - first element in list to be scanned + +Return Value: + + true if p found in List, false otherwise + +--*/ + +{ + while(List) { + if(p == List) { + return(TRUE); + } + List = List->Next; + } + return(FALSE); +} + + +BOOLEAN +IsInLogicalList( + IN ULONG Disk, + IN PPARTITION p + ) + +/*++ + +Routine Description: + + This routine determines whether a PARTITION element is in + the logical volume list for a given disk. + +Arguments: + + Disk - index of disk to be checked + + p - pointer to element to be checked for + +Return Value: + + true if p found in Disk's logical volume list, false otherwise + +--*/ + +{ + return(IsInLinkedList(p,LogicalVolumes[Disk])); +} + + +BOOLEAN +IsInPartitionList( + IN ULONG Disk, + IN PPARTITION p + ) + +/*++ + +Routine Description: + + This routine determines whether a PARTITION element is in + the primary partition list for a given disk. + +Arguments: + + Disk - index of disk to be checked + + p - pointer to element to be checked for + +Return Value: + + true if p found in Disk's primary partition list, false otherwise + +--*/ + +{ + return(IsInLinkedList(p,PrimaryPartitions[Disk])); +} + + +VOID +MergeFreePartitions( + IN PPARTITION p + ) + +/*++ + +Routine Description: + + This routine merges adjacent free space elements in the + given linked list of PARTITION elements. It is designed + to be called after adding or deleting a partition. + +Arguments: + + p - pointer to first item in list whose free elements are to + be merged. + +Return Value: + + None. + +--*/ + +{ + PPARTITION next; + + while(p && p->Next) { + + if((p->SysID == SYSID_UNUSED) && (p->Next->SysID == SYSID_UNUSED)) { + + next = p->Next; + + p->Length.QuadPart = (next->Offset.QuadPart + next->Length.QuadPart) - p->Offset.QuadPart; + + if(p->Next = next->Next) { + next->Next->Prev = p; + } + + FreeMemory(next); + + } else { + p = p->Next; + } + } +} + + +VOID +RenumberPartitions( + IN ULONG Disk + ) + +/*++ + +Routine Description: + + This routine determines the partition number for each region + on a disk. For a used region, the partition number is the number + that the system will assign to the partition. All partitions + (except the extended partition) are numbered first starting at 1, + and then all logical volumes in the extended partition. + For a free region, the partition number is the number that the + system WOULD assign to the partition if the space were to be + converted to a partition and all other regions on the disk were + left as is. + + The partition numbers are stored in the PARTITION elements. + +Arguments: + + Disk - index of disk whose partitions are to be renumbered. + +Return Value: + + None. + +--*/ + +{ + PPARTITION p = PrimaryPartitions[Disk]; + ULONG n = 1; + + while(p) { + if(!IsExtended(p->SysID)) { + p->PartitionNumber = n; + if(p->SysID != SYSID_UNUSED) { + n++; + } + } + p = p->Next; + } + p = LogicalVolumes[Disk]; + while(p) { + p->PartitionNumber = n; + if(p->SysID != SYSID_UNUSED) { + n++; + } + p = p->Next; + } +} + + +PPARTITION +FindPartitionElement( + IN ULONG Disk, + IN ULONG Partition + ) + +/*++ + +Routine Description: + + This routine locates a PARTITION element for a disk/partition + number pair. The partition number is the number that the + system assigns to the partition. + +Arguments: + + Disk - index of relevent disk + + Partition - partition number of partition to find + +Return Value: + + pointer to PARTITION element, or NULL if not found. + +--*/ + +{ + PPARTITION p; + + ASRT(Partition); + + p = PrimaryPartitions[Disk]; + while(p) { + if((p->SysID != SYSID_UNUSED) + && !IsExtended(p->SysID) + && (p->PartitionNumber == Partition)) + { + return(p); + } + p = p->Next; + } + p = LogicalVolumes[Disk]; + while(p) { + if((p->SysID != SYSID_UNUSED) + && (p->PartitionNumber == Partition)) + { + return(p); + } + p = p->Next; + } + return(NULL); +} + + +VOID +SetSysID( + IN ULONG Disk, + IN ULONG Partition, + IN UCHAR SysID + ) + +/*++ + +Routine Description: + + This routine sets the system id of the given partition + on the given disk. + +Arguments: + + Disk - index of relevent disk + + Partition - partition number of relevent partition + + SysID - new system ID for Partition on Disk + +Return Value: + + None. + +--*/ + +{ + PPARTITION p = FindPartitionElement(Disk,Partition); + + ASRT(p); + + if(p) { + p->SysID = SysID; + if(!p->Update) { + p->Update = CHANGED_DONT_ZAP; + } + ChangesMade[p->Disk] = TRUE; + } +} + + +VOID +SetSysID2( + IN PREGION_DESCRIPTOR Region, + IN UCHAR SysID + ) +{ + PPARTITION p = ((PREGION_DATA)(Region->Reserved))->Partition; + + p->SysID = SysID; + if(!p->Update) { + p->Update = CHANGED_DONT_ZAP; + } + ChangesMade[p->Disk] = TRUE; +} + + +ULONG +GetHiddenSectorCount( + IN ULONG Disk, + IN ULONG Partition + ) + +/*++ + +Routine Description: + + This routine determines the hidden sector count for a + partition. This value is used by format and is placed in + the BPB of a FAT partition when the partition is formatted. + +Arguments: + + Disk - index of relevent disk + + Partition - partition number of relevent partition + +Return Value: + + The number of hidden sectors (will be 0 if the partition + does not exist). + +--*/ + +{ + PPARTITION p = FindPartitionElement(Disk,Partition); + ULONG HiddenSectorCount = 0; + LARGE_INTEGER Result; + + ASRT(p); + + if(p) { + + if(IsInLogicalList(Disk,p)) { + HiddenSectorCount = DiskGeometryArray[Disk].SectorsPerTrack; + } else { + ASRT(IsInPartitionList(Disk,p)); + Result.QuadPart = p->Offset.QuadPart / DiskGeometryArray[Disk].BytesPerSector; + HiddenSectorCount = LOWPART(Result); + } + } + return(HiddenSectorCount); +} + + +VOID +FreeLinkedPartitionList( + IN OUT PPARTITION *q + ) + +/*++ + +Routine Description: + + This routine frees a linked list of PARTITION elements. The head + pointer is set to NULL. + +Arguments: + + p - pointer to pointer to first element of list to free. + +Return Value: + + None. + +--*/ + +{ + PARTITION *n; + PARTITION *p = *q; + + while(p) { + n = p->Next; + FreeMemory(p); + p = n; + } + *q = NULL; +} + + +VOID +FreePartitionInfoLinkedLists( + IN PPARTITION *ListHeadArray + ) + +/*++ + +Routine Description: + + This routine frees the linked lists of PARTITION elements + for each disk. + +Arguments: + + ListHeadArray - pointer to array of pointers to first elements of + PARTITION element lists. + +Return Value: + + None. + +--*/ + +{ + ULONG i; + + for(i=0; iNext = NULL; + p->Prev = NULL; + p->Offset = Offset; + p->Length = Length; + p->Disk = Disk; + p->Update = Update; + p->Active = Active; + p->Recognized = Recognized; + p->SysID = SysID; + p->OriginalPartitionNumber = 0; + p->PartitionNumber = 0; + p->PersistentData = 0; + } + return(p); +} + + +ARC_STATUS +InitializeFreeSpace( + IN ULONG Disk, + IN PPARTITION *PartitionList, // list the free space goes in + IN LARGE_INTEGER StartOffset, + IN LARGE_INTEGER Length + ) + +/*++ + +Routine Description: + + This routine determines all the free spaces within a given area + on a disk, allocates PARTITION structures to describe them, + and adds these structures to the relevent partition list + (primary partitions or logical volumes). + + No rounding or alignment is performed here. Spaces of even one + byte will be counted and inserted in the partition list. + +Arguments: + + Disk - index of disk whose free spaces are being sought. + + PartitionList - pointer to first element on PARTITION list that + the free spaces will go in. + + StartOffset - start offset of area on disk to consider (ie, 0 for + primary spaces or the first byte of the extended + partition for logical spaces). + + Length - length of area on disk to consider (ie, size of disk + for primary spaces or size of extended partition for + logical spaces). + +Return Value: + + OK_STATUS or error code. + +--*/ + +{ + PPARTITION p = *PartitionList,q; + LARGE_INTEGER Start,Size; + + Start = StartOffset; + + while(p) { + + Size.QuadPart = p->Offset.QuadPart - Start.QuadPart; + + if(Size.QuadPart > 0) { + + if(!(q = AllocatePartitionStructure(Disk, + Start, + Size, + SYSID_UNUSED, + FALSE, + FALSE, + FALSE + ) + ) + ) + { + RETURN_OUT_OF_MEMORY; + } + + AddPartitionToLinkedList(PartitionList,q); + } + + Start.QuadPart = p->Offset.QuadPart + p->Length.QuadPart; + + p = p->Next; + + } + + Size.QuadPart = (StartOffset.QuadPart + Length.QuadPart) - Start.QuadPart; + + if(Size.QuadPart > 0) { + + if(!(q = AllocatePartitionStructure(Disk, + Start, + Size, + SYSID_UNUSED, + FALSE, + FALSE, + FALSE + ) + ) + ) + { + RETURN_OUT_OF_MEMORY; + } + + AddPartitionToLinkedList(PartitionList,q); + } + + return(OK_STATUS); +} + + +ARC_STATUS +InitializeLogicalVolumeList( + IN ULONG Disk, + IN PDRIVE_LAYOUT_INFORMATION DriveLayout, + IN ULONG PartitionNumber + ) + +/*++ + +Routine Description: + + This routine creates the logical volume linked list of + PARTITION structures for the given disk. + +Arguments: + + Disk - index of disk + + DriveLayout - pointer to structure describing the raw partition + layout of the disk. + + PartitionNumber - number to assign to the first logical volume + on the disk. + +Return Value: + + OK_STATUS or error code. + +--*/ + +{ + PPARTITION p,q; + ULONG i,j; + PPARTITION_INFORMATION d; + LARGE_INTEGER HiddenBytes; + ULONG BytesPerSector = DiskGeometryArray[Disk].BytesPerSector; + LARGE_INTEGER Result1, Result2; + + FreeLinkedPartitionList(&LogicalVolumes[Disk]); + + p = PrimaryPartitions[Disk]; + while(p) { + if(IsExtended(p->SysID)) { + break; + } + p = p->Next; + } + + if(p) { + for(i=ENTRIES_PER_BOOTSECTOR; iPartitionCount; i+=ENTRIES_PER_BOOTSECTOR) { + + for(j=i; jPartitionEntry[j]; + + if((d->PartitionType != SYSID_UNUSED) && (d->PartitionType != SYSID_EXTENDED)) { + + HiddenBytes.QuadPart = UInt32x32To64(d->HiddenSectors,BytesPerSector); + + Result1.QuadPart = d->StartingOffset.QuadPart - HiddenBytes.QuadPart; + Result2.QuadPart = d->PartitionLength.QuadPart + HiddenBytes.QuadPart; + if(!(q = AllocatePartitionStructure(Disk, + Result1, + Result2, + d->PartitionType, + FALSE, + d->BootIndicator, + d->RecognizedPartition + ) + ) + ) + { + RETURN_OUT_OF_MEMORY; + } + + q->OriginalPartitionNumber = PartitionNumber++; + AddPartitionToLinkedList(&LogicalVolumes[Disk],q); + + break; + } + } + } + return(InitializeFreeSpace(Disk, + &LogicalVolumes[Disk], + p->Offset, + p->Length + ) + ); + } + return(OK_STATUS); +} + + +ARC_STATUS +InitializePrimaryPartitionList( + IN ULONG Disk, + IN PDRIVE_LAYOUT_INFORMATION DriveLayout, + OUT PULONG NextPartitionNumber + ) + +/*++ + +Routine Description: + + This routine creates the primary partition linked list of + PARTITION structures for the given disk. + +Arguments: + + Disk - index of disk + + DriveLayout - pointer to structure describing the raw partition + layout of the disk. + + NextPartitionNumber - where to put partition number that should be + assigned to the first logical volume on the + disk. + +Return Value: + + OK_STATUS or error code. + +--*/ + +{ + ULONG i; + PPARTITION p; + PPARTITION_INFORMATION d; + ULONG PartitionNumber = 1; + LARGE_INTEGER LargeZero; + + FreeLinkedPartitionList(&PrimaryPartitions[Disk]); + + if(DriveLayout->PartitionCount >= ENTRIES_PER_BOOTSECTOR) { + + for(i=0; iPartitionEntry[i]; + + if(d->PartitionType != SYSID_UNUSED) { + + if(!(p = AllocatePartitionStructure(Disk, + d->StartingOffset, + d->PartitionLength, + d->PartitionType, + FALSE, + d->BootIndicator, + d->RecognizedPartition + ) + ) + ) + { + RETURN_OUT_OF_MEMORY; + } + + p->OriginalPartitionNumber = IsExtended(p->SysID) + ? 0 + : PartitionNumber++; + + AddPartitionToLinkedList(&PrimaryPartitions[Disk],p); + } + } + } + *NextPartitionNumber = PartitionNumber; + LargeZero.QuadPart = 0; + return(InitializeFreeSpace(Disk, + &PrimaryPartitions[Disk], + LargeZero, + DiskLengthBytes(Disk) + ) + ); +} + + +ARC_STATUS +InitializePartitionLists( + VOID + ) + +/*++ + +Routine Description: + + This routine scans the PARTITION_INFO array returned for each disk + by the OS. A linked list of PARTITION structures is layered on top + of each array; the net result is a sorted list that covers an entire + disk, because free spaces are also factored in as 'dummy' partitions. + +Arguments: + + None. + +Return Value: + + OK_STATUS or error code. + +--*/ + +{ + ARC_STATUS status; + ULONG Disk; + PDRIVE_LAYOUT_INFORMATION DriveLayout; + ULONG PNum; + + + for(Disk=0; Disk= ONE_MEG/2) { + SizeMB++; + } + + return(SizeMB); +} + +ULONG +DiskSizeMB( + IN ULONG Disk + ) + +/*++ + +Routine Description: + + This routine determines the disk length in megabytes. The returned + value is rounded down after division by 1024*1024. + +Arguments: + + Disk - index of disk whose size is desired + +Return Value: + + Size of Disk. + +--*/ + +{ + return(SIZEMB(DiskLengthBytes(Disk))); +} + + +LARGE_INTEGER +AlignTowardsDiskStart( + IN ULONG Disk, + IN LARGE_INTEGER Offset + ) + +/*++ + +Routine Description: + + This routine snaps a byte offset to a cylinder boundary, towards + the start of the disk. + +Arguments: + + Disk - index of disk whose offset is to be snapped + + Offset - byte offset to be aligned (snapped to cylinder boundary) + +Return Value: + + Aligned offset. + +--*/ + +{ + LARGE_INTEGER mod; + LARGE_INTEGER Result; + + mod.QuadPart = Offset.QuadPart % DiskGeometryArray[Disk].BytesPerCylinder; + Result.QuadPart = Offset.QuadPart - mod.QuadPart; + return(Result); +} + + +LARGE_INTEGER +AlignTowardsDiskEnd( + IN ULONG Disk, + IN LARGE_INTEGER Offset + ) + +/*++ + +Routine Description: + + This routine snaps a byte offset to a cylinder boundary, towards + the end of the disk. + +Arguments: + + Disk - index of disk whose offset is to be snapped + + Offset - byte offset to be aligned (snapped to cylinder boundary) + +Return Value: + + Aligned offset. + +--*/ + +{ + LARGE_INTEGER mod; + LARGE_INTEGER LargeInteger; + + mod.QuadPart = Offset.QuadPart % DiskGeometryArray[Disk].BytesPerCylinder; + if(mod.QuadPart != 0) { + + LargeInteger.QuadPart = Offset.QuadPart + DiskGeometryArray[Disk].BytesPerCylinder; + Offset = AlignTowardsDiskStart(Disk, + LargeInteger + ); + } + return(Offset); +} + + +BOOLEAN +IsExtended( + IN UCHAR SysID + ) + +/*++ + +Routine Description: + + This routine determines whether a given system id is for an + extended type (ie, link) entry. + +Arguments: + + SysID - system id to be tested. + +Return Value: + + true/false based on whether SysID is for an extended type. + +--*/ + +{ + return((BOOLEAN)(SysID == SYSID_EXTENDED)); +} + + +ARC_STATUS +IsAnyCreationAllowed( + IN ULONG Disk, + IN BOOLEAN AllowMultiplePrimaries, + OUT PBOOLEAN AnyAllowed, + OUT PBOOLEAN PrimaryAllowed, + OUT PBOOLEAN ExtendedAllowed, + OUT PBOOLEAN LogicalAllowed + ) + +/*++ + +Routine Description: + + This routine determines whether any partition may be created on a + given disk, based on three sub-queries -- whether creation is allowed + of a primary partition, an extended partition, or a logical volume. + +Arguments: + + Disk - index of disk to check + + AllowMultiplePrimaries - whether to allow multiple primary partitions + + AnyAllowed - returns whether any creation is allowed + + PrimaryAllowed - returns whether creation of a primary partition + is allowed + + ExtendedAllowed - returns whether creation of an extended partition + is allowed + + Logical Allowed - returns whether creation of a logical volume is allowed. + +Return Value: + + OK_STATUS or error code + +--*/ + +{ + ARC_STATUS status; + + if((status = IsCreationOfPrimaryAllowed(Disk,AllowMultiplePrimaries,PrimaryAllowed)) != OK_STATUS) { + return(status); + } + if((status = IsCreationOfExtendedAllowed(Disk,ExtendedAllowed)) != OK_STATUS) { + return(status); + } + if((status = IsCreationOfLogicalAllowed(Disk,LogicalAllowed)) != OK_STATUS) { + return(status); + } + *AnyAllowed = (BOOLEAN)(*PrimaryAllowed || *ExtendedAllowed || *LogicalAllowed); + return(OK_STATUS); +} + + +ARC_STATUS +IsCreationOfPrimaryAllowed( + IN ULONG Disk, + IN BOOLEAN AllowMultiplePrimaries, + OUT BOOLEAN *Allowed + ) + +/*++ + +Routine Description: + + This routine determines whether creation of a primary partition is + allowed. This is true when there is a free entry in the MBR and + there is free primary space on the disk. If multiple primaries + are not allowed, then there must also not exist any primary partitions + in order for a primary creation to be allowed. + +Arguments: + + Disk - index of disk to check + + AllowMultiplePrimaries - whether existnace of primary partition + disallows creation of a primary partition + + Allowed - returns whether creation of a primary partition + is allowed + +Return Value: + + OK_STATUS or error code + +--*/ + +{ + PREGION_DESCRIPTOR Regions; + ULONG RegionCount; + ULONG UsedCount,RecogCount,i; + ARC_STATUS status; + BOOLEAN FreeSpace = FALSE; + + status = GetPrimaryDiskRegions(Disk,&Regions,&RegionCount); + if(status != OK_STATUS) { + return(status); + } + + for(UsedCount = RecogCount = i = 0; iOffset.QuadPart + BytesPerTrack.QuadPart; + pinfo[Entry].PartitionLength.QuadPart = pLogical->Length.QuadPart - BytesPerTrack.QuadPart; + pinfo[Entry].HiddenSectors = SectorsPerTrack.LowPart; + pinfo[Entry].RewritePartition = pLogical->Update; + pinfo[Entry].BootIndicator = pLogical->Active; + pinfo[Entry].PartitionType = pLogical->SysID; + + if(pinfo[Entry].RewritePartition) { + StartingOffset = pinfo[Entry].StartingOffset; + } + + Entry++; + } + + if(pNextLogical) { + + pinfo[Entry].StartingOffset = pNextLogical->Offset; + pinfo[Entry].PartitionLength = pNextLogical->Length; + pinfo[Entry].HiddenSectors = 0; + pinfo[Entry].RewritePartition = TRUE; + pinfo[Entry].BootIndicator = FALSE; + pinfo[Entry].PartitionType = SYSID_EXTENDED; + + Entry++; + } + + UnusedEntryFill(pinfo+Entry,ENTRIES_PER_BOOTSECTOR-Entry); + return(StartingOffset); +} + + +ARC_STATUS +ZapSector( + ULONG Disk, + LARGE_INTEGER Offset + ) + +/*++ + +Routine Description: + + This routine writes zeros into a sector at a given offset. This is + used to clear out a new partition's filesystem boot record, so that + no previous filesystem appears in a new partition; or to clear out the + first EBR in the extended partition if there are to be no logical vols. + +Arguments: + + Disk - disk to write to + + Offset - byte offset to a newly created partition on Disk + +Return Value: + + OK_STATUS or error code. + +--*/ + +{ + ULONG SectorSize = DiskGeometryArray[Disk].BytesPerSector; + ULONG i; + PCHAR SectorBuffer,AlignedSectorBuffer; + ARC_STATUS status; + ULONG Handle; + LARGE_INTEGER LargeInteger; + + if((SectorBuffer = AllocateMemory(2*SectorSize)) == NULL) { + RETURN_OUT_OF_MEMORY; + } + + AlignedSectorBuffer = (PCHAR)(((ULONG)SectorBuffer+SectorSize) & ~(SectorSize-1)); + + for(i=0; iPartitionEntry[0]; + + // first do the mbr. + + EntryCount=0; + p = PrimaryPartitions[Disk]; + + while(p) { + + if(p->SysID != SYSID_UNUSED) { + + ASRT(EntryCount < ENTRIES_PER_BOOTSECTOR); + + if(IsExtended(p->SysID)) { + ExtendedStartingOffset = p->Offset; + } + + pinfo[EntryCount].StartingOffset = p->Offset; + pinfo[EntryCount].PartitionLength = p->Length; + pinfo[EntryCount].PartitionType = p->SysID; + pinfo[EntryCount].BootIndicator = p->Active; + pinfo[EntryCount].RewritePartition = p->Update; + + // BUGBUG we know that this field is not used by the + // set drive layout IOCTL or the ARC stub. + + pinfo[EntryCount].HiddenSectors = 0; + + // if we're creating this partition, clear out the + // filesystem boot sector. + + if(pinfo[EntryCount].RewritePartition + && (p->Update != CHANGED_DONT_ZAP) + && !IsExtended(pinfo[EntryCount].PartitionType)) + { + status = ZapSector(Disk,pinfo[EntryCount].StartingOffset); + if(status != OK_STATUS) { + FreeMemory(DriveLayout); + return(status); + } + } + + EntryCount++; + } + p = p->Next; + } + + // fill the remainder of the MBR with unused entries. + // NOTE that there will thus always be an MBR even if there + // are no partitions defined. + + UnusedEntryFill(pinfo+EntryCount,ENTRIES_PER_BOOTSECTOR - EntryCount); + EntryCount = ENTRIES_PER_BOOTSECTOR; + + // + // now handle the logical volumes. + // first check to see whether we need a dummy EBR at the beginning + // of the extended partition. This is the case when there is + // free space at the beginning of the extended partition. +#if 0 + // Also handle the case where we are creating an empty extended + // partition -- need to zap the first sector to eliminate any residue + // that might start an EBR chain. +#else + // BUGBUG 4/24/92 tedm: Currently the io subsystem returns an error + // status (status_bad_master_boot_record) if any mbr or ebr is bad. + // Zeroing the first sector of the extended partition therefore causes + // the whole disk to be seen as empty. So create a blank, but valid, + // EBR in the 'empty extended partition' case. Code is in the 'else' + // part of the #if 0, below. +#endif + // + + if((p = LogicalVolumes[Disk]) && (p->SysID == SYSID_UNUSED)) { + if(p->Next) { + ASRT(p->Next->SysID != SYSID_UNUSED); + + MakeBootRec(Disk,pinfo+EntryCount,NULL,p->Next); + EntryCount += ENTRIES_PER_BOOTSECTOR; + p = p->Next; + } else { + ASRT(ExtendedStartingOffset.QuadPart != 0); +#if 0 + status = ZapSector(Disk,ExtendedStartingOffset); + if(status != OK_STATUS) { + FreeMemory(DriveLayout); + return(status); + } +#else + MakeBootRec(Disk,pinfo+EntryCount,NULL,NULL); + EntryCount += ENTRIES_PER_BOOTSECTOR; +#endif + } + } + + while(p) { + if(p->SysID != SYSID_UNUSED) { + + // find the next logical volume. + + n = p->Next; + while(n) { + if(n->SysID != SYSID_UNUSED) { + break; + } + n = n->Next; + } + + StartingOffset = MakeBootRec(Disk,pinfo+EntryCount,p,n); + + // if we're creating a volume, clear out its filesystem + // boot sector so it starts out fresh. + + if((StartingOffset.QuadPart != 0) && (p->Update != CHANGED_DONT_ZAP)) { + status = ZapSector(Disk,StartingOffset); + if(status != OK_STATUS) { + FreeMemory(DriveLayout); + return(status); + } + } + + EntryCount += ENTRIES_PER_BOOTSECTOR; + } + p = p->Next; + } + + DriveLayout->PartitionCount = EntryCount; + status = LowSetDiskLayout(DiskNames[Disk],DriveLayout); + + FreeMemory(DriveLayout); + + return(status); +} + + +ARC_STATUS +CommitPartitionChanges( + IN ULONG Disk + ) + +/*++ + +Routine Description: + + This routine is the entry point for updating the on-disk partition + structures of a disk. The disk is only written to if the partition + structure has been changed by adding or deleting partitions. + +Arguments: + + Disk - index of disk whose on-disk partition structure is to be updated. + +Return Value: + + OK_STATUS or error code. + +--*/ + +{ + PPARTITION p; + ARC_STATUS status; + + ASRT(!OffLine[Disk]); + + if(!HavePartitionsBeenChanged(Disk)) { + return(OK_STATUS); + } + + if((status = WriteDriveLayout(Disk)) != OK_STATUS) { + return(status); + } + + // BUGBUG for ARC and NT MIPS, update NVRAM vars so partitions are right. + // Do that here, before partition numbers are reassigned. + + p = PrimaryPartitions[Disk]; + while(p) { + p->Update = FALSE; + p->OriginalPartitionNumber = p->PartitionNumber; + p = p->Next; + } + p = LogicalVolumes[Disk]; + while(p) { + p->Update = FALSE; + p->OriginalPartitionNumber = p->PartitionNumber; + p = p->Next; + } + + ChangesMade[Disk] = FALSE; + return(OK_STATUS); +} + + +BOOLEAN +HavePartitionsBeenChanged( + IN ULONG Disk + ) + +/*++ + +Routine Description: + + This routine returns TRUE if the given disk's partition structures + have been modified by adding or deleting partitions, since the + on-disk structures were last written by a call to CommitPartitionChanges + (or first read). + +Arguments: + + Disk - index of disk to check + +Return Value: + + true if Disk's partition structure has changed. + +--*/ + +{ + if(OffLine[Disk]) { + ASRT(!ChangesMade[Disk]); + } + return(ChangesMade[Disk]); +} + +VOID +FdMarkDiskDirty( + IN ULONG Disk + ) +{ + ASRT(!OffLine[Disk]); + + ChangesMade[Disk] = TRUE; +} + +VOID +FdSetPersistentData( + IN PREGION_DESCRIPTOR Region, + IN ULONG Data + ) +{ + ((PREGION_DATA)(Region->Reserved))->Partition->PersistentData = Data; +} + + +ULONG +FdGetMinimumSizeMB( + IN ULONG Disk + ) + +/*++ + +Routine Description: + + Return the minimum size for a partition on a given disk. + + This is the rounded size of one cylinder or 1, whichever is greater. + +Arguments: + + Region - region describing the partition to check. + +Return Value: + + Actual offset + +--*/ + +{ + LARGE_INTEGER LargeInteger; + + LargeInteger.QuadPart = DiskGeometryArray[Disk].BytesPerCylinder; + return(max(SIZEMB(LargeInteger),1)); +} + + +ULONG +FdGetMaximumSizeMB( + IN PREGION_DESCRIPTOR Region, + IN REGION_TYPE CreationType + ) +{ + PREGION_DATA CreateData = Region->Reserved; + LARGE_INTEGER MaxSize = CreateData->AlignedRegionSize; + + ASRT(Region->SysID == SYSID_UNUSED); + + if(CreateData->AlignedRegionOffset.QuadPart == 0) { + + ULONG Delta; + + ASRT((CreationType == REGION_EXTENDED) || (CreationType == REGION_PRIMARY)) + + Delta = (CreationType == REGION_EXTENDED) + ? DiskGeometryArray[Region->Disk].BytesPerCylinder + : DiskGeometryArray[Region->Disk].BytesPerTrack; + + MaxSize.QuadPart = MaxSize.QuadPart - Delta; + } + + return(SIZEMB(MaxSize)); +} + + +LARGE_INTEGER +FdGetExactSize( + IN PREGION_DESCRIPTOR Region, + IN BOOLEAN ForExtended + ) +{ + PREGION_DATA RegionData = Region->Reserved; + LARGE_INTEGER LargeSize = RegionData->AlignedRegionSize; + LARGE_INTEGER BytesPerTrack; + LARGE_INTEGER BytesPerCylinder; + + BytesPerTrack.QuadPart = (DiskGeometryArray[Region->Disk].BytesPerTrack); + BytesPerCylinder.QuadPart = (DiskGeometryArray[Region->Disk].BytesPerCylinder); + + if(Region->RegionType == REGION_LOGICAL) { + + // + // The region is within the extended partition. It doesn't matter + // whether it's free space or used -- in either case, we need to + // account for the reserved EBR track. + // + + LargeSize.QuadPart = LargeSize.QuadPart - BytesPerTrack.QuadPart; + + } else if(Region->SysID == SYSID_UNUSED) { + + // + // The region is unused space not inside the extended partition. + // We must know whether the caller will put a primary or extended + // partition there -- a primary partition can use all the space, but + // a logical volume in the extended partition won't include the first + // track. If the free space starts at offset 0 on the disk, a special + // calculation must be used to move the start of the partition to + // skip a track for a primary or a cylinder and a track for an + // extended+logical. + // + + if((RegionData->AlignedRegionOffset.QuadPart == 0) || ForExtended) { + LargeSize.QuadPart = LargeSize.QuadPart - BytesPerTrack.QuadPart; + } + + if((RegionData->AlignedRegionOffset.QuadPart == 0) && ForExtended) { + LargeSize.QuadPart = LargeSize.QuadPart - BytesPerCylinder.QuadPart; + } + } + + return(LargeSize); +} + + +LARGE_INTEGER +FdGetExactOffset( + IN PREGION_DESCRIPTOR Region + ) + +/*++ + +Routine Description: + + Determine where a given partition _actually_ starts, which may be + different than where is appears because of EBR reserved tracks, etc. + + NOTE: This routine is not meant to operate on unused regions or + extended partitions. In these cases, it just returns the apparant offset. + +Arguments: + + Region - region describing the partition to check. + +Return Value: + + Actual offset + +--*/ + +{ + LARGE_INTEGER Offset = ((PREGION_DATA)(Region->Reserved))->Partition->Offset; + + if((Region->SysID != SYSID_UNUSED) && (Region->RegionType == REGION_LOGICAL)) { + + // + // The region is a logical volume. + // Account for the reserved EBR track. + // + + Offset.QuadPart = Offset.QuadPart + + DiskGeometryArray[Region->Disk].BytesPerTrack; + } + + return(Offset); +} + + +BOOLEAN +FdCrosses1024Cylinder( + IN PREGION_DESCRIPTOR Region, + IN ULONG CreationSizeMB, + IN REGION_TYPE RegionType + ) + +/*++ + +Routine Description: + + Determine whether a used region corsses the 1024th cylinder, or whether + a partition created within a free space will cross the 1024th cylinder. + +Arguments: + + Region - region describing the partition to check. + + CreationSizeMB - if the Region is for a free space, this is the size of + the partition to be checked. + + RegionType - one of REGION_PRIMARY, REGION_EXTENDED, or REGION_LOGICAL + +Return Value: + + TRUE if the end cylinder >= 1024. + +--*/ + +{ + LARGE_INTEGER Start,Size,End, LargeZero; + + if(Region->SysID == SYSID_UNUSED) { + + // + // Determine the exact size and offset of the partition, according + // to how CreatePartitionEx() will do it. + // + + LargeZero.QuadPart = 0; + DetermineCreateSizeAndOffset( Region, + LargeZero, + CreationSizeMB, + RegionType, + &Start, + &Size + ); + + } else { + + Start = ((PREGION_DATA)(Region->Reserved))->Partition->Offset; + Size = ((PREGION_DATA)(Region->Reserved))->Partition->Length; + } + + End.QuadPart = (Start.QuadPart + Size.QuadPart) - 1; + + // + // End is the last byte in the partition. Divide by the number of + // bytes in a cylinder and see whether the result is > 1023. + // + + return( (End.QuadPart / DiskGeometryArray[Region->Disk].BytesPerCylinder) > 1023 ); +} + + +BOOLEAN +IsDiskOffLine( + IN ULONG Disk + ) +{ + return(OffLine[Disk]); +} diff --git a/private/ntos/arcinst/fmtexp.c b/private/ntos/arcinst/fmtexp.c new file mode 100644 index 000000000..6164f94bd --- /dev/null +++ b/private/ntos/arcinst/fmtexp.c @@ -0,0 +1,942 @@ +#include "precomp.h" +#pragma hdrstop + +#define READ_SIZE 65536 + +typedef struct { + UCHAR IntelNearJumpCommand[1]; // Intel Jump command + UCHAR BootStrapJumpOffset[2]; // offset of boot strap code + UCHAR OemData[8]; // OEM data + UCHAR BytesPerSector[2]; // BPB + UCHAR SectorsPerCluster[1]; // + UCHAR ReservedSectors[2]; // + UCHAR Fats[1]; // + UCHAR RootEntries[2]; // + UCHAR Sectors[2]; // + UCHAR Media[1]; // + UCHAR SectorsPerFat[2]; // + UCHAR SectorsPerTrack[2]; // + UCHAR Heads[2]; // + UCHAR HiddenSectors[4]; // + UCHAR LargeSectors[4]; // + UCHAR PhysicalDrive[1]; // 0 = removable, 80h = fixed + UCHAR CurrentHead[1]; // not used by fs utils + UCHAR Signature[1]; // boot signature + UCHAR SerialNumber[4]; // serial number + UCHAR Label[11]; // volume label, aligned padded + UCHAR SystemIdText[8]; // system ID, FAT for example +} UNALIGNED_SECTOR_ZERO, *PUNALIGNED_SECTOR_ZERO; + + +#define CSEC_FAT32MEG 65536 +#define CSEC_FAT16BIT 32680 +#define SYSID_FAT12BIT 1 +#define SYSID_FAT16BIT 4 +#define SYSID_FAT32MEG 6 +#define MIN_CLUS_BIG 4085 // Minimum clusters for a big FAT. +#define MAX_CLUS_BIG 65525 // Maximum + 1 clusters for big FAT. + + + +ARC_STATUS +FmtIsFatPartition( + IN ULONG PartitionId, + IN ULONG SectorSize, + OUT PBOOLEAN IsFatPartition + ) +/*++ + +Routine Description: + + This routine computes whether or not the given partition is a FAT + partition. + +Arguments: + + VolumeId - Supplies the volume to check. + SectorSize - Supplies the number of bytes per sector. + IsFatPartition - Returns whether or not the partition is FAT. + +Return Value: + + LowReadSectors, ENOMEM, ESUCCESS + +--*/ +{ + PUCHAR Buffer; + ARC_STATUS r; + + if (!(Buffer = AllocateMemory(SectorSize*2))) { + return ENOMEM; + } + + r = LowReadSectors(PartitionId, SectorSize, 0, 2, Buffer); + + if (r != ESUCCESS) { + FreeMemory(Buffer); + return r; + } + + *IsFatPartition = Buffer[510] == 0x55 && + Buffer[511] == 0xAA && + Buffer[0x10] != 0 && + Buffer[0x15] == Buffer[SectorSize] && + Buffer[SectorSize + 1] == 0xFF && + Buffer[SectorSize + 2] == 0xFF; + + FreeMemory(Buffer); + return ESUCCESS; +} + + +ARC_STATUS +FmtIsFat( + IN PCHAR PartitionPath, + OUT PBOOLEAN IsFatPartition + ) +/*++ + +Routine Description: + + This routine computes whether or not the given partition is a FAT + partition. + +Arguments: + + PartitionPath - Supplies a path to the partition. + IsFatPartition - Returns whether or not the partition is FAT. + +Return Value: + + ArcOpen, ArcClose, LowGetPartitionGeometry, FmtIsFatPartition + +--*/ +{ + ULONG partition_id; + ARC_STATUS r; + ULONG total_sectors, sector_size, sec_per_track, heads; + + r = LowGetPartitionGeometry(PartitionPath, &total_sectors, §or_size, + &sec_per_track, &heads); + + if (r != ESUCCESS) { + return r; + } + + r = ArcOpen(PartitionPath, ArcOpenReadOnly, &partition_id); + + if (r != ESUCCESS) { + return r; + } + + r = FmtIsFatPartition(partition_id, sector_size, IsFatPartition); + + if (r != ESUCCESS) { + ArcClose(partition_id); + return r; + } + + return ArcClose(partition_id); +} + + + + +USHORT +ComputeSecPerCluster( + IN ULONG NumSectors, + IN BOOLEAN SmallFat + ) +/*++ + +Routine Description: + + This routine computes the number of sectors per cluster. + +Arguments: + + NumSectors - Supplies the number of sectors on the disk. + SmallFat - Supplies whether or not the FAT should be small. + +Return Value: + + The number of sectors per cluster necessary. + +--*/ +{ + ULONG threshold; + USHORT sec_per_clus; + USHORT min_sec_per_clus; + + threshold = SmallFat ? MIN_CLUS_BIG : MAX_CLUS_BIG; + sec_per_clus = 1; + + while (NumSectors >= threshold) { + sec_per_clus *= 2; + threshold *= 2; + } + + if (SmallFat) { + min_sec_per_clus = 8; + } else { + min_sec_per_clus = 4; + } + + return max(sec_per_clus, min_sec_per_clus); +} + + +ULONG +ComputeNewSerialNumber( + IN ULONG Seed + ) +/*++ + +Routine Description: + + This routine computes a new serial number for a volume. + +Arguments: + + Seed - Supplies a seed for the serial number. + +Return Value: + + A new volume serial number. + +--*/ +{ + PUCHAR p; + ULONG i; + + p = (PUCHAR) &Seed; + + for (i = 0; i < sizeof(ULONG); i++) { + + Seed += p[i]; + Seed = (Seed >> 2) + (Seed << 30); + } + + return Seed; +} + + +VOID +EditFat( + IN USHORT ClusterNumber, + IN USHORT ClusterEntry, + IN OUT PUCHAR Fat, + IN BOOLEAN SmallFat + ) +/*++ + +Routine Description: + + This routine edits the FAT entry 'ClusterNumber' with 'ClusterEntry'. + +Arguments: + + ClusterNumber - Supplies the number of the cluster to edit. + ClusterEntry - Supplies the new value for that cluster number. + Fat - Supplies the FAT to edit. + SmallFat - Supplies whether or not the FAT is small. + +Return Value: + + None. + +--*/ +{ + ULONG n; + + if (SmallFat) { + + n = ClusterNumber*3; + if (n%2) { + Fat[n/2] = (UCHAR) ((Fat[n/2]&0x0F) | ((ClusterEntry&0x000F)<<4)); + Fat[n/2 + 1] = (UCHAR) ((ClusterEntry&0x0FF0)>>4); + } else { + Fat[n/2] = (UCHAR) (ClusterEntry&0x00FF); + Fat[n/2 + 1] = (UCHAR) ((Fat[n/2 + 1]&0xF0) | + ((ClusterEntry&0x0F00)>>8)); + } + + } else { + + ((PUSHORT) Fat)[ClusterNumber] = ClusterEntry; + + } +} + + +ARC_STATUS +FmtFillFormatBuffer( + IN ULONG NumberOfSectors, + IN ULONG SectorSize, + IN ULONG SectorsPerTrack, + IN ULONG NumberOfHeads, + IN ULONG NumberOfHiddenSectors, + OUT PVOID FormatBuffer, + IN ULONG FormatBufferSize, + OUT PULONG SuperAreaSize, + IN ULONG TimeSeed, + IN PULONG BadSectorsList, + IN ULONG NumberOfBadSectors + ) +/*++ + +Routine Description: + + This routine computes a FAT super area based on the disk size, + disk geometry, and bad sectors of the volume. + +Arguments: + + NumberOfSectors - Supplies the number of sectors on the volume. + SectorSize - Supplies the number of bytes per sector. + SectorsPerTrack - Supplies the number of sectors per track. + NumberOfHeads - Supplies the number of heads. + NumberOfHiddenSectors - Supplies the number of hidden sectors. + FormatBuffer - Returns the super area for the volume. + FormatBufferSize - Supplies the number of bytes in the supplied + buffer. + SuperAreaSize - Returns the number of bytes in the super area. + TimeSeed - Supplies a time seed for serial number. + BadSectorsList - Supplies the list of bad sectors on the volume. + NumberOfBadSectors - Supplies the number of bad sectors in the list. + +Return Value: + + ENOMEM - The buffer wasn't big enough. + E2BIG - The disk is too large to be formatted. + EIO - There is a bad sector in the super area. + EINVAL - There is a bad sector off the end of the disk. + ESUCCESS + +--*/ +{ + PUNALIGNED_SECTOR_ZERO psecz; + PUCHAR puchar; + USHORT tmp_ushort; + ULONG tmp_ulong; + BOOLEAN small_fat; + ULONG num_sectors; + ULONG partition_id; + ULONG sec_per_fat; + ULONG sec_per_root; + ULONG sec_per_clus; + ULONG i; + ULONG sec_per_sa; + + + // First memset the buffer to all zeros; + memset(FormatBuffer, 0, (unsigned int) FormatBufferSize); + + + // Make sure that there's enough room for the BPB. + + if (!FormatBuffer || FormatBufferSize < SectorSize) { + return ENOMEM; + } + + // Compute the number of sectors on disk. + num_sectors = NumberOfSectors; + + // Compute the partition identifier. + partition_id = num_sectors < CSEC_FAT16BIT ? SYSID_FAT12BIT : + num_sectors < CSEC_FAT32MEG ? SYSID_FAT16BIT : + SYSID_FAT32MEG; + + // Compute whether or not to have a big or small FAT. + small_fat = (BOOLEAN) (partition_id == SYSID_FAT12BIT); + + + psecz = (PUNALIGNED_SECTOR_ZERO) FormatBuffer; + puchar = (PUCHAR) FormatBuffer; + + // Set up the jump instruction. + psecz->IntelNearJumpCommand[0] = 0xEB; + tmp_ushort = 0x903C; + memcpy(psecz->BootStrapJumpOffset, &tmp_ushort, sizeof(USHORT)); + + // Set up the OEM data. + memcpy(psecz->OemData, "WINNT1.0", 8); // BUGBUG norbertk + + // Set up the bytes per sector. + tmp_ushort = (USHORT) SectorSize; + memcpy(psecz->BytesPerSector, &tmp_ushort, sizeof(USHORT)); + + // Set up the number of sectors per cluster. + sec_per_clus = ComputeSecPerCluster(num_sectors, small_fat); + if (sec_per_clus > 128) { + + // The disk is too large to be formatted. + return E2BIG; + } + psecz->SectorsPerCluster[0] = (UCHAR) sec_per_clus; + + // Set up the number of reserved sectors. + tmp_ushort = 1; + memcpy(psecz->ReservedSectors, &tmp_ushort, sizeof(USHORT)); + + // Set up the number of FATs. + psecz->Fats[0] = 2; + + // Set up the number of root entries and number of sectors for the root. + tmp_ushort = 512; + memcpy(psecz->RootEntries, &tmp_ushort, sizeof(USHORT)); + sec_per_root = (512*32 - 1)/SectorSize + 1; + + // Set up the number of sectors. + if (num_sectors >= 1<<16) { + tmp_ushort = 0; + tmp_ulong = num_sectors; + } else { + tmp_ushort = (USHORT) num_sectors; + tmp_ulong = 0; + } + memcpy(psecz->Sectors, &tmp_ushort, sizeof(USHORT)); + memcpy(psecz->LargeSectors, &tmp_ulong, sizeof(ULONG)); + + // Set up the media byte. + psecz->Media[0] = 0xF8; + + // Set up the number of sectors per FAT. + if (small_fat) { + sec_per_fat = num_sectors/(2 + SectorSize*sec_per_clus*2/3); + } else { + sec_per_fat = num_sectors/(2 + SectorSize*sec_per_clus/2); + } + sec_per_fat++; + tmp_ushort = (USHORT) sec_per_fat; + memcpy(psecz->SectorsPerFat, &tmp_ushort, sizeof(USHORT)); + + // Set up the number of sectors per track. + tmp_ushort = (USHORT) SectorsPerTrack; + memcpy(psecz->SectorsPerTrack, &tmp_ushort, sizeof(USHORT)); + + // Set up the number of heads. + tmp_ushort = (USHORT) NumberOfHeads; + memcpy(psecz->Heads, &tmp_ushort, sizeof(USHORT)); + + // Set up the number of hidden sectors. + memcpy(psecz->HiddenSectors, &NumberOfHiddenSectors, sizeof(ULONG)); + + // Set up the physical drive number. + psecz->PhysicalDrive[0] = 0x80; + + // Set up the BPB signature. + psecz->Signature[0] = 0x29; + + // Set up the serial number. + tmp_ulong = ComputeNewSerialNumber(TimeSeed); + memcpy(psecz->SerialNumber, &tmp_ulong, sizeof(ULONG)); + + // Set up the system id. + memcpy(psecz->SystemIdText, "FAT ", 8); + + // Set up the boot signature. + puchar[510] = 0x55; + puchar[511] = 0xAA; + + + // Now make sure that the buffer has enough room for both of the + // FATs and the root directory. + + sec_per_sa = 1 + 2*sec_per_fat + sec_per_root; + *SuperAreaSize = SectorSize*sec_per_sa; + if (*SuperAreaSize > FormatBufferSize) { + return ENOMEM; + } + + + // Set up the first FAT. + + puchar[SectorSize] = 0xF8; + puchar[SectorSize + 1] = 0xFF; + puchar[SectorSize + 2] = 0xFF; + + if (!small_fat) { + puchar[SectorSize + 3] = 0xFF; + } + + + for (i = 0; i < NumberOfBadSectors; i++) { + + if (BadSectorsList[i] < sec_per_sa) { + // There's a bad sector in the super area. + return EIO; + } + + if (BadSectorsList[i] >= num_sectors) { + // Bad sector out of range. + return EINVAL; + } + + // Compute the bad cluster number; + tmp_ushort = (USHORT) + ((BadSectorsList[i] - sec_per_sa)/sec_per_clus + 2); + + EditFat(tmp_ushort, (USHORT) 0xFFF7, &puchar[SectorSize], small_fat); + } + + + // Copy the first FAT onto the second. + + memcpy(&puchar[SectorSize*(1 + sec_per_fat)], + &puchar[SectorSize], + (unsigned int) SectorSize*sec_per_fat); + + return ESUCCESS; +} + + +ARC_STATUS +FmtVerifySectors( + IN ULONG PartitionId, + IN ULONG NumberOfSectors, + IN ULONG SectorSize, + OUT PULONG* BadSectorsList, + OUT PULONG NumberOfBadSectors + ) +/*++ + +Routine Description: + + This routine verifies all of the sectors on the volume. + It returns a pointer to a list of bad sectors. The pointer + will be NULL if there was an error detected. + +Arguments: + + PartitionId - Supplies a handle to the partition for reading. + NumberOfSectors - Supplies the number of partition sectors. + SectorSize - Supplies the number of bytes per sector. + BadSectorsList - Returns the list of bad sectors. + NumberOfBadSectors - Returns the number of bad sectors in the list. + +Return Value: + + ENOMEM, ESUCCESS + +--*/ +{ + ULONG num_read_sec; + PVOID read_buffer; + ULONG i, j; + PULONG bad_sec_buf; + ULONG max_num_bad; + ARC_STATUS r; + ULONG percent; + + if (!(read_buffer = AllocateMemory(READ_SIZE))) { + return ENOMEM; + } + + max_num_bad = 100; + if (!(bad_sec_buf = (PULONG) AllocateMemory(max_num_bad*sizeof(ULONG)))) { + FreeMemory(read_buffer); + return ENOMEM; + } + + *NumberOfBadSectors = 0; + + num_read_sec = READ_SIZE/SectorSize; + + + percent = 1; + for (i = 0; i < NumberOfSectors; i += num_read_sec) { + + if (percent != i*100/NumberOfSectors) { + percent = i*100/NumberOfSectors; + AlPrint("%s%d percent formatted.\r", MSGMARGIN, percent); + } + + if (i + num_read_sec > NumberOfSectors) { + num_read_sec = NumberOfSectors - i; + } + + r = LowReadSectors(PartitionId, SectorSize, i, + num_read_sec, read_buffer); + + if (r != ESUCCESS) { + + for (j = 0; j < num_read_sec; j++) { + + r = LowReadSectors(PartitionId, SectorSize, i+j, 1, + read_buffer); + + if (r != ESUCCESS) { + + if (*NumberOfBadSectors == max_num_bad) { + + max_num_bad += 100; + if (!(bad_sec_buf = (PULONG) + ReallocateMemory(bad_sec_buf, + max_num_bad*sizeof(ULONG)))) { + + FreeMemory(read_buffer); + FreeMemory(bad_sec_buf); + return ENOMEM; + } + } + + bad_sec_buf[(*NumberOfBadSectors)++] = i + j; + } + } + } + } + + AlPrint("%s100 percent formatted.\r\n",MSGMARGIN); + + *BadSectorsList = bad_sec_buf; + + FreeMemory(read_buffer); + + return ESUCCESS; +} + + +ARC_STATUS +FmtFatFormat( + IN PCHAR PartitionPath, + IN ULONG HiddenSectorCount + ) +/*++ + +Routine Description: + + This routine does a FAT format on the given partition. + +Arguments: + + PartitionPath - Supplies a path to the partition to format. + +Return Value: + + LowGetPartitionGeometry, ArcOpen, + FmtVerifySectors, FmtFillFormatBuffer, LowWriteSectors, + ArcClose, ENOMEM + +--*/ +{ + ULONG num_sectors; + ULONG sector_size; + ULONG sec_per_track; + ULONG heads; + ULONG hidden_sectors; + PULONG bad_sectors; + ULONG num_bad_sectors; + PVOID format_buffer; + ULONG max_sec_per_sa; + ULONG super_area_size; + ARC_STATUS r; + ULONG partition_id; + ULONG time_seed; + PTIME_FIELDS ptime_fields; + + + r = LowGetPartitionGeometry(PartitionPath, &num_sectors, + §or_size, &sec_per_track, &heads); + + if (r != ESUCCESS) { + return r; + } + + hidden_sectors = HiddenSectorCount; + + r = ArcOpen(PartitionPath, ArcOpenReadWrite, &partition_id); + + if (r != ESUCCESS) { + return r; + } + + bad_sectors = NULL; + + r = FmtVerifySectors(partition_id, num_sectors, sector_size, + &bad_sectors, &num_bad_sectors); + + if (r != ESUCCESS) { + ArcClose(partition_id); + return r; + } + + max_sec_per_sa = 1 + + 2*((2*65536 - 1)/sector_size + 1) + + ((512*32 - 1)/sector_size + 1); + + ptime_fields = ArcGetTime(); + + time_seed = (ptime_fields->Year - 1970)*366*24*60*60 + + (ptime_fields->Month)*31*24*60*60 + + (ptime_fields->Day)*24*60*60 + + (ptime_fields->Hour)*60*60 + + (ptime_fields->Minute)*60 + + (ptime_fields->Second); + + if (!(format_buffer = AllocateMemory(max_sec_per_sa*sector_size))) { + + if (bad_sectors) { + FreeMemory(bad_sectors); + } + ArcClose(partition_id); + return ENOMEM; + } + + r = FmtFillFormatBuffer(num_sectors, + sector_size, + sec_per_track, + heads, + hidden_sectors, + format_buffer, + max_sec_per_sa*sector_size, + &super_area_size, + time_seed, + bad_sectors, + num_bad_sectors); + + + if (bad_sectors) { + FreeMemory(bad_sectors); + } + + if (r != ESUCCESS) { + ArcClose(partition_id); + FreeMemory(format_buffer); + return r; + } + + r = LowWriteSectors(partition_id, sector_size, 0, + super_area_size/sector_size, format_buffer); + + FreeMemory(format_buffer); + + if (r != ESUCCESS) { + ArcClose(partition_id); + return r; + } + + return ArcClose(partition_id); +} + + +ARC_STATUS +FmtQueryFatPartitionList( + OUT PCHAR** FatPartitionList, + OUT PULONG ListLength + ) +/*++ + +Routine Description: + + This routine browses the component tree for all disk peripherals + and the attempts to open partitions on all of them. It add all + FAT partitions to the list and returns it. + +Arguments: + + FatPartitionList - Returns a list of FAT partitions. + ListLength - Returns the length of the list. + +Return Value: + + LowQueryPathList, ArcOpen, ArcClose, FmtIsFat, EIO, ENOMEM, ESUCCESS + +--*/ +{ + CONFIGURATION_TYPE config_type; + ARC_STATUS r; + PCHAR* peripheral_list; + ULONG peripheral_list_length; + ULONG i, j; + ULONG num_partitions; + CHAR partition_buf[21]; + ULONG partition_id; + PCHAR* fat_partition_list; + ULONG fat_partition_list_length; + BOOLEAN is_fat; + PCHAR partition_name; + + + // First get a list of the all of the disk peripheral paths. + + config_type = DiskPeripheral; + r = LowQueryPathList(NULL, &config_type, &peripheral_list, + &peripheral_list_length); + + if (r != ESUCCESS) { + return r; + } + + // Now we have a list of disk peripheral paths. + + + + // Next, count how many partitions there are. + + num_partitions = 0; + for (i = 0; i < peripheral_list_length; i++) { + + partition_name = AllocateMemory(strlen(peripheral_list[i]) + 21); + + if (!partition_name) { + LowFreePathList(peripheral_list, peripheral_list_length); + return ENOMEM; + } + + for (j = 1; ; j++) { + + strcpy(partition_name, peripheral_list[i]); + sprintf(partition_buf, "partition(%d)", j); + strcat(partition_name, partition_buf); + + r = ArcOpen(partition_name, ArcOpenReadOnly, &partition_id); + + if (r != ESUCCESS) { + break; + } + + num_partitions++; + + r = ArcClose(partition_id); + + if (r != ESUCCESS) { + LowFreePathList(peripheral_list, peripheral_list_length); + FreeMemory(partition_name); + return r; + } + } + + FreeMemory(partition_name); + } + + // 'num_partitions' indicates the number of partitions on the disk. + + + // Allocate a buffer for the FAT partitions list. There can be + // no more FAT partitions then there are partitions. + + fat_partition_list = (PCHAR*) AllocateMemory(num_partitions*sizeof(PCHAR)); + + if (!fat_partition_list) { + LowFreePathList(peripheral_list, peripheral_list_length); + return ENOMEM; + } + + for (i = 0; i < num_partitions; i++) { + fat_partition_list[i] = NULL; + } + + fat_partition_list_length = 0; + + // 'fat_partition_list_length' indicates the number of FAT partitions. + + + + // Now go through all of the peripherals trying all possible + // partitions on each. Test these to see if they are FAT and + // put the FAT ones in 'fat_partitions_list'. + + for (i = 0; i < peripheral_list_length; i++) { + + partition_name = AllocateMemory(strlen(peripheral_list[i]) + 21); + + if (!partition_name) { + LowFreePathList(peripheral_list, peripheral_list_length); + LowFreePathList(fat_partition_list, fat_partition_list_length); + return ENOMEM; + } + + for (j = 1; ; j++) { + + strcpy(partition_name, peripheral_list[i]); + sprintf(partition_buf, "partition(%d)", j); + strcat(partition_name, partition_buf); + + r = ArcOpen(partition_name, ArcOpenReadOnly, &partition_id); + + if (r != ESUCCESS) { + break; + } + + r = ArcClose(partition_id); + + if (r != ESUCCESS) { + LowFreePathList(peripheral_list, peripheral_list_length); + LowFreePathList(fat_partition_list, fat_partition_list_length); + FreeMemory(partition_name); + return r; + } + + r = FmtIsFat(partition_name, &is_fat); + + if (r != ESUCCESS) { + LowFreePathList(peripheral_list, peripheral_list_length); + LowFreePathList(fat_partition_list, fat_partition_list_length); + FreeMemory(partition_name); + return r; + } + + if (is_fat) { + + if (fat_partition_list_length == num_partitions) { + // This can't happen. + LowFreePathList(peripheral_list, peripheral_list_length); + LowFreePathList(fat_partition_list, fat_partition_list_length); + FreeMemory(partition_name); + return EIO; + } + + fat_partition_list[fat_partition_list_length] = + AllocateMemory(strlen(partition_name) + 1); + + if (!fat_partition_list[fat_partition_list_length]) { + LowFreePathList(peripheral_list, peripheral_list_length); + LowFreePathList(fat_partition_list, fat_partition_list_length); + FreeMemory(partition_name); + return ENOMEM; + } + + strcpy(fat_partition_list[fat_partition_list_length], partition_name); + + fat_partition_list_length++; + } + } + + FreeMemory(partition_name); + } + + LowFreePathList(peripheral_list, peripheral_list_length); + + *FatPartitionList = fat_partition_list; + *ListLength = fat_partition_list_length; + + return ESUCCESS; +} + + +ARC_STATUS +FmtFreeFatPartitionList( + IN OUT PCHAR* FatPartitionList, + IN ULONG ListLength + ) +/*++ + +Routine Description: + + This routine frees up the heap space taken by the FAT partition + list. + +Arguments: + + FatPartitionList - Supplies the buffer to free. + ListLength - Supplies the buffer length. + +Return Value: + + LowFreePathList + +--*/ +{ + return LowFreePathList(FatPartitionList, ListLength); +} diff --git a/private/ntos/arcinst/jzcrap.c b/private/ntos/arcinst/jzcrap.c new file mode 100644 index 000000000..8cc77c1a9 --- /dev/null +++ b/private/ntos/arcinst/jzcrap.c @@ -0,0 +1,52 @@ +#include "precomp.h" +#pragma hdrstop + +VOID +JzDeleteVariableSegment ( + PCHAR VariableName, + ULONG Selection + ) +{ + PCHAR Variable; + CHAR VariableValue[MAXIMUM_ENVIRONMENT_VALUE]; + ULONG Index; + ULONG Count; + BOOLEAN FirstSegment; + + if ((Variable = ArcGetEnvironmentVariable(VariableName)) == NULL) { + return; + } + + FirstSegment = TRUE; + Index = 0; + *VariableValue = 0; + while (strchr(Variable,';') != NULL) { + Count = strchr(Variable,';') - Variable; + if (Index != Selection) { + if (!FirstSegment) { + strcat(VariableValue,";"); + } + strncat(VariableValue, Variable, Count); + FirstSegment = FALSE; + } + Variable += Count + 1; + Index++; + } + + if (Index != Selection) { + if (!FirstSegment) { + strcat(VariableValue,";"); + } + strcat(VariableValue,Variable); + } + + ArcSetEnvironmentVariable(VariableName, VariableValue); + return; +} + +PCHAR BootString[] = { "LOADIDENTIFIER", + "SYSTEMPARTITION", + "OSLOADER", + "OSLOADPARTITION", + "OSLOADFILENAME", + "OSLOADOPTIONS" }; diff --git a/private/ntos/arcinst/low.c b/private/ntos/arcinst/low.c new file mode 100644 index 000000000..e24324f44 --- /dev/null +++ b/private/ntos/arcinst/low.c @@ -0,0 +1,1186 @@ +#include "precomp.h" +#pragma hdrstop +#include + +ARC_STATUS +LowOpenDisk( + IN PCHAR DevicePath, + OUT PULONG DiskId + ) +/*++ + +Routine Description: + + This routine opens the supplied device for DASD access. + +Arguments: + + DevicePath - Supplies the device path to be opened. + DiskId - Returns the disk id. + +Return Value: + + ArcOpen + +--*/ +{ + char buffer[256]; + + sprintf(buffer,"%spartition(0)",DevicePath); + + return ArcOpen(buffer, ArcOpenReadWrite, DiskId); +} + + +ARC_STATUS +LowCloseDisk( + IN ULONG DiskId + ) +/*++ + +Routine Description: + + This routine closes the supplied device. + +Arguments: + + DiskId - Supplies the disk id. + +Return Value: + + ArcClose + +--*/ +{ + return ArcClose(DiskId); +} + +ARC_STATUS +LowGetDriveGeometry( + IN PCHAR DevicePath, + OUT PULONG TotalSectorCount, + OUT PULONG SectorSize, + OUT PULONG SectorsPerTrack, + OUT PULONG Heads + ) +{ + char Buffer[256]; + + sprintf(Buffer,"%spartition(0)",DevicePath); + return(LowGetPartitionGeometry(Buffer,TotalSectorCount,SectorSize,SectorsPerTrack,Heads)); +} + + + +ARC_STATUS +LowGetPartitionGeometry( + IN PCHAR PartitionPath, + OUT PULONG TotalSectorCount, + OUT PULONG SectorSize, + OUT PULONG SectorsPerTrack, + OUT PULONG Heads + ) +/*++ + +Routine Description: + + This routine computes the drive geometry for the given partition or + physical disk. + +Arguments: + + PartitionPath - Supplies a path to the partition or physical disk. + NumberOfSectors - Returns the number of sectors. + SectorSize - Returns the sector size. + SectorsPerTrack - Returns the number of sectors per track. + Heads - Returns the number of heads. + +Return Value: + + ArcOpen, ArcGetFileInformation, ArcClose, E2BIG, ESUCCESS + +--*/ +{ + FILE_INFORMATION file_info; + ARC_STATUS r; + ULONG fileid; + LARGE_INTEGER l; + CM_DISK_GEOMETRY_DEVICE_DATA *DiskGeometry; + CONFIGURATION_COMPONENT *DiskComponent; + CM_PARTIAL_RESOURCE_LIST *DiskConfiguration; + CHAR DataBuffer[sizeof(CM_PARTIAL_RESOURCE_LIST) + + sizeof(CM_DISK_GEOMETRY_DEVICE_DATA)]; + CM_PARTIAL_RESOURCE_DESCRIPTOR *DiskData; + + // Always assume 512 bytes per sector. + + *SectorSize = 512; + + // Assume the SCSI default values for number of heads and sectors per track + + *SectorsPerTrack = 32; + *Heads = 64; + + // See if there is device specific data describing the geometry of + // the drive. If there is none, then just use the default SCSI + // values. + + DiskComponent = ArcGetComponent(PartitionPath); + + if (DiskComponent == NULL) { + return EINVAL; + } + + // + // See if the ConfigurationDataLength is correct + // It should contain one DeviceSpecific resource descriptor + // + + if (DiskComponent->ConfigurationDataLength == sizeof(CM_PARTIAL_RESOURCE_LIST) + + sizeof(CM_DISK_GEOMETRY_DEVICE_DATA) ) { + + DiskConfiguration = (CM_PARTIAL_RESOURCE_LIST *)DataBuffer; + + r = ArcGetConfigurationData(DiskConfiguration,DiskComponent); + + if (r == ESUCCESS) { + + // + // See if the Configuration Data has ARC version 1.3 or greater + // + + if ( (DiskConfiguration->Version == 1 && DiskConfiguration->Revision >=3 ) || + (DiskConfiguration->Version > 1) ) { + + DiskData = &(DiskConfiguration->PartialDescriptors[DiskConfiguration->Count-1]); + + if (DiskData->Type == CmResourceTypeDeviceSpecific) { + + if (DiskData->u.DeviceSpecificData.DataSize == sizeof(CM_DISK_GEOMETRY_DEVICE_DATA)) { + DiskGeometry = (CM_DISK_GEOMETRY_DEVICE_DATA *) + &(DiskConfiguration->PartialDescriptors[DiskConfiguration->Count]); + *SectorsPerTrack = DiskGeometry->SectorsPerTrack; + *Heads = DiskGeometry->NumberOfHeads; + *SectorSize = DiskGeometry->BytesPerSector; + } + } + } + } + } + +// PrintError("SectorSize = %08x",*SectorSize); +// PrintError("SectorsPerTrack = %08x",*SectorsPerTrack); +// PrintError("Heads = %08x",*Heads); + + r = ArcOpen(PartitionPath, ArcOpenReadOnly, &fileid); + + if (r != ESUCCESS) { + return r; + } + + r = ArcGetFileInformation(fileid, &file_info); + + if (r != ESUCCESS) { + return r; + } + + r = ArcClose(fileid); + + if (r != ESUCCESS) { + return r; + } + + l.QuadPart = file_info.EndingAddress.QuadPart - + file_info.StartingAddress.QuadPart; + + l.QuadPart = ((ULONGLONG)l.QuadPart) / ((ULONGLONG)(*SectorSize)); + + if (l.HighPart) { + return E2BIG; + } + + *TotalSectorCount = l.LowPart; + + return ESUCCESS; +} + + +#define MAX_TRANSFER 65536 + + +ARC_STATUS +LowReadSectors( + IN ULONG VolumeId, + IN ULONG SectorSize, + IN ULONG StartingSector, + IN ULONG NumberOfSectors, + OUT PVOID Buffer + ) +/*++ + +Routine Description: + + This routine reads 'NumberOfSectors' sectors starting at sector + 'StartingSector' on the volume with ID 'VolumeId'. + +Arguments: + + VolumeId - Supplies the ID for the volume. + SectorSize - Supplies the number of bytes per sector. + StartingSector - Supplies the starting sector for the read. + NumberOfSectors - Supplies the number of sectors to read. + Buffer - Returns the read in sectors. + +Return Value: + + ArcSeek, ArcRead, EIO, ESUCCESS + +--*/ +{ + ARC_STATUS r; + ULONG c; + LARGE_INTEGER l; + ULONG i; + ULONG transfer; + PCHAR buf; + ULONG total; + + + l.QuadPart = UInt32x32To64(StartingSector,SectorSize); + + buf = (PCHAR) Buffer; + + r = ArcSeek(VolumeId, &l, SeekAbsolute); + + if (r != ESUCCESS) { + return r; + } + + total = SectorSize*NumberOfSectors; + + for (i = 0; i < total; i += MAX_TRANSFER) { + + transfer = min(MAX_TRANSFER, total - i); + + r = ArcRead(VolumeId, &buf[i], transfer, &c); + + if (r != ESUCCESS) { + return r; + } + + if (c != transfer) { + return EIO; + } + } + + return ESUCCESS; +} + + +ARC_STATUS +LowWriteSectors( + IN ULONG VolumeId, + IN ULONG SectorSize, + IN ULONG StartingSector, + IN ULONG NumberOfSectors, + IN PVOID Buffer + ) +/*++ + +Routine Description: + + This routine write 'NumberOfSectors' sectors starting at sector + 'StartingSector' on the volume with ID 'VolumeId'. + +Arguments: + + VolumeId - Supplies the ID for the volume. + SectorSize - Supplies the number of bytes per sector. + StartingSector - Supplies the starting sector for the write. + NumberOfSectors - Supplies the number of sectors to write. + Buffer - Supplies the sectors to write. + +Return Value: + + ArcSeek, ArcWrite, EIO, ESUCCESS + +--*/ +{ + ARC_STATUS r; + ULONG c; + LARGE_INTEGER l; + ULONG i; + ULONG transfer; + PCHAR buf; + ULONG total; + + l.QuadPart = UInt32x32To64(StartingSector,SectorSize); + + buf = (PCHAR) Buffer; + + r = ArcSeek(VolumeId, &l, SeekAbsolute); + + if (r != ESUCCESS) { + return r; + } + + total = SectorSize*NumberOfSectors; + + for (i = 0; i < total; i += MAX_TRANSFER) { + + transfer = min(MAX_TRANSFER, total - i); + + r = ArcWrite(VolumeId, &buf[i], transfer, &c); + + if (r != ESUCCESS) { + return r; + } + + if (c != transfer) { + return EIO; + } + } + + return ESUCCESS; +} + + +/******************** DAVIDRO CODE *************************************/ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + alpath.c + +Abstract: + + This module provides ARC pathname functions. + +Author: + + David M. Robinson (davidro) 13-November-1991 + +Revision History: + +--*/ + +// +// Define the ARC pathname mnemonics. +// + +PCHAR MnemonicTable[] = { + "arc", + "cpu", + "fpu", + "pic", + "pdc", + "sic", + "sdc", + "sc", + "eisa", + "tc", + "scsi", + "dti", + "multi", + "disk", + "tape", + "cdrom", + "worm", + "serial", + "net", + "video", + "par", + "point", + "key", + "audio", + "other", + "rdisk", + "fdisk", + "tape", + "modem", + "monitor", + "print", + "pointer", + "keyboard", + "term", + "other", + "line", + "netper", + "memory" + }; + +// +// Static storage for the pathname return value. +// + +CHAR Pathname[256]; + + +PCHAR +AlGetPathnameFromComponent ( + IN PCONFIGURATION_COMPONENT Component + ) + +/*++ + +Routine Description: + + This function builds an ARC pathname for the specified component. + +Arguments: + + Component - Supplies a pointer to a configuration component. + +Return Value: + + Returns a pointer to a string which contains the ARC pathname for the + component. NOTE: The string is stored in static storage, and must be + copied by the user before another call to this routine. + +--*/ +{ + PCONFIGURATION_COMPONENT ParentComponent; + CHAR NewSegment[16]; + CHAR Tempname[256]; + + Pathname[0] = 0; + + // + // Loop while not at the root component. + // + + while ((ParentComponent = ArcGetParent(Component)) != NULL) { + + // + // Build new pathname segment from the Component type and key. + // + + sprintf(NewSegment, + "%s(%d)", + MnemonicTable[Component->Type], + Component->Key); + + // + // Add the new segment as a prefix of the current pathname. + // + + strcpy(Tempname, Pathname); + strcpy(Pathname, NewSegment); + strcat(Pathname, Tempname); + + // + // Move to the parent component. + // + + Component = ParentComponent; + } + + return Pathname; +} +/******************* END OF DAVIDRO CODE *********************************/ + + +ARC_STATUS +LowQueryPathFromComponent( + IN PCONFIGURATION_COMPONENT Component, + OUT PCHAR* Path + ) +/*++ + +Routine Description: + + This routine computes a path from a component. The resulting + path is allocated on the heap. + +Arguments: + + Component - Supplies a component. + Path - Returns the path corresponding to that component. + +Return Value: + + ENOMEM, ESUCCESS + +--*/ +{ + PCHAR p; + PCHAR path; + + p = AlGetPathnameFromComponent(Component); + + path = AllocateMemory(strlen(p) + 1); + + if (!path) { + return ENOMEM; + } + + strcpy(path, p); + + *Path = path; + + return ESUCCESS; +} + + +ARC_STATUS +LowTraverseChildren( + IN PCONFIGURATION_COMPONENT Parent, + IN CONFIGURATION_CLASS* ConfigClass OPTIONAL, + IN CONFIGURATION_TYPE* ConfigType OPTIONAL, + IN OUT PCONFIGURATION_COMPONENT* MatchingArray OPTIONAL, + IN OUT PULONG CurrentLength + ) +/*++ + +Routine Description: + + This routine traverses the trees whose parent is 'Parent'. + If the Matching array is provided then it will be filled + with pointers to all of the components whose type and class + match 'ConfigType' and 'ConfigClass'. Also, the 'CurrentLength' + is incremented by the number of nodes that match. + +Arguments: + + Parent - Supplies the root of the tree. + ConfigClass - Supplies the class to search for. + ConfigType - Supplies the type to search for. + CurrentLength - Supplies the current count. + +Return Value: + + ESUCCESS + +--*/ +{ + PCONFIGURATION_COMPONENT pc; + ARC_STATUS r; + + if (!(pc = ArcGetChild(Parent))) { + return ESUCCESS; + } + + for (;;) { + + if ((!ConfigClass || pc->Class == *ConfigClass) && + (!ConfigType || pc->Type == *ConfigType)) { + + if (MatchingArray) { + + MatchingArray[*CurrentLength] = pc; + } + + (*CurrentLength)++; + } + + r = LowTraverseChildren(pc, ConfigClass, ConfigType, + MatchingArray, CurrentLength); + + if (r != ESUCCESS) { + return r; + } + + if (!(pc = ArcGetPeer(pc))) { + break; + } + } + + return ESUCCESS; +} + + +ARC_STATUS +LowQueryComponentList( + IN CONFIGURATION_CLASS* ConfigClass OPTIONAL, + IN CONFIGURATION_TYPE* ConfigType OPTIONAL, + OUT PCONFIGURATION_COMPONENT** ComponentList, + OUT PULONG ListLength + ) +/*++ + +Routine Description: + + This routine returns an array of components whose class and + type match the ones given. (Since each parameter is optional, + you can do type-only and class-only searches.) + + The array is allocated on the heap and contains pointers to + the actual components (NOT copies). + +Arguments: + + ConfigClass - Supplies the configuation class to search for. + ConfigType - Supplies the configuration type to search for. + ComponentList - Returns a list of pointers to components whose + class and type match 'ConfigClass' and + 'ConfigType'. + ListLength - Returns the number of components in the list. + +Return Value: + + LowTraverseChildren, ENOMEM + +--*/ +{ + ARC_STATUS r; + + *ListLength = 0; + + r = LowTraverseChildren(NULL, ConfigClass, ConfigType, NULL, ListLength); + + if (r != ESUCCESS) { + return r; + } + + if (!(*ComponentList = (PCONFIGURATION_COMPONENT*) AllocateMemory( + (*ListLength)*sizeof(PCONFIGURATION_COMPONENT)))) { + + return ENOMEM; + } + + *ListLength = 0; + + return LowTraverseChildren(NULL, ConfigClass, ConfigType, + *ComponentList, ListLength); +} + + +ARC_STATUS +LowQueryPathList( + IN CONFIGURATION_CLASS* ConfigClass OPTIONAL, + IN CONFIGURATION_TYPE* ConfigType OPTIONAL, + OUT PCHAR** PathList, + OUT PULONG ListLength + ) +/*++ + +Routine Description: + + This routine returns a list of paths to the components that are + of class ConfigClass and of type ConfigType. + +Arguments: + + ConfigClass - Supplies the configuation class to search for. + ConfigType - Supplies the configuration type to search for. + PathList - Returns a list of paths to the components. + ListLength - Returns the number of components in the list. + +Return Value: + + LowQueryComponentList, LowQueryPathFromComponent + +--*/ +{ + PCONFIGURATION_COMPONENT* component_list; + ULONG list_length; + ARC_STATUS r; + ULONG i; + PCHAR* path_list; + + r = LowQueryComponentList(ConfigClass, ConfigType, + &component_list, &list_length); + + if (r != ESUCCESS) { + return r; + } + + if (!(path_list = (PCHAR*) AllocateMemory(list_length*sizeof(PCHAR)))) { + FreeMemory(component_list); + return ENOMEM; + } + + + for (i = 0; i < list_length; i++) { + path_list[i] = NULL; + } + + for (i = 0; i < list_length; i++) { + + r = LowQueryPathFromComponent(component_list[i], &path_list[i]); + + if (r != ESUCCESS) { + FreeMemory(component_list); + LowFreePathList(path_list, list_length); + return r; + } + } + + FreeMemory(component_list); + + *PathList = path_list; + *ListLength = list_length; + + return ESUCCESS; +} + + +ARC_STATUS +LowFreePathList( + IN PCHAR* PathList, + IN ULONG ListLength + ) +/*++ + +Routine Description: + + This routine frees up the space taken by the path lists. + +Arguments: + + PathList - Supplies the paths. + ListLength - Supplies the number of paths. + +Return Value: + + ESUCCESS + +--*/ +{ + ULONG i; + + for (i = 0; i < ListLength; i++) { + if (PathList[i]) { + FreeMemory(PathList[i]); + } + } + FreeMemory(PathList); + + return ESUCCESS; +} + + +ARC_STATUS +LowQueryFdiskPathList( + OUT PCHAR** PathList, + OUT PULONG ListLength + ) +/*++ + +Routine Description: + + This routine returns a list of paths to all the devices of interest + to FDISK. + +Arguments: + + PathList - Returns a list of paths. + ListLength - Returns the length of the list. + +Return Value: + + LowQueryComponentList, LowQueryPathFromComponent, ESUCCESS + +--*/ +{ + CONFIGURATION_TYPE config_type; + + config_type = DiskPeripheral; + return LowQueryPathList(NULL, &config_type, PathList, ListLength); +} + + +ARC_STATUS +LowFreeFdiskPathList( + IN OUT PCHAR* PathList, + IN ULONG ListLength + ) +/*++ + +Routine Description: + + This routine frees up the space taken by the path lists. + +Arguments: + + PathList - Supplies the paths. + ListLength - Supplies the number of paths. + +Return Value: + + ESUCCESS + +--*/ +{ + return LowFreePathList(PathList, ListLength); +} + + +ARC_STATUS +LowGetDiskLayout( + IN PCHAR Path, + OUT PDRIVE_LAYOUT_INFORMATION* DriveLayout + ) +{ + ARC_STATUS status; + ULONG Handle; + ULONG i,ExtendedStart,BootSector,Entry; + ULONG dummy,bps; + BOOLEAN Link,mbr; + PDRIVE_LAYOUT_INFORMATION DriveInfo; + PPARTITION_INFORMATION p; + PCHAR SectorBuffer; + PPARTITION_DESCRIPTOR ptable; + + +#define PSTART(p) ( \ + (ULONG) ((p)->StartingSectorLsb0) + \ + (ULONG) ((p)->StartingSectorLsb1 << 8) + \ + (ULONG) ((p)->StartingSectorMsb0 << 16) + \ + (ULONG) ((p)->StartingSectorMsb1 << 24) ) + +#define PLENGTH(p) ( \ + (ULONG) ((p)->PartitionLengthLsb0) + \ + (ULONG) ((p)->PartitionLengthLsb1 << 8) + \ + (ULONG) ((p)->PartitionLengthMsb0 << 16) + \ + (ULONG) ((p)->PartitionLengthMsb1 << 24) ) + + + + if((DriveInfo = AlAllocateHeap(sizeof(DRIVE_LAYOUT_INFORMATION) + (500*sizeof(PARTITION_INFORMATION)))) == NULL) { + return(ENOMEM); + } + p = &DriveInfo->PartitionEntry[0]; + + if((status = LowGetDriveGeometry(Path,&dummy,&bps,&dummy,&dummy)) != ESUCCESS) { + AlDeallocateHeap(DriveInfo); + return(status); + } + + if((SectorBuffer = AlAllocateHeap(bps)) == NULL) { + AlDeallocateHeap(DriveInfo); + return(ENOMEM); + } + + ptable = (PPARTITION_DESCRIPTOR)(SectorBuffer + (2*PARTITION_TABLE_OFFSET)); + + if((status = LowOpenDisk(Path,&Handle)) != ESUCCESS) { + AlDeallocateHeap(SectorBuffer); + AlDeallocateHeap(DriveInfo); + return(status); + } + + mbr = TRUE; + Entry = 0; + BootSector = 0; + ExtendedStart = 0; + status = ESUCCESS; + + do { + + if((status = LowReadSectors(Handle,bps,BootSector,1,SectorBuffer)) != ESUCCESS) { + break; + } + + // This is to catch the case where there is no MBR yet. + + if(((PUSHORT)SectorBuffer)[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE) { + break; + } + + Link = FALSE; + + for(i=0; iPartitionCount = Entry; + + *DriveLayout = DriveInfo; + + return(ESUCCESS); +} + + +// +// cylinder/head/sector stuff placed in partition table +// + +typedef struct _tagCHS { + USHORT StartCylinder; + UCHAR StartHead; + UCHAR StartSector; + USHORT EndCylinder; + UCHAR EndHead; + UCHAR EndSector; +} CHS, *PCHS; + + +VOID +CalculateCHSVals( + IN ULONG Start, + IN ULONG Size, + IN ULONG spt, + IN ULONG h, + OUT PCHS chs + ) +{ + ULONG spc = spt * h; // sectors per cylinder + ULONG r; + ULONG End = Start+Size-1; + + chs->StartCylinder = (USHORT)(Start/spc); + r = Start % spc; + chs->StartHead = (UCHAR)(r / spt); + chs->StartSector = (UCHAR)((r % spt) + 1); // sector is 1-based + + chs->EndCylinder = (USHORT)(End/spc); + r = End % spc; + chs->EndHead = (UCHAR)(r / spt); + chs->EndSector = (UCHAR)((r % spt) + 1); // sector is 1-based +} + + +VOID +SetPartitionTableEntry( + IN OUT PPARTITION_DESCRIPTOR p, + IN UCHAR Active, + IN UCHAR SysID, + IN ULONG RelativeSector, + IN ULONG SectorCount, + IN PCHS chs + ) +{ + // first get the easy ones out of the way. + + p->ActiveFlag = Active; + p->PartitionType = SysID; + + if(chs) { + p->StartingTrack = chs->StartHead; + p->EndingTrack = chs->EndHead; + } else { + p->StartingTrack = 0; + p->EndingTrack = 0; + } + + if(chs) { + + // pack sector/cyl values + + p->StartingCylinderLsb = (chs->StartSector & 0x3f) | ((chs->StartCylinder >> 2) & 0xc0); + p->StartingCylinderMsb = (UCHAR)chs->StartCylinder; + + p->EndingCylinderLsb = (chs->EndSector & 0x3f) | ((chs->EndCylinder >> 2) & 0xc0); + p->EndingCylinderMsb = (UCHAR)chs->EndCylinder; + + } else { + + p->StartingCylinderLsb = 0; + p->StartingCylinderMsb = 0; + + p->EndingCylinderLsb = 0; + p->EndingCylinderMsb = 0; + } + + // now handle the relative and total sector counts + + p->StartingSectorLsb0 = (UCHAR)(RelativeSector >> 0 ); + p->StartingSectorLsb1 = (UCHAR)(RelativeSector >> 8 ); + p->StartingSectorMsb0 = (UCHAR)(RelativeSector >> 16); + p->StartingSectorMsb1 = (UCHAR)(RelativeSector >> 24); + + p->PartitionLengthLsb0 = (UCHAR)(SectorCount >> 0 ); + p->PartitionLengthLsb1 = (UCHAR)(SectorCount >> 8 ); + p->PartitionLengthMsb0 = (UCHAR)(SectorCount >> 16); + p->PartitionLengthMsb1 = (UCHAR)(SectorCount >> 24); +} + + +#define ZeroPartitionTableEntry(p) SetPartitionTableEntry(p,0,SYSID_UNUSED,0,0,NULL); + +VOID +ZeroPartitionTable( + PPARTITION_DESCRIPTOR PartitionTable + ) +{ + ULONG i; + + for(i=0; iPartitionCount); + + if((status = LowGetDriveGeometry(Path,&dummy,&bps,&spt,&h)) != ESUCCESS) { + return(status); + } + + // allocate a buffer for sector I/O + + if((SectorBuffer = AlAllocateHeap(bps)) == NULL) { + return(ENOMEM); + } + + // + // Use x86 bootcode as a template so the disk will boot an x86 + // if it is moved to disk0 on an x86 machine. + // + RtlMoveMemory(SectorBuffer,x86BootCode,min(X86BOOTCODE_SIZE,bps)); + + ((PUSHORT)SectorBuffer)[BOOT_SIGNATURE_OFFSET] = BOOT_RECORD_SIGNATURE; + PartitionTable = (PPARTITION_DESCRIPTOR)(&(((PUSHORT)SectorBuffer)[PARTITION_TABLE_OFFSET])); + + if((status = LowOpenDisk(Path,&Handle)) != ESUCCESS) { + AlDeallocateHeap(SectorBuffer); + return(status); + } + + ASRT(!(DriveLayout->PartitionCount % ENTRIES_PER_BOOTSECTOR)); + for(i=0; iPartitionCount; i+=ENTRIES_PER_BOOTSECTOR) { + + Update = FALSE; + UsedCount = 0; + + ZeroPartitionTable(PartitionTable); + + for(j=0; jPartitionEntry[i+j]; + + switch(p->PartitionType) { + case SYSID_UNUSED: + ZeroPartitionTableEntry(PartitionTable+j); + break; + + case SYSID_EXTENDED: + NextBootSector = SECCNT(p->StartingOffset); + CalculateCHSVals(NextBootSector,SECCNT(p->PartitionLength),spt,h,&chs); + SetPartitionTableEntry(PartitionTable+j, + p->BootIndicator, + SYSID_EXTENDED, + SECCNT(p->StartingOffset) - ExtendedPartitionStart, + SECCNT(p->PartitionLength), + &chs + ); + if(mbr) { + mbr = FALSE; + ExtendedPartitionStart = NextBootSector; + } + break; + + default: + CalculateCHSVals(SECCNT(p->StartingOffset),SECCNT(p->PartitionLength),spt,h,&chs); + SetPartitionTableEntry(PartitionTable+j, + p->BootIndicator, + p->PartitionType, + SECCNT(p->StartingOffset) - BootSector, + SECCNT(p->PartitionLength), + &chs + ); + break; + } + Update = Update || p->RewritePartition; + + if(p->PartitionType != SYSID_UNUSED) { + UsedCount++; + } + } + if(Update || !UsedCount) { + if((status = LowWriteSectors(Handle,bps,BootSector,1,SectorBuffer)) != ESUCCESS) { + LowCloseDisk(Handle); + AlDeallocateHeap(SectorBuffer); + return(status); + } + } + BootSector = NextBootSector; + } + + LowCloseDisk(Handle); + AlDeallocateHeap(SectorBuffer); + return(ESUCCESS); +} diff --git a/private/ntos/arcinst/makefile b/private/ntos/arcinst/makefile new file mode 100644 index 000000000..14f79b701 --- /dev/null +++ b/private/ntos/arcinst/makefile @@ -0,0 +1 @@ +!include $(NTMAKEENV)\makefile.def diff --git a/private/ntos/arcinst/makefile.inc b/private/ntos/arcinst/makefile.inc new file mode 100644 index 000000000..20f0257fb --- /dev/null +++ b/private/ntos/arcinst/makefile.inc @@ -0,0 +1 @@ +!INCLUDE $(TARGET_DIRECTORY)\mk.inc diff --git a/private/ntos/arcinst/memory.c b/private/ntos/arcinst/memory.c new file mode 100644 index 000000000..4160044e4 --- /dev/null +++ b/private/ntos/arcinst/memory.c @@ -0,0 +1,1184 @@ +#include "precomp.h" +#pragma hdrstop + +// +// SEGMENT_HEADER is the header that resides at the beginning of every +// segment of memory managed by this package. For non-growable heaps, +// there is only one segment for the entire heap. For growable heaps, +// segments are created as needed whenever there is not enough free space +// to satisfy an allocation request. +// +typedef struct _SEGMENT_HEADER { + struct _SEGMENT_HEADER *Next; + ULONG Size; + ULONG Spare[ 2 ]; // Make sizeof match granularity +} SEGMENT_HEADER, *PSEGMENT_HEADER; + +// +// FREE_HEADER is the header that resides at the beginning of every +// free block of memory managed by this package. All free blocks are +// linked together on a free list rooted in the heap header. The segment +// field of a free header prevents free blocks in different segments from +// being coalesced. +// +typedef struct _FREE_HEADER { + struct _FREE_HEADER *Next; + ULONG Size; + struct _SEGMENT_HEADER *Segment; + ULONG Spare; +} FREE_HEADER, *PFREE_HEADER; + +// +// BUSY_HEADER is the header that resides at the beginning of allocated +// block of memory managed by this package. When the block is +// allocated, the Busy structure is valid. The address that the user +// sees actually points to the byte following the header. When the +// block is on the free list, the Free structure is valid. +// +typedef struct _BUSY_HEADER { + struct _SEGMENT_HEADER *Segment; + ULONG Size; + HANDLE HandleValue; + ULONG Spare; +} BUSY_HEADER, *PBUSY_HEADER; + +// +// Flags are stored in the low order two bits of the first word of the +// header. This is possible, since all blocks are aligned on 16 byte +// boundaries. To make walking the free list fast, the flag value for +// a free block is zero, so we can use the Next pointer without modification. +// +#define FLAGS_FREE 0x00000000 +#define FLAGS_BUSY 0x00000001 +#define FLAGS_MASK 0x00000003 + +// +// All allocations are made as a multiple of ALLOCATION_GRANULARITY. +// The size requested is rounded up to a multiple of the allocation +// granularity. The size of an allocation header is then added and +// that is the amount of memory that is actually allocated. +// +#define ALLOCATION_GRANULARITY 16 // bytes + +// +// HEAP_HEADER is the header for a heap. All access to the heap is +// synchronized by the Lock field. +// +typedef struct _HEAP_HEADER { + // + // Heap routines use Length to determine if the heap is valid. + // + ULONG Length; + + // + // If the ZeroExtraMemory field is true, then the heap allocation + // logic will zero initialize any extra space at the end of an allocated + // block, due to rounding up to the ALIGNMENT_GRANULARITY amount. + // + BOOLEAN ZeroExtraMemory; + + // + // The address of the first valid address at the begining of the + // heap. Used for validating pointers passed to AlFreeHeap + // + PVOID ValidAddress; + + // + // The address of the first address of memory beyond the end of the heap + // + PVOID EndAddress; + + // + // FreeList is the header for the heap free list. + // + ULONG Spare; // Make free list align on granularity + FREE_HEADER FreeList; +} HEAP_HEADER, *PHEAP_HEADER; + + +// +// The heap is constructed out of a memory descriptor +// block that is below the descriptor for the loaded program. This block +// also accomodates the loaded program stack. It is essential therefore +// to estimate the stack space requirement for your arc program. (16 pages +// should be enough.) The StackPages and HeapPages are 4K each. +// + +#define HEAP_ZERO_EXTRA_MEMORY 0x00000008 +// +// Define memory allocation descriptor listhead and heap storage variables. +// + +ULONG AlHeapFree; +ULONG AlHeapLimit; + +PVOID HeapHandle; + + +PVOID +AlRtCreateHeap( + IN ULONG Flags, + IN PVOID HeapBase, + IN ULONG Size + ) + +/*++ + +Routine Description: + + This routine initializes a heap. + +Arguments: + + Flags - Specifies optional attributes of the heap. + + Valid Flags Values: + HEAP_ZERO_EXTRA_MEMORY. to make sure that extra memory passed + in is zeroed out. + + HeapBase - if not NULL, this specifies the base address for memory + to use as the heap. If NULL, memory is allocated by these routines. + + Size - Size of the block of memory passed in to be used as a heap + +Return Value: + + PVOID - a pointer to be used in accessing the created heap. + +--*/ + +{ + PHEAP_HEADER Heap = NULL; + PFREE_HEADER FreeBlock; + + + Heap = (PHEAP_HEADER)HeapBase; + Heap->Length = sizeof( HEAP_HEADER ); + Heap->ZeroExtraMemory = (BOOLEAN)((Flags & HEAP_ZERO_EXTRA_MEMORY) ? TRUE : FALSE); + Heap->ValidAddress = (PCH)Heap + ((sizeof(*Heap) + (ALLOCATION_GRANULARITY-1)) & ~(ALLOCATION_GRANULARITY-1)); + Heap->EndAddress = (PCH)Heap + Size; + + // + // Initialize the free list to be a single block that starts immediately + // after the heap header. + // + + FreeBlock = (PFREE_HEADER)Heap->ValidAddress; + FreeBlock->Next = NULL; + FreeBlock->Size = (ULONG)Heap->EndAddress - + (ULONG)FreeBlock; + FreeBlock->Segment = NULL; + + Heap->FreeList.Next = FreeBlock; + Heap->FreeList.Size = 0; + Heap->FreeList.Segment = NULL; + + return( (PVOID)Heap ); +} // AlRtCreateHeap + + + +#if DBG + +BOOLEAN +DumpHeapSegment( + BOOLEAN DumpHeap, + PHEAP_HEADER Heap, + PVOID FirstValidBlock, + PVOID FirstInvalidBlock, + PULONG CountOfFreeBlocks + ) +{ + PVOID CurrentBlock = FirstValidBlock; + PFREE_HEADER FreeBlock; + PBUSY_HEADER BusyBlock; + + while (CurrentBlock < FirstInvalidBlock) { + BusyBlock = CurrentBlock; + FreeBlock = CurrentBlock; + if (((ULONG)BusyBlock->Segment & FLAGS_MASK) == FLAGS_BUSY) { + if (DumpHeap) { + AlPrint( " %08lx: BUSY Flags=%lx Size: %lx Segment: %lx\n", + BusyBlock, + (ULONG)BusyBlock->Segment & FLAGS_MASK, + BusyBlock->Size, + (ULONG)BusyBlock->Segment & ~FLAGS_MASK + ); + } + + CurrentBlock = (PCH)CurrentBlock + BusyBlock->Size; + } + else + if (((ULONG)FreeBlock->Next & FLAGS_MASK) == FLAGS_FREE) { + *CountOfFreeBlocks += 1; + if (DumpHeap) { + AlPrint( " %08lx: FREE Next=%lx Size: %lx Segment: %lx\n", + FreeBlock, + FreeBlock->Next, + FreeBlock->Size, + FreeBlock->Segment + ); + } + + CurrentBlock = (PCH)CurrentBlock + FreeBlock->Size; + } + else { + if (DumpHeap) { + AlPrint( "*** Invalid heap block at %lx\n", CurrentBlock ); + } + + return( FALSE ); + } + + } + + if (CurrentBlock != FirstInvalidBlock) { + if (DumpHeap) { + AlPrint( "*** Heap segment ends at %lx instead of %lx\n", + CurrentBlock, FirstInvalidBlock + ); + } + + return( FALSE ); + } + + return( TRUE ); +} + + +BOOLEAN +AlRtValidateHeap( + IN PVOID HeapHandle, + IN BOOLEAN DumpHeap + ) +{ + PHEAP_HEADER Heap = (PHEAP_HEADER)HeapHandle; + PFREE_HEADER FreeBlock; + BOOLEAN HeapValid = TRUE; + ULONG LengthOfFreeList; + ULONG CountOfFreeBlocks; + + // + // Validate that HeapAddress points to a HEAP_HEADER structure. + // + + if (Heap->Length != sizeof( HEAP_HEADER )) { + if (DumpHeap) { + AlPrint( "AlRtHEAP: Invalid heap header- %lx\n", Heap ); + } + + HeapValid = FALSE; + goto exit; + } + + + if (DumpHeap) { + AlPrint( "Heap at %lx, Length=%lx\n", Heap, Heap->Length ); + AlPrint( " FreeList: Head=%lx\n", Heap->FreeList.Next ); + AlPrint( " Heap: End Address = %lx\n",Heap->EndAddress); + } + + + if (Heap->FreeList.Size != 0) { + if (DumpHeap) { + AlPrint( "*** head of free list is invalid (size)\n" ); + } + + HeapValid = FALSE; + goto exit; + } + + LengthOfFreeList = 0; + FreeBlock = Heap->FreeList.Next; + while (FreeBlock) { + if (DumpHeap) { + AlPrint( " %08lx: Next=%lx Size: %lx Segment: %lx\n", + FreeBlock, + FreeBlock->Next, + FreeBlock->Size, + FreeBlock->Segment + ); + } + + if (((ULONG)FreeBlock->Next & FLAGS_MASK) != FLAGS_FREE) { + if (DumpHeap) { + AlPrint( "*** free list element is not a valid free block\n" ); + } + + HeapValid = FALSE; + goto exit; + } + + LengthOfFreeList += 1; + FreeBlock = FreeBlock->Next; + } + + CountOfFreeBlocks = 0; + if (DumpHeap) { + AlPrint( " Heap Blocks starting at %lx:\n", Heap->ValidAddress ); + } + + HeapValid = DumpHeapSegment( DumpHeap, + Heap, + Heap->ValidAddress, + Heap->EndAddress, + &CountOfFreeBlocks + ); + if (!HeapValid) { + goto exit; + } + + if (LengthOfFreeList != CountOfFreeBlocks) { + if (DumpHeap) { + AlPrint( "*** Number of free blocks in arena (%ld) does not match number in the free list (%ld)\n", + CountOfFreeBlocks, + LengthOfFreeList + ); + } + + HeapValid = FALSE; + goto exit; + } + +exit: + return( HeapValid ); + +} // AlRtValidateHeap + + +#else + +BOOLEAN +AlRtValidateHeap( + IN PVOID HeapHandle, + IN BOOLEAN DumpHeap + ) +{ + return( TRUE ); +} + +#endif + + + +PVOID +AlRtAllocateHeap( + IN PVOID HeapHandle, + IN ULONG Size + ) +{ + PHEAP_HEADER Heap = (PHEAP_HEADER)HeapHandle; + ULONG allocationSize; +// PSEGMENT_HEADER Segment; + PFREE_HEADER FreeBlock; + PFREE_HEADER PreviousFreeBlock; + PFREE_HEADER NewFreeBlock; + PBUSY_HEADER BusyBlock; + + + // + // Validate that HeapAddress points to a HEAP_HEADER structure. + // + + if (Heap->Length != sizeof( HEAP_HEADER )) { +#if DBG + AlPrint( "ALHEAP: Invalid heap header- %lx\n", Heap ); +#endif // DBG + return( NULL ); + } + + // + // Additional check, see if the heap is valid, call the heap validation + // code, requesting it to not dump stuff. + // + if(!AlRtValidateHeap( HeapHandle, FALSE)) { + +#if DBG + AlPrint("Heap validation failed\n"); +#endif + return ( NULL ); + } + + + // + // Round the requested size up to the allocation granularity. Note + // that if the request is for 0 bytes, we still allocate memory. + // + + allocationSize = ((Size ? Size : ALLOCATION_GRANULARITY) + + sizeof( BUSY_HEADER ) + + ALLOCATION_GRANULARITY - + 1 + ) & ~(ALLOCATION_GRANULARITY - 1); + if (allocationSize < Size) { +#if DBG + AlPrint( "ALHEAP: Invalid heap size - %lx\n", Size ); +// RtlpBreakPointHeap(); +#endif // DBG + return( NULL ); + } + + // + // Point to the free list header. + // + + FreeBlock = &Heap->FreeList; +#if DBG + if (FreeBlock->Size != 0) { + AlPrint( "ALHEAP: Heap free list HEAD hosed at %lx\n", FreeBlock ); +// RtlpBreakPointHeap(); + + return( NULL ); + } +#endif // DBG + + // + // Continuous loop. We'll break out of the loop when we've found + // (or created) some free memory. + // + + while (TRUE) { + // + // Have we reached the end of the free list? + // + + if (FreeBlock->Next == NULL) + return( NULL ); + else { + // + // Point to the next free block, saving a pointer to the + // previous one. + // + + PreviousFreeBlock = FreeBlock; + FreeBlock = PreviousFreeBlock->Next; + } + +#if DBG + if (FreeBlock->Size == 0) { + AlPrint( "ALHEAP: Heap free list ENTRY hosed at %lx\n", + FreeBlock + ); +// RtlpBreakPointHeap(); + return( NULL ); + } +#endif // DBG + + // + // We haven't exhausted the free list yet. If this block is + // large enough for what we need, break out of the while loop. + // + + if (FreeBlock->Size >= allocationSize) { + break; + } + + } // while ( TRUE ) + + // + // We have found a free block that is large enough to hold what the + // user requested. If it's exactly the right size, simply point the + // previous free block to the successor of this free block. If it's + // larger than what we want, we allocate from the front of the block, + // leaving the trailing part free. Exactly the right size is fuzzy, + // as if we decide to split we need at least enough extra space for + // a free header plus some space to statisfy an allocation. + // + + if ((FreeBlock->Size - allocationSize) < (2 * sizeof( FREE_HEADER ))) { + // + // If the amount of extra space is less than twice the size of + // a free header, just give the caller all the space, as the + // extra amount is too small to waste a free block on. + // + + allocationSize = FreeBlock->Size; + + // + // Exactly the right size. Point previous free block to the + // next free block. + // + + PreviousFreeBlock->Next = FreeBlock->Next; + + } + else { + + // + // More memory than we need. Make the trailing part of the block + // into a free block. Point the previous block to the new block + // and the new block to the next block. + // + + NewFreeBlock = (PFREE_HEADER)((PCH)FreeBlock + allocationSize); + PreviousFreeBlock->Next = NewFreeBlock; + NewFreeBlock->Next = FreeBlock->Next; + NewFreeBlock->Size = FreeBlock->Size - allocationSize; + NewFreeBlock->Segment = FreeBlock->Segment; + } + + // + // Set up the header for the allocated block. + // + + BusyBlock = (PBUSY_HEADER)FreeBlock; + BusyBlock->Segment = (PSEGMENT_HEADER)((ULONG)FreeBlock->Segment | + FLAGS_BUSY + ); + BusyBlock->Size = allocationSize; + BusyBlock->HandleValue = NULL; + + if (Heap->ZeroExtraMemory) { + ULONG extraSize; + + extraSize = allocationSize - Size - sizeof( BUSY_HEADER ); + memset( (PCHAR)BusyBlock + (allocationSize - extraSize), + 0, + extraSize + ); + } + +#if DBG + BusyBlock->Spare = 0; +#endif + + // + // Return the address of the user portion of the allocated block. + // This is the byte following the header. + // + + return( (PVOID)(BusyBlock + 1) ); +} // AlRtAllocateHeap + + +PVOID +AlRtFreeHeap( + IN PVOID HeapHandle, + IN PVOID BaseAddress + ) +{ + PHEAP_HEADER Heap = (PHEAP_HEADER)HeapHandle; + PFREE_HEADER FreeBlock; + PFREE_HEADER PreviousFreeBlock; + PFREE_HEADER SecondPrevFreeBlock; + PBUSY_HEADER BusyBlock; + PSEGMENT_HEADER BusySegment; + ULONG BusyFlags; + ULONG BusySize; + + if (BaseAddress == NULL) { + return( NULL ); + } + + // + // Validate that HeapAddress points to a HEAP_HEADER structure. + // + + if (Heap->Length != sizeof( HEAP_HEADER )) { +#if DBG + AlPrint( "ALHEAP: Invalid heap header- %lx\n", Heap ); +// RtlpBreakPointHeap(); +#endif // DBG + return( BaseAddress ); + } + + // + // Additional check, see if the heap is valid, call the heap validation + // code, requesting it to not dump stuff. + // + if(!AlRtValidateHeap( HeapHandle, FALSE)) { + +#if DBG + AlPrint("Heap validation failed\n"); +#endif + return ( BaseAddress ); + } + + + // + // Get the 'real' address of the allocation unit. (That is, the + // address of the allocation header.) Make sure the address lies + // within the bounds of the valid portion of the heap. + // + + BusyBlock = (PBUSY_HEADER)BaseAddress - 1; + BusyFlags = (ULONG)BusyBlock->Segment & FLAGS_MASK; + BusySegment = (PSEGMENT_HEADER)((ULONG)BusyBlock->Segment & ~FLAGS_MASK); + BusySize = BusyBlock->Size; + + if (BusyFlags != FLAGS_BUSY +#if DBG + || (BusySegment == NULL && + ((PCHAR)BusyBlock < (PCHAR)Heap->ValidAddress || + (PCHAR)BusyBlock >= (PCHAR)Heap->EndAddress + ) + ) || + (BusySegment != NULL && + (BusyBlock < (PBUSY_HEADER)(BusySegment+1) || + BusyBlock >= (PBUSY_HEADER)((ULONG)BusySegment + BusySegment->Size) + ) + ) || + (BusySize < ALLOCATION_GRANULARITY + ) || + (BusySize & (ALLOCATION_GRANULARITY-1) != 0 + ) +#endif // DBG + ) { +#if DBG + AlPrint( "ALHEAP: Invalid Address specified to AlRtFreeHeap( %lx, %lx )\n", + Heap, + BaseAddress + ); +// RtlpBreakPointHeap(); +#endif // DBG + return( BaseAddress ); + } + + + // + // Free blocks are stored in the free list in ascending order by + // base address. As we search the free list to find the place for + // this block, we remember the previous two free blocks that we + // passed through. These are used during combining of adjacent + // free blocks. + // + + SecondPrevFreeBlock = NULL; + PreviousFreeBlock = &Heap->FreeList; +#if DBG + if (PreviousFreeBlock->Size != 0) { + AlPrint( "ALHEAP: Heap free list HEAD hosed at %lx\n", + PreviousFreeBlock + ); +// RtlpBreakPointHeap(); + + return( BaseAddress ); + } +#endif // DBG + + // + // Continuous loop. We'll break out of the loop when we've found + // the first block of free memory whose address is larger than the + // address of the block being freed. (Or the end of the free list.) + // + + while (TRUE) { + + // + // Get the address of the next free block. If we've exhausted + // the free list, break out of the loop -- the block we're + // freeing goes at the end of the list. + // + + FreeBlock = PreviousFreeBlock->Next; + + if (FreeBlock == NULL) { + break; + } + +#if DBG + if (FreeBlock->Size == 0) { + AlPrint( "ALHEAP: Heap free list ENTRY hosed at %lx\n", + FreeBlock + ); +// RtlpBreakPointHeap(); + + return( BaseAddress ); + } +#endif // DBG + + // + // If the address of the current block is higher than the + // address of the block we're freeing, break out of the loop. + // The freed block goes immediately before the current block. + // + + if (FreeBlock > (PFREE_HEADER)BusyBlock) { + break; + } + + // + // We haven't found the spot yet. Remember the last two blocks. + // + + SecondPrevFreeBlock = PreviousFreeBlock; + PreviousFreeBlock = FreeBlock; + + } // while ( TRUE ) + + + // + // We've found the place for the block we're freeing. If the previous + // block is adjacent to this one, merge the two by summing their sizes, + // adjusting the address of the block being freed, and making the second + // previous block the first previous block. (Note that the previous + // block may actually be the listhead. In this case, the if condition + // will never be true, because the Size of the listhead is 0.) + // + + if (((PCH)PreviousFreeBlock + PreviousFreeBlock->Size) == (PCH)BusyBlock && + PreviousFreeBlock->Segment == BusySegment + ) { + BusySize += PreviousFreeBlock->Size; + BusyBlock = (PBUSY_HEADER)PreviousFreeBlock; + PreviousFreeBlock = SecondPrevFreeBlock; +#if DBG + } + else + if ((PreviousFreeBlock != &Heap->FreeList) && + ((PCH)PreviousFreeBlock + PreviousFreeBlock->Size) > (PCH)BusyBlock + ) { + AlPrint( "ALHEAP: Heap free list overlaps freed block at %lx\n", + BusyBlock + ); +// RtlpBreakPointHeap(); + + return( BaseAddress ); +#endif // DBG + } + + // + // If the block being freed is adjacent to the current block, merge + // the two by summing their sizes and making the next block the + // current block. (Note that the current block may not exist, in + // which case FreeBlock == NULL, and the if condition will not be + // true.) + //*** There is an assumption here that we'll never EVER use the + //*** very highest part of the address space for user mode allocatable + //*** memory! + // + + if (((PCH)BusyBlock + BusySize) == (PCH)FreeBlock && + FreeBlock->Segment == BusySegment + ) { + BusySize += FreeBlock->Size; + FreeBlock = FreeBlock->Next; +#if DBG + if (FreeBlock != NULL) { + if (FreeBlock->Size == 0) { + AlPrint( "ALHEAP: Heap free list ENTRY hosed at %lx\n", + FreeBlock + ); +// RtlpBreakPointHeap(); + + return( BaseAddress ); + } + } + } + else + if ((FreeBlock != NULL) && + ((PCH)BusyBlock + BusySize) > (PCH)FreeBlock + ) { + AlPrint( "ALHEAP: Freed block overlaps heap free list at %lx\n", + BusyBlock + ); +// RtlpBreakPointHeap(); + + return( BaseAddress ); +#endif // DBG + } + + // + // Done merging. Update the free list and the free block header. + //*** May want to reclaim (i.e., release) pages sometime. That is, + //*** if we find ourselves with oodles of contiguous pages on the + //*** free list, we could delete them from our address space. On + //*** the other hand, it probably doesn't cost very much to keep + //*** them around, and if the process needed that much memory once, + //*** it's likely to need it again. + // + + PreviousFreeBlock->Next = (PFREE_HEADER)BusyBlock; + ((PFREE_HEADER)BusyBlock)->Next = FreeBlock; + ((PFREE_HEADER)BusyBlock)->Size = BusySize; + ((PFREE_HEADER)BusyBlock)->Segment = BusySegment; + + // + // Release the free list lock and return to the caller. + // + + + return( NULL ); +} // AlRtFreeHeap + + + +PVOID +AlRtReAllocateHeap( + IN PVOID HeapHandle, + IN PVOID BaseAddress, + IN ULONG Size + ) +{ + PHEAP_HEADER Heap = (PHEAP_HEADER)HeapHandle; + PVOID NewBaseAddress; + ULONG allocationSize; + PBUSY_HEADER BusyBlock; + PBUSY_HEADER ExtraBusyBlock; + PSEGMENT_HEADER BusySegment; + ULONG BusyFlags; + ULONG BusySize; + LONG DeltaSize; + + // + // Validate that HeapAddress points to a HEAP_HEADER structure. + // + + if (Heap->Length != sizeof( HEAP_HEADER )) { +#if DBG + AlPrint( "ALHEAP: Invalid heap header- %lx\n", Heap ); +// RtlpBreakPointHeap(); +#endif // DBG + return( NULL ); + } + + // + // Additional check, see if the heap is valid, call the heap validation + // code, requesting it to not dump stuff. + // + if(!AlRtValidateHeap( HeapHandle, FALSE)) { + +#if DBG + AlPrint("Heap validation failed\n"); +#endif + return ( NULL ); + } + + + // + // Round the requested size up to the allocation granularity. Note + // that if the request is for 0 bytes, we still allocate memory. + // + + allocationSize = ((Size ? Size : ALLOCATION_GRANULARITY) + + sizeof( BUSY_HEADER ) + + ALLOCATION_GRANULARITY - + 1 + ) & ~(ALLOCATION_GRANULARITY - 1); + + if (allocationSize < Size) { +#if DBG + AlPrint( "ALHEAP: Invalid heap size - %lx\n", Size ); +// RtlpBreakPointHeap(); +#endif // DBG + return( NULL ); + } + + if (BaseAddress == NULL) { +#if DBG + AlPrint( "ALHEAP: Invalid heap address - %lx\n", BaseAddress ); +// RtlpBreakPointHeap(); +#endif // DBG + return( NULL ); + } + + // + // Get the 'real' address of the allocation unit. (That is, the + // address of the allocation header.) Make sure the address lies + // within the bounds of the valid portion of the heap. + // + + BusyBlock = (PBUSY_HEADER)BaseAddress - 1; + BusySize = BusyBlock->Size; + BusySegment = (PSEGMENT_HEADER)((ULONG)BusyBlock->Segment & ~FLAGS_MASK); + BusyFlags = (ULONG)BusyBlock->Segment & FLAGS_MASK; + + if (BusyFlags != FLAGS_BUSY +#if DBG + || (BusySegment == NULL && + ((PCHAR)BusyBlock < (PCHAR)Heap->ValidAddress || + (PCHAR)BusyBlock >= (PCHAR)Heap->EndAddress + ) + ) || + (BusySegment != NULL && + (BusyBlock < (PBUSY_HEADER)(BusySegment+1) || + BusyBlock >= (PBUSY_HEADER)((ULONG)BusySegment + BusySegment->Size) + ) + ) || + (BusySize < ALLOCATION_GRANULARITY + ) || + (BusySize & (ALLOCATION_GRANULARITY-1) != 0 + ) +#endif // DBG + ) { +#if DBG + AlPrint( "ALHEAP: Invalid Address specified to AlRtFreeHeap( %lx, %lx )\n", + Heap, + BaseAddress + ); +// RtlpBreakPointHeap(); +#endif // DBG + return( NULL ); + } + + + // + // See if new size less than or equal to the current size. + // + + DeltaSize = (LONG)(BusySize - allocationSize); + if (DeltaSize >= 0) { + // + // Then shrinking block. If amount of shrinkage is less than + // the size of a free block, then nothing to do. + // + + if (DeltaSize < sizeof( FREE_HEADER )) { + if (Heap->ZeroExtraMemory) { + memset( (PCHAR)BusyBlock + (allocationSize - DeltaSize),0, + DeltaSize + ); + } + + return( BaseAddress ); + } + + // + // Otherwise, shrink size of this block to new size, and make extra + // space at end look like another busy block and call AlRtFreeHeap + // to free it. + // + + BusyBlock->Size = allocationSize; + ExtraBusyBlock = (PBUSY_HEADER)((PCH)BusyBlock + allocationSize); + ExtraBusyBlock->Segment = BusyBlock->Segment; + ExtraBusyBlock->Size = (ULONG)(DeltaSize); +#if DBG + ExtraBusyBlock->Spare = 0; +#endif + + AlRtFreeHeap( HeapHandle, (PVOID)(ExtraBusyBlock+1) ); + + if (Heap->ZeroExtraMemory) { + ULONG extraSize; + + extraSize = allocationSize - Size - sizeof( BUSY_HEADER ); + memset( (PCHAR)BusyBlock + (allocationSize - extraSize),0, + extraSize + ); + } + + return( BaseAddress ); + } + + // + // Otherwise growing block, so allocate a new block with the bigger + // size, copy the contents of the old block to the new block and then + // free the old block. Return the address of the new block. + // + + NewBaseAddress = AlRtAllocateHeap( HeapHandle, Size ); + if (NewBaseAddress != NULL) { +#if DBG + ExtraBusyBlock = (PBUSY_HEADER)NewBaseAddress - 1; + ExtraBusyBlock->Spare = 0; +#endif + memmove( NewBaseAddress, + BaseAddress, + BusySize - sizeof( BUSY_HEADER ) + ); + + AlRtFreeHeap( HeapHandle, BaseAddress ); + } + + return( NewBaseAddress ); +} + + + + +ARC_STATUS +AlMemoryInitialize ( + ULONG StackPages, + ULONG HeapPages + ) + +/*++ + +Routine Description: + + This routine allocates stack space for the OS loader, initializes + heap storage, and initializes the memory allocation list. + +Arguments: + + None. + +Return Value: + + ESUCCESS is returned if the initialization is successful. Otherwise, + ENOMEM is returned. + +--*/ + +{ + + PMEMORY_DESCRIPTOR FreeDescriptor; + PMEMORY_DESCRIPTOR ProgramDescriptor; + + // + // Find the memory descriptor that describes the allocation for the OS + // loader itself. + // + + ProgramDescriptor = NULL; + while ((ProgramDescriptor = ArcGetMemoryDescriptor(ProgramDescriptor)) != NULL) { + if (ProgramDescriptor->MemoryType == MemoryLoadedProgram) { + break; + } + } + + // + // If a loaded program memory descriptor was found, then it must be + // for the OS loader since that is the only program that can be loaded. + // If a loaded program memory descriptor was not found, then firmware + // is not functioning properly and an unsuccessful status is returned. + // + + if (ProgramDescriptor == NULL) { + return ENOMEM; + } + + // + // Find the free memory descriptor that is just below the loaded + // program in memory. There should be several megabytes of free + // memory just preceeding the OS loader. + // + + FreeDescriptor = NULL; + while ((FreeDescriptor = ArcGetMemoryDescriptor(FreeDescriptor)) != NULL) { + if ((FreeDescriptor->MemoryType == MemoryFree) && + (FreeDescriptor->PageCount >= (StackPages+HeapPages))) { + break; + } + } + + // + // If a free memory descriptor was not found that describes the free + // memory just below the OS loader, then firmware is not functioning + // properly and an unsuccessful status is returned. + // + + if (FreeDescriptor == NULL) { + return ENOMEM; + } + + // + // Check to determine if enough free memory is available for the OS + // loader stack and the heap area. If enough memory is not available, + // then return an unsuccessful status. + // + + if (FreeDescriptor->PageCount < (StackPages + HeapPages)) { + return ENOMEM; + } + + // + // Compute the address of the loader heap, initialize the heap + // allocation variables, and zero the heap memory. + // + + AlHeapFree = KSEG0_BASE | ((ProgramDescriptor->BasePage - + (StackPages + HeapPages)) << PAGE_SHIFT); + + AlHeapLimit = AlHeapFree + (HeapPages << PAGE_SHIFT); + + memset((PVOID)AlHeapFree, 0,HeapPages << PAGE_SHIFT); + + + // + // Changed to new heap allocater + // + + if ((HeapHandle = AlRtCreateHeap + ( + HEAP_ZERO_EXTRA_MEMORY, + (PVOID)AlHeapFree, + HeapPages << PAGE_SHIFT + )) + == NULL) + return ENOMEM; + else + return ESUCCESS; + +} + + +// +// AlAllocateHeap. +// +// Heap space allocator. Size is in bytes required. + +PVOID +AlAllocateHeap ( + IN ULONG Size + ) +{ + return (AlRtAllocateHeap + ( + HeapHandle, + Size + )); + +} + + + +// 3. AlDeallocateHeap +// +// Heap Deallocation needs to be defined and implemented. +// +// + +PVOID +AlDeallocateHeap ( + IN PVOID HeapAddress + ) +{ + return (AlRtFreeHeap + ( + HeapHandle, + HeapAddress + )); +} + + +// +// 4. AlReallocateHeap +// +// +// + +PVOID +AlReallocateHeap ( + IN PVOID HeapAddress, + IN ULONG NewSize + ) +{ + return (AlRtReAllocateHeap + ( + HeapHandle, + HeapAddress, + NewSize + )); +} + +// +// 5. AlValidateHeap +// +// Heap validation +// +// + +BOOLEAN +AlValidateHeap( + IN BOOLEAN DumpHeap + ) +{ + return (AlRtValidateHeap + ( + HeapHandle, + DumpHeap + )); +} + diff --git a/private/ntos/arcinst/mips/mk.inc b/private/ntos/arcinst/mips/mk.inc new file mode 100644 index 000000000..261d0d0e3 --- /dev/null +++ b/private/ntos/arcinst/mips/mk.inc @@ -0,0 +1,16 @@ +obj\mips\arcinst.exe: obj\mips\arcinst.lib makefile.inc + link -out:obj\mips\arcinst.exe @<< +-machine:mips +-align:0x200 +-rom +-fixed +-map:obj\mips\arcinst.map +-debug:notmapped +-debugtype:coff +-ignore:4001 +-base:0xa0600000,0xa0618000 +-entry:main +obj\mips\arcinst.lib +\nt\public\sdk\lib\mips\libcntpr.lib +<= 'a' && (C) <= 'z' ? (C) - ('a' - 'A') : (C))) + + +NTSTATUS +RtlAnsiStringToUnicodeString( + OUT PUNICODE_STRING DestinationString, + IN PANSI_STRING SourceString, + IN BOOLEAN AllocateDestinationString + ) + +{ + ULONG UnicodeLength; + ULONG Index; + NTSTATUS st; + + UnicodeLength = (SourceString->Length << 1) + sizeof(UNICODE_NULL); + + if ( UnicodeLength > MAXUSHORT ) { + return STATUS_INVALID_PARAMETER_2; + } + + DestinationString->Length = (USHORT)(UnicodeLength - sizeof(UNICODE_NULL)); + if ( AllocateDestinationString ) { + return STATUS_NO_MEMORY; + } + else { + if ( DestinationString->Length >= DestinationString->MaximumLength ) { + return STATUS_BUFFER_OVERFLOW; + } + } + + Index = 0; + while(Index < DestinationString->Length ) { + DestinationString->Buffer[Index] = (WCHAR)SourceString->Buffer[Index]; + Index++; + } + DestinationString->Buffer[Index] = UNICODE_NULL; + + return STATUS_SUCCESS; +} + +LONG +RtlCompareUnicodeString( + IN PUNICODE_STRING String1, + IN PUNICODE_STRING String2, + IN BOOLEAN CaseInSensitive + ) + +/*++ + +Routine Description: + + The RtlCompareUnicodeString function compares two counted strings. The + return value indicates if the strings are equal or String1 is less than + String2 or String1 is greater than String2. + + The CaseInSensitive parameter specifies if case is to be ignored when + doing the comparison. + +Arguments: + + String1 - Pointer to the first string. + + String2 - Pointer to the second string. + + CaseInsensitive - TRUE if case should be ignored when doing the + comparison. + +Return Value: + + Signed value that gives the results of the comparison: + + Zero - String1 equals String2 + + < Zero - String1 less than String2 + + > Zero - String1 greater than String2 + + +--*/ + +{ + + UNALIGNED WCHAR *s1, *s2; + USHORT n1, n2; + WCHAR c1, c2; + LONG cDiff; + + s1 = String1->Buffer; + s2 = String2->Buffer; + n1 = (USHORT )(String1->Length / sizeof(WCHAR)); + n2 = (USHORT )(String2->Length / sizeof(WCHAR)); + while (n1 && n2) { + c1 = *s1++; + c2 = *s2++; + + if (CaseInSensitive) { + // + // Note that this needs to reference the translation table ! + // + c1 = upcase(c1); + c2 = upcase(c2); + } + + if ((cDiff = ((LONG)c1 - (LONG)c2)) != 0) { + return( cDiff ); + } + + n1--; + n2--; + } + + return( n1 - n2 ); +} + +BOOLEAN +RtlEqualUnicodeString( + IN PUNICODE_STRING String1, + IN PUNICODE_STRING String2, + IN BOOLEAN CaseInSensitive + ) + +/*++ + +Routine Description: + + The RtlEqualUnicodeString function compares two counted unicode strings for + equality. + + The CaseInSensitive parameter specifies if case is to be ignored when + doing the comparison. + +Arguments: + + String1 - Pointer to the first string. + + String2 - Pointer to the second string. + + CaseInsensitive - TRUE if case should be ignored when doing the + comparison. + +Return Value: + + Boolean value that is TRUE if String1 equals String2 and FALSE otherwise. + +--*/ + +{ + UNALIGNED WCHAR *s1, *s2; + USHORT n1, n2; + WCHAR c1, c2; + + s1 = String1->Buffer; + s2 = String2->Buffer; + n1 = (USHORT )(String1->Length / sizeof(WCHAR)); + n2 = (USHORT )(String2->Length / sizeof(WCHAR)); + + if ( n1 != n2 ) { + return FALSE; + } + + if (CaseInSensitive) { + + while ( n1 ) { + + if ( *s1++ != *s2++ ) { + c1 = upcase(*(s1-1)); + c2 = upcase(*(s2-1)); + if (c1 != c2) { + return( FALSE ); + } + } + n1--; + } + } + else { + + while ( n1 ) { + + if (*s1++ != *s2++) { + return( FALSE ); + } + + n1--; + } + } + + return TRUE; +} + + +VOID +RtlInitString( + OUT PSTRING DestinationString, + IN PCSZ SourceString OPTIONAL + ) + +/*++ + +Routine Description: + + The RtlInitString function initializes an NT counted string. + The DestinationString is initialized to point to the SourceString + and the Length and MaximumLength fields of DestinationString are + initialized to the length of the SourceString, which is zero if + SourceString is not specified. + +Arguments: + + DestinationString - Pointer to the counted string to initialize + + SourceString - Optional pointer to a null terminated string that + the counted string is to point to. + + +Return Value: + + None. + +--*/ + +{ + DestinationString->Length = 0; + DestinationString->Buffer = (PCHAR)SourceString; + if (ARGUMENT_PRESENT( SourceString )) { + while (*SourceString++) { + DestinationString->Length++; + } + + DestinationString->MaximumLength = (SHORT)(DestinationString->Length+1); + } + else { + DestinationString->MaximumLength = 0; + } +} + + +VOID +RtlInitUnicodeString( + OUT PUNICODE_STRING DestinationString, + IN PCWSTR SourceString OPTIONAL + ) + +/*++ + +Routine Description: + + The RtlInitUnicodeString function initializes an NT counted + unicode string. The DestinationString is initialized to point to + the SourceString and the Length and MaximumLength fields of + DestinationString are initialized to the length of the SourceString, + which is zero if SourceString is not specified. + +Arguments: + + DestinationString - Pointer to the counted string to initialize + + SourceString - Optional pointer to a null terminated unicode string that + the counted string is to point to. + + +Return Value: + + None. + +--*/ + +{ + USHORT Length = 0; + DestinationString->Length = 0; + DestinationString->Buffer = (PWSTR)SourceString; + if (ARGUMENT_PRESENT( SourceString )) { + while (*SourceString++) { + Length += sizeof(*SourceString); + } + + DestinationString->Length = Length; + + DestinationString->MaximumLength = Length+(USHORT)sizeof(UNICODE_NULL); + } + else { + DestinationString->MaximumLength = 0; + } +} + + +NTSTATUS +RtlAppendUnicodeStringToString ( + IN PUNICODE_STRING Destination, + IN PUNICODE_STRING Source + ) + +/*++ + +Routine Description: + + This routine will concatinate two PSTRINGs together. It will copy + bytes from the source up to the MaximumLength of the destination. + +Arguments: + + IN PSTRING Destination, - Supplies the destination string + IN PSTRING Source - Supplies the source for the string copy + +Return Value: + + STATUS_SUCCESS - The source string was successfully appended to the + destination counted string. + + STATUS_BUFFER_TOO_SMALL - The destination string length was not big + enough to allow the source string to be appended. The Destination + string length is not updated. + +--*/ + +{ + USHORT n = Source->Length; + UNALIGNED WCHAR *dst; + + if (n) { + if ((n + Destination->Length) > Destination->MaximumLength) { + return( STATUS_BUFFER_TOO_SMALL ); + } + + dst = &Destination->Buffer[ (Destination->Length / sizeof( WCHAR )) ]; + RtlMoveMemory( dst, Source->Buffer, n ); + + Destination->Length += n; + + if (Destination->Length < Destination->MaximumLength) { + dst[ n / sizeof( WCHAR ) ] = UNICODE_NULL; + } + } + + return( STATUS_SUCCESS ); +} + + +NTSTATUS +RtlAppendUnicodeToString ( + IN PUNICODE_STRING Destination, + IN PWSTR Source OPTIONAL + ) + +/*++ + +Routine Description: + + This routine appends the supplied UNICODE string to an existing + PUNICODE_STRING. + + It will copy bytes from the Source PSZ to the destination PSTRING up to + the destinations PUNICODE_STRING->MaximumLength field. + +Arguments: + + IN PUNICODE_STRING Destination, - Supplies a pointer to the destination + string + IN PWSTR Source - Supplies the string to append to the destination + +Return Value: + + STATUS_SUCCESS - The source string was successfully appended to the + destination counted string. + + STATUS_BUFFER_TOO_SMALL - The destination string length was not big + enough to allow the source string to be appended. The Destination + string length is not updated. + +--*/ + +{ + USHORT n; + UNALIGNED WCHAR *dst; + + if (ARGUMENT_PRESENT( Source )) { + UNICODE_STRING UniSource; + + RtlInitUnicodeString(&UniSource, Source); + + n = UniSource.Length; + + if ((n + Destination->Length) > Destination->MaximumLength) { + return( STATUS_BUFFER_TOO_SMALL ); + } + + dst = &Destination->Buffer[ (Destination->Length / sizeof( WCHAR )) ]; + RtlMoveMemory( dst, Source, n ); + + Destination->Length += n; + + if (Destination->Length < Destination->MaximumLength) { + dst[ n / sizeof( WCHAR ) ] = UNICODE_NULL; + } + } + + return( STATUS_SUCCESS ); +} + +WCHAR +RtlUpcaseUnicodeChar( + IN WCHAR SourceCharacter + ) + +/*++ + +Routine Description: + + This function translates the specified unicode character to its + equivalent upcased unicode chararacter. The purpose for this routine + is to allow for character by character upcase translation. The + translation is done with respect to the current system locale + information. + + +Arguments: + + SourceCharacter - Supplies the unicode character to be upcased. + +Return Value: + + Returns the upcased unicode equivalent of the specified input character. + +--*/ + +{ + + return (upcase(SourceCharacter)); +} + +WCHAR +RtlAnsiCharToUnicodeChar( + IN OUT PUCHAR *SourceCharacter + ) + +/*++ + +Routine Description: + + This function translates the specified ansi character to unicode and + returns the unicode value. The purpose for this routine is to allow + for character by character ansi to unicode translation. The + translation is done with respect to the current system locale + information. + + +Arguments: + + SourceCharacter - Supplies a pointer to an ansi character pointer. + Through two levels of indirection, this supplies an ansi + character that is to be translated to unicode. After + translation, the ansi character pointer is modified to point to + the next character to be converted. This is done to allow for + dbcs ansi characters. + +Return Value: + + Returns the unicode equivalent of the specified ansi character. + +--*/ + +{ + WCHAR UnicodeCharacter; + ULONG cbCharSize; + NTSTATUS st; + + + UnicodeCharacter = (WCHAR)**SourceCharacter; + (*SourceCharacter)++; + return(UnicodeCharacter); +} + +NTSTATUS +RtlUpcaseUnicodeToMultiByteN( + OUT PCH MultiByteString, + IN ULONG MaxBytesInMultiByteString, + OUT PULONG BytesInMultiByteString OPTIONAL, + IN PWCH UnicodeString, + IN ULONG BytesInUnicodeString) + +/*++ + +Routine Description: + + This functions upper cases the specified unicode source string and + converts it into an ansi string. The translation is done with respect + to the ANSI Code Page (ACP) loaded at boot time. + +Arguments: + + MultiByteString - Returns an ansi string that is equivalent to the + upper case of the unicode source string. If the translation can + not be done, an error is returned. + + MaxBytesInMultiByteString - Supplies the maximum number of bytes to be + written to MultiByteString. If this causes MultiByteString to be a + truncated equivalent of UnicodeString, no error condition results. + + BytesInMultiByteString - Returns the number of bytes in the returned + ansi string pointed to by MultiByteString. + + UnicodeString - Supplies the unicode source string that is to be + converted to ansi. + + BytesInUnicodeString - The number of bytes in the the string pointed to by + UnicodeString. + +Return Value: + + SUCCESS - The conversion was successful + +--*/ + +{ + ULONG TmpCount; + ULONG LoopCount; + ULONG CharsInUnicodeString; + UCHAR SbChar; + WCHAR UnicodeChar; + ULONG i; + + // + // Convert Unicode byte count to character count. Byte count of + // multibyte string is equivalent to character count. + // + CharsInUnicodeString = BytesInUnicodeString / sizeof(WCHAR); + + LoopCount = (CharsInUnicodeString < MaxBytesInMultiByteString) ? + CharsInUnicodeString : MaxBytesInMultiByteString; + + if (ARGUMENT_PRESENT(BytesInMultiByteString)) + *BytesInMultiByteString = LoopCount; + + + for (i=0;i= 0; Disk--) { + + DiskName = GetDiskName(Disk); + + if ((strstr(DiskName, "scsi") != NULL) && + (strstr(DiskName, "disk") != NULL) ) { + + ScsiNumber = ScsiId = DiskNumber = 0; + TempDiskName = DiskName; + + while (TempDiskName != NULL) { + TempDiskName = AlGetNextArcNamToken(TempDiskName, + Token, + &UnitNumber); + + if (strcmp(Token,"scsi") == 0) { + ScsiNumber = UnitNumber; + } + + if (strcmp(Token,"disk") == 0) { + ScsiId = UnitNumber; + } + + if (strcmp(Token,"rdisk") == 0) { + DiskNumber = UnitNumber; + } + } + + sprintf(sprintfBuffer, + "Scsi bus %d, Identifier %d, Disk %d (%s)", + ScsiNumber, + ScsiId, + DiskNumber, + GetDiskName(Disk)); + } else { + sprintf(sprintfBuffer,"Disk %d (%s)",Disk,GetDiskName(Disk)); + } + + + if (!AlAddMenuItem(MenuID,sprintfBuffer,Disk,0)) { + MsgNoMem(); + return(-1); + } + } + + if (!AlDisplayMenu(MenuID,FALSE,0,&ChosenDisk,MENU_ROW,"Select Disk")) { + return(-1); + } else { + return(ChosenDisk); + } +} + + +BOOLEAN // true if partition was created +DoPartitionCreate( + OUT PULONG DiskNo, + OUT PULONG PartitionNo + ) +{ + ULONG Disk,i; + PREGION_DESCRIPTOR Regions; + ULONG RegionCount,Choice; + ULONG ChosenSize; + ARC_STATUS status; + BOOLEAN xAny,xP,xE,xL,PrimaryExists; + PVOID MenuID; + ULONG PartitionNumber; + char PartitionPath[256]; + + + if ((Disk = ChooseDisk()) == -1) { + return(FALSE); + } + + if ((status = DoesAnyPrimaryExist(Disk,&PrimaryExists)) != ESUCCESS) { + PrintErrorMsg(NOCNFMSG,status); + return(FALSE); + } + + if ((status = IsAnyCreationAllowed(Disk, + TRUE, + &xAny, + &xP, + &xE, + &xL + ) + ) + != ESUCCESS) + { + PrintErrorMsg(NOCNFMSG,status); + return(FALSE); + } + + // in order for a creation to be allowed there must be + // - free space on the disk and a free mbr entry OR + // - free space in an existing extended partition. + + if (!xAny) { + PrintErrorMsg(DSKFLMSG); + return(FALSE); + } + + if ((status = GetFreeDiskRegions(Disk,&Regions,&RegionCount)) != ESUCCESS) { + PrintErrorMsg(NOCNFMSG,status); + return(FALSE); + } + + if (!AlNewMenu(&MenuID)) { + MsgNoMem(); + FreeRegionArray(Regions,RegionCount); + return(FALSE); + } + + // Present the user with a list of the free spaces + // on the disk (and within the extended partition, if it + // exists). + + if (RegionCount > 1) { + + for(i=0; i Regions[Choice].SizeMB)) { + PrintErrorMsg("Invalid size."); + } else { + break; + } + } while(1); + + // The chosen space is either in the extended partition or not. + // If it is, just create the requested partition. + + if (Regions[Choice].RegionType == REGION_LOGICAL) { + + status = CreatePartition(&Regions[Choice],ChosenSize,REGION_LOGICAL); + PartitionNumber = Regions[Choice].PartitionNumber; + + } else { + + // The chosen space is not in an extended partition. + // If there's already a primary and we can create + // an extended partition, then first create an + // extended partition spanning the entire space chosen + // by the user, and then a logical volume within it of + // size entered by the user. Otherwise [ie, there's no primary + // or we're not allowed to create an extended partition] + // create a primary of the size entered by the user. + + + if (PrimaryExists && xE) { + + // create extended partition first. + status = CreatePartition(&Regions[Choice],Regions[Choice].SizeMB,REGION_EXTENDED); + FreeRegionArray(Regions,RegionCount); + + if ((status = GetFreeLogicalDiskRegions(Disk,&Regions,&RegionCount)) != ESUCCESS) { + PrintErrorMsg(NOCNFMSG,status); + return(FALSE); + } + // since we just created the extended partition, there will be one free + // region in it. + + status = CreatePartition(Regions,ChosenSize,REGION_LOGICAL); + PartitionNumber = Regions[0].PartitionNumber; + + } else { + + status = CreatePartition(&Regions[Choice],ChosenSize,REGION_PRIMARY); + PartitionNumber = Regions[Choice].PartitionNumber; + } + } + FreeRegionArray(Regions,RegionCount); + + if ( (status == ESUCCESS) + && ((status = CommitPartitionChanges(Disk)) == ESUCCESS)) + { + PrintMsg("Partition successfully created."); + +#if 0 + // + // This is bogus since this routine is called in the code path where + // the user is creating a system partition. + // + if (ArcGetEnvironmentVariable(SYSPARTVAR) == NULL) { + if (Confirm("Do you want to make this the system partition")) { + sprintf(PartitionPath,"%spartition(%u)",GetDiskName(Disk),PartitionNumber); + if ((status = ArcSetEnvironmentVariable(SYSPARTVAR,PartitionPath)) != ESUCCESS) { + PrintErrorMsg(NOEVAMSG,status); + } + } + } +#endif + + *DiskNo = Disk; + *PartitionNo = PartitionNumber; + return(TRUE); + + } else { + PrintErrorMsg(NOCREMSG,status); + return(FALSE); + } +} + + +VOID +DoPartitionDelete( + VOID + ) +{ + BOOLEAN xAny,xPrimary,xExtended,xLogical; + ARC_STATUS status; + PVOID MenuID; + ULONG i,RegionCount,Choice; + ULONG MatchNumber,Index; + LONG Disk; + PREGION_DESCRIPTOR Regions; + BOOLEAN err,Confirmation; + + + if ((Disk = ChooseDisk()) == -1) { + return; + } + + if ((status = DoesAnyPartitionExist(Disk,&xAny,&xPrimary,&xExtended,&xLogical)) != ESUCCESS) { + PrintErrorMsg(NOCNFMSG,status); + return; + } + + if (xAny) { + + if (!AlNewMenu(&MenuID)) { + MsgNoMem(); + return; + } + + if ((status = GetUsedDiskRegions(Disk,&Regions,&RegionCount)) != ESUCCESS) { + + PrintErrorMsg(NOCNFMSG,status); + + } else { + + err = FALSE; + + for(i=0; i