示例#1
0
        /**
         * Finds a free block, and returns its offset.
         * This method will extend the file if needed, and if doing
         *  so, allocate new FAT blocks to Address the extra space.
         */
        public override int GetFreeBlock()
        {
            int sectorsPerSBAT = _filesystem.GetBigBlockSizeDetails().GetBATEntriesPerBlock();

            // First up, do we have any spare ones?
            int offset = 0;

            for (int i = 0; i < _sbat_blocks.Count; i++)
            {
                // Check this one
                BATBlock sbat = _sbat_blocks[i];
                if (sbat.HasFreeSectors)
                {
                    // Claim one of them and return it
                    for (int j = 0; j < sectorsPerSBAT; j++)
                    {
                        int sbatValue = sbat.GetValueAt(j);
                        if (sbatValue == POIFSConstants.UNUSED_BLOCK)
                        {
                            // Bingo
                            return(offset + j);
                        }
                    }
                }

                // Move onto the next SBAT
                offset += sectorsPerSBAT;
            }

            // If we Get here, then there aren't any
            //  free sectors in any of the SBATs
            // So, we need to extend the chain and add another

            // Create a new BATBlock
            BATBlock newSBAT    = BATBlock.CreateEmptyBATBlock(_filesystem.GetBigBlockSizeDetails(), false);
            int      batForSBAT = _filesystem.GetFreeBlock();

            newSBAT.OurBlockIndex = batForSBAT;

            // Are we the first SBAT?
            if (_header.SBATCount == 0)
            {
                _header.SBATStart      = batForSBAT;
                _header.SBATBlockCount = 1;
            }
            else
            {
                // Find the end of the SBAT stream, and add the sbat in there
                ChainLoopDetector loopDetector = _filesystem.GetChainLoopDetector();
                int batOffset = _header.SBATStart;
                while (true)
                {
                    loopDetector.Claim(batOffset);
                    int nextBat = _filesystem.GetNextBlock(batOffset);
                    if (nextBat == POIFSConstants.END_OF_CHAIN)
                    {
                        break;
                    }
                    batOffset = nextBat;
                }

                // Add it in at the end
                _filesystem.SetNextBlock(batOffset, batForSBAT);

                // And update the count
                _header.SBATBlockCount = _header.SBATCount + 1;
            }

            // Finish allocating
            _filesystem.SetNextBlock(batForSBAT, POIFSConstants.END_OF_CHAIN);
            _sbat_blocks.Add(newSBAT);

            // Return our first spot
            return(offset);
        }