Пример #1
0
        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);
        }
Пример #2
0
        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;
            }
        }