public void Test_STREAM_VIEW_2() { Stream b = null; List <Sector> temp = new List <Sector>(); StreamView sv = new StreamView(temp, 512, b); sv.Write(BitConverter.GetBytes(1), 0, 4); sv.Seek(0, SeekOrigin.Begin); BinaryReader br = new BinaryReader(sv); Int32 t = br.ReadInt32(); Assert.IsTrue(t == 1); }
public void Test_STREAM_VIEW_LARGE_DATA() { Stream b = null; List <Sector> temp = new List <Sector>(); StreamView sv = new StreamView(temp, 512, b); for (int i = 0; i < 200; i++) { sv.Write(BitConverter.GetBytes(i), 0, 4); } sv.Seek(0, SeekOrigin.Begin); BinaryReader br = new BinaryReader(sv); for (int i = 0; i < 200; i++) { Assert.IsTrue(i == br.ReadInt32(), "Failed with " + i.ToString()); } }
/// <summary> /// Scan FAT o miniFAT for free sectors to reuse. /// </summary> /// <param name="sType">Type of sector to look for</param> /// <returns>A stack of available sectors or minisectors already allocated</returns> internal Queue<Sector> FindFreeSectors(SectorType sType) { var freeList = new Queue<Sector>(); if (sType == SectorType.Normal) { var fatChain = GetSectorChain(-1, SectorType.FAT); var fatStream = new StreamView(fatChain, GetSectorSize(), _header.FATSectorsNumber*GetSectorSize(), SourceStream); var idx = 0; while (idx < _sectors.Count) { var id = fatStream.ReadInt32(); if (id == Sector.FreeSector) { if (_sectors[idx] == null) { var sector = new Sector(GetSectorSize(), SourceStream) {Id = idx}; _sectors[idx] = sector; } freeList.Enqueue(_sectors[idx]); } idx++; } } else { var miniFAT = GetSectorChain(_header.FirstMiniFATSectorId, SectorType.Normal); var miniFATView = new StreamView(miniFAT, GetSectorSize(), _header.MiniFATSectorsNumber*Sector.MinisectorSize, SourceStream); var miniStream = GetSectorChain(RootEntry.StartSector, SectorType.Normal); var miniStreamView = new StreamView(miniStream, GetSectorSize(), RootStorage.Size, SourceStream); long ptr = 0; var nMinisectors = (int) (miniStreamView.Length/Sector.MinisectorSize); while (ptr < nMinisectors) { //AssureLength(miniStreamView, (int)miniFATView.Length); var id = miniFATView.ReadInt32(); ptr += 4; if (id != Sector.FreeSector) continue; var miniSector = new Sector(Sector.MinisectorSize, SourceStream) { Id = (int) ((ptr - 4)/4), Type = SectorType.Mini }; miniStreamView.Seek(miniSector.Id*Sector.MinisectorSize, SeekOrigin.Begin); miniStreamView.Read(miniSector.GetData(), 0, Sector.MinisectorSize); freeList.Enqueue(miniSector); } } return freeList; }
/// <summary> /// Allocate space, setup sectors id and refresh header /// for the new or updated FAT sector chain. /// </summary> /// <param name="sectorChain">The new or updated generic sector chain</param> private void SetFATSectorChain(IList<Sector> sectorChain) { var fatSectors = GetSectorChain(-1, SectorType.FAT); var fatStream = new StreamView( fatSectors, GetSectorSize(), _header.FATSectorsNumber*GetSectorSize(), SourceStream ); // Write FAT chain values -- for (var i = 0; i < sectorChain.Count - 1; i++) { var sN = sectorChain[i + 1]; var sC = sectorChain[i]; fatStream.Seek(sC.Id*4, SeekOrigin.Begin); fatStream.Write(BitConverter.GetBytes(sN.Id), 0, 4); } fatStream.Seek(sectorChain[sectorChain.Count - 1].Id*4, SeekOrigin.Begin); fatStream.Write(BitConverter.GetBytes(Sector.Endofchain), 0, 4); // Merge chain to CFS SetDIFATSectorChain(fatStream.BaseSectorChain); }
/// <summary> /// Allocate space, setup sectors id and refresh header /// for the new or updated mini sector chain. /// </summary> /// <param name="sectorChain">The new MINI sector chain</param> private void SetMiniSectorChain(IList<Sector> sectorChain) { var miniFAT = GetSectorChain(_header.FirstMiniFATSectorId, SectorType.Normal); var miniStream = GetSectorChain(RootEntry.StartSector, SectorType.Normal); var miniFATView = new StreamView( miniFAT, GetSectorSize(), _header.MiniFATSectorsNumber*Sector.MinisectorSize, SourceStream ); var miniStreamView = new StreamView( miniStream, GetSectorSize(), RootStorage.Size, SourceStream); // Set updated/new sectors within the ministream foreach (var sector in sectorChain) { if (sector.Id != -1) { // Overwrite miniStreamView.Seek(Sector.MinisectorSize*sector.Id, SeekOrigin.Begin); miniStreamView.Write(sector.GetData(), 0, Sector.MinisectorSize); } else { // Allocate, position ministream at the end of already allocated // ministream's sectors miniStreamView.Seek(RootStorage.Size, SeekOrigin.Begin); miniStreamView.Write(sector.GetData(), 0, Sector.MinisectorSize); sector.Id = (int) (miniStreamView.Position - Sector.MinisectorSize)/Sector.MinisectorSize; RootStorage.DirEntry.Size = miniStreamView.Length; } } // Update miniFAT for (var i = 0; i < sectorChain.Count - 1; i++) { var currentId = sectorChain[i].Id; var nextId = sectorChain[i + 1].Id; //AssureLength(miniFATView, Math.Max(currentId * SIZE_OF_SID, nextId * SIZE_OF_SID)); miniFATView.Seek(currentId*4, SeekOrigin.Begin); miniFATView.Write(BitConverter.GetBytes(nextId), 0, 4); } // Write End of Chain in MiniFAT miniFATView.Seek(sectorChain[sectorChain.Count - 1].Id*SizeOfSID, SeekOrigin.Begin); miniFATView.Write(BitConverter.GetBytes(Sector.Endofchain), 0, 4); // Update sector chains SetNormalSectorChain(miniStreamView.BaseSectorChain); SetNormalSectorChain(miniFATView.BaseSectorChain); //Update HEADER and root storage when ministream changes if (miniFAT.Count > 0) { RootStorage.DirEntry.StartSector = miniStream[0].Id; _header.MiniFATSectorsNumber = (uint) miniFAT.Count; _header.FirstMiniFATSectorId = miniFAT[0].Id; } }
/// <summary> /// Get a standard sector chain /// </summary> /// <param name="secId">First SecID of the required chain</param> /// <returns>A list of sectors</returns> /// <exception cref="CFCorruptedFileException">Raised when the file is corrupt</exception> private List<Sector> GetNormalSectorChain(int secId) { var result = new List<Sector>(); var nextSecId = secId; var fatSectors = GetFatSectorChain(); var fatStream = new StreamView(fatSectors, GetSectorSize(), fatSectors.Count*GetSectorSize(), SourceStream); while (true) { if (nextSecId == Sector.Endofchain) break; if (nextSecId >= _sectors.Count) throw new CFCorruptedFileException( string.Format( "Next Sector ID reference an out of range sector. NextID : {0} while sector count {1}", nextSecId, _sectors.Count)); var sector = _sectors[nextSecId]; if (sector == null) { sector = new Sector(GetSectorSize(), SourceStream) {Id = nextSecId, Type = SectorType.Normal}; _sectors[nextSecId] = sector; } result.Add(sector); fatStream.Seek(nextSecId*4, SeekOrigin.Begin); var next = fatStream.ReadInt32(); if (next != nextSecId) nextSecId = next; else throw new CFCorruptedFileException("Cyclic sector chain found. File is corrupted"); } return result; }
/// <summary> /// Setup the DIFAT sector chain /// </summary> /// <param name="faTsectorChain">A FAT sector chain</param> private void SetDIFATSectorChain(List<Sector> faTsectorChain) { // Get initial sector's count _header.FATSectorsNumber = faTsectorChain.Count; // Allocate Sectors foreach (var s in faTsectorChain) { if (s.Id != -1) continue; _sectors.Add(s); s.Id = _sectors.Count - 1; s.Type = SectorType.FAT; } // Sector count... var nCurrentSectors = _sectors.Count; // Temp DIFAT count var nDIFATSectors = (int) _header.DIFATSectorsNumber; if (faTsectorChain.Count > HeaderDIFATEntriesCount) { nDIFATSectors = Ceiling((double) (faTsectorChain.Count - HeaderDIFATEntriesCount)/_difatSectorFATEntriesCount); nDIFATSectors = LowSaturation(nDIFATSectors - (int) _header.DIFATSectorsNumber); //required DIFAT } // ...sum with new required DIFAT sectors count nCurrentSectors += nDIFATSectors; // ReCheck FAT bias while (_header.FATSectorsNumber*_fatSectorEntriesCount < nCurrentSectors) { var extraFATSector = new Sector(GetSectorSize(), SourceStream); _sectors.Add(extraFATSector); extraFATSector.Id = _sectors.Count - 1; extraFATSector.Type = SectorType.FAT; faTsectorChain.Add(extraFATSector); _header.FATSectorsNumber++; nCurrentSectors++; //... so, adding a FAT sector may induce DIFAT sectors to increase by one // and consequently this may induce ANOTHER FAT sector (TO-THINK: May this condition occure ?) if (nDIFATSectors*_difatSectorFATEntriesCount >= (_header.FATSectorsNumber > HeaderDIFATEntriesCount ? _header.FATSectorsNumber - HeaderDIFATEntriesCount : 0)) continue; nDIFATSectors++; nCurrentSectors++; } var difatSectors = GetSectorChain(-1, SectorType.DIFAT); var difatStream = new StreamView(difatSectors, GetSectorSize(), SourceStream); // Write DIFAT Sectors (if required) // Save room for the following chaining for (var i = 0; i < faTsectorChain.Count; i++) { if (i < HeaderDIFATEntriesCount) _header.DIFAT[i] = faTsectorChain[i].Id; else { // room for DIFAT chaining at the end of any DIFAT sector (4 bytes) if (i != HeaderDIFATEntriesCount && (i - HeaderDIFATEntriesCount)%_difatSectorFATEntriesCount == 0) { var temp = new byte[sizeof (int)]; difatStream.Write(temp, 0, sizeof (int)); } difatStream.Write(BitConverter.GetBytes(faTsectorChain[i].Id), 0, sizeof (int)); } } // Allocate room for DIFAT sectors foreach (var sector in difatStream.BaseSectorChain) { if (sector.Id != -1) continue; _sectors.Add(sector); sector.Id = _sectors.Count - 1; sector.Type = SectorType.DIFAT; } _header.DIFATSectorsNumber = (uint) nDIFATSectors; // Chain first sector if (difatStream.BaseSectorChain != null && difatStream.BaseSectorChain.Count > 0) { _header.FirstDIFATSectorId = difatStream.BaseSectorChain[0].Id; // Update header information _header.DIFATSectorsNumber = (uint) difatStream.BaseSectorChain.Count; // Write chaining information at the end of DIFAT Sectors for (var i = 0; i < difatStream.BaseSectorChain.Count - 1; i++) { Buffer.BlockCopy( BitConverter.GetBytes(difatStream.BaseSectorChain[i + 1].Id), 0, difatStream.BaseSectorChain[i].GetData(), GetSectorSize() - sizeof (int), 4); } Buffer.BlockCopy( BitConverter.GetBytes(Sector.Endofchain), 0, difatStream.BaseSectorChain[difatStream.BaseSectorChain.Count - 1].GetData(), GetSectorSize() - sizeof (int), sizeof (int) ); } else _header.FirstDIFATSectorId = Sector.Endofchain; // Mark DIFAT Sectors in FAT var fatSv = new StreamView(faTsectorChain, GetSectorSize(), _header.FATSectorsNumber*GetSectorSize(), SourceStream); for (var i = 0; i < _header.DIFATSectorsNumber; i++) { fatSv.Seek(difatStream.BaseSectorChain[i].Id*4, SeekOrigin.Begin); fatSv.Write(BitConverter.GetBytes(Sector.DifSector), 0, 4); } for (var i = 0; i < _header.FATSectorsNumber; i++) { fatSv.Seek(fatSv.BaseSectorChain[i].Id*4, SeekOrigin.Begin); fatSv.Write(BitConverter.GetBytes(Sector.FATSector), 0, 4); } _header.FATSectorsNumber = fatSv.BaseSectorChain.Count; }
/// <summary> /// Get a mini sector chain /// </summary> /// <param name="sectorId">First sector id of the required chain</param> /// <returns>A list of mini sectors (64 bytes)</returns> private List<Sector> GetMiniSectorChain(int sectorId) { var result = new List<Sector>(); if (sectorId == Sector.Endofchain) return result; var miniFAT = GetNormalSectorChain(_header.FirstMiniFATSectorId); var miniStream = GetNormalSectorChain(RootEntry.StartSector); var miniFATView = new StreamView(miniFAT, GetSectorSize(), _header.MiniFATSectorsNumber*Sector.MinisectorSize, SourceStream); var miniStreamView = new StreamView(miniStream, GetSectorSize(), RootStorage.Size, SourceStream); var miniFATReader = new BinaryReader(miniFATView); var nextSectorId = sectorId; while (true) { if (nextSectorId == Sector.Endofchain) break; var miniSector = new Sector(Sector.MinisectorSize, SourceStream) { Id = nextSectorId, Type = SectorType.Mini }; miniStreamView.Seek(nextSectorId*Sector.MinisectorSize, SeekOrigin.Begin); miniStreamView.Read(miniSector.GetData(), 0, Sector.MinisectorSize); result.Add(miniSector); miniFATView.Seek(nextSectorId*4, SeekOrigin.Begin); nextSectorId = miniFATReader.ReadInt32(); } return result; }
/// <summary> /// Get the FAT sector chain /// </summary> /// <returns>List of FAT sectors</returns> private List<Sector> GetFatSectorChain() { const int numberOfHeaderFATEntry = 109; //Number of FAT sectors id in the header var result = new List<Sector>(); int nextSecId; var difatSectors = GetDifatSectorChain(); var idx = 0; // Read FAT entries from the header Fat entry array (max 109 entries) while (idx < _header.FATSectorsNumber && idx < numberOfHeaderFATEntry) { nextSecId = _header.DIFAT[idx]; var sector = _sectors[nextSecId]; if (sector == null) { sector = new Sector(GetSectorSize(), SourceStream) {Id = nextSecId, Type = SectorType.FAT}; _sectors[nextSecId] = sector; } result.Add(sector); idx++; } //Is there any DIFAT sector containing other FAT entries ? if (difatSectors.Count <= 0) return result; var difatStream = new StreamView ( difatSectors, GetSectorSize(), _header.FATSectorsNumber > numberOfHeaderFATEntry ? (_header.FATSectorsNumber - numberOfHeaderFATEntry)*4 : 0, SourceStream ); var nextDIFATSectorBuffer = new byte[4]; difatStream.Read(nextDIFATSectorBuffer, 0, 4); nextSecId = BitConverter.ToInt32(nextDIFATSectorBuffer, 0); var i = 0; var numberOfFatHeaderEntries = numberOfHeaderFATEntry; while (numberOfFatHeaderEntries < _header.FATSectorsNumber) { if (difatStream.Position == ((GetSectorSize() - 4) + i*GetSectorSize())) { difatStream.Seek(4, SeekOrigin.Current); i++; continue; } var sector = _sectors[nextSecId]; if (sector == null) { sector = new Sector(GetSectorSize(), SourceStream) {Type = SectorType.FAT, Id = nextSecId}; _sectors[nextSecId] = sector; //UUU } result.Add(sector); difatStream.Read(nextDIFATSectorBuffer, 0, 4); nextSecId = BitConverter.ToInt32(nextDIFATSectorBuffer, 0); numberOfFatHeaderEntries++; } return result; }
private void FreeMiniChain(IList<Sector> sectorChain, bool zeroSector) { var zeroedMiniSector = new byte[Sector.MinisectorSize]; var miniFAT = GetSectorChain(_header.FirstMiniFATSectorId, SectorType.Normal); var miniStream = GetSectorChain(RootEntry.StartSector, SectorType.Normal); var miniFATView = new StreamView(miniFAT, GetSectorSize(), _header.MiniFATSectorsNumber*Sector.MinisectorSize, SourceStream); var miniStreamView = new StreamView(miniStream, GetSectorSize(), RootStorage.Size, SourceStream); // Set updated/new sectors within the ministream if (zeroSector) { foreach (var sector in sectorChain) { if (sector.Id == -1) continue; // Overwrite miniStreamView.Seek(Sector.MinisectorSize*sector.Id, SeekOrigin.Begin); miniStreamView.Write(zeroedMiniSector, 0, Sector.MinisectorSize); } } // Update miniFAT for (var i = 0; i < sectorChain.Count - 1; i++) { var currentId = sectorChain[i].Id; miniFATView.Seek(currentId*4, SeekOrigin.Begin); miniFATView.Write(BitConverter.GetBytes(Sector.FreeSector), 0, 4); } //AssureLength(miniFATView, sectorChain[sectorChain.Count - 1].Id * SIZE_OF_SID); // Write End of Chain in MiniFAT miniFATView.Seek(sectorChain[sectorChain.Count - 1].Id*SizeOfSID, SeekOrigin.Begin); miniFATView.Write(BitConverter.GetBytes(Sector.FreeSector), 0, 4); // Update sector chains SetNormalSectorChain(miniStreamView.BaseSectorChain); SetNormalSectorChain(miniFATView.BaseSectorChain); //Update HEADER and root storage when ministream changes if (miniFAT.Count > 0) { RootStorage.DirEntry.StartSector = miniStream[0].Id; _header.MiniFATSectorsNumber = (uint) miniFAT.Count; _header.FirstMiniFATSectorId = miniFAT[0].Id; } }
private void FreeChain(IList<Sector> sectorChain, bool zeroSector) { var fat = GetSectorChain(-1, SectorType.FAT); var fatView = new StreamView(fat, GetSectorSize(), fat.Count*GetSectorSize(), SourceStream); // Zeroes out sector data (if requested) if (zeroSector) { foreach (var sector in sectorChain) sector.ZeroData(); } // Update FAT marking unallocated sectors for (var i = 0; i < sectorChain.Count - 1; i++) { var currentId = sectorChain[i].Id; //AssureLength(FATView, Math.Max(currentId * SIZE_OF_SID, nextId * SIZE_OF_SID)); fatView.Seek(currentId*4, SeekOrigin.Begin); fatView.Write(BitConverter.GetBytes(Sector.FreeSector), 0, 4); } }
/// <summary> /// Check for transaction lock sector addition and mark it in the FAT. /// </summary> private void CheckForLockSector() { //If transaction lock has been added and not yet allocated in the FAT... if (TransactionLockAdded && !TransactionLockAllocated) { var fatStream = new StreamView(GetFatSectorChain(), GetSectorSize(), SourceStream); fatStream.Seek(LockSectorId*4, SeekOrigin.Begin); fatStream.Write(BitConverter.GetBytes(Sector.Endofchain), 0, 4); TransactionLockAllocated = true; } }