test: fdengine.c Source File

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# fdengine.c

Go to the documentation of this file.

    00001 /*++
    00002
    00003 Copyright (c) 1991  Microsoft Corporation
    00004
    00005 Module Name:
    00006
    00007     fdengine.c
    00008
    00009 Abstract:
    00010
    00011     This module contains the disk partitioning engine.  The code
    00012     in this module can be compiled for either the NT platform
    00013     or the ARC platform (-DARC).
    00014
    00015 Author:
    00016
    00017     Ted Miller        (tedm)    Nov-1991
    00018
    00019 Revision History:
    00020
    00021 --*/
    00022
    00023 #include "precomp.h"
    00024 #pragma hdrstop
    00025
    00026 #define ARCDBG
    00027
    00028 // Attached disk devices.
    00029
    00030 ULONG              CountOfDisks;
    00031 PCHAR             *DiskNames;
    00032
    00033 // Information about attached disks.
    00034
    00035 DISKGEOM          *DiskGeometryArray;
    00036
    00037 PPARTITION        *PrimaryPartitions,
    00038                   *LogicalVolumes;
    00039
    00040 //
    00041 // Array keeping track of whether each disk is off line.
    00042 //
    00043 PBOOLEAN           OffLine;
    00044
    00045 // Keeps track of whether changes have been made
    00046 // to each disk's partition structure.
    00047
    00048 BOOLEAN           *ChangesMade;
    00049
    00050
    00051 //
    00052 // Value used to indicate that the partition entry has changed but in a non-
    00053 // destructive way (ie, made active/inactive).
    00054 //
    00055 #define CHANGED_DONT_ZAP ((BOOLEAN)(5))
    00056
    00057 // forward declarations
    00058
    00059
    00060 ARC_STATUS
    00061 OpenDisks(
    00062     VOID
    00063     );
    00064
    00065 VOID
    00066 CloseDisks(
    00067     VOID
    00068     );
    00069
    00070 ARC_STATUS
    00071 GetGeometry(
    00072     VOID
    00073     );
    00074
    00075 BOOLEAN
    00076 CheckIfDiskIsOffLine(
    00077     IN ULONG Disk
    00078     );
    00079
    00080 ARC_STATUS
    00081 InitializePartitionLists(
    00082     VOID
    00083     );
    00084
    00085 ARC_STATUS
    00086 GetRegions(
    00087     IN  ULONG               Disk,
    00088     IN  PPARTITION          p,
    00089     IN  BOOLEAN             WantUsedRegions,
    00090     IN  BOOLEAN             WantFreeRegions,
    00091     IN  BOOLEAN             WantLogicalRegions,
    00092     OUT PREGION_DESCRIPTOR *Region,
    00093     OUT ULONG              *RegionCount,
    00094     IN  REGION_TYPE         RegionType
    00095     );
    00096
    00097 BOOLEAN
    00098 AddRegionEntry(
    00099     IN OUT PREGION_DESCRIPTOR *Regions,
    00100     IN OUT ULONG              *RegionCount,
    00101     IN     ULONG               SizeMB,
    00102     IN     REGION_TYPE         RegionType,
    00103     IN     PPARTITION          Partition,
    00104     IN     LARGE_INTEGER       AlignedRegionOffset,
    00105     IN     LARGE_INTEGER       AlignedRegionSize
    00106     );
    00107
    00108 VOID
    00109 AddPartitionToLinkedList(
    00110     IN PARTITION **Head,
    00111     IN PARTITION *p
    00112     );
    00113
    00114 BOOLEAN
    00115 IsInLinkedList(
    00116     IN PPARTITION p,
    00117     IN PPARTITION List
    00118     );
    00119
    00120 BOOLEAN
    00121 IsInLogicalList(
    00122     IN ULONG      Disk,
    00123     IN PPARTITION p
    00124     );
    00125
    00126 BOOLEAN
    00127 IsInPartitionList(
    00128     IN ULONG      Disk,
    00129     IN PPARTITION p
    00130     );
    00131
    00132 LARGE_INTEGER
    00133 AlignTowardsDiskStart(
    00134     IN ULONG         Disk,
    00135     IN LARGE_INTEGER Offset
    00136     );
    00137
    00138 LARGE_INTEGER
    00139 AlignTowardsDiskEnd(
    00140     IN ULONG         Disk,
    00141     IN LARGE_INTEGER Offset
    00142     );
    00143
    00144 VOID
    00145 FreeLinkedPartitionList(
    00146     IN PARTITION **q
    00147     );
    00148
    00149 VOID
    00150 MergeFreePartitions(
    00151     IN PPARTITION p
    00152     );
    00153
    00154 VOID
    00155 RenumberPartitions(
    00156     ULONG Disk
    00157     );
    00158
    00159 VOID
    00160 FreePartitionInfoLinkedLists(
    00161     IN PARTITION **ListHeadArray
    00162     );
    00163
    00164 LARGE_INTEGER
    00165 DiskLengthBytes(
    00166     IN ULONG Disk
    00167     );
    00168
    00169 PPARTITION
    00170 AllocatePartitionStructure(
    00171     IN ULONG         Disk,
    00172     IN LARGE_INTEGER Offset,
    00173     IN LARGE_INTEGER Length,
    00174     IN UCHAR         SysID,
    00175     IN BOOLEAN       Update,
    00176     IN BOOLEAN       Active,
    00177     IN BOOLEAN       Recognized
    00178     );
    00179
    00180
    00181
    00182 ARC_STATUS
    00183 FdiskInitialize(
    00184     VOID
    00185     )
    00186
    00187 /*++
    00188
    00189 Routine Description:
    00190
    00191     This routine initializes the partitioning engine, including allocating
    00192     arrays, determining attached disk devices, and reading their
    00193     partition tables.
    00194
    00195 Arguments:
    00196
    00197     None.
    00198
    00199 Return Value:
    00200
    00201     OK_STATUS or error code.
    00202
    00203 --*/
    00204
    00205 {
    00206     ARC_STATUS status;
    00207     ULONG        i;
    00208
    00209
    00210     if((status = LowQueryFdiskPathList(&DiskNames,&CountOfDisks)) != OK_STATUS) {
    00211         return(status);
    00212     }
    00213
    00214 #if 0
    00215 #ifdef ARCDBG
    00216     AlPrint("Disk count = %u\r\n",CountOfDisks);
    00217     for(i=0; i<CountOfDisks; i++) {
    00218         AlPrint("Disk %u: %s\r\n",i,DiskNames[i]);
    00219     }
    00220     WaitKey();
    00221 #endif
    00222 #endif
    00223
    00224     DiskGeometryArray = NULL;
    00225     PrimaryPartitions = NULL;
    00226     LogicalVolumes = NULL;
    00227
    00228     if(((DiskGeometryArray      = AllocateMemory(CountOfDisks * sizeof(DISKGEOM  ))) == NULL)
    00229     || ((ChangesMade            = AllocateMemory(CountOfDisks * sizeof(BOOLEAN   ))) == NULL)
    00230     || ((PrimaryPartitions      = AllocateMemory(CountOfDisks * sizeof(PPARTITION))) == NULL)
    00231     || ((OffLine                = AllocateMemory(CountOfDisks * sizeof(BOOLEAN   ))) == NULL)
    00232     || ((LogicalVolumes         = AllocateMemory(CountOfDisks * sizeof(PPARTITION))) == NULL))
    00233     {
    00234         RETURN_OUT_OF_MEMORY;
    00235     }
    00236
    00237     for(i=0; i<CountOfDisks; i++) {
    00238         PrimaryPartitions[i] = NULL;
    00239         LogicalVolumes[i] = NULL;
    00240         ChangesMade[i] = FALSE;
    00241         OffLine[i] = CheckIfDiskIsOffLine(i);
    00242         if(OffLine[i]) {
    00243             return(ENODEV);
    00244         }
    00245     }
    00246
    00247     if(((status = GetGeometry()             ) != OK_STATUS)
    00248     || ((status = InitializePartitionLists()) != OK_STATUS))
    00249     {
    00250         return(status);
    00251     }
    00252
    00253     return(OK_STATUS);
    00254 }
    00255
    00256
    00257 VOID
    00258 FdiskCleanUp(
    00259     VOID
    00260     )
    00261
    00262 /*++
    00263
    00264 Routine Description:
    00265
    00266     This routine deallocates storage used by the partitioning engine.
    00267
    00268 Arguments:
    00269
    00270     None.
    00271
    00272 Return Value:
    00273
    00274     None.
    00275
    00276 --*/
    00277
    00278 {
    00279     LowFreeFdiskPathList(DiskNames,CountOfDisks);
    00280
    00281     if(DiskGeometryArray != NULL) {
    00282         FreeMemory(DiskGeometryArray);
    00283     }
    00284     if(PrimaryPartitions != NULL) {
    00285         FreePartitionInfoLinkedLists(PrimaryPartitions);
    00286         FreeMemory(PrimaryPartitions);
    00287     }
    00288     if(LogicalVolumes != NULL) {
    00289         FreePartitionInfoLinkedLists(LogicalVolumes);
    00290         FreeMemory(LogicalVolumes);
    00291     }
    00292     if(ChangesMade != NULL) {
    00293         FreeMemory(ChangesMade);
    00294     }
    00295     if(OffLine != NULL) {
    00296         FreeMemory(OffLine);
    00297     }
    00298 }
    00299
    00300
    00301 BOOLEAN
    00302 CheckIfDiskIsOffLine(
    00303     IN ULONG Disk
    00304     )
    00305
    00306 /*++
    00307
    00308 Routine Description:
    00309
    00310     Determine whether a disk is off-line by attempting to open it.
    00311     If this is diskman, also attempt to read from it.
    00312
    00313 Arguments:
    00314
    00315     Disk - supplies number of the disk to check
    00316
    00317 Return Value:
    00318
    00319     TRUE if disk is off-line, FALSE is disk is on-line.
    00320
    00321 --*/
    00322
    00323 {
    00324     ULONG Handle;
    00325     BOOLEAN IsOffLine;
    00326
    00327     if(LowOpenDisk(GetDiskName(Disk),&Handle) == OK_STATUS) {
    00328
    00329         IsOffLine = FALSE;
    00330         LowCloseDisk(Handle);
    00331
    00332     } else {
    00333
    00334         IsOffLine = TRUE;
    00335     }
    00336
    00337     return(IsOffLine);
    00338 }
    00339
    00340
    00341 ARC_STATUS
    00342 GetGeometry(
    00343     VOID
    00344     )
    00345
    00346 /*++
    00347
    00348 Routine Description:
    00349
    00350     This routine determines disk geometry for each disk device.
    00351     Disk geometry includes heads, sectors per track, cylinder count,
    00352     and bytes per sector.  It also includes bytes per track and
    00353     bytes per cylinder, which are calculated from the other values
    00354     for the convenience of the rest of this module.
    00355
    00356     Geometry information is placed in the DiskGeometryArray global variable.
    00357
    00358     Geometry information is undefined for an off-line disk.
    00359
    00360 Arguments:
    00361
    00362     None.
    00363
    00364 Return Value:
    00365
    00366     OK_STATUS or error code.
    00367
    00368 --*/
    00369
    00370 {
    00371     ULONG       i;
    00372     ARC_STATUS status;
    00373     ULONG       TotalSectorCount,
    00374                 SectorSize,
    00375                 SectorsPerTrack,
    00376                 Heads;
    00377
    00378     for(i=0; i<CountOfDisks; i++) {
    00379
    00380         if(OffLine[i]) {
    00381             continue;
    00382         }
    00383
    00384         if((status = LowGetDriveGeometry(DiskNames[i],&TotalSectorCount,&SectorSize,&SectorsPerTrack,&Heads)) != OK_STATUS) {
    00385             return(status);
    00386         }
    00387
    00388         DiskGeometryArray[i].BytesPerSector   = SectorSize;
    00389         DiskGeometryArray[i].SectorsPerTrack  = SectorsPerTrack;
    00390         DiskGeometryArray[i].Heads            = Heads;
    00391         DiskGeometryArray[i].Cylinders.QuadPart = TotalSectorCount / (SectorsPerTrack * Heads);
    00392         DiskGeometryArray[i].BytesPerTrack    = SectorsPerTrack * SectorSize;
    00393         DiskGeometryArray[i].BytesPerCylinder = SectorsPerTrack * SectorSize * Heads;
    00394     }
    00395     return(OK_STATUS);
    00396 }
    00397
    00398
    00399 #if i386
    00400 VOID
    00401 SetPartitionActiveFlag(
    00402     IN PREGION_DESCRIPTOR Region,
    00403     IN UCHAR              value
    00404     )
    00405 {
    00406     PPARTITION p = ((PREGION_DATA)Region->Reserved)->Partition;
    00407
    00408     if((UCHAR)p->Active != value) {
    00409
    00410         //
    00411         // Unfortuneately, the Update flag becomes the RewritePartition flag
    00412         // at commit time.  This causes us to zap the boot sector.  To avoid
    00413         // this, we use a spacial non-boolean value that can be checked for
    00414         // at commit time and that will cause us NOT to zap the bootsector
    00415         // even though RewritePartition will be TRUE.
    00416         //
    00417
    00418         p->Active = value;
    00419         if(!p->Update) {
    00420             p->Update = CHANGED_DONT_ZAP;
    00421         }
    00422         ChangesMade[p->Disk] = TRUE;
    00423     }
    00424 }
    00425 #endif
    00426
    00427
    00428 VOID
    00429 DetermineCreateSizeAndOffset(
    00430     IN  PREGION_DESCRIPTOR Region,
    00431     IN  LARGE_INTEGER      MinimumSize,
    00432     IN  ULONG              CreationSizeMB,
    00433     IN  REGION_TYPE        Type,
    00434     OUT PLARGE_INTEGER     CreationStart,
    00435     OUT PLARGE_INTEGER     CreationSize
    00436     )
    00437
    00438 /*++
    00439
    00440 Routine Description:
    00441
    00442     Determine the actual offset and size of the partition, given the
    00443     size in megabytes.
    00444
    00445 Arguments:
    00446
    00447     Region  - a region descriptor returned by GetDiskRegions().  Must
    00448               be an unused region.
    00449
    00450     MinimumSize - if non-0, this is the minimum size that the partition
    00451         or logical drive can be.
    00452
    00453     CreationSizeMB - If MinimumSize is 0, size of partition to create, in MB.
    00454
    00455     Type    - REGION_PRIMARY, REGION_EXTENDED, or REGION_LOGICAL, for
    00456               creating a primary partition, extended partition, or
    00457               logical volume, respectively.
    00458
    00459     CreationStart - receives the offset where the partition should be placed.
    00460
    00461     CreationSize - receives the exact size for the partition.
    00462
    00463 Return Value:
    00464
    00465     None.
    00466
    00467 --*/
    00468
    00469 {
    00470     PREGION_DATA CreateData = Region->Reserved;
    00471     LARGE_INTEGER CSize,CStart;
    00472     LARGE_INTEGER Mod;
    00473     ULONG  bpc = DiskGeometryArray[Region->Disk].BytesPerCylinder;
    00474     ULONG  bpt = DiskGeometryArray[Region->Disk].BytesPerTrack;
    00475
    00476     ASRT(Region->SysID == SYSID_UNUSED);
    00477
    00478     //
    00479     // If we are creating a partition at offset 0, adjust the aligned region
    00480     // offset and the aligned region size, because no partition can actually
    00481     // start at offset 0.
    00482     //
    00483
    00484     if(CreateData->AlignedRegionOffset.QuadPart == 0) {
    00485
    00486         LARGE_INTEGER Delta;
    00487
    00488         if(Type == REGION_EXTENDED) {
    00489
    00490             Delta.QuadPart = bpc;
    00491
    00492         } else {
    00493
    00494             ASRT(Type == REGION_PRIMARY);
    00495             Delta.QuadPart = bpt;
    00496         }
    00497
    00498         CreateData->AlignedRegionOffset = Delta;
    00499         CreateData->AlignedRegionSize.QuadPart = (CreateData->AlignedRegionSize.QuadPart - Delta.QuadPart);
    00500     }
    00501
    00502     CStart = CreateData->AlignedRegionOffset;
    00503     if(MinimumSize.QuadPart == 0) {
    00504         CSize.QuadPart = UInt32x32To64(CreationSizeMB,ONE_MEG);
    00505     } else {
    00506         CSize = MinimumSize;
    00507         if(Type == REGION_LOGICAL) {
    00508             CSize.QuadPart = CSize.QuadPart + bpt;
    00509         }
    00510     }
    00511
    00512     //
    00513     // Decide whether to align the ending cylinder up or down.
    00514     // If the offset of end of the partition is more than half way into the
    00515     // final cylinder, align towrds the disk end.  Otherwise align toward
    00516     // the disk start.
    00517     //
    00518
    00519     Mod.QuadPart = (CStart.QuadPart + CSize.QuadPart) % bpc;
    00520
    00521     if(Mod.QuadPart != 0) {
    00522
    00523         if((MinimumSize.QuadPart != 0) || (Mod.QuadPart > bpc/2)) {
    00524             CSize.QuadPart = (CSize.QuadPart + (bpc - Mod.QuadPart));
    00525         } else {
    00526             CSize.QuadPart = (CSize.QuadPart - Mod.QuadPart);        // snap downwards tp cyl boundary
    00527         }
    00528     }
    00529
    00530     if(CSize.QuadPart > CreateData->AlignedRegionSize.QuadPart) {
    00531
    00532         //
    00533         // Space available in the free space isn't large enough to accomodate
    00534         // the request in its entirety;  just use the entire free space.
    00535         //
    00536
    00537         CSize  = CreateData->AlignedRegionSize;
    00538     }
    00539
    00540     ASRT(CStart.QuadPart != 0);
    00541     ASRT(CSize.QuadPart != 0);
    00542
    00543     *CreationStart = CStart;
    00544     *CreationSize  = CSize;
    00545 }
    00546
    00547
    00548 ARC_STATUS
    00549 CreatePartitionEx(
    00550     IN PREGION_DESCRIPTOR Region,
    00551     IN LARGE_INTEGER      MinimumSize,
    00552     IN ULONG              CreationSizeMB,
    00553     IN REGION_TYPE        Type,
    00554     IN UCHAR              SysId
    00555     )
    00556
    00557 /*++
    00558
    00559 Routine Description:
    00560
    00561     This routine creates a partition from a free region on the disk.  The
    00562     partition is always created at the beginning of the free space, and any
    00563     left over space at the end is kept on the free space list.
    00564
    00565 Arguments:
    00566
    00567     Region  - a region descriptor returned by GetDiskRegions().  Must
    00568               be an unused region.
    00569
    00570     CreationSizeMB - size of partition to create, in MB.
    00571
    00572     Type    - REGION_PRIMARY, REGION_EXTENDED, or REGION_LOGICAL, for
    00573               creating a primary partition, extended pasrtition, or
    00574               logical volume, respectively.
    00575
    00576     SysId - system ID byte to be assigned to the partition
    00577
    00578 Return Value:
    00579
    00580     OK_STATUS or error code.
    00581
    00582 --*/
    00583
    00584 {
    00585     PPARTITION    p1,p2,p3;
    00586     PREGION_DATA  CreateData = Region->Reserved;
    00587     LARGE_INTEGER CreationStart,CreationSize,LeftOver;
    00588     PPARTITION   *PartitionList;
    00589
    00590     ASRT(Region->SysID == SYSID_UNUSED);
    00591
    00592     DetermineCreateSizeAndOffset( Region,
    00593                                   MinimumSize,
    00594                                   CreationSizeMB,
    00595                                   Type,
    00596                                   &CreationStart,
    00597                                   &CreationSize
    00598                                 );
    00599
    00600     //
    00601     // now we've got the start and size of the partition to be created.
    00602     // If there's left-over at the beginning of the free space (after
    00603     // alignment), make a new PARTITION structure.
    00604
    00605     p1 = NULL;
    00606     LeftOver.QuadPart = (CreationStart.QuadPart - CreateData->Partition->Offset.QuadPart);
    00607
    00608     if(LeftOver.QuadPart > 0) {
    00609
    00610         p1 = AllocatePartitionStructure(Region->Disk,
    00611                                         CreateData->Partition->Offset,
    00612                                         LeftOver,
    00613                                         SYSID_UNUSED,
    00614                                         FALSE,
    00615                                         FALSE,
    00616                                         FALSE
    00617                                        );
    00618         if(p1 == NULL) {
    00619             RETURN_OUT_OF_MEMORY;
    00620         }
    00621     }
    00622
    00623     // make a new partition structure for space being left free as
    00624     // a result of this creation.
    00625
    00626     p2 = NULL;
    00627     LeftOver.QuadPart = (CreateData->Partition->Offset.QuadPart + CreateData->Partition->Length.QuadPart) -
    00628                         (CreationStart.QuadPart + CreationSize.QuadPart);
    00629
    00630     if(LeftOver.QuadPart != 0) {
    00631
    00632         LARGE_INTEGER   TmpResult;
    00633
    00634         TmpResult.QuadPart = CreationStart.QuadPart + CreationSize.QuadPart;
    00635         p2 = AllocatePartitionStructure(Region->Disk,
    00636                                         TmpResult,
    00637                                         LeftOver,
    00638                                         SYSID_UNUSED,
    00639                                         FALSE,
    00640                                         FALSE,
    00641                                         FALSE
    00642                                        );
    00643         if(p2 == NULL) {
    00644             RETURN_OUT_OF_MEMORY;
    00645         }
    00646     }
    00647
    00648     // adjust the free partition's fields.
    00649
    00650     CreateData->Partition->Offset = CreationStart;
    00651     CreateData->Partition->Length = CreationSize;
    00652     CreateData->Partition->SysID  = SysId;
    00653     CreateData->Partition->Update = TRUE;
    00654     CreateData->Partition->Recognized = TRUE;
    00655
    00656     // if we just created an extended partition, show the whole thing
    00657     // as one free logical region.
    00658
    00659     if(Type == REGION_EXTENDED) {
    00660
    00661         ASRT(LogicalVolumes[Region->Disk] == NULL);
    00662
    00663         p3 = AllocatePartitionStructure(Region->Disk,
    00664                                         CreationStart,
    00665                                         CreationSize,
    00666                                         SYSID_UNUSED,
    00667                                         FALSE,
    00668                                         FALSE,
    00669                                         FALSE
    00670                                        );
    00671         if(p3 == NULL) {
    00672             RETURN_OUT_OF_MEMORY;
    00673         }
    00674         AddPartitionToLinkedList(&LogicalVolumes[Region->Disk],p3);
    00675     }
    00676
    00677     PartitionList = (Type == REGION_LOGICAL)
    00678                   ? &LogicalVolumes[Region->Disk]
    00679                   : &PrimaryPartitions[Region->Disk];
    00680
    00681     if(p1) {
    00682         AddPartitionToLinkedList(PartitionList,p1);
    00683     }
    00684     if(p2) {
    00685         AddPartitionToLinkedList(PartitionList,p2);
    00686     }
    00687
    00688     MergeFreePartitions(*PartitionList);
    00689     RenumberPartitions(Region->Disk);
    00690
    00691     ChangesMade[Region->Disk] = TRUE;
    00692
    00693     return(OK_STATUS);
    00694 }
    00695
    00696
    00697 ARC_STATUS
    00698 CreatePartition(
    00699     IN PREGION_DESCRIPTOR Region,
    00700     IN ULONG              CreationSizeMB,
    00701     IN REGION_TYPE        Type
    00702     )
    00703 {
    00704     LARGE_INTEGER   LargeZero;
    00705
    00706     LargeZero.QuadPart = 0;
    00707     return(CreatePartitionEx(Region,
    00708                              LargeZero,
    00709                              CreationSizeMB,
    00710                              Type,
    00711                              (UCHAR)((Type == REGION_EXTENDED) ? SYSID_EXTENDED
    00712                                                                : SYSID_BIGFAT
    00713                                     )
    00714                             )
    00715           );
    00716 }
    00717
    00718
    00719
    00720 ARC_STATUS
    00721 DeletePartition(
    00722     IN PREGION_DESCRIPTOR Region
    00723     )
    00724
    00725 /*++
    00726
    00727 Routine Description:
    00728
    00729     This routine deletes a partition, returning its space to the
    00730     free space on the disk.  If deleting the extended partition,
    00731     all logical volumes within it are also deleted.
    00732
    00733 Arguments:
    00734
    00735     Region  - a region descriptor returned by GetDiskRegions().  Must
    00736               be a used region.
    00737
    00738 Return Value:
    00739
    00740     OK_STATUS or error code.
    00741
    00742 --*/
    00743
    00744 {
    00745     PREGION_DATA  RegionData = Region->Reserved;
    00746     PPARTITION   *PartitionList;
    00747
    00748     ASRT(    IsInPartitionList(Region->Disk,RegionData->Partition)
    00749           || IsInLogicalList  (Region->Disk,RegionData->Partition)
    00750         );
    00751
    00752     if(IsExtended(Region->SysID)) {
    00753
    00754         ASRT(IsInPartitionList(Region->Disk,RegionData->Partition));
    00755
    00756         // Deleting extended partition.  Also delete all logical volumes.
    00757
    00758         FreeLinkedPartitionList(&LogicalVolumes[Region->Disk]);
    00759     }
    00760
    00761     RegionData->Partition->SysID  = SYSID_UNUSED;
    00762     RegionData->Partition->Update = TRUE;
    00763     RegionData->Partition->Active = FALSE;
    00764     RegionData->Partition->OriginalPartitionNumber = 0;
    00765
    00766     PartitionList = (Region->RegionType == REGION_LOGICAL)
    00767                   ? &LogicalVolumes[Region->Disk]
    00768                   : &PrimaryPartitions[Region->Disk];
    00769
    00770     MergeFreePartitions(*PartitionList);
    00771     RenumberPartitions(Region->Disk);
    00772
    00773     ChangesMade[Region->Disk] = TRUE;
    00774
    00775     return(OK_STATUS);
    00776 }
    00777
    00778
    00779 ARC_STATUS
    00780 GetDiskRegions(
    00781     IN  ULONG               Disk,
    00782     IN  BOOLEAN             WantUsedRegions,
    00783     IN  BOOLEAN             WantFreeRegions,
    00784     IN  BOOLEAN             WantPrimaryRegions,
    00785     IN  BOOLEAN             WantLogicalRegions,
    00786     OUT PREGION_DESCRIPTOR *Region,
    00787     OUT ULONG              *RegionCount
    00788     )
    00789
    00790 /*++
    00791
    00792 Routine Description:
    00793
    00794     This routine returns an array of region descriptors to the caller.
    00795     A region desscriptor describes a space on the disk, either used
    00796     or free.  The caller can control which type of regions are returned.
    00797
    00798     The caller must free the returned array via FreeRegionArray().
    00799
    00800 Arguments:
    00801
    00802     Disk            - index of disk whose regions are to be returned
    00803
    00804     WantUsedRegions - whether to return used disk regions
    00805
    00806     WantFreeRegions - whether to return free disk regions
    00807
    00808     WantPrimaryRegions - whether to return regions not in the
    00809                          extended partition
    00810
    00811     WantLogicalRegions - whether to return regions within the
    00812                          extended partition
    00813
    00814     Region          - where to put a pointer to the array of regions
    00815
    00816     RegionCount     - where to put the number of items in the returned
    00817                       Region array
    00818
    00819 Return Value:
    00820
    00821     OK_STATUS or error code.
    00822
    00823 --*/
    00824
    00825 {
    00826     *Region = AllocateMemory(0);
    00827     *RegionCount = 0;
    00828
    00829     if(WantPrimaryRegions) {
    00830         return(GetRegions(Disk,
    00831                           PrimaryPartitions[Disk],
    00832                           WantUsedRegions,
    00833                           WantFreeRegions,
    00834                           WantLogicalRegions,
    00835                           Region,
    00836                           RegionCount,
    00837                           REGION_PRIMARY
    00838                          )
    00839               );
    00840     } else if(WantLogicalRegions) {
    00841         return(GetRegions(Disk,
    00842                           LogicalVolumes[Disk],
    00843                           WantUsedRegions,
    00844                           WantFreeRegions,
    00845                           FALSE,
    00846                           Region,
    00847                           RegionCount,
    00848                           REGION_LOGICAL
    00849                          )
    00850               );
    00851     }
    00852     return(OK_STATUS);
    00853 }
    00854
    00855
    00856 // workers for GetDiskRegions
    00857
    00858 ARC_STATUS
    00859 GetRegions(
    00860     IN  ULONG               Disk,
    00861     IN  PPARTITION          p,
    00862     IN  BOOLEAN             WantUsedRegions,
    00863     IN  BOOLEAN             WantFreeRegions,
    00864     IN  BOOLEAN             WantLogicalRegions,
    00865     OUT PREGION_DESCRIPTOR *Region,
    00866     OUT ULONG              *RegionCount,
    00867     IN  REGION_TYPE         RegionType
    00868     )
    00869 {
    00870     ARC_STATUS   status;
    00871     LARGE_INTEGER AlignedOffset,AlignedSize;
    00872     ULONG         SizeMB;
    00873
    00874     while(p) {
    00875
    00876         if(p->SysID == SYSID_UNUSED) {
    00877
    00878             if(WantFreeRegions) {
    00879
    00880                 LARGE_INTEGER   Result1, Result2;
    00881
    00882                 AlignedOffset = AlignTowardsDiskEnd(p->Disk,p->Offset);
    00883
    00884                 Result2.QuadPart = p->Offset.QuadPart + p->Length.QuadPart;
    00885                 Result1 = AlignTowardsDiskStart(p->Disk,Result2);
    00886                 AlignedSize.QuadPart   = Result1.QuadPart - AlignedOffset.QuadPart;
    00887
    00888                 SizeMB        = SIZEMB(AlignedSize);
    00889
    00890
    00891                 //
    00892                 // Show the space free if it is greater than 1 meg, AND
    00893                 // it is not a space starting at the beginning of the disk
    00894                 // and of length <= 1 cylinder.
    00895                 // This prevents the user from seeing the first cylinder
    00896                 // of the disk as free (could otherwise happen with an
    00897                 // extended partition starting on cylinder 1 and cylinders
    00898                 // of 1 megabyte or larger).
    00899                 //
    00900
    00901                 if(    (AlignedSize.QuadPart > 0)
    00902                     && SizeMB
    00903                     && (    (p->Offset.QuadPart != 0)
    00904                          || ( p->Length.QuadPart >
    00905                               DiskGeometryArray[p->Disk].BytesPerCylinder )
    00906                        )
    00907                   )
    00908                 {
    00909                     if(!AddRegionEntry(Region,
    00910                                        RegionCount,
    00911                                        SizeMB,
    00912                                        RegionType,
    00913                                        p,
    00914                                        AlignedOffset,
    00915                                        AlignedSize
    00916                                       ))
    00917                     {
    00918                         RETURN_OUT_OF_MEMORY;
    00919                     }
    00920                 }
    00921             }
    00922         } else {
    00923
    00924             if(WantUsedRegions) {
    00925
    00926                 AlignedOffset = p->Offset;
    00927                 AlignedSize   = p->Length;
    00928                 SizeMB        = SIZEMB(AlignedSize);
    00929
    00930                 if(!AddRegionEntry(Region,
    00931                                    RegionCount,
    00932                                    SizeMB,
    00933                                    RegionType,
    00934                                    p,
    00935                                    AlignedOffset,
    00936                                    AlignedSize
    00937                                   ))
    00938                 {
    00939                     RETURN_OUT_OF_MEMORY;
    00940                 }
    00941             }
    00942
    00943             if(IsExtended(p->SysID) && WantLogicalRegions) {
    00944                 status = GetRegions(Disk,
    00945                                     LogicalVolumes[Disk],
    00946                                     WantUsedRegions,
    00947                                     WantFreeRegions,
    00948                                     FALSE,
    00949                                     Region,
    00950                                     RegionCount,
    00951                                     REGION_LOGICAL
    00952                                    );
    00953                 if(status != OK_STATUS) {
    00954                     return(status);
    00955                 }
    00956             }
    00957         }
    00958         p = p->Next;
    00959     }
    00960     return(OK_STATUS);
    00961 }
    00962
    00963
    00964 BOOLEAN
    00965 AddRegionEntry(
    00966     OUT PREGION_DESCRIPTOR *Regions,
    00967     OUT ULONG              *RegionCount,
    00968     IN  ULONG               SizeMB,
    00969     IN  REGION_TYPE         RegionType,
    00970     IN  PPARTITION          Partition,
    00971     IN  LARGE_INTEGER       AlignedRegionOffset,
    00972     IN  LARGE_INTEGER       AlignedRegionSize
    00973     )
    00974 {
    00975     PREGION_DESCRIPTOR p;
    00976     PREGION_DATA       data;
    00977
    00978     p = ReallocateMemory(*Regions,((*RegionCount) + 1) * sizeof(REGION_DESCRIPTOR));
    00979     if(p == NULL) {
    00980         return(FALSE);
    00981     } else {
    00982         *Regions = p;
    00983         (*RegionCount)++;
    00984     }
    00985
    00986     p = &(*Regions)[(*RegionCount)-1];
    00987
    00988     if(!(p->Reserved = AllocateMemory(sizeof(REGION_DATA)))) {
    00989         return(FALSE);
    00990     }
    00991
    00992     p->Disk                    = Partition->Disk;
    00993     p->SysID                   = Partition->SysID;
    00994     p->SizeMB                  = SizeMB;
    00995     p->Active                  = Partition->Active;
    00996     p->Recognized              = Partition->Recognized;
    00997     p->PartitionNumber         = Partition->PartitionNumber;
    00998     p->OriginalPartitionNumber = Partition->OriginalPartitionNumber;
    00999     p->RegionType              = RegionType;
    01000     p->PersistentData          = Partition->PersistentData;
    01001
    01002     data = p->Reserved;
    01003
    01004     data->Partition             = Partition;
    01005     data->AlignedRegionOffset   = AlignedRegionOffset;
    01006     data->AlignedRegionSize     = AlignedRegionSize;
    01007
    01008     return(TRUE);
    01009 }
    01010
    01011
    01012 VOID
    01013 FreeRegionArray(
    01014     IN PREGION_DESCRIPTOR Region,
    01015     IN ULONG              RegionCount
    01016     )
    01017
    01018 /*++
    01019
    01020 Routine Description:
    01021
    01022     This routine frees a region array returned by GetDiskRegions().
    01023
    01024 Arguments:
    01025
    01026     Region          - pointer to the array of regions to be freed
    01027
    01028     RegionCount     - number of items in the Region array
    01029
    01030 Return Value:
    01031
    01032     None.
    01033
    01034 --*/
    01035
    01036 {
    01037     ULONG i;
    01038
    01039     for(i=0; i<RegionCount; i++) {
    01040
    01041         if(Region[i].Reserved) {
    01042             FreeMemory(Region[i].Reserved);
    01043         }
    01044     }
    01045     FreeMemory(Region);
    01046 }
    01047
    01048
    01049
    01050 VOID
    01051 AddPartitionToLinkedList(
    01052     IN OUT PARTITION **Head,
    01053     IN     PARTITION *p
    01054     )
    01055
    01056 /*++
    01057
    01058 Routine Description:
    01059
    01060     This routine adds a PARTITION structure to a doubly-linked
    01061     list, sorted by the Offset field in ascending order.
    01062
    01063 Arguments:
    01064
    01065     Head    - pointer to pointer to first element in list
    01066
    01067     p       - pointer to item to be added to list
    01068
    01069 Return Value:
    01070
    01071     None.
    01072
    01073 --*/
    01074
    01075 {
    01076     PARTITION *cur,*prev;
    01077
    01078     if((cur = *Head) == NULL) {
    01079         *Head = p;
    01080         return;
    01081     }
    01082
    01083     if(p->Offset.QuadPart < cur->Offset.QuadPart) {
    01084         p->Next = cur;
    01085         cur->Prev = p;
    01086         *Head = p;
    01087         return;
    01088     }
    01089
    01090     prev = *Head;
    01091     cur = cur->Next;
    01092
    01093     while(cur) {
    01094         if(p->Offset.QuadPart < cur->Offset.QuadPart) {
    01095
    01096             p->Next = cur;
    01097             p->Prev = prev;
    01098             prev->Next = p;
    01099             cur->Prev = p;
    01100             return;
    01101         }
    01102         prev = cur;
    01103         cur = cur->Next;
    01104     }
    01105
    01106     prev->Next = p;
    01107     p->Prev = prev;
    01108     return;
    01109 }
    01110
    01111
    01112 BOOLEAN
    01113 IsInLinkedList(
    01114     IN PPARTITION p,
    01115     IN PPARTITION List
    01116     )
    01117
    01118 /*++
    01119
    01120 Routine Description:
    01121
    01122     This routine determines whether a PARTITION element is in
    01123     a given linked list of PARTITION elements.
    01124
    01125 Arguments:
    01126
    01127     p       - pointer to element to be checked for
    01128
    01129     List    - first element in list to be scanned
    01130
    01131 Return Value:
    01132
    01133     true if p found in List, false otherwise
    01134
    01135 --*/
    01136
    01137 {
    01138     while(List) {
    01139         if(p == List) {
    01140             return(TRUE);
    01141         }
    01142         List = List->Next;
    01143     }
    01144     return(FALSE);
    01145 }
    01146
    01147
    01148 BOOLEAN
    01149 IsInLogicalList(
    01150     IN ULONG      Disk,
    01151     IN PPARTITION p
    01152     )
    01153
    01154 /*++
    01155
    01156 Routine Description:
    01157
    01158     This routine determines whether a PARTITION element is in
    01159     the logical volume list for a given disk.
    01160
    01161 Arguments:
    01162
    01163     Disk    - index of disk to be checked
    01164
    01165     p       - pointer to element to be checked for
    01166
    01167 Return Value:
    01168
    01169     true if p found in Disk's logical volume list, false otherwise
    01170
    01171 --*/
    01172
    01173 {
    01174     return(IsInLinkedList(p,LogicalVolumes[Disk]));
    01175 }
    01176
    01177
    01178 BOOLEAN
    01179 IsInPartitionList(
    01180     IN ULONG      Disk,
    01181     IN PPARTITION p
    01182     )
    01183
    01184 /*++
    01185
    01186 Routine Description:
    01187
    01188     This routine determines whether a PARTITION element is in
    01189     the primary partition list for a given disk.
    01190
    01191 Arguments:
    01192
    01193     Disk    - index of disk to be checked
    01194
    01195     p       - pointer to element to be checked for
    01196
    01197 Return Value:
    01198
    01199     true if p found in Disk's primary partition list, false otherwise
    01200
    01201 --*/
    01202
    01203 {
    01204     return(IsInLinkedList(p,PrimaryPartitions[Disk]));
    01205 }
    01206
    01207
    01208 VOID
    01209 MergeFreePartitions(
    01210     IN PPARTITION p
    01211     )
    01212
    01213 /*++
    01214
    01215 Routine Description:
    01216
    01217     This routine merges adjacent free space elements in the
    01218     given linked list of PARTITION elements.  It is designed
    01219     to be called after adding or deleting a partition.
    01220
    01221 Arguments:
    01222
    01223     p - pointer to first item in list whose free elements are to
    01224         be merged.
    01225
    01226 Return Value:
    01227
    01228     None.
    01229
    01230 --*/
    01231
    01232 {
    01233     PPARTITION next;
    01234
    01235     while(p && p->Next) {
    01236
    01237         if((p->SysID == SYSID_UNUSED) && (p->Next->SysID == SYSID_UNUSED)) {
    01238
    01239             next = p->Next;
    01240
    01241             p->Length.QuadPart = (next->Offset.QuadPart + next->Length.QuadPart) - p->Offset.QuadPart;
    01242
    01243             if(p->Next = next->Next) {
    01244                 next->Next->Prev = p;
    01245             }
    01246
    01247             FreeMemory(next);
    01248
    01249         } else {
    01250             p = p->Next;
    01251         }
    01252     }
    01253 }
    01254
    01255
    01256 VOID
    01257 RenumberPartitions(
    01258     IN ULONG Disk
    01259     )
    01260
    01261 /*++
    01262
    01263 Routine Description:
    01264
    01265     This routine determines the partition number for each region
    01266     on a disk.  For a used region, the partition number is the number
    01267     that the system will assign to the partition.  All partitions
    01268     (except the extended partition) are numbered first starting at 1,
    01269     and then all logical volumes in the extended partition.
    01270     For a free region, the partition number is the number that the
    01271     system WOULD assign to the partition if the space were to be
    01272     converted to a partition and all other regions on the disk were
    01273     left as is.
    01274
    01275     The partition numbers are stored in the PARTITION elements.
    01276
    01277 Arguments:
    01278
    01279     Disk - index of disk whose partitions are to be renumbered.
    01280
    01281 Return Value:
    01282
    01283     None.
    01284
    01285 --*/
    01286
    01287 {
    01288     PPARTITION p = PrimaryPartitions[Disk];
    01289     ULONG      n = 1;
    01290
    01291     while(p) {
    01292         if(!IsExtended(p->SysID)) {
    01293             p->PartitionNumber = n;
    01294             if(p->SysID != SYSID_UNUSED) {
    01295                 n++;
    01296             }
    01297         }
    01298         p = p->Next;
    01299     }
    01300     p = LogicalVolumes[Disk];
    01301     while(p) {
    01302         p->PartitionNumber = n;
    01303         if(p->SysID != SYSID_UNUSED) {
    01304             n++;
    01305         }
    01306         p = p->Next;
    01307     }
    01308 }
    01309
    01310
    01311 PPARTITION
    01312 FindPartitionElement(
    01313     IN ULONG Disk,
    01314     IN ULONG Partition
    01315     )
    01316
    01317 /*++
    01318
    01319 Routine Description:
    01320
    01321     This routine locates a PARTITION element for a disk/partition
    01322     number pair.  The partition number is the number that the
    01323     system assigns to the partition.
    01324
    01325 Arguments:
    01326
    01327     Disk - index of relevent disk
    01328
    01329     Partition - partition number of partition to find
    01330
    01331 Return Value:
    01332
    01333     pointer to PARTITION element, or NULL if not found.
    01334
    01335 --*/
    01336
    01337 {
    01338     PPARTITION p;
    01339
    01340     ASRT(Partition);
    01341
    01342     p = PrimaryPartitions[Disk];
    01343     while(p) {
    01344         if((p->SysID != SYSID_UNUSED)
    01345         && !IsExtended(p->SysID)
    01346         && (p->PartitionNumber == Partition))
    01347         {
    01348             return(p);
    01349         }
    01350         p = p->Next;
    01351     }
    01352     p = LogicalVolumes[Disk];
    01353     while(p) {
    01354         if((p->SysID != SYSID_UNUSED)
    01355         && (p->PartitionNumber == Partition))
    01356         {
    01357             return(p);
    01358         }
    01359         p = p->Next;
    01360     }
    01361     return(NULL);
    01362 }
    01363
    01364
    01365 VOID
    01366 SetSysID(
    01367     IN ULONG Disk,
    01368     IN ULONG Partition,
    01369     IN UCHAR SysID
    01370     )
    01371
    01372 /*++
    01373
    01374 Routine Description:
    01375
    01376     This routine sets the system id of the given partition
    01377     on the given disk.
    01378
    01379 Arguments:
    01380
    01381     Disk - index of relevent disk
    01382
    01383     Partition - partition number of relevent partition
    01384
    01385     SysID - new system ID for Partition on Disk
    01386
    01387 Return Value:
    01388
    01389     None.
    01390
    01391 --*/
    01392
    01393 {
    01394     PPARTITION p = FindPartitionElement(Disk,Partition);
    01395
    01396     ASRT(p);
    01397
    01398     if(p) {
    01399         p->SysID = SysID;
    01400         if(!p->Update) {
    01401             p->Update = CHANGED_DONT_ZAP;
    01402         }
    01403         ChangesMade[p->Disk] = TRUE;
    01404     }
    01405 }
    01406
    01407
    01408 VOID
    01409 SetSysID2(
    01410     IN PREGION_DESCRIPTOR Region,
    01411     IN UCHAR              SysID
    01412     )
    01413 {
    01414     PPARTITION p = ((PREGION_DATA)(Region->Reserved))->Partition;
    01415
    01416     p->SysID = SysID;
    01417     if(!p->Update) {
    01418         p->Update = CHANGED_DONT_ZAP;
    01419     }
    01420     ChangesMade[p->Disk] = TRUE;
    01421 }
    01422
    01423
    01424 ULONG
    01425 GetHiddenSectorCount(
    01426     IN ULONG Disk,
    01427     IN ULONG Partition
    01428     )
    01429
    01430 /*++
    01431
    01432 Routine Description:
    01433
    01434     This routine determines the hidden sector count for a
    01435     partition.  This value is used by format and is placed in
    01436     the BPB of a FAT partition when the partition is formatted.
    01437
    01438 Arguments:
    01439
    01440     Disk - index of relevent disk
    01441
    01442     Partition - partition number of relevent partition
    01443
    01444 Return Value:
    01445
    01446     The number of hidden sectors (will be 0 if the partition
    01447     does not exist).
    01448
    01449 --*/
    01450
    01451 {
    01452     PPARTITION p = FindPartitionElement(Disk,Partition);
    01453     ULONG      HiddenSectorCount = 0;
    01454     LARGE_INTEGER   Result;
    01455
    01456     ASRT(p);
    01457
    01458     if(p) {
    01459
    01460         if(IsInLogicalList(Disk,p)) {
    01461             HiddenSectorCount = DiskGeometryArray[Disk].SectorsPerTrack;
    01462         } else {
    01463             ASRT(IsInPartitionList(Disk,p));
    01464             Result.QuadPart = p->Offset.QuadPart / DiskGeometryArray[Disk].BytesPerSector;
    01465             HiddenSectorCount = LOWPART(Result);
    01466         }
    01467     }
    01468     return(HiddenSectorCount);
    01469 }
    01470
    01471
    01472 VOID
    01473 FreeLinkedPartitionList(
    01474     IN OUT PPARTITION *q
    01475     )
    01476
    01477 /*++
    01478
    01479 Routine Description:
    01480
    01481     This routine frees a linked list of PARTITION elements. The head
    01482     pointer is set to NULL.
    01483
    01484 Arguments:
    01485
    01486     p - pointer to pointer to first element of list to free.
    01487
    01488 Return Value:
    01489
    01490     None.
    01491
    01492 --*/
    01493
    01494 {
    01495     PARTITION *n;
    01496     PARTITION *p = *q;
    01497
    01498     while(p) {
    01499         n = p->Next;
    01500         FreeMemory(p);
    01501         p = n;
    01502     }
    01503     *q = NULL;
    01504 }
    01505
    01506
    01507 VOID
    01508 FreePartitionInfoLinkedLists(
    01509     IN PPARTITION *ListHeadArray
    01510     )
    01511
    01512 /*++
    01513
    01514 Routine Description:
    01515
    01516     This routine frees the linked lists of PARTITION elements
    01517     for each disk.
    01518
    01519 Arguments:
    01520
    01521     ListHeadArray - pointer to array of pointers to first elements of
    01522                     PARTITION element lists.
    01523
    01524 Return Value:
    01525
    01526     None.
    01527
    01528 --*/
    01529
    01530 {
    01531     ULONG i;
    01532
    01533     for(i=0; i<CountOfDisks; i++) {
    01534
    01535         FreeLinkedPartitionList(&ListHeadArray[i]);
    01536     }
    01537 }
    01538
    01539
    01540 PPARTITION
    01541 AllocatePartitionStructure(
    01542     IN ULONG         Disk,
    01543     IN LARGE_INTEGER Offset,
    01544     IN LARGE_INTEGER Length,
    01545     IN UCHAR         SysID,
    01546     IN BOOLEAN       Update,
    01547     IN BOOLEAN       Active,
    01548     IN BOOLEAN       Recognized
    01549     )
    01550
    01551 /*++
    01552
    01553 Routine Description:
    01554
    01555     This routine allocates space for, and initializes a PARTITION
    01556     structure.
    01557
    01558 Arguments:
    01559
    01560     Disk    - index of disk, one of whose regions the new PARTITION
    01561               strucure describes.
    01562
    01563     Offset  - byte offset of region on the disk
    01564
    01565     Length  - length in bytes of the region
    01566
    01567     SysID   - system id of region, of SYSID_UNUSED of this PARTITION
    01568               is actually a free space.
    01569
    01570     Update  - whether this PARTITION is dirty, ie, has changed and needs
    01571               to be written to disk.
    01572
    01573     Active  - flag for the BootIndicator field in a partition table entry,
    01574               indicates to the x86 master boot program which partition
    01575               is active.
    01576
    01577     Recognized - whether the partition is a type recognized by NT
    01578
    01579 Return Value:
    01580
    01581     NULL if allocation failed, or new initialized PARTITION strucure.
    01582
    01583 --*/
    01584
    01585 {
    01586     PPARTITION p = AllocateMemory(sizeof(PARTITION));
    01587
    01588     if(p) {
    01589         p->Next                    = NULL;
    01590         p->Prev                    = NULL;
    01591         p->Offset                  = Offset;
    01592         p->Length                  = Length;
    01593         p->Disk                    = Disk;
    01594         p->Update                  = Update;
    01595         p->Active                  = Active;
    01596         p->Recognized              = Recognized;
    01597         p->SysID                   = SysID;
    01598         p->OriginalPartitionNumber = 0;
    01599         p->PartitionNumber         = 0;
    01600         p->PersistentData          = 0;
    01601     }
    01602     return(p);
    01603 }
    01604
    01605
    01606 ARC_STATUS
    01607 InitializeFreeSpace(
    01608     IN ULONG             Disk,
    01609     IN PPARTITION       *PartitionList,      // list the free space goes in
    01610     IN LARGE_INTEGER     StartOffset,
    01611     IN LARGE_INTEGER     Length
    01612     )
    01613
    01614 /*++
    01615
    01616 Routine Description:
    01617
    01618     This routine determines all the free spaces within a given area
    01619     on a disk, allocates PARTITION structures to describe them,
    01620     and adds these structures to the relevent partition list
    01621     (primary partitions or logical volumes).
    01622
    01623     No rounding or alignment is performed here.  Spaces of even one
    01624     byte will be counted and inserted in the partition list.
    01625
    01626 Arguments:
    01627
    01628     Disk    - index of disk whose free spaces are being sought.
    01629
    01630     PartitionList - pointer to first element on PARTITION list that
    01631                     the free spaces will go in.
    01632
    01633     StartOffset - start offset of area on disk to consider (ie, 0 for
    01634                   primary spaces or the first byte of the extended
    01635                   partition for logical spaces).
    01636
    01637     Length - length of area on disk to consider (ie, size of disk
    01638              for primary spaces or size of extended partition for
    01639              logical spaces).
    01640
    01641 Return Value:
    01642
    01643     OK_STATUS or error code.
    01644
    01645 --*/
    01646
    01647 {
    01648     PPARTITION              p = *PartitionList,q;
    01649     LARGE_INTEGER           Start,Size;
    01650
    01651     Start = StartOffset;
    01652
    01653     while(p) {
    01654
    01655         Size.QuadPart = p->Offset.QuadPart - Start.QuadPart;
    01656
    01657         if(Size.QuadPart > 0) {
    01658
    01659             if(!(q = AllocatePartitionStructure(Disk,
    01660                                                 Start,
    01661                                                 Size,
    01662                                                 SYSID_UNUSED,
    01663                                                 FALSE,
    01664                                                 FALSE,
    01665                                                 FALSE
    01666                                                )
    01667                 )
    01668               )
    01669             {
    01670                 RETURN_OUT_OF_MEMORY;
    01671             }
    01672
    01673             AddPartitionToLinkedList(PartitionList,q);
    01674         }
    01675
    01676         Start.QuadPart = p->Offset.QuadPart + p->Length.QuadPart;
    01677
    01678         p = p->Next;
    01679
    01680     }
    01681
    01682     Size.QuadPart = (StartOffset.QuadPart + Length.QuadPart) - Start.QuadPart;
    01683
    01684     if(Size.QuadPart > 0) {
    01685
    01686         if(!(q = AllocatePartitionStructure(Disk,
    01687                                             Start,
    01688                                             Size,
    01689                                             SYSID_UNUSED,
    01690                                             FALSE,
    01691                                             FALSE,
    01692                                             FALSE
    01693                                            )
    01694             )
    01695           )
    01696         {
    01697             RETURN_OUT_OF_MEMORY;
    01698         }
    01699
    01700         AddPartitionToLinkedList(PartitionList,q);
    01701     }
    01702
    01703     return(OK_STATUS);
    01704 }
    01705
    01706
    01707 ARC_STATUS
    01708 InitializeLogicalVolumeList(
    01709     IN ULONG                      Disk,
    01710     IN PDRIVE_LAYOUT_INFORMATION  DriveLayout,
    01711     IN ULONG                      PartitionNumber
    01712     )
    01713
    01714 /*++
    01715
    01716 Routine Description:
    01717
    01718     This routine creates the logical volume linked list of
    01719     PARTITION structures for the given disk.
    01720
    01721 Arguments:
    01722
    01723     Disk    - index of disk
    01724
    01725     DriveLayout - pointer to structure describing the raw partition
    01726                   layout of the disk.
    01727
    01728     PartitionNumber - number to assign to the first logical volume
    01729                       on the disk.
    01730
    01731 Return Value:
    01732
    01733     OK_STATUS or error code.
    01734
    01735 --*/
    01736
    01737 {
    01738     PPARTITION             p,q;
    01739     ULONG                   i,j;
    01740     PPARTITION_INFORMATION d;
    01741     LARGE_INTEGER          HiddenBytes;
    01742     ULONG                  BytesPerSector = DiskGeometryArray[Disk].BytesPerSector;
    01743     LARGE_INTEGER          Result1, Result2;
    01744
    01745     FreeLinkedPartitionList(&LogicalVolumes[Disk]);
    01746
    01747     p = PrimaryPartitions[Disk];
    01748     while(p) {
    01749         if(IsExtended(p->SysID)) {
    01750             break;
    01751         }
    01752         p = p->Next;
    01753     }
    01754
    01755     if(p) {
    01756         for(i=ENTRIES_PER_BOOTSECTOR; i<DriveLayout->PartitionCount; i+=ENTRIES_PER_BOOTSECTOR) {
    01757
    01758             for(j=i; j<i+ENTRIES_PER_BOOTSECTOR; j++) {
    01759
    01760                 d = &DriveLayout->PartitionEntry[j];
    01761
    01762                 if((d->PartitionType != SYSID_UNUSED) && (d->PartitionType != SYSID_EXTENDED)) {
    01763
    01764                     HiddenBytes.QuadPart = UInt32x32To64(d->HiddenSectors,BytesPerSector);
    01765
    01766                     Result1.QuadPart = d->StartingOffset.QuadPart - HiddenBytes.QuadPart;
    01767                     Result2.QuadPart = d->PartitionLength.QuadPart + HiddenBytes.QuadPart;
    01768                     if(!(q = AllocatePartitionStructure(Disk,
    01769                                                         Result1,
    01770                                                         Result2,
    01771                                                         d->PartitionType,
    01772                                                         FALSE,
    01773                                                         d->BootIndicator,
    01774                                                         d->RecognizedPartition
    01775                                                        )
    01776                         )
    01777                       )
    01778                     {
    01779                         RETURN_OUT_OF_MEMORY;
    01780                     }
    01781
    01782                     q->OriginalPartitionNumber = PartitionNumber++;
    01783                     AddPartitionToLinkedList(&LogicalVolumes[Disk],q);
    01784
    01785                     break;
    01786                 }
    01787             }
    01788         }
    01789         return(InitializeFreeSpace(Disk,
    01790                                    &LogicalVolumes[Disk],
    01791                                    p->Offset,
    01792                                    p->Length
    01793                                   )
    01794               );
    01795     }
    01796     return(OK_STATUS);
    01797 }
    01798
    01799
    01800 ARC_STATUS
    01801 InitializePrimaryPartitionList(
    01802     IN  ULONG                     Disk,
    01803     IN  PDRIVE_LAYOUT_INFORMATION DriveLayout,
    01804     OUT PULONG                    NextPartitionNumber
    01805     )
    01806
    01807 /*++
    01808
    01809 Routine Description:
    01810
    01811     This routine creates the primary partition linked list of
    01812     PARTITION structures for the given disk.
    01813
    01814 Arguments:
    01815
    01816     Disk    - index of disk
    01817
    01818     DriveLayout - pointer to structure describing the raw partition
    01819                   layout of the disk.
    01820
    01821     NextPartitionNumber - where to put partition number that should be
    01822                           assigned to the first logical volume on the
    01823                           disk.
    01824
    01825 Return Value:
    01826
    01827     OK_STATUS or error code.
    01828
    01829 --*/
    01830
    01831 {
    01832     ULONG                  i;
    01833     PPARTITION             p;
    01834     PPARTITION_INFORMATION d;
    01835     ULONG                  PartitionNumber = 1;
    01836     LARGE_INTEGER          LargeZero;
    01837
    01838     FreeLinkedPartitionList(&PrimaryPartitions[Disk]);
    01839
    01840     if(DriveLayout->PartitionCount >= ENTRIES_PER_BOOTSECTOR) {
    01841
    01842         for(i=0; i<ENTRIES_PER_BOOTSECTOR; i++) {
    01843
    01844             d = &DriveLayout->PartitionEntry[i];
    01845
    01846             if(d->PartitionType != SYSID_UNUSED) {
    01847
    01848                 if(!(p = AllocatePartitionStructure(Disk,
    01849                                                     d->StartingOffset,
    01850                                                     d->PartitionLength,
    01851                                                     d->PartitionType,
    01852                                                     FALSE,
    01853                                                     d->BootIndicator,
    01854                                                     d->RecognizedPartition
    01855                                                    )
    01856                     )
    01857                   )
    01858                 {
    01859                     RETURN_OUT_OF_MEMORY;
    01860                 }
    01861
    01862                 p->OriginalPartitionNumber = IsExtended(p->SysID)
    01863                                            ? 0
    01864                                            : PartitionNumber++;
    01865
    01866                 AddPartitionToLinkedList(&PrimaryPartitions[Disk],p);
    01867             }
    01868         }
    01869     }
    01870     *NextPartitionNumber = PartitionNumber;
    01871     LargeZero.QuadPart = 0;
    01872     return(InitializeFreeSpace(Disk,
    01873                                &PrimaryPartitions[Disk],
    01874                                LargeZero,
    01875                                DiskLengthBytes(Disk)
    01876                               )
    01877           );
    01878 }
    01879
    01880
    01881 ARC_STATUS
    01882 InitializePartitionLists(
    01883     VOID
    01884     )
    01885
    01886 /*++
    01887
    01888 Routine Description:
    01889
    01890     This routine scans the PARTITION_INFO array returned for each disk
    01891     by the OS.  A linked list of PARTITION structures is layered on top
    01892     of each array;  the net result is a sorted list that covers an entire
    01893     disk, because free spaces are also factored in as 'dummy' partitions.
    01894
    01895 Arguments:
    01896
    01897     None.
    01898
    01899 Return Value:
    01900
    01901     OK_STATUS or error code.
    01902
    01903 --*/
    01904
    01905 {
    01906     ARC_STATUS               status;
    01907     ULONG                     Disk;
    01908     PDRIVE_LAYOUT_INFORMATION DriveLayout;
    01909     ULONG                     PNum;
    01910
    01911
    01912     for(Disk=0; Disk<CountOfDisks; Disk++) {
    01913
    01914         if(OffLine[Disk]) {
    01915             continue;
    01916         }
    01917
    01918         if((status = LowGetDiskLayout(DiskNames[Disk],&DriveLayout)) != OK_STATUS) {
    01919             return(status);
    01920         }
    01921
    01922         if((status = InitializePrimaryPartitionList(Disk,DriveLayout,&PNum)) != OK_STATUS) {
    01923             FreeMemory(DriveLayout);
    01924             return(status);
    01925         }
    01926         if((status = InitializeLogicalVolumeList(Disk,DriveLayout,PNum)) != OK_STATUS) {
    01927             FreeMemory(DriveLayout);
    01928             return(status);
    01929         }
    01930
    01931         FreeMemory(DriveLayout);
    01932         RenumberPartitions(Disk);
    01933     }
    01934     return(OK_STATUS);
    01935 }
    01936
    01937
    01938
    01939 LARGE_INTEGER
    01940 DiskLengthBytes(
    01941     IN ULONG Disk
    01942     )
    01943
    01944 /*++
    01945
    01946 Routine Description:
    01947
    01948     This routine determines the disk length in bytes.  This value
    01949     is calculated from the disk geometry information.
    01950
    01951 Arguments:
    01952
    01953     Disk - index of disk whose size is desired
    01954
    01955 Return Value:
    01956
    01957     Size of Disk.
    01958
    01959 --*/
    01960
    01961 {
    01962     LARGE_INTEGER l;
    01963
    01964     l.QuadPart = (ULONGLONG)DiskGeometryArray[Disk].Cylinders.QuadPart
    01965                * (ULONGLONG)DiskGeometryArray[Disk].BytesPerCylinder;
    01966
    01967     return(l);
    01968 }
    01969
    01970
    01971 ULONG
    01972 SIZEMB(
    01973     IN LARGE_INTEGER ByteCount
    01974     )
    01975
    01976 /*++
    01977
    01978 Routine Description:
    01979
    01980     Calculate the size in megabytes of a given byte count. The value is
    01981     properly rounded (ie, not merely truncated).
    01982
    01983     This function replaces a macro of the same name that was truncating
    01984     instead of rounding.
    01985
    01986 Arguments:
    01987
    01988     ByteCount - supplies number of bytes
    01989
    01990 Return Value:
    01991
    01992     Size in MB equivalent to ByteCount.
    01993
    01994 --*/
    01995
    01996 {
    01997     ULONG Remainder;
    01998     ULONG SizeMB;
    01999
    02000     SizeMB = (ULONG)((ULONGLONG)ByteCount.QuadPart / (ULONGLONG)ONE_MEG);
    02001     Remainder = (ULONG)((ULONGLONG)ByteCount.QuadPart % (ULONGLONG)ONE_MEG);
    02002
    02003     if(Remainder >= ONE_MEG/2) {
    02004         SizeMB++;
    02005     }
    02006
    02007     return(SizeMB);
    02008 }
    02009
    02010 ULONG
    02011 DiskSizeMB(
    02012     IN ULONG Disk
    02013     )
    02014
    02015 /*++
    02016
    02017 Routine Description:
    02018
    02019     This routine determines the disk length in megabytes.  The returned
    02020     value is rounded down after division by 1024*1024.
    02021
    02022 Arguments:
    02023
    02024     Disk - index of disk whose size is desired
    02025
    02026 Return Value:
    02027
    02028     Size of Disk.
    02029
    02030 --*/
    02031
    02032 {
    02033     return(SIZEMB(DiskLengthBytes(Disk)));
    02034 }
    02035
    02036
    02037 LARGE_INTEGER
    02038 AlignTowardsDiskStart(
    02039     IN ULONG         Disk,
    02040     IN LARGE_INTEGER Offset
    02041     )
    02042
    02043 /*++
    02044
    02045 Routine Description:
    02046
    02047     This routine snaps a byte offset to a cylinder boundary, towards
    02048     the start of the disk.
    02049
    02050 Arguments:
    02051
    02052     Disk - index of disk whose offset is to be snapped
    02053
    02054     Offset - byte offset to be aligned (snapped to cylinder boundary)
    02055
    02056 Return Value:
    02057
    02058     Aligned offset.
    02059
    02060 --*/
    02061
    02062 {
    02063     LARGE_INTEGER mod;
    02064     LARGE_INTEGER Result;
    02065
    02066     mod.QuadPart = Offset.QuadPart % DiskGeometryArray[Disk].BytesPerCylinder;
    02067     Result.QuadPart = Offset.QuadPart - mod.QuadPart;
    02068     return(Result);
    02069 }
    02070
    02071
    02072 LARGE_INTEGER
    02073 AlignTowardsDiskEnd(
    02074     IN ULONG         Disk,
    02075     IN LARGE_INTEGER Offset
    02076     )
    02077
    02078 /*++
    02079
    02080 Routine Description:
    02081
    02082     This routine snaps a byte offset to a cylinder boundary, towards
    02083     the end of the disk.
    02084
    02085 Arguments:
    02086
    02087     Disk - index of disk whose offset is to be snapped
    02088
    02089     Offset - byte offset to be aligned (snapped to cylinder boundary)
    02090
    02091 Return Value:
    02092
    02093     Aligned offset.
    02094
    02095 --*/
    02096
    02097 {
    02098     LARGE_INTEGER mod;
    02099     LARGE_INTEGER LargeInteger;
    02100
    02101     mod.QuadPart = Offset.QuadPart % DiskGeometryArray[Disk].BytesPerCylinder;
    02102     if(mod.QuadPart != 0) {
    02103
    02104         LargeInteger.QuadPart = Offset.QuadPart + DiskGeometryArray[Disk].BytesPerCylinder;
    02105         Offset = AlignTowardsDiskStart(Disk,
    02106                                        LargeInteger
    02107                                       );
    02108     }
    02109     return(Offset);
    02110 }
    02111
    02112
    02113 BOOLEAN
    02114 IsExtended(
    02115     IN UCHAR SysID
    02116     )
    02117
    02118 /*++
    02119
    02120 Routine Description:
    02121
    02122     This routine determines whether a given system id is for an
    02123     extended type (ie, link) entry.
    02124
    02125 Arguments:
    02126
    02127     SysID - system id to be tested.
    02128
    02129 Return Value:
    02130
    02131     true/false based on whether SysID is for an extended type.
    02132
    02133 --*/
    02134
    02135 {
    02136     return((BOOLEAN)(SysID == SYSID_EXTENDED));
    02137 }
    02138
    02139
    02140 ARC_STATUS
    02141 IsAnyCreationAllowed(
    02142     IN  ULONG    Disk,
    02143     IN  BOOLEAN  AllowMultiplePrimaries,
    02144     OUT PBOOLEAN AnyAllowed,
    02145     OUT PBOOLEAN PrimaryAllowed,
    02146     OUT PBOOLEAN ExtendedAllowed,
    02147     OUT PBOOLEAN LogicalAllowed
    02148     )
    02149
    02150 /*++
    02151
    02152 Routine Description:
    02153
    02154     This routine determines whether any partition may be created on a
    02155     given disk, based on three sub-queries -- whether creation is allowed
    02156     of a primary partition, an extended partition, or a logical volume.
    02157
    02158 Arguments:
    02159
    02160     Disk            - index of disk to check
    02161
    02162     AllowMultiplePrimaries - whether to allow multiple primary partitions
    02163
    02164     AnyAllowed - returns whether any creation is allowed
    02165
    02166     PrimaryAllowed - returns whether creation of a primary partition
    02167                      is allowed
    02168
    02169     ExtendedAllowed - returns whether creation of an extended partition
    02170                       is allowed
    02171
    02172     Logical Allowed - returns whether creation of a logical volume is allowed.
    02173
    02174 Return Value:
    02175
    02176     OK_STATUS or error code
    02177
    02178 --*/
    02179
    02180 {
    02181     ARC_STATUS status;
    02182
    02183     if((status = IsCreationOfPrimaryAllowed(Disk,AllowMultiplePrimaries,PrimaryAllowed)) != OK_STATUS) {
    02184         return(status);
    02185     }
    02186     if((status = IsCreationOfExtendedAllowed(Disk,ExtendedAllowed)) != OK_STATUS) {
    02187         return(status);
    02188     }
    02189     if((status = IsCreationOfLogicalAllowed(Disk,LogicalAllowed)) != OK_STATUS) {
    02190         return(status);
    02191     }
    02192     *AnyAllowed = (BOOLEAN)(*PrimaryAllowed || *ExtendedAllowed || *LogicalAllowed);
    02193     return(OK_STATUS);
    02194 }
    02195
    02196
    02197 ARC_STATUS
    02198 IsCreationOfPrimaryAllowed(
    02199     IN  ULONG    Disk,
    02200     IN  BOOLEAN  AllowMultiplePrimaries,
    02201     OUT BOOLEAN *Allowed
    02202     )
    02203
    02204 /*++
    02205
    02206 Routine Description:
    02207
    02208     This routine determines whether creation of a primary partition is
    02209     allowed.  This is true when there is a free entry in the MBR and
    02210     there is free primary space on the disk.  If multiple primaries
    02211     are not allowed, then there must also not exist any primary partitions
    02212     in order for a primary creation to be allowed.
    02213
    02214 Arguments:
    02215
    02216     Disk            - index of disk to check
    02217
    02218     AllowMultiplePrimaries - whether existnace of primary partition
    02219                              disallows creation of a primary partition
    02220
    02221     Allowed - returns whether creation of a primary partition
    02222               is allowed
    02223
    02224 Return Value:
    02225
    02226     OK_STATUS or error code
    02227
    02228 --*/
    02229
    02230 {
    02231     PREGION_DESCRIPTOR Regions;
    02232     ULONG              RegionCount;
    02233     ULONG              UsedCount,RecogCount,i;
    02234     ARC_STATUS        status;
    02235     BOOLEAN            FreeSpace = FALSE;
    02236
    02237     status = GetPrimaryDiskRegions(Disk,&Regions,&RegionCount);
    02238     if(status != OK_STATUS) {
    02239         return(status);
    02240     }
    02241
    02242     for(UsedCount = RecogCount = i = 0; i<RegionCount; i++) {
    02243         ASRT(Regions[i].RegionType != REGION_LOGICAL);
    02244         if(Regions[i].SysID == SYSID_UNUSED) {
    02245             FreeSpace = TRUE;
    02246         } else {
    02247             UsedCount++;
    02248             if(!IsExtended(Regions[i].SysID) && Regions[i].Recognized) {
    02249                 RecogCount++;
    02250             }
    02251         }
    02252     }
    02253     ASRT(UsedCount <= ENTRIES_PER_BOOTSECTOR);
    02254     ASRT(RecogCount <= ENTRIES_PER_BOOTSECTOR);
    02255     ASRT(RecogCount <= UsedCount);
    02256
    02257     if((UsedCount < ENTRIES_PER_BOOTSECTOR)
    02258     && FreeSpace
    02259     && (!RecogCount || AllowMultiplePrimaries))
    02260     {
    02261         *Allowed = TRUE;
    02262     } else {
    02263         *Allowed = FALSE;
    02264     }
    02265
    02266     FreeRegionArray(Regions,RegionCount);
    02267     return(OK_STATUS);
    02268 }
    02269
    02270
    02271 ARC_STATUS
    02272 IsCreationOfExtendedAllowed(
    02273     IN  ULONG    Disk,
    02274     OUT BOOLEAN *Allowed
    02275     )
    02276
    02277 /*++
    02278
    02279 Routine Description:
    02280
    02281     This routine determines whether creation of an extended partition is
    02282     allowed.  This is true when there is a free entry in the MBR,
    02283     there is free primary space on the disk, and there is no existing
    02284     extended partition.
    02285
    02286 Arguments:
    02287
    02288     Disk            - index of disk to check
    02289
    02290     Allowed - returns whether creation of an extended partition
    02291               is allowed
    02292
    02293 Return Value:
    02294
    02295     OK_STATUS or error code
    02296
    02297 --*/
    02298
    02299 {
    02300     PREGION_DESCRIPTOR Regions;
    02301     ULONG              RegionCount;
    02302     ULONG              UsedCount,FreeCount,i;
    02303     ARC_STATUS        status;
    02304
    02305     status = GetPrimaryDiskRegions(Disk,&Regions,&RegionCount);
    02306     if(status != OK_STATUS) {
    02307         return(status);
    02308     }
    02309
    02310     for(UsedCount = FreeCount = i = 0; i<RegionCount; i++) {
    02311         ASRT(Regions[i].RegionType != REGION_LOGICAL);
    02312         if(Regions[i].SysID == SYSID_UNUSED) {
    02313             // BUGBUG should adjust the size here and see if it's non0 first
    02314             // (ie, take into account that the extended partition can't
    02315             // start on cyl 0).
    02316             FreeCount++;
    02317         } else {
    02318             UsedCount++;
    02319             if(IsExtended(Regions[i].SysID)) {
    02320                 FreeRegionArray(Regions,RegionCount);
    02321                 *Allowed = FALSE;
    02322                 return(OK_STATUS);
    02323             }
    02324         }
    02325     }
    02326     *Allowed = (BOOLEAN)((UsedCount < ENTRIES_PER_BOOTSECTOR) && FreeCount);
    02327     FreeRegionArray(Regions,RegionCount);
    02328     return(OK_STATUS);
    02329 }
    02330
    02331
    02332 ARC_STATUS
    02333 IsCreationOfLogicalAllowed(
    02334     IN  ULONG    Disk,
    02335     OUT BOOLEAN *Allowed
    02336     )
    02337
    02338 /*++
    02339
    02340 Routine Description:
    02341
    02342     This routine determines whether creation of a logical volume is
    02343     allowed.  This is true when there is an extended partition and
    02344     free space within it.
    02345
    02346 Arguments:
    02347
    02348     Disk            - index of disk to check
    02349
    02350     Allowed - returns whether creation of a logical volume is allowed
    02351
    02352 Return Value:
    02353
    02354     OK_STATUS or error code
    02355
    02356 --*/
    02357
    02358 {
    02359     PREGION_DESCRIPTOR Regions;
    02360     ULONG              RegionCount;
    02361     ULONG              i;
    02362     ARC_STATUS        status;
    02363     BOOLEAN            ExtendedExists;
    02364
    02365     *Allowed = FALSE;
    02366
    02367     status = DoesExtendedExist(Disk,&ExtendedExists);
    02368     if(status != OK_STATUS) {
    02369         return(status);
    02370     }
    02371     if(!ExtendedExists) {
    02372         return(OK_STATUS);
    02373     }
    02374
    02375     status = GetLogicalDiskRegions(Disk,&Regions,&RegionCount);
    02376     if(status != OK_STATUS) {
    02377         return(status);
    02378     }
    02379
    02380     for(i = 0; i<RegionCount; i++) {
    02381         ASRT(Regions[i].RegionType == REGION_LOGICAL);
    02382         if(Regions[i].SysID == SYSID_UNUSED) {
    02383             *Allowed = TRUE;
    02384             break;
    02385         }
    02386     }
    02387     FreeRegionArray(Regions,RegionCount);
    02388     return(OK_STATUS);
    02389 }
    02390
    02391
    02392
    02393 ARC_STATUS
    02394 DoesAnyPartitionExist(
    02395     IN  ULONG    Disk,
    02396     OUT PBOOLEAN AnyExists,
    02397     OUT PBOOLEAN PrimaryExists,
    02398     OUT PBOOLEAN ExtendedExists,
    02399     OUT PBOOLEAN LogicalExists
    02400     )
    02401
    02402 /*++
    02403
    02404 Routine Description:
    02405
    02406     This routine determines whether any partition exists on a given disk.
    02407     This is based on three sub queries: whether there are any primary or
    02408     extended partitions, or logical volumes on the disk.
    02409
    02410 Arguments:
    02411
    02412     Disk            - index of disk to check
    02413
    02414     AnyExists - returns whether any partitions exist on Disk
    02415
    02416     PrimaryExists - returns whether any primary partitions exist on Disk
    02417
    02418     ExtendedExists - returns whether there is an extended partition on Disk
    02419
    02420     LogicalExists - returns whether any logical volumes exist on Disk
    02421
    02422 Return Value:
    02423
    02424     OK_STATUS or error code
    02425
    02426 --*/
    02427
    02428 {
    02429     ARC_STATUS status;
    02430
    02431     if((status = DoesAnyPrimaryExist(Disk,PrimaryExists )) != OK_STATUS) {
    02432         return(status);
    02433     }
    02434     if((status = DoesExtendedExist  (Disk,ExtendedExists)) != OK_STATUS) {
    02435         return(status);
    02436     }
    02437     if((status = DoesAnyLogicalExist(Disk,LogicalExists )) != OK_STATUS) {
    02438         return(status);
    02439     }
    02440     *AnyExists = (BOOLEAN)(*PrimaryExists || *ExtendedExists || *LogicalExists);
    02441     return(OK_STATUS);
    02442 }
    02443
    02444
    02445 ARC_STATUS
    02446 DoesAnyPrimaryExist(
    02447     IN  ULONG    Disk,
    02448     OUT BOOLEAN *Exists
    02449     )
    02450
    02451 /*++
    02452
    02453 Routine Description:
    02454
    02455     This routine determines whether any non-extended primary partition exists
    02456     on a given disk.
    02457
    02458 Arguments:
    02459
    02460     Disk   - index of disk to check
    02461
    02462     Exists - returns whether any primary partitions exist on Disk
    02463
    02464 Return Value:
    02465
    02466     OK_STATUS or error code
    02467
    02468 --*/
    02469
    02470 {
    02471     PREGION_DESCRIPTOR Regions;
    02472     ULONG               RegionCount,i;
    02473     ARC_STATUS        status;
    02474
    02475     status = GetUsedPrimaryDiskRegions(Disk,&Regions,&RegionCount);
    02476     if(status != OK_STATUS) {
    02477         return(status);
    02478     }
    02479
    02480     *Exists = FALSE;
    02481
    02482     for(i=0; i<RegionCount; i++) {
    02483         ASRT(Regions[i].RegionType != REGION_LOGICAL);
    02484         ASRT(Regions[i].SysID != SYSID_UNUSED);
    02485         if(!IsExtended(Regions[i].SysID)) {
    02486             *Exists = TRUE;
    02487             break;
    02488         }
    02489     }
    02490     FreeRegionArray(Regions,RegionCount);
    02491     return(OK_STATUS);
    02492 }
    02493
    02494
    02495 ARC_STATUS
    02496 DoesExtendedExist(
    02497     IN  ULONG    Disk,
    02498     OUT BOOLEAN *Exists
    02499     )
    02500
    02501 /*++
    02502
    02503 Routine Description:
    02504
    02505     This routine determines whether an extended partition exists
    02506     on a given disk.
    02507
    02508 Arguments:
    02509
    02510     Disk   - index of disk to check
    02511
    02512     Exists - returns whether an extended partition exists on Disk
    02513
    02514 Return Value:
    02515
    02516     OK_STATUS or error code
    02517
    02518 --*/
    02519
    02520 {
    02521     PREGION_DESCRIPTOR Regions;
    02522     ULONG               RegionCount,i;
    02523     ARC_STATUS        status;
    02524
    02525     status = GetUsedPrimaryDiskRegions(Disk,&Regions,&RegionCount);
    02526     if(status != OK_STATUS) {
    02527         return(status);
    02528     }
    02529
    02530     *Exists = FALSE;
    02531
    02532     for(i=0; i<RegionCount; i++) {
    02533         ASRT(Regions[i].RegionType != REGION_LOGICAL);
    02534         ASRT(Regions[i].SysID != SYSID_UNUSED);
    02535         if(IsExtended(Regions[i].SysID)) {
    02536             *Exists = TRUE;
    02537             break;
    02538         }
    02539     }
    02540     FreeRegionArray(Regions,RegionCount);
    02541     return(OK_STATUS);
    02542 }
    02543
    02544
    02545 ARC_STATUS
    02546 DoesAnyLogicalExist(
    02547     IN  ULONG    Disk,
    02548     OUT BOOLEAN *Exists
    02549     )
    02550
    02551 /*++
    02552
    02553 Routine Description:
    02554
    02555     This routine determines whether any logical volumes exist
    02556     on a given disk.
    02557
    02558 Arguments:
    02559
    02560     Disk   - index of disk to check
    02561
    02562     Exists - returns whether any logical volumes exist on Disk
    02563
    02564 Return Value:
    02565
    02566     OK_STATUS or error code
    02567
    02568 --*/
    02569
    02570 {
    02571     PREGION_DESCRIPTOR Regions;
    02572     ULONG               RegionCount;
    02573     ARC_STATUS        status;
    02574
    02575     status = GetUsedLogicalDiskRegions(Disk,&Regions,&RegionCount);
    02576     if(status != OK_STATUS) {
    02577         return(status);
    02578     }
    02579
    02580     *Exists = (BOOLEAN)(RegionCount != 0);
    02581     FreeRegionArray(Regions,RegionCount);
    02582     return(OK_STATUS);
    02583 }
    02584
    02585
    02586 ULONG
    02587 GetDiskCount(
    02588     VOID
    02589     )
    02590
    02591 /*++
    02592
    02593 Routine Description:
    02594
    02595     This routine returns the number of attached partitionable disk
    02596     devices.  The returned value is one greater than the maximum index
    02597     allowed for Disk parameters to partitioning engine routines.
    02598
    02599 Arguments:
    02600
    02601     None.
    02602
    02603 Return Value:
    02604
    02605     Count of disks.
    02606
    02607 --*/
    02608
    02609 {
    02610     return(CountOfDisks);
    02611 }
    02612
    02613
    02614 PCHAR
    02615 GetDiskName(
    02616     ULONG Disk
    02617     )
    02618
    02619 /*++
    02620
    02621 Routine Description:
    02622
    02623     This routine returns the system name for the disk device whose
    02624     index is given.
    02625
    02626 Arguments:
    02627
    02628     Disk - index of disk whose name is desired.
    02629
    02630 Return Value:
    02631
    02632     System name for the disk device.  The caller must not attempt to
    02633     free this buffer or modify it.
    02634
    02635 --*/
    02636
    02637 {
    02638     return(DiskNames[Disk]);
    02639 }
    02640
    02641
    02642 // sys ID type names
    02643
    02644 char    UNKNOWN[] = "Unknown type";
    02645
    02646 PCHAR   SysIDStrings[256] = { "Free Space","FAT","XENIX1","XENIX2", // 00-03
    02647                               "FAT", "Extended", "FAT", "HPFS/NTFS",// 04-07
    02648                               UNKNOWN, UNKNOWN,                     // 08-09
    02649                               "OS/2 Boot Manager", UNKNOWN,         // 0a-0b
    02650                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // 0c-0f
    02651                               UNKNOWN, UNKNOWN,                     // 10-11
    02652                               "EISA Utilities", UNKNOWN,            // 12-13
    02653                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // 14-17
    02654                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // 18-1b
    02655                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // 1c-1f
    02656                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // 20-23
    02657                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // 24-27
    02658                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // 28-2b
    02659                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // 2c-2f
    02660                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // 30-33
    02661                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // 34-37
    02662                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // 38-3b
    02663                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // 3c-3f
    02664                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // 40-43
    02665                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // 44-47
    02666                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // 48-4b
    02667                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // 4c-4f
    02668                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // 50-53
    02669                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // 54-57
    02670                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // 58-5b
    02671                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // 5c-5f
    02672                               UNKNOWN, UNKNOWN, UNKNOWN, "Unix",    // 60-63
    02673                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // 64-67
    02674                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // 68-6b
    02675                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // 6c-6f
    02676                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // 70-73
    02677                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // 74-77
    02678                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // 78-7b
    02679                               UNKNOWN, UNKNOWN, UNKNOWN, "Unused",  // 7c-7f
    02680                               UNKNOWN, "Windows NT Fault Tolerance",// 80-81
    02681                               UNKNOWN, UNKNOWN,                     // 82-83
    02682                               "Windows NT Fault Tolerance", UNKNOWN,// 84-85
    02683                               "Windows NT Fault Tolerance",         // 86-86
    02684                               "Windows NT Fault Tolerance",         // 87-87
    02685                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // 88-8b
    02686                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // 8c-8f
    02687                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // 90-93
    02688                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // 94-97
    02689                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // 98-9b
    02690                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // 9c-9f
    02691                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // a0-a3
    02692                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // a4-a7
    02693                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // a8-ab
    02694                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // ac-af
    02695                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // b0-b3
    02696                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // b4-b7
    02697                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // b8-bb
    02698                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // bc-bf
    02699                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // c0-c3
    02700                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // c4-c7
    02701                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // c8-cb
    02702                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // cc-cf
    02703                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // d0-d3
    02704                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // d4-d7
    02705                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // d8-db
    02706                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // dc-df
    02707                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // e0-e3
    02708                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // e4-e7
    02709                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // e8-eb
    02710                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // ec-ef
    02711                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // f0-f3
    02712                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // f4-f7
    02713                               UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   // f8-fb
    02714                               UNKNOWN, UNKNOWN, UNKNOWN, "Table",   // fc-ff
    02715                             };
    02716
    02717
    02718 PCHAR
    02719 GetSysIDName(
    02720     UCHAR SysID
    02721     )
    02722
    02723 /*++
    02724
    02725 Routine Description:
    02726
    02727     This routine returns the name for a given system ID.
    02728
    02729 Arguments:
    02730
    02731     SysID - system id in question
    02732
    02733 Return Value:
    02734
    02735     Name of system id.  The caller must not attempt to free or
    02736     modify this buffer.
    02737
    02738 --*/
    02739
    02740 {
    02741     return(SysIDStrings[SysID]);
    02742 }
    02743
    02744
    02745 // worker routines for WriteDriveLayout
    02746
    02747 VOID
    02748 UnusedEntryFill(
    02749     IN PPARTITION_INFORMATION pinfo,
    02750     IN ULONG                  EntryCount
    02751     )
    02752 {
    02753     ULONG         i;
    02754     LARGE_INTEGER Zero;
    02755
    02756     Zero.QuadPart = 0;
    02757
    02758     for(i=0; i<EntryCount; i++) {
    02759
    02760         pinfo[i].StartingOffset   = Zero;
    02761         pinfo[i].PartitionLength  = Zero;
    02762         pinfo[i].HiddenSectors    = 0;
    02763         pinfo[i].PartitionType    = SYSID_UNUSED;
    02764         pinfo[i].BootIndicator    = FALSE;
    02765         pinfo[i].RewritePartition = TRUE;
    02766     }
    02767 }
    02768
    02769
    02770 LARGE_INTEGER
    02771 MakeBootRec(
    02772     ULONG                  Disk,
    02773     PPARTITION_INFORMATION pinfo,
    02774     PPARTITION             pLogical,
    02775     PPARTITION             pNextLogical
    02776     )
    02777 {
    02778     ULONG         Entry = 0;
    02779     LARGE_INTEGER BytesPerTrack;
    02780     LARGE_INTEGER SectorsPerTrack;
    02781     LARGE_INTEGER StartingOffset;
    02782
    02783     BytesPerTrack.QuadPart = (DiskGeometryArray[Disk].BytesPerTrack);
    02784     SectorsPerTrack.QuadPart = (DiskGeometryArray[Disk].SectorsPerTrack);
    02785     StartingOffset.QuadPart = 0;
    02786
    02787 //  ASRT(pLogical || pNextLogical);
    02788
    02789     if(pLogical) {
    02790
    02791         pinfo[Entry].StartingOffset.QuadPart   = pLogical->Offset.QuadPart + BytesPerTrack.QuadPart;
    02792         pinfo[Entry].PartitionLength.QuadPart  = pLogical->Length.QuadPart - BytesPerTrack.QuadPart;
    02793         pinfo[Entry].HiddenSectors    = SectorsPerTrack.LowPart;
    02794         pinfo[Entry].RewritePartition = pLogical->Update;
    02795         pinfo[Entry].BootIndicator    = pLogical->Active;
    02796         pinfo[Entry].PartitionType    = pLogical->SysID;
    02797
    02798         if(pinfo[Entry].RewritePartition) {
    02799             StartingOffset = pinfo[Entry].StartingOffset;
    02800         }
    02801
    02802         Entry++;
    02803     }
    02804
    02805     if(pNextLogical) {
    02806
    02807         pinfo[Entry].StartingOffset   = pNextLogical->Offset;
    02808         pinfo[Entry].PartitionLength  = pNextLogical->Length;
    02809         pinfo[Entry].HiddenSectors    = 0;
    02810         pinfo[Entry].RewritePartition = TRUE;
    02811         pinfo[Entry].BootIndicator    = FALSE;
    02812         pinfo[Entry].PartitionType    = SYSID_EXTENDED;
    02813
    02814         Entry++;
    02815     }
    02816
    02817     UnusedEntryFill(pinfo+Entry,ENTRIES_PER_BOOTSECTOR-Entry);
    02818     return(StartingOffset);
    02819 }
    02820
    02821
    02822 ARC_STATUS
    02823 ZapSector(
    02824     ULONG         Disk,
    02825     LARGE_INTEGER Offset
    02826     )
    02827
    02828 /*++
    02829
    02830 Routine Description:
    02831
    02832     This routine writes zeros into a sector at a given offset.  This is
    02833     used to clear out a new partition's filesystem boot record, so that
    02834     no previous filesystem appears in a new partition; or to clear out the
    02835     first EBR in the extended partition if there are to be no logical vols.
    02836
    02837 Arguments:
    02838
    02839     Disk - disk to write to
    02840
    02841     Offset - byte offset to a newly created partition on Disk
    02842
    02843 Return Value:
    02844
    02845     OK_STATUS or error code.
    02846
    02847 --*/
    02848
    02849 {
    02850     ULONG       SectorSize = DiskGeometryArray[Disk].BytesPerSector;
    02851     ULONG       i;
    02852     PCHAR       SectorBuffer,AlignedSectorBuffer;
    02853     ARC_STATUS status;
    02854     ULONG    Handle;
    02855     LARGE_INTEGER   LargeInteger;
    02856
    02857     if((SectorBuffer = AllocateMemory(2*SectorSize)) == NULL) {
    02858         RETURN_OUT_OF_MEMORY;
    02859     }
    02860
    02861     AlignedSectorBuffer = (PCHAR)(((ULONG)SectorBuffer+SectorSize) & ~(SectorSize-1));
    02862
    02863     for(i=0; i<SectorSize; AlignedSectorBuffer[i++] = 0);
    02864
    02865     if((status = LowOpenDisk(GetDiskName(Disk),&Handle)) != OK_STATUS) {
    02866         FreeMemory(SectorBuffer);
    02867         return(status);
    02868     }
    02869
    02870     LargeInteger.QuadPart = Offset.QuadPart / SectorSize;
    02871     status = LowWriteSectors(Handle,
    02872                              SectorSize,
    02873                              LOWPART(LargeInteger),
    02874                              1,
    02875                              AlignedSectorBuffer
    02876                             );
    02877
    02878     LowCloseDisk(Handle);
    02879     FreeMemory(SectorBuffer);
    02880
    02881     return(status);
    02882 }
    02883
    02884
    02885 ARC_STATUS
    02886 WriteDriveLayout(
    02887     IN ULONG Disk
    02888     )
    02889
    02890 /*++
    02891
    02892 Routine Description:
    02893
    02894     This routine writes the current partition layout for a given disk
    02895     out to disk.  The high-level PARTITION lists are transformed into
    02896     a DRIVE_LAYOUT_INFORMATION structure before being passed down
    02897     to the low-level partition table writing routine.
    02898
    02899 Arguments:
    02900
    02901     Disk - index of disk whose on-disk partition structure is to be updated.
    02902
    02903 Return Value:
    02904
    02905     OK_STATUS or error code.
    02906
    02907 --*/
    02908
    02909 {
    02910     PDRIVE_LAYOUT_INFORMATION DriveLayout;
    02911     PPARTITION_INFORMATION    pinfo;
    02912     PPARTITION                n,p;
    02913     ULONG                     EntryCount;
    02914     ARC_STATUS               status;
    02915     LARGE_INTEGER             StartingOffset;
    02916     LARGE_INTEGER             ExtendedStartingOffset;
    02917
    02918     ExtendedStartingOffset.QuadPart = 0;
    02919
    02920     // allocate a huge buffer now to avoid complicated dynamic
    02921     // reallocation schemes later.
    02922
    02923     if(!(DriveLayout = AllocateMemory(250 * sizeof(PARTITION_INFORMATION)))) {
    02924         RETURN_OUT_OF_MEMORY;
    02925     }
    02926
    02927     pinfo = &DriveLayout->PartitionEntry[0];
    02928
    02929     // first do the mbr.
    02930
    02931     EntryCount=0;
    02932     p = PrimaryPartitions[Disk];
    02933
    02934     while(p) {
    02935
    02936         if(p->SysID != SYSID_UNUSED) {
    02937
    02938             ASRT(EntryCount < ENTRIES_PER_BOOTSECTOR);
    02939
    02940             if(IsExtended(p->SysID)) {
    02941                 ExtendedStartingOffset = p->Offset;
    02942             }
    02943
    02944             pinfo[EntryCount].StartingOffset   = p->Offset;
    02945             pinfo[EntryCount].PartitionLength  = p->Length;
    02946             pinfo[EntryCount].PartitionType    = p->SysID;
    02947             pinfo[EntryCount].BootIndicator    = p->Active;
    02948             pinfo[EntryCount].RewritePartition = p->Update;
    02949
    02950             // BUGBUG we know that this field is not used by the
    02951             //        set drive layout IOCTL or the ARC stub.
    02952
    02953             pinfo[EntryCount].HiddenSectors    = 0;
    02954
    02955             // if we're creating this partition, clear out the
    02956             // filesystem boot sector.
    02957
    02958             if(pinfo[EntryCount].RewritePartition
    02959             && (p->Update != CHANGED_DONT_ZAP)
    02960             && !IsExtended(pinfo[EntryCount].PartitionType))
    02961             {
    02962                 status = ZapSector(Disk,pinfo[EntryCount].StartingOffset);
    02963                 if(status != OK_STATUS) {
    02964                     FreeMemory(DriveLayout);
    02965                     return(status);
    02966                 }
    02967             }
    02968
    02969             EntryCount++;
    02970         }
    02971         p = p->Next;
    02972     }
    02973
    02974     // fill the remainder of the MBR with unused entries.
    02975     // NOTE that there will thus always be an MBR even if there
    02976     // are no partitions defined.
    02977
    02978     UnusedEntryFill(pinfo+EntryCount,ENTRIES_PER_BOOTSECTOR - EntryCount);
    02979     EntryCount = ENTRIES_PER_BOOTSECTOR;
    02980
    02981     //
    02982     // now handle the logical volumes.
    02983     // first check to see whether we need a dummy EBR at the beginning
    02984     // of the extended partition.  This is the case when there is
    02985     // free space at the beginning of the extended partition.
    02986 #if 0
    02987     // Also handle the case where we are creating an empty extended
    02988     // partition -- need to zap the first sector to eliminate any residue
    02989     // that might start an EBR chain.
    02990 #else
    02991     // BUGBUG 4/24/92 tedm:  Currently the io subsystem returns an error
    02992     // status (status_bad_master_boot_record) if any mbr or ebr is bad.
    02993     // Zeroing the first sector of the extended partition therefore causes
    02994     // the whole disk to be seen as empty.  So create a blank, but valid,
    02995     // EBR in the 'empty extended partition' case.  Code is in the 'else'
    02996     // part of the #if 0, below.
    02997 #endif
    02998     //
    02999
    03000     if((p = LogicalVolumes[Disk]) && (p->SysID == SYSID_UNUSED)) {
    03001         if(p->Next) {
    03002             ASRT(p->Next->SysID != SYSID_UNUSED);
    03003
    03004             MakeBootRec(Disk,pinfo+EntryCount,NULL,p->Next);
    03005             EntryCount += ENTRIES_PER_BOOTSECTOR;
    03006             p = p->Next;
    03007         } else {
    03008             ASRT(ExtendedStartingOffset.QuadPart != 0);
    03009 #if 0
    03010             status = ZapSector(Disk,ExtendedStartingOffset);
    03011             if(status != OK_STATUS) {
    03012                 FreeMemory(DriveLayout);
    03013                 return(status);
    03014             }
    03015 #else
    03016             MakeBootRec(Disk,pinfo+EntryCount,NULL,NULL);
    03017             EntryCount += ENTRIES_PER_BOOTSECTOR;
    03018 #endif
    03019         }
    03020     }
    03021
    03022     while(p) {
    03023         if(p->SysID != SYSID_UNUSED) {
    03024
    03025             // find the next logical volume.
    03026
    03027             n = p->Next;
    03028             while(n) {
    03029                 if(n->SysID != SYSID_UNUSED) {
    03030                     break;
    03031                 }
    03032                 n = n->Next;
    03033             }
    03034
    03035             StartingOffset = MakeBootRec(Disk,pinfo+EntryCount,p,n);
    03036
    03037             // if we're creating a volume, clear out its filesystem
    03038             // boot sector so it starts out fresh.
    03039
    03040             if((StartingOffset.QuadPart != 0) && (p->Update != CHANGED_DONT_ZAP)) {
    03041                 status = ZapSector(Disk,StartingOffset);
    03042                 if(status != OK_STATUS) {
    03043                     FreeMemory(DriveLayout);
    03044                     return(status);
    03045                 }
    03046             }
    03047
    03048             EntryCount += ENTRIES_PER_BOOTSECTOR;
    03049         }
    03050         p = p->Next;
    03051     }
    03052
    03053     DriveLayout->PartitionCount = EntryCount;
    03054     status = LowSetDiskLayout(DiskNames[Disk],DriveLayout);
    03055
    03056     FreeMemory(DriveLayout);
    03057
    03058     return(status);
    03059 }
    03060
    03061
    03062 ARC_STATUS
    03063 CommitPartitionChanges(
    03064     IN ULONG Disk
    03065     )
    03066
    03067 /*++
    03068
    03069 Routine Description:
    03070
    03071     This routine is the entry point for updating the on-disk partition
    03072     structures of a disk.  The disk is only written to if the partition
    03073     structure has been changed by adding or deleting partitions.
    03074
    03075 Arguments:
    03076
    03077     Disk - index of disk whose on-disk partition structure is to be updated.
    03078
    03079 Return Value:
    03080
    03081     OK_STATUS or error code.
    03082
    03083 --*/
    03084
    03085 {
    03086     PPARTITION  p;
    03087     ARC_STATUS status;
    03088
    03089     ASRT(!OffLine[Disk]);
    03090
    03091     if(!HavePartitionsBeenChanged(Disk)) {
    03092         return(OK_STATUS);
    03093     }
    03094
    03095     if((status = WriteDriveLayout(Disk)) != OK_STATUS) {
    03096         return(status);
    03097     }
    03098
    03099     // BUGBUG for ARC and NT MIPS, update NVRAM vars so partitions are right.
    03100     //        Do that here, before partition numbers are reassigned.
    03101
    03102     p = PrimaryPartitions[Disk];
    03103     while(p) {
    03104         p->Update = FALSE;
    03105         p->OriginalPartitionNumber = p->PartitionNumber;
    03106         p = p->Next;
    03107     }
    03108     p = LogicalVolumes[Disk];
    03109     while(p) {
    03110         p->Update = FALSE;
    03111         p->OriginalPartitionNumber = p->PartitionNumber;
    03112         p = p->Next;
    03113     }
    03114
    03115     ChangesMade[Disk] = FALSE;
    03116     return(OK_STATUS);
    03117 }
    03118
    03119
    03120 BOOLEAN
    03121 HavePartitionsBeenChanged(
    03122     IN ULONG Disk
    03123     )
    03124
    03125 /*++
    03126
    03127 Routine Description:
    03128
    03129     This routine returns TRUE if the given disk's partition structures
    03130     have been modified by adding or deleting partitions, since the
    03131     on-disk structures were last written by a call to CommitPartitionChanges
    03132     (or first read).
    03133
    03134 Arguments:
    03135
    03136     Disk - index of disk to check
    03137
    03138 Return Value:
    03139
    03140     true if Disk's partition structure has changed.
    03141
    03142 --*/
    03143
    03144 {
    03145     if(OffLine[Disk]) {
    03146         ASRT(!ChangesMade[Disk]);
    03147     }
    03148     return(ChangesMade[Disk]);
    03149 }
    03150
    03151 VOID
    03152 FdMarkDiskDirty(
    03153     IN ULONG Disk
    03154     )
    03155 {
    03156     ASRT(!OffLine[Disk]);
    03157
    03158     ChangesMade[Disk] = TRUE;
    03159 }
    03160
    03161 VOID
    03162 FdSetPersistentData(
    03163     IN PREGION_DESCRIPTOR Region,
    03164     IN ULONG              Data
    03165     )
    03166 {
    03167     ((PREGION_DATA)(Region->Reserved))->Partition->PersistentData = Data;
    03168 }
    03169
    03170
    03171 ULONG
    03172 FdGetMinimumSizeMB(
    03173     IN ULONG Disk
    03174     )
    03175
    03176 /*++
    03177
    03178 Routine Description:
    03179
    03180     Return the minimum size for a partition on a given disk.
    03181
    03182     This is the rounded size of one cylinder or 1, whichever is greater.
    03183
    03184 Arguments:
    03185
    03186     Region - region describing the partition to check.
    03187
    03188 Return Value:
    03189
    03190     Actual offset
    03191
    03192 --*/
    03193
    03194 {
    03195     LARGE_INTEGER   LargeInteger;
    03196
    03197     LargeInteger.QuadPart = DiskGeometryArray[Disk].BytesPerCylinder;
    03198     return(max(SIZEMB(LargeInteger),1));
    03199 }
    03200
    03201
    03202 ULONG
    03203 FdGetMaximumSizeMB(
    03204     IN PREGION_DESCRIPTOR Region,
    03205     IN REGION_TYPE        CreationType
    03206     )
    03207 {
    03208     PREGION_DATA CreateData = Region->Reserved;
    03209     LARGE_INTEGER MaxSize = CreateData->AlignedRegionSize;
    03210
    03211     ASRT(Region->SysID == SYSID_UNUSED);
    03212
    03213     if(CreateData->AlignedRegionOffset.QuadPart == 0) {
    03214
    03215         ULONG Delta;
    03216
    03217         ASRT((CreationType == REGION_EXTENDED) || (CreationType == REGION_PRIMARY))
    03218
    03219         Delta = (CreationType == REGION_EXTENDED)
    03220               ? DiskGeometryArray[Region->Disk].BytesPerCylinder
    03221               : DiskGeometryArray[Region->Disk].BytesPerTrack;
    03222
    03223         MaxSize.QuadPart = MaxSize.QuadPart - Delta;
    03224     }
    03225
    03226     return(SIZEMB(MaxSize));
    03227 }
    03228
    03229
    03230 LARGE_INTEGER
    03231 FdGetExactSize(
    03232     IN PREGION_DESCRIPTOR Region,
    03233     IN BOOLEAN            ForExtended
    03234     )
    03235 {
    03236     PREGION_DATA  RegionData = Region->Reserved;
    03237     LARGE_INTEGER LargeSize = RegionData->AlignedRegionSize;
    03238     LARGE_INTEGER BytesPerTrack;
    03239     LARGE_INTEGER BytesPerCylinder;
    03240
    03241     BytesPerTrack.QuadPart = (DiskGeometryArray[Region->Disk].BytesPerTrack);
    03242     BytesPerCylinder.QuadPart = (DiskGeometryArray[Region->Disk].BytesPerCylinder);
    03243
    03244     if(Region->RegionType == REGION_LOGICAL) {
    03245
    03246         //
    03247         // The region is within the extended partition.  It doesn't matter
    03248         // whether it's free space or used -- in either case, we need to
    03249         // account for the reserved EBR track.
    03250         //
    03251
    03252         LargeSize.QuadPart = LargeSize.QuadPart - BytesPerTrack.QuadPart;
    03253
    03254     } else if(Region->SysID == SYSID_UNUSED) {
    03255
    03256         //
    03257         // The region is unused space not inside the extended partition.
    03258         // We must know whether the caller will put a primary or extended
    03259         // partition there -- a primary partition can use all the space, but
    03260         // a logical volume in the extended partition won't include the first
    03261         // track.  If the free space starts at offset 0 on the disk, a special
    03262         // calculation must be used to move the start of the partition to
    03263         // skip a track for a primary or a cylinder and a track for an
    03264         // extended+logical.
    03265         //
    03266
    03267         if((RegionData->AlignedRegionOffset.QuadPart == 0) || ForExtended) {
    03268             LargeSize.QuadPart = LargeSize.QuadPart - BytesPerTrack.QuadPart;
    03269         }
    03270
    03271         if((RegionData->AlignedRegionOffset.QuadPart == 0) && ForExtended) {
    03272             LargeSize.QuadPart = LargeSize.QuadPart - BytesPerCylinder.QuadPart;
    03273         }
    03274     }
    03275
    03276     return(LargeSize);
    03277 }
    03278
    03279
    03280 LARGE_INTEGER
    03281 FdGetExactOffset(
    03282     IN PREGION_DESCRIPTOR Region
    03283     )
    03284
    03285 /*++
    03286
    03287 Routine Description:
    03288
    03289     Determine where a given partition _actually_ starts, which may be
    03290     different than where is appears because of EBR reserved tracks, etc.
    03291
    03292     NOTE: This routine is not meant to operate on unused regions or
    03293     extended partitions.  In these cases, it just returns the apparant offset.
    03294
    03295 Arguments:
    03296
    03297     Region - region describing the partition to check.
    03298
    03299 Return Value:
    03300
    03301     Actual offset
    03302
    03303 --*/
    03304
    03305 {
    03306     LARGE_INTEGER Offset = ((PREGION_DATA)(Region->Reserved))->Partition->Offset;
    03307
    03308     if((Region->SysID != SYSID_UNUSED) && (Region->RegionType == REGION_LOGICAL)) {
    03309
    03310         //
    03311         // The region is a logical volume.
    03312         // Account for the reserved EBR track.
    03313         //
    03314
    03315         Offset.QuadPart = Offset.QuadPart +
    03316                                  DiskGeometryArray[Region->Disk].BytesPerTrack;
    03317     }
    03318
    03319     return(Offset);
    03320 }
    03321
    03322
    03323 BOOLEAN
    03324 FdCrosses1024Cylinder(
    03325     IN PREGION_DESCRIPTOR Region,
    03326     IN ULONG              CreationSizeMB,
    03327     IN REGION_TYPE        RegionType
    03328     )
    03329
    03330 /*++
    03331
    03332 Routine Description:
    03333
    03334     Determine whether a used region corsses the 1024th cylinder, or whether
    03335     a partition created within a free space will cross the 1024th cylinder.
    03336
    03337 Arguments:
    03338
    03339     Region - region describing the partition to check.
    03340
    03341     CreationSizeMB - if the Region is for a free space, this is the size of
    03342         the partition to be checked.
    03343
    03344     RegionType - one of REGION_PRIMARY, REGION_EXTENDED, or REGION_LOGICAL
    03345
    03346 Return Value:
    03347
    03348     TRUE if the end cylinder >= 1024.
    03349
    03350 --*/
    03351
    03352 {
    03353     LARGE_INTEGER Start,Size,End, LargeZero;
    03354
    03355     if(Region->SysID == SYSID_UNUSED) {
    03356
    03357         //
    03358         // Determine the exact size and offset of the partition, according
    03359         // to how CreatePartitionEx() will do it.
    03360         //
    03361
    03362         LargeZero.QuadPart = 0;
    03363         DetermineCreateSizeAndOffset( Region,
    03364                                       LargeZero,
    03365                                       CreationSizeMB,
    03366                                       RegionType,
    03367                                       &Start,
    03368                                       &Size
    03369                                     );
    03370
    03371     } else {
    03372
    03373         Start = ((PREGION_DATA)(Region->Reserved))->Partition->Offset;
    03374         Size  = ((PREGION_DATA)(Region->Reserved))->Partition->Length;
    03375     }
    03376
    03377     End.QuadPart = (Start.QuadPart + Size.QuadPart) - 1;
    03378
    03379     //
    03380     // End is the last byte in the partition.  Divide by the number of
    03381     // bytes in a cylinder and see whether the result is > 1023.
    03382     //
    03383
    03384     return( (End.QuadPart / DiskGeometryArray[Region->Disk].BytesPerCylinder) > 1023 );
    03385 }
    03386
    03387
    03388 BOOLEAN
    03389 IsDiskOffLine(
    03390     IN ULONG Disk
    03391     )
    03392 {
    03393     return(OffLine[Disk]);
    03394 }