private void InitializeFs(MfsFsHeader *header, MfsParameters createParams)
        {
            header->Magic         = MfsMagic;
            header->NextFreeBlock = 1;

            if (createParams != null)
            {
                // Validate the parameters.
                this.ValidateFsParameters(createParams.BlockSize, createParams.CellSize);

                header->BlockSize = createParams.BlockSize;
                header->CellSize  = createParams.CellSize;
            }
            else
            {
                header->BlockSize = MfsDefaultBlockSize;
                header->CellSize  = MfsDefaultCellSize;
            }

            // Store root object in the next cell.
            MfsObjectHeader *obj = (MfsObjectHeader *)((byte *)header + header->CellSize);

            this.InitializeObject(obj, _rootObjectCellId);
            this.SetObjectName(obj, "root");
        }
        public MemoryFileSystem(string fileName, MfsOpenMode mode, bool readOnly, MfsParameters createParams)
        {
            FileCreationDispositionWin32 cdWin32;

            if (readOnly && mode != MfsOpenMode.Open)
            {
                throw new ArgumentException("Invalid mode for read only access.");
            }

            switch (mode)
            {
            case MfsOpenMode.Open:
                cdWin32 = FileCreationDispositionWin32.OpenExisting;
                break;

            default:
            case MfsOpenMode.OpenIf:
                cdWin32 = FileCreationDispositionWin32.OpenAlways;
                break;

            case MfsOpenMode.OverwriteIf:
                cdWin32 = FileCreationDispositionWin32.CreateAlways;
                break;
            }

            using (var fhandle = FileHandle.CreateWin32(
                       fileName,
                       FileAccess.GenericRead | (!readOnly ? FileAccess.GenericWrite : 0),
                       FileShareMode.Read,
                       cdWin32
                       ))
            {
                bool justCreated = false;

                _readOnly   = readOnly;
                _protection = !readOnly ? MemoryProtection.ReadWrite : MemoryProtection.ReadOnly;

                if (fhandle.GetSize() == 0)
                {
                    if (readOnly)
                    {
                        throw new MfsInvalidFileSystemException();
                    }
                    else
                    {
                        // File is too small. Make it 1 byte large and we'll deal with it
                        // soon.
                        fhandle.SetEnd(1);
                    }
                }

                _section = new Section(fhandle, _protection);

                _blockSize = MfsBlockSizeBase; // fake block size to begin with; we'll fix it up later.

                if (fhandle.GetSize() < _blockSize)
                {
                    if (readOnly)
                    {
                        throw new MfsInvalidFileSystemException();
                    }
                    else
                    {
                        // We're creating a new file system. We need the correct block size
                        // now.
                        if (createParams != null)
                        {
                            _blockSize = createParams.BlockSize;
                        }
                        else
                        {
                            _blockSize = MfsDefaultBlockSize;
                        }

                        _section.Extend(_blockSize);

                        using (var view = _section.MapView(0, _blockSize, _protection))
                            this.InitializeFs((MfsFsHeader *)view.Memory, createParams);

                        justCreated = true;
                    }
                }

                _header = (MfsFsHeader *)this.ReferenceBlock(0);

                // Check the magic.
                if (_header->Magic != MfsMagic)
                {
                    throw new MfsInvalidFileSystemException();
                }

                // Set up the local constants.
                _blockSize = _header->BlockSize;
                _cellSize  = _header->CellSize;

                // Backwards compatibility.
                if (_blockSize == 0)
                {
                    _blockSize = MfsDefaultBlockSize;
                }
                if (_cellSize == 0)
                {
                    _cellSize = MfsDefaultCellSize;
                }

                // Validate the parameters.
                this.ValidateFsParameters(_blockSize, _cellSize);

                _blockMask             = _blockSize - 1;
                _cellCount             = _blockSize / _cellSize;
                _dataCellDataMaxLength = _cellSize - MfsDataCell.DataOffset;

                // Remap block 0 with the correct block size.
                this.DereferenceBlock(0);

                // If we just created a new file system, fix the section size.
                if (justCreated)
                {
                    _section.Extend(_blockSize);
                }

                _header = (MfsFsHeader *)this.ReferenceBlock(0);

                // Set up the root object.
                _rootObject   = (MfsObjectHeader *)((byte *)_header + _cellSize);
                _rootObjectMo = new MemoryObject(this, _rootObjectCellId, true);

                if (_header->NextFreeBlock != 1 && !readOnly)
                {
                    ushort lastBlockId = (ushort)(_header->NextFreeBlock - 1);

                    this.ReferenceBlock(lastBlockId);
                    _cachedLastBlockView = _views[lastBlockId];
                }
            }
        }