/// <summary> /// Reads the master boot block. /// </summary> /// <returns></returns> public bool Read() { valid = false; MasterBootBlock mbr = new MasterBootBlock(diskDevice); if (!mbr.Valid) return false; if ((mbr.Partitions[0].PartitionType != PartitionType.GPT) || (mbr.Partitions[1].PartitionType != PartitionType.Empty) || (mbr.Partitions[2].PartitionType != PartitionType.Empty) || (mbr.Partitions[3].PartitionType != PartitionType.Empty) || (!mbr.Partitions[0].Bootable) || (mbr.Partitions[0].StartLBA != 1)) return false; BinaryFormat gpt = new BinaryFormat(diskDevice.ReadBlock(1, 1)); if ((gpt.GetByte(0) != 45) && (gpt.GetByte(1) != 46) && (gpt.GetByte(2) != 49) && (gpt.GetByte(3) != 20) && (gpt.GetByte(4) != 50) && (gpt.GetByte(5) != 41) && (gpt.GetByte(6) != 52) && (gpt.GetByte(7) != 54)) return false; if ((gpt.GetUInt(GPT.Revision) != GPTConstant.SupportedRevision) || (gpt.GetUInt(GPT.HeaderSize) != GPTConstant.HeaderSize) || (gpt.GetUInt(GPT.Reserved) != 0) || (gpt.GetUInt(GPT.PartitionStartingLBA) != 2) ) return false; valid = true; return valid; }
/// <summary> /// Compares the specified data. /// </summary> /// <param name="data">The data.</param> /// <param name="offset">The offset.</param> /// <param name="type">The type.</param> /// <returns></returns> public bool Compare(byte[] data, uint offset, FatType type) { BinaryFormat entry = new BinaryFormat(data); byte first = entry.GetByte(Entry.DOSName + offset); if (first == FileNameAttribute.LastEntry) return false; if ((first == FileNameAttribute.Deleted) | (first == FileNameAttribute.Dot)) return false; if (first == FileNameAttribute.Escape) return false; FatFileAttributes attribute = (FatFileAttributes)entry.GetByte(Entry.FileAttributes + offset); if ((attribute & FatFileAttributes.VolumeLabel) == FatFileAttributes.VolumeLabel) return true; return false; }
/// <summary> /// Compares the specified data. /// </summary> /// <param name="data">The data.</param> /// <param name="offset">The offset.</param> /// <param name="type">The type.</param> /// <returns></returns> public bool Compare(byte[] data, uint offset, FatType type) { BinaryFormat entry = new BinaryFormat(data); byte first = entry.GetByte(offset + Entry.DOSName); if (first == FileNameAttribute.LastEntry) return true; if ((first == FileNameAttribute.Deleted) | (first == FileNameAttribute.Dot)) return true; return false; }
return false; if ((first == FileNameAttribute.Deleted) | (first == FileNameAttribute.Dot)) return false; if (first == FileNameAttribute.Escape) return false; uint startcluster = FatFileSystem.GetClusterEntry(data, offset, type); if (startcluster == cluster) return true; return false; } } }
/// <summary> /// Compares the specified data. /// </summary> /// <param name="data">The data.</param> /// <param name="offset">The offset.</param> /// <param name="type">The type.</param> /// <returns></returns> public bool Compare(byte[] data, uint offset, FatType type) { var entry = new BinaryFormat(data); byte first = entry.GetByte(offset + Entry.DOSName); if (first == FileNameAttribute.LastEntry) return false; if ((first == FileNameAttribute.Deleted) | (first == FileNameAttribute.Dot)) return false; if (first == FileNameAttribute.Escape) return false; string entryname = FatFileSystem.ExtractFileName(data, offset); if (entryname == name) return true; return false; }
/// <summary> /// Finds the entry. /// </summary> /// <param name="compare">The compare.</param> /// <param name="startCluster">The start cluster.</param> /// <returns></returns> public FatFileLocation FindEntry(FatFileSystem.ICompare compare, uint startCluster) { uint activeSector = startCluster * sectorsPerCluster; if (startCluster == 0) activeSector = (fatType == FatType.FAT32) ? GetSectorByCluster(rootCluster32) : firstRootDirectorySector; uint increment = 0; for (;;) { BinaryFormat directory = new BinaryFormat(partition.ReadBlock(activeSector, 1)); for (uint index = 0; index < entriesPerSector; index++) { if (compare.Compare(directory.Data, index * 32, fatType)) { FatFileAttributes attribute = (FatFileAttributes)directory.GetByte((index * Entry.EntrySize) + Entry.FileAttributes); return new FatFileLocation(GetClusterEntry(directory.Data, index, fatType), activeSector, index, (attribute & FatFileAttributes.SubDirectory) != 0); } if (directory.GetByte(Entry.DOSName + (index * Entry.EntrySize)) == FileNameAttribute.LastEntry) return new FatFileLocation(); } ++increment; if ((startCluster == 0) && (fatType != FatType.FAT32)) { // FAT12/16 Root directory if (increment >= rootDirSectors) return new FatFileLocation(); activeSector = startCluster + increment; continue; } else { // subdirectory if (increment < sectorsPerCluster) { // still within cluster activeSector = startCluster + increment; continue; } // exiting cluster // goto next cluster (if any) uint cluster = GetClusterBySector(startCluster); if (cluster == 0) return new FatFileLocation(); uint nextCluster = GetClusterEntryValue(cluster); if ((IsClusterLast(nextCluster)) || (IsClusterBad(nextCluster)) || (IsClusterFree(nextCluster)) || (IsClusterReserved(nextCluster))) return new FatFileLocation(); activeSector = (uint)(dataAreaStart + (nextCluster - 1 * sectorsPerCluster)); continue; } } }
/// <summary> /// Extracts the name of the file. /// </summary> /// <param name="directory">The directory.</param> /// <param name="index">The index.</param> /// <returns></returns> public static string ExtractFileName(byte[] directory, uint index) { // rewrite to use string BinaryFormat entry = new BinaryFormat(directory); char[] name = new char[12]; for (uint i = 0; i < 8; i++) name[i] = (char)entry.GetByte(index + i + Entry.DOSName); int len = 8; for (int i = 7; i > 0; i--) if (name[i] == ' ') len--; else break; // special case where real character is same as the delete if ((len >= 1) && (name[0] == (char)FileNameAttribute.Escape)) name[0] = (char)FileNameAttribute.Deleted; name[len] = '.'; len++; for (uint i = 0; i < 3; i++) name[len + i] = (char)entry.GetByte(index + i + Entry.DOSExtension); len = len + 3; int spaces = 0; for (int i = len - 1; i >= 0; i--) if (name[i] == ' ') spaces++; else break; if (spaces == 3) spaces = 4; len = len - spaces; // FIXME string str = string.Empty; for (uint i = 0; i < len; i++) str = str + (char)name[i]; return str; }
/// <summary> /// Reads the boot sector. /// </summary> /// <returns></returns> protected bool ReadBootSector() { valid = false; if (blockSize != 512) // only going to work with 512 sector sizes (for now) return false; BinaryFormat bootSector = new BinaryFormat(partition.ReadBlock(0, 1)); if (bootSector.GetUShort(BootSector.BootSectorSignature) != 0xAA55) return false; byte extendedBootSignature = bootSector.GetByte(BootSector.ExtendedBootSignature); byte extendedBootSignature32 = bootSector.GetByte(BootSector.FAT32_ExtendedBootSignature); if ((extendedBootSignature != 0x29) && (extendedBootSignature != 0x28) && (extendedBootSignature32 != 0x29)) return false; volumeLabel = bootSector.GetString(BootSector.VolumeLabel, 8).ToString().TrimEnd(); bytesPerSector = bootSector.GetUShort(BootSector.BytesPerSector); sectorsPerCluster = bootSector.GetByte(BootSector.SectorsPerCluster); reservedSectors = bootSector.GetByte(BootSector.ReservedSectors); nbrFats = bootSector.GetByte(BootSector.FatAllocationTables); rootEntries = bootSector.GetUShort(BootSector.MaxRootDirEntries); rootCluster32 = bootSector.GetUInt(BootSector.FAT32_ClusterNumberOfRoot); uint sectorsPerFat16 = bootSector.GetUShort(BootSector.SectorsPerFAT); uint sectorsPerFat32 = bootSector.GetUInt(BootSector.FAT32_SectorPerFAT); uint totalSectors16 = bootSector.GetUShort(BootSector.TotalSectors16); uint totalSectors32 = bootSector.GetUInt(BootSector.TotalSectors32); uint sectorsPerFat = (sectorsPerFat16 != 0) ? sectorsPerFat16 : sectorsPerFat32; uint fatSectors = 0; try { fatSectors = nbrFats * sectorsPerFat; clusterSizeInBytes = sectorsPerCluster * blockSize; rootDirSectors = (((rootEntries * 32) + (bytesPerSector - 1)) / bytesPerSector); firstDataSector = reservedSectors + (nbrFats * sectorsPerFat) + rootDirSectors; totalSectors = (totalSectors16 != 0) ? totalSectors16 : totalSectors32; dataSectors = totalSectors - (reservedSectors + (nbrFats * sectorsPerFat) + rootDirSectors); totalClusters = dataSectors / sectorsPerCluster; entriesPerSector = (bytesPerSector / 32); firstRootDirectorySector = reservedSectors + fatSectors; dataAreaStart = firstRootDirectorySector + rootDirSectors; } catch { return false; } // Some basic checks if ((nbrFats == 0) || (nbrFats > 2) || (totalSectors == 0) || (sectorsPerFat == 0)) return false; if (totalClusters < 4085) fatType = FatType.FAT12; else if (totalClusters < 65525) fatType = FatType.FAT16; else fatType = FatType.FAT32; if (fatType == FatType.FAT12) { reservedClusterMark = 0xFF0; endOfClusterMark = 0x0FF8; badClusterMark = 0x0FF7; fatMask = 0xFFFFFFFF; fatEntries = sectorsPerFat * 3 * blockSize / 2; } else if (fatType == FatType.FAT16) { reservedClusterMark = 0xFFF0; endOfClusterMark = 0xFFF8; badClusterMark = 0xFFF7; fatMask = 0xFFFFFFFF; fatEntries = sectorsPerFat * blockSize / 2; } else { // if (type == FatType.FAT32) { reservedClusterMark = 0xFFF0; endOfClusterMark = 0x0FFFFFF8; badClusterMark = 0x0FFFFFF7; fatMask = 0x0FFFFFFF; fatEntries = sectorsPerFat * blockSize / 4; } // More basic checks if ((fatType == FatType.FAT32) && (rootCluster32 == 0)) return false; valid = true; serialNbr = bootSector.GetBytes(fatType != FatType.FAT32 ? BootSector.IDSerialNumber : BootSector.FAT32_IDSerialNumber, 4); return true; }
/// <summary> /// Reads the master boot block. /// </summary> /// <returns></returns> public bool Read() { valid = false; if (diskDevice.BlockSize != 512) return false; // only going to work with 512 sector sizes if (diskDevice.TotalBlocks < 3) return false; BinaryFormat masterboot = new BinaryFormat(diskDevice.ReadBlock(0, 1)); if (masterboot.GetUShort(MBR.MBRSignature) != MBRConstant.MBRSignature) return false; valid = true; diskSignature = masterboot.GetUInt(MBR.DiskSignature); for (uint index = 0; index < MaxMBRPartitions; index++) { uint offset = MBR.FirstPartition + (index * MBRConstant.PartitionSize); GenericPartition partition = new GenericPartition(index); partition.Bootable = masterboot.GetByte(offset + PartitionRecord.Status) == MBRConstant.Bootable; partition.PartitionType = masterboot.GetByte(offset + PartitionRecord.PartitionType); partition.StartLBA = masterboot.GetUInt(offset + PartitionRecord.LBA); partition.TotalBlocks = masterboot.GetUInt(offset + PartitionRecord.Sectors); Partitions[index] = partition; } //TODO: Extended Partitions code = new byte[MBRConstant.CodeAreaSize]; for (uint index = 0; index < MBRConstant.CodeAreaSize; index++) code[index] = masterboot.GetByte(index); return valid; }