예제 #1
0
        /// <summary>
        /// Formats the specified volume.
        /// </summary>
        /// <param name="volume">The volume.</param>
        /// <param name="options">The options.</param>
        /// <param name="label">The label.</param>
        /// <returns></returns>
        public static ExFatFileSystem Format(PhysicalVolumeInfo volume, ExFatFormatOptions options = null, string label = null)
        {
            var partitionStream = volume.Open();

            using (ExFatPathFilesystem.Format(partitionStream, options, label)) { }
            return(new ExFatFileSystem(partitionStream));
        }
예제 #2
0
        /// <summary>
        /// Formats the specified partition stream.
        /// </summary>
        /// <param name="partitionStream">The partition stream.</param>
        /// <param name="options">The options.</param>
        /// <param name="volumeLabel">The volume label.</param>
        /// <returns></returns>
        public static ExFatPartition Format(Stream partitionStream, ExFatFormatOptions options, string volumeLabel = null)
        {
            var partition = new ExFatPartition(partitionStream, 0, false);

            partitionStream.Seek(0, SeekOrigin.Begin);

            var volumeSpace       = options?.VolumeSpace ?? (ulong)partitionStream.Length;
            var bytesPerSector    = options?.BytesPerSector ?? 512;
            var totalSectors      = volumeSpace / bytesPerSector;
            var sectorsPerCluster = options?.SectorsPerCluster ?? ComputeSectorsPerCluster(totalSectors);

            if (sectorsPerCluster > 1 << 25)
            {
                throw new ArgumentException("Sectors per cluster can not exceed 2^25");
            }
            const uint fats        = 1;
            const uint usedFats    = fats;
            const uint bootSectors = 12;
            const uint bpbSectors  = 2 * bootSectors;

            // create bootsector
            var bootSectorBytes = new byte[bytesPerSector * 12];
            var bootSector      = new ExFatBootSector(bootSectorBytes);
            var totalClusters   = (uint)(totalSectors - bpbSectors) / (usedFats * 4 / bytesPerSector + sectorsPerCluster);
            var sectorsPerFat   = totalClusters * 4 / bytesPerSector;

            bootSector.JmpBoot.Set(ExFatBootSector.DefaultJmpBoot);
            bootSector.OemName.Value             = ExFatBootSector.ExFatOemName;
            bootSector.VolumeLengthSectors.Value = totalSectors;
            bootSector.FatOffsetSector.Value     = Align(bpbSectors, bytesPerSector);
            bootSector.FatLengthSectors.Value    = Align(sectorsPerFat, bytesPerSector);
            bootSector.ClusterOffsetSector.Value = Align(bootSector.FatOffsetSector.Value + usedFats * bootSector.FatLengthSectors.Value, bytesPerSector);
            totalClusters = (uint)((volumeSpace / bytesPerSector - bootSector.ClusterOffsetSector.Value) / sectorsPerCluster);
            if (totalClusters > 0xFFFFFFF0)
            {
                throw new ArgumentException("clusters are too small to address full disk");
            }
            bootSector.ClusterCount.Value       = totalClusters;
            bootSector.VolumeSerialNumber.Value = (uint)new Random().Next();
            bootSector.FileSystemRevision.Value = 256;
            bootSector.VolumeFlags.Value        = 0;
            bootSector.BytesPerSector.Value     = bytesPerSector;
            bootSector.SectorsPerCluster.Value  = sectorsPerCluster;
            bootSector.NumberOfFats.Value       = (byte)fats;
            bootSector.DriveSelect.Value        = 0x80;
            bootSector.PercentInUse.Value       = 0xFF;
            for (int sectorIndex = 0; sectorIndex <= 8; sectorIndex++)
            {
                bootSectorBytes[sectorIndex * bytesPerSector + bytesPerSector - 2] = 0x55;
                bootSectorBytes[sectorIndex * bytesPerSector + bytesPerSector - 1] = 0xAA;
            }
            partition.BootSector = bootSector;

            // prepare FAT
            partition.ClearFat();
            partition.SetNextCluster(0, Cluster.Marker);
            partition.SetNextCluster(1, Cluster.Last);

            // create allocation bitmap
            var allocationBitmapEntry = CreateAllocationBitmap(partition, totalClusters);

            // create root directory
            var directoryDataDescriptor = new DataDescriptor(0, false, ulong.MaxValue, ulong.MaxValue);

            using (var s = partition.OpenClusterStream(directoryDataDescriptor, FileAccess.ReadWrite,
                                                       d => directoryDataDescriptor = new DataDescriptor(d.FirstCluster, d.Contiguous, long.MaxValue, long.MaxValue)))
            {
                s.SetDataLength(bytesPerSector * sectorsPerCluster);
            }
            bootSector.RootDirectoryCluster.Value = directoryDataDescriptor.FirstCluster.ToUInt32();

            // boot sector is now complete
            var checksum = bootSector.ComputeChecksum();

            for (var offset = 11 * bytesPerSector; offset < 12 * bytesPerSector; offset += 4)
            {
                bootSectorBytes[offset]     = checksum[0];
                bootSectorBytes[offset + 1] = checksum[1];
                bootSectorBytes[offset + 2] = checksum[2];
                bootSectorBytes[offset + 3] = checksum[3];
            }
            partition.WriteSectors(0, bootSectorBytes, (int)bootSectors);
            partition.WriteSectors(bootSectors, bootSectorBytes, (int)bootSectors);

            using (var directoryStream = partition.OpenClusterStream(directoryDataDescriptor, FileAccess.ReadWrite))
            {
                allocationBitmapEntry.Write(directoryStream);

                CreateUpCaseTable(partition, directoryStream);
                CreateVolumeLabel(directoryStream, volumeLabel);
            }
            partition.Flush();
            return(partition);
        }
예제 #3
0
        /// <summary>
        /// Formats the specified partition.
        /// </summary>
        /// <param name="partitionStream">The partition stream.</param>
        /// <param name="options">The options.</param>
        /// <param name="volumeLabel">The volume label.</param>
        /// <returns></returns>
        public static ExFatEntryFilesystem Format(Stream partitionStream, ExFatFormatOptions options, string volumeLabel = null)
        {
            var partition = ExFatPartition.Format(partitionStream, options, volumeLabel);

            return(new ExFatEntryFilesystem(partition));
        }