summaryrefslogtreecommitdiffstats
path: root/private/ntos/arcinst
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/arcinst
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to 'private/ntos/arcinst')
-rw-r--r--private/ntos/arcinst/almisc.c1565
-rw-r--r--private/ntos/arcinst/alpha/mk.inc16
-rw-r--r--private/ntos/arcinst/alpha/sources12
-rw-r--r--private/ntos/arcinst/arcinst.c234
-rw-r--r--private/ntos/arcinst/arcinst.h827
-rw-r--r--private/ntos/arcinst/fdengine.c3394
-rw-r--r--private/ntos/arcinst/fmtexp.c942
-rw-r--r--private/ntos/arcinst/jzcrap.c52
-rw-r--r--private/ntos/arcinst/low.c1186
-rw-r--r--private/ntos/arcinst/makefile1
-rw-r--r--private/ntos/arcinst/makefile.inc1
-rw-r--r--private/ntos/arcinst/memory.c1184
-rw-r--r--private/ntos/arcinst/mips/mk.inc16
-rw-r--r--private/ntos/arcinst/mips/sources12
-rw-r--r--private/ntos/arcinst/nlsboot.c711
-rw-r--r--private/ntos/arcinst/partit.c727
-rw-r--r--private/ntos/arcinst/precomp.h1
-rw-r--r--private/ntos/arcinst/sources16
18 files changed, 10897 insertions, 0 deletions
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; i<p->ItemCount; 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; i<ItemCount; i++) {
+ if(!AlAddMenuItem(MenuID,Text[i],i+base,0)) {
+ return(FALSE);
+ }
+ }
+ return(TRUE);
+}
+
+
+BOOLEAN
+AlDisplayMenu(
+ PVOID MenuID,
+ BOOLEAN PrintOnly,
+ ULONG AssociatedDataOfDefaultChoice,
+ ULONG *AssociatedDataOfChoice,
+ ULONG Row,
+ PCHAR MenuName
+ )
+{
+ return(CommonMenuDisplay((PMENUCOOKIE)MenuID,
+ FALSE,
+ NULL,
+ ((PMENUCOOKIE)MenuID)->ItemCount,
+ 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; i<x; i++) {
+// AlPrint("-");
+// }
+// AlPrint("\r\n\r\n");
+// MenuBaseLine += 3;
+// }
+
+ for(i=0; i<ItemCount; i++) {
+ AlSetScreenAttributes(1,0,0); // hi intensity
+ AlPrint("%s%s\r\n",MARGIN,StaticMenu ? Items[i] : Menu->Items[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; i<ItemCount; i++) {
+ if(Menu->Items[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
+<<NOKEEP
+ binplace obj\alpha\arcinst.exe
diff --git a/private/ntos/arcinst/alpha/sources b/private/ntos/arcinst/alpha/sources
new file mode 100644
index 000000000..75914a65b
--- /dev/null
+++ b/private/ntos/arcinst/alpha/sources
@@ -0,0 +1,12 @@
+ALPHA_SOURCES=\
+ fdengine.c \
+ memory.c \
+ almisc.c \
+ fmtexp.c \
+ low.c \
+ nlsboot.c \
+ partit.c \
+ jzcrap.c \
+ arcinst.c
+
+NTTARGETFILES=obj\alpha\arcinst.exe
diff --git a/private/ntos/arcinst/arcinst.c b/private/ntos/arcinst/arcinst.c
new file mode 100644
index 000000000..7e81de0f3
--- /dev/null
+++ b/private/ntos/arcinst/arcinst.c
@@ -0,0 +1,234 @@
+/*++
+
+Copyright (c) 1991-1996 Microsoft Corporation
+Copyright (c) 1992, 1992 Digital Equipment Corporation
+
+Module Name:
+
+ arcinst.c
+
+Abstract:
+
+ This module contains the code that prepares a ARC compliant platform
+ for OS installation. It creates system partitions and formats system
+ partitions
+
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+PCHAR Banner1 = " Arc Installation Program Version 4.00";
+PCHAR Banner2 = " Copyright (c) 1991-1996 Microsoft Corporation";
+
+//
+// Menu definitions
+//
+
+PCHAR rgszMainMenu[] = {
+ "Configure Partitions",
+ "Exit"
+
+ };
+
+
+//
+// NOTE! This must be the number of entries in rgszMainMenu. It is used
+// to tell AddMenuItems the number of menu items to add.
+//
+
+#define CSZMENUITEMS 2
+
+
+//
+// NOTE! These must be kept in sync with the indices for rgszMainMenu
+// The main menu is created by AddMenuItems which will generated
+// associated data values based upon the index into the array of
+// strings passed in. These #defines must match those values
+// or the switch statement used to handle the menu selection will
+// dispatch to the wrong code.
+//
+
+#define CONFIG_SYS_PARTITION 0
+#define EXIT 1
+
+#define MENU_START_ROW 4
+#define ERROR_ROW_TOP 13
+#define ERROR_ROW_BOTTOM 16
+
+//
+// Max size for a path or environment variable
+//
+
+#define MAX_PATH 256
+
+//
+// Max bytes in a line
+//
+
+#define CBMAXLINE 120
+
+//
+// Define constants to generate a 2 meg stack and a 2 meg heap.
+//
+#define ARCINST_STACK_PAGES (2*1024*1024 / PAGE_SIZE)
+#define ARCINST_HEAP_PAGES (2*1024*1024 / PAGE_SIZE)
+
+ARC_STATUS GetTitlesAndPaths ( PCHAR, PCHAR, ULONG, ULONG, PCHAR **,PULONG, PCHAR **, PULONG);
+ARC_STATUS GetSectionElementList ( PCHAR, PCHAR, ULONG, PCHAR **, PULONG );
+ARC_STATUS CopySection( PCHAR, PCHAR, PCHAR, PCHAR );
+ARC_STATUS UpdateOSFiles( PCHAR, PCHAR, PCHAR );
+
+VOID PrintError( PCHAR, ... );
+
+// Needed for C string functions
+int errno;
+
+ARC_STATUS __cdecl
+main(
+ IN ULONG argc,
+ IN PCHAR argv[],
+ IN PCHAR envp[]
+ )
+{
+ PCHAR szSysPartition = NULL;
+ PCHAR szInfPath = NULL;
+ PVOID hdMenuId;
+ ULONG MenuChoice;
+
+ DBG_UNREFERENCED_PARAMETER( argc );
+ DBG_UNREFERENCED_PARAMETER( argv );
+ DBG_UNREFERENCED_PARAMETER( envp );
+
+ if (AlMemoryInitialize (ARCINST_STACK_PAGES, ARCINST_HEAP_PAGES) != ESUCCESS) {
+
+ PrintError(NULL, "Failed to initialize the heap");
+ return( ESUCCESS );
+ }
+
+ if (!AlInitializeMenuPackage()) {
+
+ PrintError(NULL, "Could not initialize menu package");
+ return( ESUCCESS );
+
+ }
+
+ if (FdiskInitialize() != ESUCCESS) {
+
+ PrintError(NULL, "Failed to initialize the FDISK package");
+ return( ESUCCESS );
+
+ }
+
+ if (!AlNewMenu(&hdMenuId)) {
+
+ PrintError(NULL, "Could not create main menu");
+ return( ESUCCESS );
+
+ }
+
+ //
+ // Initialize the main ArcInst menu.
+ //
+ // Not that when you add items in this way the associated data becomes
+ // the index in the array of strings. Make sure the values used for
+ // associated data the predefined values CHANGE_ENV etc.
+ //
+
+ if (!AlAddMenuItems(hdMenuId, rgszMainMenu, CSZMENUITEMS)) {
+
+ PrintError(NULL, "Failed to Initialize Main Menu");
+ return( ESUCCESS );
+ }
+
+ //
+ // Loop till Exit or an ESC key is it.
+ //
+ while (TRUE) {
+
+ //
+ // Print Banner
+ //
+ AlClearScreen();
+ AlSetPosition(1, 0);
+ AlPrint(Banner1);
+ AlPrint("\r\n");
+ AlPrint(Banner2);
+
+ if (!AlDisplayMenu(hdMenuId,
+ FALSE,
+ CONFIG_SYS_PARTITION,
+ &MenuChoice,
+ MENU_START_ROW,
+ 0)) {
+
+ //
+ // User hit ESC key
+ //
+ return( ESUCCESS );
+
+ }
+
+ switch (MenuChoice) {
+
+ case CONFIG_SYS_PARTITION:
+
+ ConfigureSystemPartitions();
+ break;
+
+ case EXIT:
+
+ return(ESUCCESS);
+ break;
+
+ }
+ }
+}
+
+VOID
+PrintError(
+ IN PCHAR szFormat,
+ ...
+ )
+
+/*++
+
+Routine Description:
+
+ This routine prints a error or information message at a specific
+ location the screen (ERROR_ROW_TOP) and waits for the user to hit
+ any key.
+
+Arguments:
+
+ szFormat - Format string, if NULL then "%s" is used.
+ szErrorMessage - Text of string to print
+
+Return Value:
+
+ none
+
+--*/
+
+{
+ va_list ArgList;
+
+ va_start(ArgList,szFormat);
+ if (szFormat == NULL ) {
+ szFormat = "%s";
+ }
+ vAlStatusMsg(ERROR_ROW_TOP, TRUE, szFormat, ArgList);
+
+ AlWaitKey(NULL);
+ AlClearStatusArea(ERROR_ROW_TOP, ERROR_ROW_BOTTOM);
+}
+
+VOID
+JzShowTime (
+ BOOLEAN First
+ )
+{
+ return;
+}
diff --git a/private/ntos/arcinst/arcinst.h b/private/ntos/arcinst/arcinst.h
new file mode 100644
index 000000000..9021cb0f6
--- /dev/null
+++ b/private/ntos/arcinst/arcinst.h
@@ -0,0 +1,827 @@
+#include <ntos.h>
+#include <ntdddisk.h>
+#include <arc.h>
+#include <arccodes.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+//
+// 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; i<CountOfDisks; i++) {
+ AlPrint("Disk %u: %s\r\n",i,DiskNames[i]);
+ }
+ WaitKey();
+#endif
+#endif
+
+ DiskGeometryArray = NULL;
+ PrimaryPartitions = NULL;
+ LogicalVolumes = NULL;
+
+ if(((DiskGeometryArray = AllocateMemory(CountOfDisks * sizeof(DISKGEOM ))) == NULL)
+ || ((ChangesMade = AllocateMemory(CountOfDisks * sizeof(BOOLEAN ))) == NULL)
+ || ((PrimaryPartitions = AllocateMemory(CountOfDisks * sizeof(PPARTITION))) == NULL)
+ || ((OffLine = AllocateMemory(CountOfDisks * sizeof(BOOLEAN ))) == NULL)
+ || ((LogicalVolumes = AllocateMemory(CountOfDisks * sizeof(PPARTITION))) == NULL))
+ {
+ RETURN_OUT_OF_MEMORY;
+ }
+
+ for(i=0; i<CountOfDisks; i++) {
+ PrimaryPartitions[i] = NULL;
+ LogicalVolumes[i] = NULL;
+ ChangesMade[i] = FALSE;
+ OffLine[i] = CheckIfDiskIsOffLine(i);
+ if(OffLine[i]) {
+ return(ENODEV);
+ }
+ }
+
+ if(((status = GetGeometry() ) != OK_STATUS)
+ || ((status = InitializePartitionLists()) != OK_STATUS))
+ {
+ return(status);
+ }
+
+ return(OK_STATUS);
+}
+
+
+VOID
+FdiskCleanUp(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deallocates storage used by the partitioning engine.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LowFreeFdiskPathList(DiskNames,CountOfDisks);
+
+ if(DiskGeometryArray != NULL) {
+ FreeMemory(DiskGeometryArray);
+ }
+ if(PrimaryPartitions != NULL) {
+ FreePartitionInfoLinkedLists(PrimaryPartitions);
+ FreeMemory(PrimaryPartitions);
+ }
+ if(LogicalVolumes != NULL) {
+ FreePartitionInfoLinkedLists(LogicalVolumes);
+ FreeMemory(LogicalVolumes);
+ }
+ if(ChangesMade != NULL) {
+ FreeMemory(ChangesMade);
+ }
+ if(OffLine != NULL) {
+ FreeMemory(OffLine);
+ }
+}
+
+
+BOOLEAN
+CheckIfDiskIsOffLine(
+ IN ULONG Disk
+ )
+
+/*++
+
+Routine Description:
+
+ Determine whether a disk is off-line by attempting to open it.
+ If this is diskman, also attempt to read from it.
+
+Arguments:
+
+ Disk - supplies number of the disk to check
+
+Return Value:
+
+ TRUE if disk is off-line, FALSE is disk is on-line.
+
+--*/
+
+{
+ ULONG Handle;
+ BOOLEAN IsOffLine;
+
+ if(LowOpenDisk(GetDiskName(Disk),&Handle) == OK_STATUS) {
+
+ IsOffLine = FALSE;
+ LowCloseDisk(Handle);
+
+ } else {
+
+ IsOffLine = TRUE;
+ }
+
+ return(IsOffLine);
+}
+
+
+ARC_STATUS
+GetGeometry(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines disk geometry for each disk device.
+ Disk geometry includes heads, sectors per track, cylinder count,
+ and bytes per sector. It also includes bytes per track and
+ bytes per cylinder, which are calculated from the other values
+ for the convenience of the rest of this module.
+
+ Geometry information is placed in the DiskGeometryArray global variable.
+
+ Geometry information is undefined for an off-line disk.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ OK_STATUS or error code.
+
+--*/
+
+{
+ ULONG i;
+ ARC_STATUS status;
+ ULONG TotalSectorCount,
+ SectorSize,
+ SectorsPerTrack,
+ Heads;
+
+ for(i=0; i<CountOfDisks; i++) {
+
+ if(OffLine[i]) {
+ continue;
+ }
+
+ if((status = LowGetDriveGeometry(DiskNames[i],&TotalSectorCount,&SectorSize,&SectorsPerTrack,&Heads)) != OK_STATUS) {
+ return(status);
+ }
+
+ DiskGeometryArray[i].BytesPerSector = SectorSize;
+ DiskGeometryArray[i].SectorsPerTrack = SectorsPerTrack;
+ DiskGeometryArray[i].Heads = Heads;
+ DiskGeometryArray[i].Cylinders.QuadPart = TotalSectorCount / (SectorsPerTrack * Heads);
+ DiskGeometryArray[i].BytesPerTrack = SectorsPerTrack * SectorSize;
+ DiskGeometryArray[i].BytesPerCylinder = SectorsPerTrack * SectorSize * Heads;
+ }
+ return(OK_STATUS);
+}
+
+
+#if i386
+VOID
+SetPartitionActiveFlag(
+ IN PREGION_DESCRIPTOR Region,
+ IN UCHAR value
+ )
+{
+ PPARTITION p = ((PREGION_DATA)Region->Reserved)->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; i<RegionCount; i++) {
+
+ if(Region[i].Reserved) {
+ FreeMemory(Region[i].Reserved);
+ }
+ }
+ FreeMemory(Region);
+}
+
+
+
+VOID
+AddPartitionToLinkedList(
+ IN OUT PARTITION **Head,
+ IN PARTITION *p
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds a PARTITION structure to a doubly-linked
+ list, sorted by the Offset field in ascending order.
+
+Arguments:
+
+ Head - pointer to pointer to first element in list
+
+ p - pointer to item to be added to list
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PARTITION *cur,*prev;
+
+ if((cur = *Head) == NULL) {
+ *Head = p;
+ return;
+ }
+
+ if(p->Offset.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; i<CountOfDisks; i++) {
+
+ FreeLinkedPartitionList(&ListHeadArray[i]);
+ }
+}
+
+
+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
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates space for, and initializes a PARTITION
+ structure.
+
+Arguments:
+
+ Disk - index of disk, one of whose regions the new PARTITION
+ strucure describes.
+
+ Offset - byte offset of region on the disk
+
+ Length - length in bytes of the region
+
+ SysID - system id of region, of SYSID_UNUSED of this PARTITION
+ is actually a free space.
+
+ Update - whether this PARTITION is dirty, ie, has changed and needs
+ to be written to disk.
+
+ Active - flag for the BootIndicator field in a partition table entry,
+ indicates to the x86 master boot program which partition
+ is active.
+
+ Recognized - whether the partition is a type recognized by NT
+
+Return Value:
+
+ NULL if allocation failed, or new initialized PARTITION strucure.
+
+--*/
+
+{
+ PPARTITION p = AllocateMemory(sizeof(PARTITION));
+
+ if(p) {
+ p->Next = 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; i<DriveLayout->PartitionCount; i+=ENTRIES_PER_BOOTSECTOR) {
+
+ for(j=i; j<i+ENTRIES_PER_BOOTSECTOR; j++) {
+
+ d = &DriveLayout->PartitionEntry[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; i<ENTRIES_PER_BOOTSECTOR; i++) {
+
+ d = &DriveLayout->PartitionEntry[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<CountOfDisks; Disk++) {
+
+ if(OffLine[Disk]) {
+ continue;
+ }
+
+ if((status = LowGetDiskLayout(DiskNames[Disk],&DriveLayout)) != OK_STATUS) {
+ return(status);
+ }
+
+ if((status = InitializePrimaryPartitionList(Disk,DriveLayout,&PNum)) != OK_STATUS) {
+ FreeMemory(DriveLayout);
+ return(status);
+ }
+ if((status = InitializeLogicalVolumeList(Disk,DriveLayout,PNum)) != OK_STATUS) {
+ FreeMemory(DriveLayout);
+ return(status);
+ }
+
+ FreeMemory(DriveLayout);
+ RenumberPartitions(Disk);
+ }
+ return(OK_STATUS);
+}
+
+
+
+LARGE_INTEGER
+DiskLengthBytes(
+ IN ULONG Disk
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines the disk length in bytes. This value
+ is calculated from the disk geometry information.
+
+Arguments:
+
+ Disk - index of disk whose size is desired
+
+Return Value:
+
+ Size of Disk.
+
+--*/
+
+{
+ LARGE_INTEGER l;
+
+ l.QuadPart = (ULONGLONG)DiskGeometryArray[Disk].Cylinders.QuadPart
+ * (ULONGLONG)DiskGeometryArray[Disk].BytesPerCylinder;
+
+ return(l);
+}
+
+
+ULONG
+SIZEMB(
+ IN LARGE_INTEGER ByteCount
+ )
+
+/*++
+
+Routine Description:
+
+ Calculate the size in megabytes of a given byte count. The value is
+ properly rounded (ie, not merely truncated).
+
+ This function replaces a macro of the same name that was truncating
+ instead of rounding.
+
+Arguments:
+
+ ByteCount - supplies number of bytes
+
+Return Value:
+
+ Size in MB equivalent to ByteCount.
+
+--*/
+
+{
+ ULONG Remainder;
+ ULONG SizeMB;
+
+ SizeMB = (ULONG)((ULONGLONG)ByteCount.QuadPart / (ULONGLONG)ONE_MEG);
+ Remainder = (ULONG)((ULONGLONG)ByteCount.QuadPart % (ULONGLONG)ONE_MEG);
+
+ if(Remainder >= 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; i<RegionCount; i++) {
+ ASRT(Regions[i].RegionType != REGION_LOGICAL);
+ if(Regions[i].SysID == SYSID_UNUSED) {
+ FreeSpace = TRUE;
+ } else {
+ UsedCount++;
+ if(!IsExtended(Regions[i].SysID) && Regions[i].Recognized) {
+ RecogCount++;
+ }
+ }
+ }
+ ASRT(UsedCount <= ENTRIES_PER_BOOTSECTOR);
+ ASRT(RecogCount <= ENTRIES_PER_BOOTSECTOR);
+ ASRT(RecogCount <= UsedCount);
+
+ if((UsedCount < ENTRIES_PER_BOOTSECTOR)
+ && FreeSpace
+ && (!RecogCount || AllowMultiplePrimaries))
+ {
+ *Allowed = TRUE;
+ } else {
+ *Allowed = FALSE;
+ }
+
+ FreeRegionArray(Regions,RegionCount);
+ return(OK_STATUS);
+}
+
+
+ARC_STATUS
+IsCreationOfExtendedAllowed(
+ IN ULONG Disk,
+ OUT BOOLEAN *Allowed
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines whether creation of an extended partition is
+ allowed. This is true when there is a free entry in the MBR,
+ there is free primary space on the disk, and there is no existing
+ extended partition.
+
+Arguments:
+
+ Disk - index of disk to check
+
+ Allowed - returns whether creation of an extended partition
+ is allowed
+
+Return Value:
+
+ OK_STATUS or error code
+
+--*/
+
+{
+ PREGION_DESCRIPTOR Regions;
+ ULONG RegionCount;
+ ULONG UsedCount,FreeCount,i;
+ ARC_STATUS status;
+
+ status = GetPrimaryDiskRegions(Disk,&Regions,&RegionCount);
+ if(status != OK_STATUS) {
+ return(status);
+ }
+
+ for(UsedCount = FreeCount = i = 0; i<RegionCount; i++) {
+ ASRT(Regions[i].RegionType != REGION_LOGICAL);
+ if(Regions[i].SysID == SYSID_UNUSED) {
+ // BUGBUG should adjust the size here and see if it's non0 first
+ // (ie, take into account that the extended partition can't
+ // start on cyl 0).
+ FreeCount++;
+ } else {
+ UsedCount++;
+ if(IsExtended(Regions[i].SysID)) {
+ FreeRegionArray(Regions,RegionCount);
+ *Allowed = FALSE;
+ return(OK_STATUS);
+ }
+ }
+ }
+ *Allowed = (BOOLEAN)((UsedCount < ENTRIES_PER_BOOTSECTOR) && FreeCount);
+ FreeRegionArray(Regions,RegionCount);
+ return(OK_STATUS);
+}
+
+
+ARC_STATUS
+IsCreationOfLogicalAllowed(
+ IN ULONG Disk,
+ OUT BOOLEAN *Allowed
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines whether creation of a logical volume is
+ allowed. This is true when there is an extended partition and
+ free space within it.
+
+Arguments:
+
+ Disk - index of disk to check
+
+ Allowed - returns whether creation of a logical volume is allowed
+
+Return Value:
+
+ OK_STATUS or error code
+
+--*/
+
+{
+ PREGION_DESCRIPTOR Regions;
+ ULONG RegionCount;
+ ULONG i;
+ ARC_STATUS status;
+ BOOLEAN ExtendedExists;
+
+ *Allowed = FALSE;
+
+ status = DoesExtendedExist(Disk,&ExtendedExists);
+ if(status != OK_STATUS) {
+ return(status);
+ }
+ if(!ExtendedExists) {
+ return(OK_STATUS);
+ }
+
+ status = GetLogicalDiskRegions(Disk,&Regions,&RegionCount);
+ if(status != OK_STATUS) {
+ return(status);
+ }
+
+ for(i = 0; i<RegionCount; i++) {
+ ASRT(Regions[i].RegionType == REGION_LOGICAL);
+ if(Regions[i].SysID == SYSID_UNUSED) {
+ *Allowed = TRUE;
+ break;
+ }
+ }
+ FreeRegionArray(Regions,RegionCount);
+ return(OK_STATUS);
+}
+
+
+
+ARC_STATUS
+DoesAnyPartitionExist(
+ IN ULONG Disk,
+ OUT PBOOLEAN AnyExists,
+ OUT PBOOLEAN PrimaryExists,
+ OUT PBOOLEAN ExtendedExists,
+ OUT PBOOLEAN LogicalExists
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines whether any partition exists on a given disk.
+ This is based on three sub queries: whether there are any primary or
+ extended partitions, or logical volumes on the disk.
+
+Arguments:
+
+ Disk - index of disk to check
+
+ AnyExists - returns whether any partitions exist on Disk
+
+ PrimaryExists - returns whether any primary partitions exist on Disk
+
+ ExtendedExists - returns whether there is an extended partition on Disk
+
+ LogicalExists - returns whether any logical volumes exist on Disk
+
+Return Value:
+
+ OK_STATUS or error code
+
+--*/
+
+{
+ ARC_STATUS status;
+
+ if((status = DoesAnyPrimaryExist(Disk,PrimaryExists )) != OK_STATUS) {
+ return(status);
+ }
+ if((status = DoesExtendedExist (Disk,ExtendedExists)) != OK_STATUS) {
+ return(status);
+ }
+ if((status = DoesAnyLogicalExist(Disk,LogicalExists )) != OK_STATUS) {
+ return(status);
+ }
+ *AnyExists = (BOOLEAN)(*PrimaryExists || *ExtendedExists || *LogicalExists);
+ return(OK_STATUS);
+}
+
+
+ARC_STATUS
+DoesAnyPrimaryExist(
+ IN ULONG Disk,
+ OUT BOOLEAN *Exists
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines whether any non-extended primary partition exists
+ on a given disk.
+
+Arguments:
+
+ Disk - index of disk to check
+
+ Exists - returns whether any primary partitions exist on Disk
+
+Return Value:
+
+ OK_STATUS or error code
+
+--*/
+
+{
+ PREGION_DESCRIPTOR Regions;
+ ULONG RegionCount,i;
+ ARC_STATUS status;
+
+ status = GetUsedPrimaryDiskRegions(Disk,&Regions,&RegionCount);
+ if(status != OK_STATUS) {
+ return(status);
+ }
+
+ *Exists = FALSE;
+
+ for(i=0; i<RegionCount; i++) {
+ ASRT(Regions[i].RegionType != REGION_LOGICAL);
+ ASRT(Regions[i].SysID != SYSID_UNUSED);
+ if(!IsExtended(Regions[i].SysID)) {
+ *Exists = TRUE;
+ break;
+ }
+ }
+ FreeRegionArray(Regions,RegionCount);
+ return(OK_STATUS);
+}
+
+
+ARC_STATUS
+DoesExtendedExist(
+ IN ULONG Disk,
+ OUT BOOLEAN *Exists
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines whether an extended partition exists
+ on a given disk.
+
+Arguments:
+
+ Disk - index of disk to check
+
+ Exists - returns whether an extended partition exists on Disk
+
+Return Value:
+
+ OK_STATUS or error code
+
+--*/
+
+{
+ PREGION_DESCRIPTOR Regions;
+ ULONG RegionCount,i;
+ ARC_STATUS status;
+
+ status = GetUsedPrimaryDiskRegions(Disk,&Regions,&RegionCount);
+ if(status != OK_STATUS) {
+ return(status);
+ }
+
+ *Exists = FALSE;
+
+ for(i=0; i<RegionCount; i++) {
+ ASRT(Regions[i].RegionType != REGION_LOGICAL);
+ ASRT(Regions[i].SysID != SYSID_UNUSED);
+ if(IsExtended(Regions[i].SysID)) {
+ *Exists = TRUE;
+ break;
+ }
+ }
+ FreeRegionArray(Regions,RegionCount);
+ return(OK_STATUS);
+}
+
+
+ARC_STATUS
+DoesAnyLogicalExist(
+ IN ULONG Disk,
+ OUT BOOLEAN *Exists
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines whether any logical volumes exist
+ on a given disk.
+
+Arguments:
+
+ Disk - index of disk to check
+
+ Exists - returns whether any logical volumes exist on Disk
+
+Return Value:
+
+ OK_STATUS or error code
+
+--*/
+
+{
+ PREGION_DESCRIPTOR Regions;
+ ULONG RegionCount;
+ ARC_STATUS status;
+
+ status = GetUsedLogicalDiskRegions(Disk,&Regions,&RegionCount);
+ if(status != OK_STATUS) {
+ return(status);
+ }
+
+ *Exists = (BOOLEAN)(RegionCount != 0);
+ FreeRegionArray(Regions,RegionCount);
+ return(OK_STATUS);
+}
+
+
+ULONG
+GetDiskCount(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the number of attached partitionable disk
+ devices. The returned value is one greater than the maximum index
+ allowed for Disk parameters to partitioning engine routines.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Count of disks.
+
+--*/
+
+{
+ return(CountOfDisks);
+}
+
+
+PCHAR
+GetDiskName(
+ ULONG Disk
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the system name for the disk device whose
+ index is given.
+
+Arguments:
+
+ Disk - index of disk whose name is desired.
+
+Return Value:
+
+ System name for the disk device. The caller must not attempt to
+ free this buffer or modify it.
+
+--*/
+
+{
+ return(DiskNames[Disk]);
+}
+
+
+// sys ID type names
+
+char UNKNOWN[] = "Unknown type";
+
+PCHAR SysIDStrings[256] = { "Free Space","FAT","XENIX1","XENIX2", // 00-03
+ "FAT", "Extended", "FAT", "HPFS/NTFS",// 04-07
+ UNKNOWN, UNKNOWN, // 08-09
+ "OS/2 Boot Manager", UNKNOWN, // 0a-0b
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // 0c-0f
+ UNKNOWN, UNKNOWN, // 10-11
+ "EISA Utilities", UNKNOWN, // 12-13
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // 14-17
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // 18-1b
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // 1c-1f
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // 20-23
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // 24-27
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // 28-2b
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // 2c-2f
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // 30-33
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // 34-37
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // 38-3b
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // 3c-3f
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // 40-43
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // 44-47
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // 48-4b
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // 4c-4f
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // 50-53
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // 54-57
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // 58-5b
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // 5c-5f
+ UNKNOWN, UNKNOWN, UNKNOWN, "Unix", // 60-63
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // 64-67
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // 68-6b
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // 6c-6f
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // 70-73
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // 74-77
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // 78-7b
+ UNKNOWN, UNKNOWN, UNKNOWN, "Unused", // 7c-7f
+ UNKNOWN, "Windows NT Fault Tolerance",// 80-81
+ UNKNOWN, UNKNOWN, // 82-83
+ "Windows NT Fault Tolerance", UNKNOWN,// 84-85
+ "Windows NT Fault Tolerance", // 86-86
+ "Windows NT Fault Tolerance", // 87-87
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // 88-8b
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // 8c-8f
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // 90-93
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // 94-97
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // 98-9b
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // 9c-9f
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // a0-a3
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // a4-a7
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // a8-ab
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // ac-af
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // b0-b3
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // b4-b7
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // b8-bb
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // bc-bf
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // c0-c3
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // c4-c7
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // c8-cb
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // cc-cf
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // d0-d3
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // d4-d7
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // d8-db
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // dc-df
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // e0-e3
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // e4-e7
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // e8-eb
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // ec-ef
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // f0-f3
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // f4-f7
+ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, // f8-fb
+ UNKNOWN, UNKNOWN, UNKNOWN, "Table", // fc-ff
+ };
+
+
+PCHAR
+GetSysIDName(
+ UCHAR SysID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the name for a given system ID.
+
+Arguments:
+
+ SysID - system id in question
+
+Return Value:
+
+ Name of system id. The caller must not attempt to free or
+ modify this buffer.
+
+--*/
+
+{
+ return(SysIDStrings[SysID]);
+}
+
+
+// worker routines for WriteDriveLayout
+
+VOID
+UnusedEntryFill(
+ IN PPARTITION_INFORMATION pinfo,
+ IN ULONG EntryCount
+ )
+{
+ ULONG i;
+ LARGE_INTEGER Zero;
+
+ Zero.QuadPart = 0;
+
+ for(i=0; i<EntryCount; i++) {
+
+ pinfo[i].StartingOffset = Zero;
+ pinfo[i].PartitionLength = Zero;
+ pinfo[i].HiddenSectors = 0;
+ pinfo[i].PartitionType = SYSID_UNUSED;
+ pinfo[i].BootIndicator = FALSE;
+ pinfo[i].RewritePartition = TRUE;
+ }
+}
+
+
+LARGE_INTEGER
+MakeBootRec(
+ ULONG Disk,
+ PPARTITION_INFORMATION pinfo,
+ PPARTITION pLogical,
+ PPARTITION pNextLogical
+ )
+{
+ ULONG Entry = 0;
+ LARGE_INTEGER BytesPerTrack;
+ LARGE_INTEGER SectorsPerTrack;
+ LARGE_INTEGER StartingOffset;
+
+ BytesPerTrack.QuadPart = (DiskGeometryArray[Disk].BytesPerTrack);
+ SectorsPerTrack.QuadPart = (DiskGeometryArray[Disk].SectorsPerTrack);
+ StartingOffset.QuadPart = 0;
+
+// ASRT(pLogical || pNextLogical);
+
+ if(pLogical) {
+
+ pinfo[Entry].StartingOffset.QuadPart = pLogical->Offset.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; i<SectorSize; AlignedSectorBuffer[i++] = 0);
+
+ if((status = LowOpenDisk(GetDiskName(Disk),&Handle)) != OK_STATUS) {
+ FreeMemory(SectorBuffer);
+ return(status);
+ }
+
+ LargeInteger.QuadPart = Offset.QuadPart / SectorSize;
+ status = LowWriteSectors(Handle,
+ SectorSize,
+ LOWPART(LargeInteger),
+ 1,
+ AlignedSectorBuffer
+ );
+
+ LowCloseDisk(Handle);
+ FreeMemory(SectorBuffer);
+
+ return(status);
+}
+
+
+ARC_STATUS
+WriteDriveLayout(
+ IN ULONG Disk
+ )
+
+/*++
+
+Routine Description:
+
+ This routine writes the current partition layout for a given disk
+ out to disk. The high-level PARTITION lists are transformed into
+ a DRIVE_LAYOUT_INFORMATION structure before being passed down
+ to the low-level partition table writing routine.
+
+Arguments:
+
+ Disk - index of disk whose on-disk partition structure is to be updated.
+
+Return Value:
+
+ OK_STATUS or error code.
+
+--*/
+
+{
+ PDRIVE_LAYOUT_INFORMATION DriveLayout;
+ PPARTITION_INFORMATION pinfo;
+ PPARTITION n,p;
+ ULONG EntryCount;
+ ARC_STATUS status;
+ LARGE_INTEGER StartingOffset;
+ LARGE_INTEGER ExtendedStartingOffset;
+
+ ExtendedStartingOffset.QuadPart = 0;
+
+ // allocate a huge buffer now to avoid complicated dynamic
+ // reallocation schemes later.
+
+ if(!(DriveLayout = AllocateMemory(250 * sizeof(PARTITION_INFORMATION)))) {
+ RETURN_OUT_OF_MEMORY;
+ }
+
+ pinfo = &DriveLayout->PartitionEntry[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, &sector_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,
+ &sector_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 <bootmbr.h>
+
+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; i<NUM_PARTITION_TABLE_ENTRIES; i++) {
+
+ if(ptable[i].PartitionType == SYSID_UNUSED) {
+
+ // set as unused.
+
+ p[Entry].PartitionType = SYSID_UNUSED;
+ p[Entry].BootIndicator = FALSE;
+ p[Entry].RewritePartition = FALSE;
+ p[Entry].PartitionLength.QuadPart = 0;
+ p[Entry].HiddenSectors = 0;
+ p[Entry].StartingOffset.QuadPart = 0;
+ p[Entry].RecognizedPartition = FALSE;
+
+ } else {
+
+ LARGE_INTEGER Result1, Result2;
+
+ p[Entry].PartitionType = ptable[i].PartitionType;
+ p[Entry].BootIndicator = ptable[i].ActiveFlag;
+ p[Entry].RewritePartition = FALSE;
+ p[Entry].PartitionLength.QuadPart = UInt32x32To64(PLENGTH(ptable + i),bps);
+
+ // BUGBUG (tedm) the following are not correct for link
+ // entries in the extended partition.
+ // But fdisk does not use these values in
+ // this case so blow it off. As of
+ // 11/13/91, IoReadPartitionTable has the
+ // same bug.
+
+ p[Entry].HiddenSectors = PSTART(ptable + i);
+ Result1.QuadPart = UInt32x32To64(PSTART(ptable + i),bps);
+ Result2.QuadPart = UInt32x32To64(BootSector,bps);
+ p[Entry].StartingOffset.QuadPart = Result1.QuadPart + Result2.QuadPart;
+
+ p[Entry].RecognizedPartition = TRUE; // BUGBUG this is broken
+
+ if(p[Entry].PartitionType == SYSID_EXTENDED) {
+
+ Link = TRUE;
+
+ if(mbr) {
+ mbr = FALSE;
+ BootSector = PSTART(ptable + i);
+ ExtendedStart = BootSector;
+ } else {
+ BootSector = ExtendedStart + PSTART(ptable + i);
+ }
+ }
+ }
+ Entry++;
+ }
+ } while(Link);
+
+ LowCloseDisk(Handle);
+
+ AlDeallocateHeap(SectorBuffer);
+
+ if(status != ESUCCESS) {
+
+ AlDeallocateHeap(DriveInfo);
+ return(status);
+ }
+
+ // reallocate DriveInfo, set PartitionCount field.
+ // DriveInfo is shrinking.
+
+ DriveInfo = AlReallocateHeap(DriveInfo,
+ sizeof(DRIVE_LAYOUT_INFORMATION)
+ + ((Entry - 1) * sizeof(PARTITION_INFORMATION))
+ );
+
+ DriveInfo->PartitionCount = 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; i<ENTRIES_PER_BOOTSECTOR; i++) {
+ ZeroPartitionTableEntry(PartitionTable+i);
+ }
+}
+
+
+ARC_STATUS
+LowSetDiskLayout(
+ IN PCHAR Path,
+ IN PDRIVE_LAYOUT_INFORMATION DriveLayout
+ )
+{
+ ARC_STATUS status;
+ ULONG dummy,bps,spt,h;
+ PCHAR SectorBuffer;
+ ULONG Handle;
+ PPARTITION_DESCRIPTOR PartitionTable;
+ PPARTITION_INFORMATION p;
+ BOOLEAN mbr = TRUE,Update;
+ ULONG BootSector = 0,ExtendedPartitionStart = 0,
+ NextBootSector;
+ ULONG i,j,UsedCount;
+ CHS chs;
+
+
+#define SECCNT(l) ((ULONG)(((ULONGLONG)l.QuadPart)/((ULONGLONG)bps)))
+
+
+ ASRT(DriveLayout->PartitionCount);
+
+ 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; i<DriveLayout->PartitionCount; i+=ENTRIES_PER_BOOTSECTOR) {
+
+ Update = FALSE;
+ UsedCount = 0;
+
+ ZeroPartitionTable(PartitionTable);
+
+ for(j=0; j<ENTRIES_PER_BOOTSECTOR; j++) {
+
+ p = &DriveLayout->PartitionEntry[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
+<<NOKEEP
+ binplace obj\mips\arcinst.exe
diff --git a/private/ntos/arcinst/mips/sources b/private/ntos/arcinst/mips/sources
new file mode 100644
index 000000000..06e5b503c
--- /dev/null
+++ b/private/ntos/arcinst/mips/sources
@@ -0,0 +1,12 @@
+MIPS_SOURCES=\
+ fdengine.c \
+ memory.c \
+ almisc.c \
+ fmtexp.c \
+ low.c \
+ nlsboot.c \
+ partit.c \
+ jzcrap.c \
+ arcinst.c
+
+NTTARGETFILES=obj\mips\arcinst.exe
diff --git a/private/ntos/arcinst/nlsboot.c b/private/ntos/arcinst/nlsboot.c
new file mode 100644
index 000000000..e7f0b6e28
--- /dev/null
+++ b/private/ntos/arcinst/nlsboot.c
@@ -0,0 +1,711 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ nlsboot.c
+
+Abstract:
+
+ This module contains NLS routines for use by the OS Loader. Before
+ the NLS tables are loaded, they convert between ANSI and Unicode by
+ zero-extending.
+
+Author:
+
+ John Vert (jvert) 11-Nov-1992
+
+Revision History:
+
+ John Vert (jvert) 11-Nov-1992
+ created - mostly copied from old RTL routines
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+//
+// Hack-o-rama string routines to use before tables are loaded
+//
+
+#define upcase(C) (WCHAR )(((C) >= '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<LoopCount;i++) {
+
+ MultiByteString[i] = (UCHAR)RtlUpcaseUnicodeChar((UCHAR)(UnicodeString[i]));
+ }
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+RtlMultiByteToUnicodeN(
+ OUT PWCH UnicodeString,
+ IN ULONG MaxBytesInUnicodeString,
+ OUT PULONG BytesInUnicodeString OPTIONAL,
+ IN PCH MultiByteString,
+ IN ULONG BytesInMultiByteString)
+
+/*++
+
+Routine Description:
+
+ This functions converts the specified ansi source string into a
+ Unicode string. The translation is done with respect to the
+ ANSI Code Page (ACP) installed at boot time. Single byte characters
+ in the range 0x00 - 0x7f are simply zero extended as a performance
+ enhancement. In some far eastern code pages 0x5c is defined as the
+ Yen sign. For system translation we always want to consider 0x5c
+ to be the backslash character. We get this for free by zero extending.
+
+ NOTE: This routine only supports precomposed Unicode characters.
+
+Arguments:
+
+ UnicodeString - Returns a unicode string that is equivalent to
+ the ansi source string.
+
+ MaxBytesInUnicodeString - Supplies the maximum number of bytes to be
+ written to UnicodeString. If this causes UnicodeString to be a
+ truncated equivalent of MultiByteString, no error condition results.
+
+ BytesInUnicodeString - Returns the number of bytes in the returned
+ unicode string pointed to by UnicodeString.
+
+ MultiByteString - Supplies the ansi source string that is to be
+ converted to unicode.
+
+ BytesInMultiByteString - The number of bytes in the string pointed to
+ by MultiByteString.
+
+Return Value:
+
+ SUCCESS - The conversion was successful.
+
+
+--*/
+
+{
+ ULONG LoopCount;
+ PUSHORT TranslateTable;
+ ULONG MaxCharsInUnicodeString;
+ ULONG i;
+
+ MaxCharsInUnicodeString = MaxBytesInUnicodeString / sizeof(WCHAR);
+
+ LoopCount = (MaxCharsInUnicodeString < BytesInMultiByteString) ?
+ MaxCharsInUnicodeString : BytesInMultiByteString;
+
+ if (ARGUMENT_PRESENT(BytesInUnicodeString))
+ *BytesInUnicodeString = LoopCount * sizeof(WCHAR);
+
+ for (i=0;i<LoopCount;i++) {
+ UnicodeString[i] = (WCHAR)((UCHAR)(MultiByteString[i]));
+ }
+
+ return(STATUS_SUCCESS);
+}
+
+NTSTATUS
+RtlUnicodeToMultiByteN(
+ OUT PCH MultiByteString,
+ IN ULONG MaxBytesInMultiByteString,
+ OUT PULONG BytesInMultiByteString OPTIONAL,
+ IN PWCH UnicodeString,
+ IN ULONG BytesInUnicodeString)
+
+/*++
+
+Routine Description:
+
+ This functions converts the specified unicode source string 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
+ 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<LoopCount;i++) {
+ MultiByteString[i] = (CHAR)UnicodeString[i];
+ }
+
+ return STATUS_SUCCESS;
+
+}
diff --git a/private/ntos/arcinst/partit.c b/private/ntos/arcinst/partit.c
new file mode 100644
index 000000000..4a0882fbd
--- /dev/null
+++ b/private/ntos/arcinst/partit.c
@@ -0,0 +1,727 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ partit.c
+
+Abstract:
+
+ This module contains entry points to perform the
+ 'configure system partition' and 'create OS loader'
+ options of the ARC installer.
+
+Author:
+
+ Ted Miller (tedm) Nov-1991
+
+Revision History:
+
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+PCHAR
+AlGetNextArcNamToken (
+ IN PCHAR TokenString,
+ OUT PCHAR OutputToken,
+ OUT PULONG UnitNumber
+ );
+
+#define STATUS_ROW_TOP 13
+#define STATUS_ROW_BOTTOM 17
+
+char NOMEMMSG[] = "Insufficient memory";
+char NOCNFMSG[] = "Unable to determine disk configuration (ARC status = %u)";
+char NOFMTMSG[] = "Format failed (ARC status = %u)";
+char DSKFLMSG[] = "Disk is full";
+char NOCREMSG[] = "Could not create partition (ARC status = %u)";
+char NODELMSG[] = "Could not delete partition (ARC status = %u)";
+char ALREAMSG[] = "Partition is already a system partition";
+char NOFILMSG[] = "Unable to determine filesystem on partition (ARC status = %u)";
+char NOENVMSG[] = "Error (ARC status = %u) determining environment";
+char NOEVAMSG[] = "Could not add partition to environment (ARC status = %u)";
+char NOEVDMSG[] = "Could not remove partition from environment (ARC status = %u)";
+char NOSYSMSG[] = "No system partitions defined";
+char NOPARMSG[] = "No partitions on this disk";
+
+char SYSPARTVAR[] = "SYSTEMPARTITION";
+char OSLOADERVAR[] = "OSLOADER";
+char OSLOADPARTVAR[] = "OSLOADPARTITION";
+
+#define MsgNoMem() AlStatusMsg(STATUS_ROW_TOP,STATUS_ROW_BOTTOM,TRUE,NOMEMMSG);
+
+PCHAR SysPartMenu[] = { "Create System Partition",
+ "Delete Partition",
+ "Make Existing Partition into System Partition",
+ "Exit"
+ };
+
+#define SYSPARTMENU_CREATE 0
+#define SYSPARTMENU_DELETE 1
+#define SYSPARTMENU_ADD 2
+#define SYSPARTMENU_EXIT 3
+
+#define MENU_ROW 4
+
+char sprintfBuffer[256];
+
+BOOLEAN
+Confirm(
+ PCHAR Warning
+ )
+{
+ char c;
+ ULONG Count;
+
+ AlClearStatusArea(STATUS_ROW_TOP,STATUS_ROW_BOTTOM);
+ AlPrint("%s%s (y/n)?",MSGMARGIN,Warning);
+ ArcRead(ARC_CONSOLE_INPUT,&c,1,&Count);
+ while((c != 'y') && (c != 'Y') && (c != 'n') && (c != 'N') && (c != ASCI_ESC)) {
+ ArcRead(ARC_CONSOLE_INPUT,&c,1,&Count);
+ }
+ AlClearStatusArea(STATUS_ROW_TOP,STATUS_ROW_BOTTOM);
+ return((BOOLEAN)((c == 'y') || (c == 'Y')));
+}
+
+
+VOID
+PrintErrorMsg(
+ PCHAR FormatString,
+ ...
+ )
+{
+ va_list ArgList;
+
+ va_start(ArgList,FormatString);
+
+ AlClearStatusArea(STATUS_ROW_TOP,STATUS_ROW_BOTTOM);
+ vAlStatusMsg(STATUS_ROW_TOP,TRUE,FormatString,ArgList);
+
+ AlWaitKey(NULL);
+ AlClearStatusArea(STATUS_ROW_TOP,STATUS_ROW_BOTTOM);
+}
+
+
+VOID
+PrintMsg(
+ PCHAR FormatString,
+ ...
+ )
+{
+ va_list ArgList;
+
+ va_start(ArgList,FormatString);
+
+ AlClearStatusArea(STATUS_ROW_TOP,STATUS_ROW_BOTTOM);
+ vAlStatusMsg(STATUS_ROW_TOP,FALSE,FormatString,ArgList);
+
+ AlWaitKey(NULL);
+ AlClearStatusArea(STATUS_ROW_TOP,STATUS_ROW_BOTTOM);
+}
+
+
+BOOLEAN
+IsBootSelectionPartition(
+ PCHAR Variable,
+ ULONG Disk,
+ ULONG Partition,
+ PULONG MatchNumber OPTIONAL
+ )
+{
+ char text[256];
+ PCHAR Var = ArcGetEnvironmentVariable(Variable);
+
+ if (Var == NULL) {
+ return(FALSE);
+ }
+
+ sprintf(text,"%spartition(%u)",GetDiskName(Disk),Partition);
+ return(AlFindNextMatchComponent(Var,text,0,MatchNumber));
+}
+
+
+LONG
+ChooseDisk(
+ VOID
+ )
+{
+ ULONG DiskCount = GetDiskCount();
+ PVOID MenuID;
+ LONG Disk;
+ ULONG ChosenDisk;
+ PCHAR DiskName,TempDiskName;
+ ULONG UnitNumber,ScsiNumber,ScsiId,DiskNumber;
+ CHAR Token[32];
+
+ if (DiskCount == 1) {
+ return(0);
+ }
+
+ if (!AlNewMenu(&MenuID)) {
+ MsgNoMem();
+ return(-1);
+ }
+
+ for(Disk = DiskCount - 1; Disk >= 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<RegionCount; i++) {
+
+ sprintf(sprintfBuffer,"%u MB space",Regions[i].SizeMB);
+ if (Regions[i].RegionType == REGION_LOGICAL) {
+ strcat(sprintfBuffer," (in extended partition)");
+ }
+ if (!AlAddMenuItem(MenuID,sprintfBuffer,i,0)) {
+ MsgNoMem();
+ AlFreeMenu(MenuID);
+ FreeRegionArray(Regions,RegionCount);
+ return(FALSE);
+ }
+ }
+
+ if (!AlDisplayMenu(MenuID,FALSE,0,&Choice,MENU_ROW,"Available Free Spaces")) {
+ // user escaped
+ AlClearStatusArea(STATUS_ROW_TOP,STATUS_ROW_BOTTOM);
+ AlFreeMenu(MenuID);
+ FreeRegionArray(Regions,RegionCount);
+ return(FALSE);
+ }
+ } else {
+ Choice = 0;
+ }
+
+ AlFreeMenu(MenuID);
+
+ // now ask the user for the size of the partition to create in the chosen space.
+
+ do {
+ AlClearStatusArea(STATUS_ROW_TOP,STATUS_ROW_BOTTOM);
+ AlPrint("%sEnter size in MB (1-%u): ",MSGMARGIN,Regions[Choice].SizeMB);
+ if (!AlGetString(sprintfBuffer,sizeof(sprintfBuffer))) {
+ FreeRegionArray(Regions,RegionCount);
+ return(FALSE);
+ }
+ ChosenSize = atoi(sprintfBuffer);
+ if (!ChosenSize || (ChosenSize > 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<RegionCount; i++) {
+
+ sprintf(sprintfBuffer,"%s%u MB ",Regions[i].RegionType == REGION_LOGICAL ? " " : "",Regions[i].SizeMB);
+ strcat(sprintfBuffer,GetSysIDName(Regions[i].SysID));
+ strcat(sprintfBuffer,Regions[i].RegionType == REGION_LOGICAL ? " Logical Volume" : " Partition");
+ if (IsExtended(Regions[i].SysID) && xLogical) {
+ strcat(sprintfBuffer,", also resulting in the deletion of:");
+ }
+
+ if (!AlAddMenuItem(MenuID,sprintfBuffer,i,0)) {
+ MsgNoMem();
+ err = TRUE;
+ break;
+ }
+ }
+
+ if (!err) {
+
+ if (AlDisplayMenu(MenuID,FALSE,0,&Choice,MENU_ROW,"Select Partition to Delete")) {
+
+ if (IsBootSelectionPartition(SYSPARTVAR,Disk,Regions[Choice].PartitionNumber,NULL)) {
+ Confirmation = Confirm("The selected partition is (or contains) a system partition.\r\n Are you sure you want to delete it");
+ } else {
+ if (IsBootSelectionPartition(OSLOADPARTVAR,Disk,Regions[Choice].PartitionNumber,NULL)) {
+ Confirmation = Confirm("The selected partition contains an operating system.\r\n Are you sure you want to delete it");
+ } else {
+ Confirmation = Confirm("Are you sure");
+ }
+ }
+ if (Confirmation) {
+ if (((status = DeletePartition(&Regions[Choice])) != ESUCCESS)
+ || ((status = CommitPartitionChanges(Disk)) != ESUCCESS))
+ {
+ PrintErrorMsg(NODELMSG,status);
+ } else {
+ PrintMsg("Partition deleted successfully.");
+
+ sprintf(sprintfBuffer,
+ "%spartition(%u)",
+ GetDiskName(Disk),
+ Regions[Choice].PartitionNumber
+ );
+
+ //
+ // If there are any boot selections and the deleted partition
+ // was used, ask if the associated boot selections should be
+ // deleted.
+ //
+
+ if (ArcGetEnvironmentVariable(OSLOADPARTVAR) != NULL) {
+ if ((IsBootSelectionPartition(SYSPARTVAR,Disk,Regions[Choice].PartitionNumber,NULL) ||
+ IsBootSelectionPartition(OSLOADPARTVAR,Disk,Regions[Choice].PartitionNumber,NULL)) &&
+ Confirm("Do you want to delete the boot selection(s) associated\r\n with the deleted partition?")) {
+
+ while (IsBootSelectionPartition(SYSPARTVAR,Disk,Regions[Choice].PartitionNumber,&MatchNumber)) {
+ for ( Index = 0 ; Index < MaximumBootVariable ; Index++ ) {
+ JzDeleteVariableSegment(BootString[Index],MatchNumber);
+ }
+ }
+
+ while (IsBootSelectionPartition(OSLOADPARTVAR,Disk,Regions[Choice].PartitionNumber,&MatchNumber)) {
+ for ( Index = 0 ; Index < MaximumBootVariable ; Index++ ) {
+ JzDeleteVariableSegment(BootString[Index],MatchNumber);
+ }
+ }
+ }
+
+ } else {
+
+ //
+ // There are no boot selections but delete all segments
+ // of the SystemPartition variable that pointed to the
+ // deleted partition.
+ //
+
+ while (IsBootSelectionPartition(SYSPARTVAR,Disk,Regions[Choice].PartitionNumber,&MatchNumber)) {
+ JzDeleteVariableSegment(BootString[SystemPartitionVariable],MatchNumber);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ FreeRegionArray(Regions,RegionCount);
+ }
+ AlFreeMenu(MenuID);
+
+ } else {
+ PrintErrorMsg("No partitions on this disk");
+ }
+}
+
+
+VOID
+DoSystemPartitionCreate(
+ VOID
+ )
+{
+ ULONG DiskNo,PartitionNo;
+ ARC_STATUS status;
+
+ if (DoPartitionCreate(&DiskNo,&PartitionNo)) {
+
+ sprintf(sprintfBuffer,"%spartition(%u)",GetDiskName(DiskNo),PartitionNo);
+
+ // add the partition to the SYSTEMPARTITION NVRAM environment variable
+
+ if ((status = AlAddSystemPartition(sprintfBuffer)) != ESUCCESS) {
+ PrintErrorMsg(NOEVAMSG,status);
+ return;
+ }
+
+ AlStatusMsgNoWait(STATUS_ROW_TOP,STATUS_ROW_BOTTOM,FALSE,"Formatting %s",sprintfBuffer);
+ status = FmtFatFormat(sprintfBuffer,GetHiddenSectorCount(DiskNo,PartitionNo));
+ if (status == ESUCCESS) {
+ SetSysID(DiskNo,PartitionNo,SYSID_BIGFAT);
+ PrintMsg("Partition formatted successfully.");
+ } else {
+ PrintErrorMsg(NOFMTMSG,status);
+ }
+ }
+}
+
+
+VOID
+DoMakePartitionSystemPartition(
+ VOID
+ )
+{
+ BOOLEAN f,IsFAT;
+ ULONG Disk,i,Choice;
+ PVOID MenuID;
+ PREGION_DESCRIPTOR Regions;
+ ULONG RegionCount;
+ ARC_STATUS status;
+ char PartitionPath[256];
+ ULONG PartitionNumber;
+
+
+ // take an existing partition and add it to the
+ // list of system partitions. Also make sure it's
+ // formatted as FAT.
+
+ if ((Disk = ChooseDisk()) == -1) {
+ return;
+ }
+
+ status = GetUsedDiskRegions(Disk,&Regions,&RegionCount);
+ if (status != ESUCCESS) {
+ PrintErrorMsg(NOCNFMSG,status);
+ return;
+ }
+
+ if (!RegionCount) {
+ FreeRegionArray(Regions,RegionCount);
+ PrintErrorMsg(NOPARMSG);
+ return;
+ }
+
+ if (!AlNewMenu(&MenuID)) {
+ FreeRegionArray(Regions,RegionCount);
+ MsgNoMem();
+ return;
+ }
+
+ for(i=0; i<RegionCount; i++) {
+ if (!IsExtended(Regions[i].SysID)) {
+ sprintf(sprintfBuffer,
+ "Partition %u (%u MB %s)",
+ Regions[i].PartitionNumber,
+ Regions[i].SizeMB,
+ GetSysIDName(Regions[i].SysID)
+ );
+ if (!AlAddMenuItem(MenuID,sprintfBuffer,i,0)) {
+ MsgNoMem();
+ AlFreeMenu(MenuID);
+ FreeRegionArray(Regions,RegionCount);
+ return;
+ }
+ }
+ }
+
+ f = AlDisplayMenu(MenuID,FALSE,0,&Choice,MENU_ROW,"Choose Partition");
+ AlFreeMenu(MenuID);
+ if (!f) { // user escaped
+ FreeRegionArray(Regions,RegionCount);
+ return;
+ }
+
+ PartitionNumber = Regions[Choice].PartitionNumber;
+ sprintf(PartitionPath,"%spartition(%u)",GetDiskName(Disk),PartitionNumber);
+
+ FreeRegionArray(Regions,RegionCount);
+
+ if(IsBootSelectionPartition(SYSPARTVAR,Disk,PartitionNumber,NULL)) {
+ PrintErrorMsg(ALREAMSG);
+ return;
+ }
+
+ status = FmtIsFat(PartitionPath,&IsFAT);
+ if (status != ESUCCESS) {
+ PrintErrorMsg(NOFILMSG,status);
+ return;
+ }
+
+ if (!IsFAT) {
+ if (Confirm("System partitions must be formatted with the FAT filesystem.\r\n Do you wish to format the chosen partition")
+ && Confirm("All existing data will be lost. Are you sure"))
+ {
+ status = FmtFatFormat(PartitionPath,GetHiddenSectorCount(Disk,PartitionNumber));
+ if (status != ESUCCESS) {
+ PrintErrorMsg(NOFMTMSG,status);
+ return;
+ }
+ SetSysID(Disk,PartitionNumber,SYSID_BIGFAT);
+ } else {
+ return;
+ }
+ }
+
+ //
+ // Add to list of system partitions.
+ //
+ if ((status = AlAddSystemPartition(PartitionPath)) == ESUCCESS) {
+ PrintMsg("Partition added successfully.");
+ } else {
+ PrintErrorMsg(NOEVAMSG,status);
+ }
+}
+
+
+
+VOID
+ConfigureSystemPartitions(
+ VOID
+ )
+{
+ ULONG Choice=0,DiskCount=GetDiskCount();
+ PVOID MenuID;
+
+ if (!AlNewMenu(&MenuID)) {
+ MsgNoMem();
+ return;
+ }
+
+ if (!AlAddMenuItems(MenuID,SysPartMenu,sizeof(SysPartMenu)/sizeof(PCHAR))) {
+ MsgNoMem();
+ AlFreeMenu(MenuID);
+ return;
+ }
+
+ while(1) {
+
+ if ((!AlDisplayMenu(MenuID,FALSE,Choice,&Choice,MENU_ROW,"Configure System Partitions"))
+ || (Choice == SYSPARTMENU_EXIT))
+ {
+ break;
+ }
+
+ switch(Choice) {
+
+ case SYSPARTMENU_CREATE:
+ // create system partition.
+ DoSystemPartitionCreate();
+ break;
+
+ case SYSPARTMENU_DELETE:
+ // delete partition
+ DoPartitionDelete();
+ break;
+
+ case SYSPARTMENU_ADD:
+ // make existing into a system partition
+ DoMakePartitionSystemPartition();
+ break;
+ }
+ }
+
+ AlFreeMenu(MenuID);
+}
diff --git a/private/ntos/arcinst/precomp.h b/private/ntos/arcinst/precomp.h
new file mode 100644
index 000000000..c73d70965
--- /dev/null
+++ b/private/ntos/arcinst/precomp.h
@@ -0,0 +1 @@
+#include "arcinst.h"
diff --git a/private/ntos/arcinst/sources b/private/ntos/arcinst/sources
new file mode 100644
index 000000000..51ce4e811
--- /dev/null
+++ b/private/ntos/arcinst/sources
@@ -0,0 +1,16 @@
+MAJORCOMP=arcinst
+MINORCOMP=arcinst
+
+TARGETNAME=arcinst
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+
+C_DEFINES=$(C_DEFINES) -D_NTSYSTEM_
+
+INCLUDES=..\inc
+
+SOURCES=
+
+PRECOMPILED_INCLUDE=precomp.h
+PRECOMPILED_PCH=precomp.pch
+PRECOMPILED_OBJ=precomp.obj