xref: /reactos/base/setup/lib/fsutil.c (revision 5c7ce447)
1 /*
2  * PROJECT:     ReactOS Setup Library
3  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE:     Filesystem support functions
5  * COPYRIGHT:   Copyright 2003-2019 Casper S. Hornstrup (chorns@users.sourceforge.net)
6  *              Copyright 2017-2020 Hermes Belusca-Maito
7  */
8 
9 //
10 // See also: https://git.reactos.org/?p=reactos.git;a=blob;f=reactos/dll/win32/fmifs/init.c;h=e895f5ef9cae4806123f6bbdd3dfed37ec1c8d33;hb=b9db9a4e377a2055f635b2fb69fef4e1750d219c
11 // for how to get FS providers in a dynamic way. In the (near) future we may
12 // consider merging some of this code with us into a fmifs / fsutil / fslib library...
13 //
14 
15 /* INCLUDES *****************************************************************/
16 
17 #include "precomp.h"
18 
19 #include "partlist.h"
20 #include "fsrec.h"
21 #include "bootcode.h"
22 #include "fsutil.h"
23 
24 #include <fslib/vfatlib.h>
25 #include <fslib/btrfslib.h>
26 // #include <fslib/ext2lib.h>
27 // #include <fslib/ntfslib.h>
28 
29 #define NDEBUG
30 #include <debug.h>
31 
32 
33 /* TYPEDEFS *****************************************************************/
34 
35 #include <pshpack1.h>
36 typedef struct _FAT_BOOTSECTOR
37 {
38     UCHAR       JumpBoot[3];                // Jump instruction to boot code
39     CHAR        OemName[8];                 // "MSWIN4.1" for MS formatted volumes
40     USHORT      BytesPerSector;             // Bytes per sector
41     UCHAR       SectorsPerCluster;          // Number of sectors in a cluster
42     USHORT      ReservedSectors;            // Reserved sectors, usually 1 (the bootsector)
43     UCHAR       NumberOfFats;               // Number of FAT tables
44     USHORT      RootDirEntries;             // Number of root directory entries (fat12/16)
45     USHORT      TotalSectors;               // Number of total sectors on the drive, 16-bit
46     UCHAR       MediaDescriptor;            // Media descriptor byte
47     USHORT      SectorsPerFat;              // Sectors per FAT table (fat12/16)
48     USHORT      SectorsPerTrack;            // Number of sectors in a track
49     USHORT      NumberOfHeads;              // Number of heads on the disk
50     ULONG       HiddenSectors;              // Hidden sectors (sectors before the partition start like the partition table)
51     ULONG       TotalSectorsBig;            // This field is the new 32-bit total count of sectors on the volume
52     UCHAR       DriveNumber;                // Int 0x13 drive number (e.g. 0x80)
53     UCHAR       Reserved1;                  // Reserved (used by Windows NT). Code that formats FAT volumes should always set this byte to 0.
54     UCHAR       BootSignature;              // Extended boot signature (0x29). This is a signature byte that indicates that the following three fields in the boot sector are present.
55     ULONG       VolumeSerialNumber;         // Volume serial number
56     CHAR        VolumeLabel[11];            // Volume label. This field matches the 11-byte volume label recorded in the root directory
57     CHAR        FileSystemType[8];          // One of the strings "FAT12   ", "FAT16   ", or "FAT     "
58 
59     UCHAR       BootCodeAndData[448];       // The remainder of the boot sector
60 
61     USHORT      BootSectorMagic;            // 0xAA55
62 
63 } FAT_BOOTSECTOR, *PFAT_BOOTSECTOR;
64 C_ASSERT(sizeof(FAT_BOOTSECTOR) == FAT_BOOTSECTOR_SIZE);
65 
66 typedef struct _FAT32_BOOTSECTOR
67 {
68     UCHAR       JumpBoot[3];                // Jump instruction to boot code
69     CHAR        OemName[8];                 // "MSWIN4.1" for MS formatted volumes
70     USHORT      BytesPerSector;             // Bytes per sector
71     UCHAR       SectorsPerCluster;          // Number of sectors in a cluster
72     USHORT      ReservedSectors;            // Reserved sectors, usually 1 (the bootsector)
73     UCHAR       NumberOfFats;               // Number of FAT tables
74     USHORT      RootDirEntries;             // Number of root directory entries (fat12/16)
75     USHORT      TotalSectors;               // Number of total sectors on the drive, 16-bit
76     UCHAR       MediaDescriptor;            // Media descriptor byte
77     USHORT      SectorsPerFat;              // Sectors per FAT table (fat12/16)
78     USHORT      SectorsPerTrack;            // Number of sectors in a track
79     USHORT      NumberOfHeads;              // Number of heads on the disk
80     ULONG       HiddenSectors;              // Hidden sectors (sectors before the partition start like the partition table)
81     ULONG       TotalSectorsBig;            // This field is the new 32-bit total count of sectors on the volume
82     ULONG       SectorsPerFatBig;           // This field is the FAT32 32-bit count of sectors occupied by ONE FAT. BPB_FATSz16 must be 0
83     USHORT      ExtendedFlags;              // Extended flags (fat32)
84     USHORT      FileSystemVersion;          // File system version (fat32)
85     ULONG       RootDirStartCluster;        // Starting cluster of the root directory (fat32)
86     USHORT      FsInfo;                     // Sector number of FSINFO structure in the reserved area of the FAT32 volume. Usually 1.
87     USHORT      BackupBootSector;           // If non-zero, indicates the sector number in the reserved area of the volume of a copy of the boot record. Usually 6.
88     UCHAR       Reserved[12];               // Reserved for future expansion
89     UCHAR       DriveNumber;                // Int 0x13 drive number (e.g. 0x80)
90     UCHAR       Reserved1;                  // Reserved (used by Windows NT). Code that formats FAT volumes should always set this byte to 0.
91     UCHAR       BootSignature;              // Extended boot signature (0x29). This is a signature byte that indicates that the following three fields in the boot sector are present.
92     ULONG       VolumeSerialNumber;         // Volume serial number
93     CHAR        VolumeLabel[11];            // Volume label. This field matches the 11-byte volume label recorded in the root directory
94     CHAR        FileSystemType[8];          // Always set to the string "FAT32   "
95 
96     UCHAR       BootCodeAndData[420];       // The remainder of the boot sector
97 
98     USHORT      BootSectorMagic;            // 0xAA55
99 
100 } FAT32_BOOTSECTOR, *PFAT32_BOOTSECTOR;
101 C_ASSERT(sizeof(FAT32_BOOTSECTOR) == FAT32_BOOTSECTOR_SIZE);
102 
103 typedef struct _BTRFS_BOOTSECTOR
104 {
105     UCHAR JumpBoot[3];
106     UCHAR ChunkMapSize;
107     UCHAR BootDrive;
108     ULONGLONG PartitionStartLBA;
109     UCHAR Fill[1521]; // 1536 - 15
110     USHORT BootSectorMagic;
111 } BTRFS_BOOTSECTOR, *PBTRFS_BOOTSECTOR;
112 C_ASSERT(sizeof(BTRFS_BOOTSECTOR) == BTRFS_BOOTSECTOR_SIZE);
113 
114 // TODO: Add more bootsector structures!
115 
116 #include <poppack.h>
117 
118 
119 /* LOCALS *******************************************************************/
120 
121 /** IFS_PROVIDER **/
122 typedef struct _FILE_SYSTEM
123 {
124     PCWSTR FileSystemName;
125     FORMATEX FormatFunc;
126     CHKDSKEX ChkdskFunc;
127 } FILE_SYSTEM, *PFILE_SYSTEM;
128 
129 /* The list of file systems on which we can install ReactOS */
130 static FILE_SYSTEM RegisteredFileSystems[] =
131 {
132     /* NOTE: The FAT formatter will automatically
133      * determine whether to use FAT12/16 or FAT32. */
134     { L"FAT"  , VfatFormat, VfatChkdsk },
135     { L"FAT32", VfatFormat, VfatChkdsk },
136 #if 0
137     { L"FATX" , VfatxFormat, VfatxChkdsk },
138     { L"NTFS" , NtfsFormat, NtfsChkdsk },
139 #endif
140     { L"BTRFS", BtrfsFormatEx, BtrfsChkdskEx },
141 #if 0
142     { L"EXT2" , Ext2Format, Ext2Chkdsk },
143     { L"EXT3" , Ext2Format, Ext2Chkdsk },
144     { L"EXT4" , Ext2Format, Ext2Chkdsk },
145     { L"FFS"  , FfsFormat , FfsChkdsk  },
146     { L"REISERFS", ReiserfsFormat, ReiserfsChkdsk },
147 #endif
148 };
149 
150 
151 /* FUNCTIONS ****************************************************************/
152 
153 /** QueryAvailableFileSystemFormat() **/
154 BOOLEAN
155 GetRegisteredFileSystems(
156     IN ULONG Index,
157     OUT PCWSTR* FileSystemName)
158 {
159     if (Index >= ARRAYSIZE(RegisteredFileSystems))
160         return FALSE;
161 
162     *FileSystemName = RegisteredFileSystems[Index].FileSystemName;
163 
164     return TRUE;
165 }
166 
167 
168 /** GetProvider() **/
169 static PFILE_SYSTEM
170 GetFileSystemByName(
171     IN PCWSTR FileSystemName)
172 {
173 #if 0 // Reenable when the list of registered FSes will again be dynamic
174 
175     PLIST_ENTRY ListEntry;
176     PFILE_SYSTEM_ITEM Item;
177 
178     ListEntry = List->ListHead.Flink;
179     while (ListEntry != &List->ListHead)
180     {
181         Item = CONTAINING_RECORD(ListEntry, FILE_SYSTEM_ITEM, ListEntry);
182         if (Item->FileSystemName &&
183             (wcsicmp(FileSystemName, Item->FileSystemName) == 0))
184         {
185             return Item;
186         }
187 
188         ListEntry = ListEntry->Flink;
189     }
190 
191 #else
192 
193     ULONG Count = ARRAYSIZE(RegisteredFileSystems);
194     PFILE_SYSTEM FileSystems = RegisteredFileSystems;
195 
196     ASSERT(FileSystems && Count != 0);
197 
198     while (Count--)
199     {
200         if (FileSystems->FileSystemName &&
201             (wcsicmp(FileSystemName, FileSystems->FileSystemName) == 0))
202         {
203             return FileSystems;
204         }
205 
206         ++FileSystems;
207     }
208 
209 #endif
210 
211     return NULL;
212 }
213 
214 
215 /** ChkdskEx() **/
216 NTSTATUS
217 ChkdskFileSystem_UStr(
218     IN PUNICODE_STRING DriveRoot,
219     IN PCWSTR FileSystemName,
220     IN BOOLEAN FixErrors,
221     IN BOOLEAN Verbose,
222     IN BOOLEAN CheckOnlyIfDirty,
223     IN BOOLEAN ScanDrive,
224     IN PFMIFSCALLBACK Callback)
225 {
226     PFILE_SYSTEM FileSystem;
227 
228     FileSystem = GetFileSystemByName(FileSystemName);
229 
230     if (!FileSystem || !FileSystem->ChkdskFunc)
231     {
232         // BOOLEAN Argument = FALSE;
233         // Callback(DONE, 0, &Argument);
234         return STATUS_NOT_SUPPORTED;
235     }
236 
237     return FileSystem->ChkdskFunc(DriveRoot,
238                                   FixErrors,
239                                   Verbose,
240                                   CheckOnlyIfDirty,
241                                   ScanDrive,
242                                   Callback);
243 }
244 
245 NTSTATUS
246 ChkdskFileSystem(
247     IN PCWSTR DriveRoot,
248     IN PCWSTR FileSystemName,
249     IN BOOLEAN FixErrors,
250     IN BOOLEAN Verbose,
251     IN BOOLEAN CheckOnlyIfDirty,
252     IN BOOLEAN ScanDrive,
253     IN PFMIFSCALLBACK Callback)
254 {
255     UNICODE_STRING DriveRootU;
256 
257     RtlInitUnicodeString(&DriveRootU, DriveRoot);
258     return ChkdskFileSystem_UStr(&DriveRootU,
259                                  FileSystemName,
260                                  FixErrors,
261                                  Verbose,
262                                  CheckOnlyIfDirty,
263                                  ScanDrive,
264                                  Callback);
265 }
266 
267 
268 /** FormatEx() **/
269 NTSTATUS
270 FormatFileSystem_UStr(
271     IN PUNICODE_STRING DriveRoot,
272     IN PCWSTR FileSystemName,
273     IN FMIFS_MEDIA_FLAG MediaFlag,
274     IN PUNICODE_STRING Label,
275     IN BOOLEAN QuickFormat,
276     IN ULONG ClusterSize,
277     IN PFMIFSCALLBACK Callback)
278 {
279     PFILE_SYSTEM FileSystem;
280 
281     FileSystem = GetFileSystemByName(FileSystemName);
282 
283     if (!FileSystem || !FileSystem->FormatFunc)
284     {
285         // BOOLEAN Argument = FALSE;
286         // Callback(DONE, 0, &Argument);
287         return STATUS_NOT_SUPPORTED;
288     }
289 
290     return FileSystem->FormatFunc(DriveRoot,
291                                   MediaFlag,
292                                   Label,
293                                   QuickFormat,
294                                   ClusterSize,
295                                   Callback);
296 }
297 
298 NTSTATUS
299 FormatFileSystem(
300     IN PCWSTR DriveRoot,
301     IN PCWSTR FileSystemName,
302     IN FMIFS_MEDIA_FLAG MediaFlag,
303     IN PCWSTR Label,
304     IN BOOLEAN QuickFormat,
305     IN ULONG ClusterSize,
306     IN PFMIFSCALLBACK Callback)
307 {
308     UNICODE_STRING DriveRootU;
309     UNICODE_STRING LabelU;
310 
311     RtlInitUnicodeString(&DriveRootU, DriveRoot);
312     RtlInitUnicodeString(&LabelU, Label);
313 
314     return FormatFileSystem_UStr(&DriveRootU,
315                                  FileSystemName,
316                                  MediaFlag,
317                                  &LabelU,
318                                  QuickFormat,
319                                  ClusterSize,
320                                  Callback);
321 }
322 
323 
324 //
325 // Bootsector routines
326 //
327 
328 NTSTATUS
329 InstallFatBootCode(
330     IN PCWSTR SrcPath,          // FAT12/16 bootsector source file (on the installation medium)
331     IN HANDLE DstPath,          // Where to save the bootsector built from the source + partition information
332     IN HANDLE RootPartition)    // Partition holding the (old) FAT12/16 information
333 {
334     NTSTATUS Status;
335     UNICODE_STRING Name;
336     IO_STATUS_BLOCK IoStatusBlock;
337     LARGE_INTEGER FileOffset;
338     BOOTCODE OrigBootSector = {0};
339     BOOTCODE NewBootSector  = {0};
340 
341     /* Allocate and read the current original partition bootsector */
342     Status = ReadBootCodeByHandle(&OrigBootSector,
343                                   RootPartition,
344                                   FAT_BOOTSECTOR_SIZE);
345     if (!NT_SUCCESS(Status))
346         return Status;
347 
348     /* Allocate and read the new bootsector from SrcPath */
349     RtlInitUnicodeString(&Name, SrcPath);
350     Status = ReadBootCodeFromFile(&NewBootSector,
351                                   &Name,
352                                   FAT_BOOTSECTOR_SIZE);
353     if (!NT_SUCCESS(Status))
354     {
355         FreeBootCode(&OrigBootSector);
356         return Status;
357     }
358 
359     /* Adjust the bootsector (copy a part of the FAT12/16 BPB) */
360     RtlCopyMemory(&((PFAT_BOOTSECTOR)NewBootSector.BootCode)->OemName,
361                   &((PFAT_BOOTSECTOR)OrigBootSector.BootCode)->OemName,
362                   FIELD_OFFSET(FAT_BOOTSECTOR, BootCodeAndData) -
363                   FIELD_OFFSET(FAT_BOOTSECTOR, OemName));
364 
365     /* Free the original bootsector */
366     FreeBootCode(&OrigBootSector);
367 
368     /* Write the new bootsector to DstPath */
369     FileOffset.QuadPart = 0ULL;
370     Status = NtWriteFile(DstPath,
371                          NULL,
372                          NULL,
373                          NULL,
374                          &IoStatusBlock,
375                          NewBootSector.BootCode,
376                          NewBootSector.Length,
377                          &FileOffset,
378                          NULL);
379 
380     /* Free the new bootsector */
381     FreeBootCode(&NewBootSector);
382 
383     return Status;
384 }
385 
386 NTSTATUS
387 InstallFat32BootCode(
388     IN PCWSTR SrcPath,          // FAT32 bootsector source file (on the installation medium)
389     IN HANDLE DstPath,          // Where to save the bootsector built from the source + partition information
390     IN HANDLE RootPartition)    // Partition holding the (old) FAT32 information
391 {
392     NTSTATUS Status;
393     UNICODE_STRING Name;
394     IO_STATUS_BLOCK IoStatusBlock;
395     LARGE_INTEGER FileOffset;
396     USHORT BackupBootSector = 0;
397     BOOTCODE OrigBootSector = {0};
398     BOOTCODE NewBootSector  = {0};
399 
400     /* Allocate and read the current original partition bootsector */
401     Status = ReadBootCodeByHandle(&OrigBootSector,
402                                   RootPartition,
403                                   FAT32_BOOTSECTOR_SIZE);
404     if (!NT_SUCCESS(Status))
405         return Status;
406 
407     /* Allocate and read the new bootsector (2 sectors) from SrcPath */
408     RtlInitUnicodeString(&Name, SrcPath);
409     Status = ReadBootCodeFromFile(&NewBootSector,
410                                   &Name,
411                                   2 * FAT32_BOOTSECTOR_SIZE);
412     if (!NT_SUCCESS(Status))
413     {
414         FreeBootCode(&OrigBootSector);
415         return Status;
416     }
417 
418     /* Adjust the bootsector (copy a part of the FAT32 BPB) */
419     RtlCopyMemory(&((PFAT32_BOOTSECTOR)NewBootSector.BootCode)->OemName,
420                   &((PFAT32_BOOTSECTOR)OrigBootSector.BootCode)->OemName,
421                   FIELD_OFFSET(FAT32_BOOTSECTOR, BootCodeAndData) -
422                   FIELD_OFFSET(FAT32_BOOTSECTOR, OemName));
423 
424     /*
425      * We know we copy the boot code to a file only when DstPath != RootPartition,
426      * otherwise the boot code is copied to the specified root partition.
427      */
428     if (DstPath != RootPartition)
429     {
430         /* Copy to a file: Disable the backup bootsector */
431         ((PFAT32_BOOTSECTOR)NewBootSector.BootCode)->BackupBootSector = 0;
432     }
433     else
434     {
435         /* Copy to a disk: Get the location of the backup bootsector */
436         BackupBootSector = ((PFAT32_BOOTSECTOR)OrigBootSector.BootCode)->BackupBootSector;
437     }
438 
439     /* Free the original bootsector */
440     FreeBootCode(&OrigBootSector);
441 
442     /* Write the first sector of the new bootcode to DstPath sector 0 */
443     FileOffset.QuadPart = 0ULL;
444     Status = NtWriteFile(DstPath,
445                          NULL,
446                          NULL,
447                          NULL,
448                          &IoStatusBlock,
449                          NewBootSector.BootCode,
450                          FAT32_BOOTSECTOR_SIZE,
451                          &FileOffset,
452                          NULL);
453     if (!NT_SUCCESS(Status))
454     {
455         DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
456         FreeBootCode(&NewBootSector);
457         return Status;
458     }
459 
460     if (DstPath == RootPartition)
461     {
462         /* Copy to a disk: Write the backup bootsector */
463         if ((BackupBootSector != 0x0000) && (BackupBootSector != 0xFFFF))
464         {
465             FileOffset.QuadPart = (ULONGLONG)((ULONG)BackupBootSector * FAT32_BOOTSECTOR_SIZE);
466             Status = NtWriteFile(DstPath,
467                                  NULL,
468                                  NULL,
469                                  NULL,
470                                  &IoStatusBlock,
471                                  NewBootSector.BootCode,
472                                  FAT32_BOOTSECTOR_SIZE,
473                                  &FileOffset,
474                                  NULL);
475             if (!NT_SUCCESS(Status))
476             {
477                 DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
478                 FreeBootCode(&NewBootSector);
479                 return Status;
480             }
481         }
482     }
483 
484     /* Write the second sector of the new bootcode to boot disk sector 14 */
485     // FileOffset.QuadPart = (ULONGLONG)(14 * FAT32_BOOTSECTOR_SIZE);
486     FileOffset.QuadPart = 14 * FAT32_BOOTSECTOR_SIZE;
487     Status = NtWriteFile(DstPath,   // or really RootPartition ???
488                          NULL,
489                          NULL,
490                          NULL,
491                          &IoStatusBlock,
492                          ((PUCHAR)NewBootSector.BootCode + FAT32_BOOTSECTOR_SIZE),
493                          FAT32_BOOTSECTOR_SIZE,
494                          &FileOffset,
495                          NULL);
496     if (!NT_SUCCESS(Status))
497     {
498         DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
499     }
500 
501     /* Free the new bootsector */
502     FreeBootCode(&NewBootSector);
503 
504     return Status;
505 }
506 
507 NTSTATUS
508 InstallBtrfsBootCode(
509     IN PCWSTR SrcPath,          // BTRFS bootsector source file (on the installation medium)
510     IN HANDLE DstPath,          // Where to save the bootsector built from the source + partition information
511     IN HANDLE RootPartition)    // Partition holding the (old) BTRFS information
512 {
513     NTSTATUS Status;
514     NTSTATUS LockStatus;
515     UNICODE_STRING Name;
516     IO_STATUS_BLOCK IoStatusBlock;
517     LARGE_INTEGER FileOffset;
518     PARTITION_INFORMATION_EX PartInfo;
519     BOOTCODE NewBootSector = {0};
520 
521     /* Allocate and read the new bootsector from SrcPath */
522     RtlInitUnicodeString(&Name, SrcPath);
523     Status = ReadBootCodeFromFile(&NewBootSector,
524                                   &Name,
525                                   BTRFS_BOOTSECTOR_SIZE);
526     if (!NT_SUCCESS(Status))
527         return Status;
528 
529     /*
530      * The BTRFS driver requires the volume to be locked in order to modify
531      * the first sectors of the partition, even though they are outside the
532      * file-system space / in the reserved area (they are situated before
533      * the super-block at 0x1000) and is in principle allowed by the NT
534      * storage stack.
535      * So we lock here in order to write the bootsector at sector 0.
536      * If locking fails, we ignore and continue nonetheless.
537      */
538     LockStatus = NtFsControlFile(DstPath,
539                                  NULL,
540                                  NULL,
541                                  NULL,
542                                  &IoStatusBlock,
543                                  FSCTL_LOCK_VOLUME,
544                                  NULL,
545                                  0,
546                                  NULL,
547                                  0);
548     if (!NT_SUCCESS(LockStatus))
549     {
550         DPRINT1("WARNING: Failed to lock BTRFS volume for writing bootsector! Operations may fail! (Status 0x%lx)\n", LockStatus);
551     }
552 
553     /* Obtain partition info and write it to the bootsector */
554     Status = NtDeviceIoControlFile(RootPartition,
555                                    NULL,
556                                    NULL,
557                                    NULL,
558                                    &IoStatusBlock,
559                                    IOCTL_DISK_GET_PARTITION_INFO_EX,
560                                    NULL,
561                                    0,
562                                    &PartInfo,
563                                    sizeof(PartInfo));
564     if (!NT_SUCCESS(Status))
565     {
566         DPRINT1("IOCTL_DISK_GET_PARTITION_INFO_EX failed (Status %lx)\n", Status);
567         goto Quit;
568     }
569 
570     /* Write new bootsector to RootPath */
571     ((PBTRFS_BOOTSECTOR)NewBootSector.BootCode)->PartitionStartLBA =
572         PartInfo.StartingOffset.QuadPart / SECTORSIZE;
573 
574     /* Write sector 0 */
575     FileOffset.QuadPart = 0ULL;
576     Status = NtWriteFile(DstPath,
577                          NULL,
578                          NULL,
579                          NULL,
580                          &IoStatusBlock,
581                          NewBootSector.BootCode,
582                          NewBootSector.Length,
583                          &FileOffset,
584                          NULL);
585     if (!NT_SUCCESS(Status))
586     {
587         DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
588         goto Quit;
589     }
590 
591 Quit:
592     /* Unlock the volume */
593     LockStatus = NtFsControlFile(DstPath,
594                                  NULL,
595                                  NULL,
596                                  NULL,
597                                  &IoStatusBlock,
598                                  FSCTL_UNLOCK_VOLUME,
599                                  NULL,
600                                  0,
601                                  NULL,
602                                  0);
603     if (!NT_SUCCESS(LockStatus))
604     {
605         DPRINT1("Failed to unlock BTRFS volume (Status 0x%lx)\n", LockStatus);
606     }
607 
608     /* Free the new bootsector */
609     FreeBootCode(&NewBootSector);
610 
611     return Status;
612 }
613 
614 
615 //
616 // Formatting routines
617 //
618 
619 BOOLEAN
620 PreparePartitionForFormatting(
621     IN struct _PARTENTRY* PartEntry,
622     IN PCWSTR FileSystemName)
623 {
624     UCHAR PartitionType;
625 
626     if (!FileSystemName || !*FileSystemName)
627     {
628         DPRINT1("No file system specified?\n");
629         return FALSE;
630     }
631 
632     PartitionType = FileSystemToPartitionType(FileSystemName,
633                                               &PartEntry->StartSector,
634                                               &PartEntry->SectorCount);
635     if (PartitionType == PARTITION_ENTRY_UNUSED)
636     {
637         /* Unknown file system */
638         DPRINT1("Unknown file system '%S'\n", FileSystemName);
639         return FALSE;
640     }
641 
642     SetPartitionType(PartEntry, PartitionType);
643 
644     /*
645      * Adjust the filesystem name in case of FAT vs. FAT32, according to
646      * the type of partition set by FileSystemToPartitionType().
647      */
648     if (wcsicmp(FileSystemName, L"FAT") == 0)
649     {
650         if ((/*PartEntry->*/PartitionType == PARTITION_FAT32) ||
651             (/*PartEntry->*/PartitionType == PARTITION_FAT32_XINT13))
652         {
653             FileSystemName = L"FAT32";
654         }
655     }
656 
657 //
658 // FIXME: Do this now, or after the partition was actually formatted??
659 //
660     /* Set the new partition's file system proper */
661     RtlStringCbCopyW(PartEntry->FileSystem,
662                      sizeof(PartEntry->FileSystem),
663                      FileSystemName);
664 
665     return TRUE;
666 }
667 
668 /* EOF */
669