/// <summary>
        /// Delete an page using pageID - transform them in Empty Page and add to EmptyPageList
        /// If you delete a page, you can using same old instance of page - page will be converter to EmptyPage
        /// If need deleted page, use GetPage again
        /// </summary>
        public void DeletePage(uint pageID, bool addSequence = false)
        {
            // get all pages in sequence or a single one
            var pages = addSequence ? this.GetSeqPages <BasePage>(pageID).ToArray() : new BasePage[] { this.GetPage <BasePage>(pageID) };

            // get my header page
            var header = this.GetPage <HeaderPage>(0);

            // adding all pages to FreeList
            foreach (var page in pages)
            {
                // create a new empty page based on a normal page
                var empty = new EmptyPage(page.PageID);

                // add empty page to cache (with now EmptyPage type) and mark as dirty
                this.SetDirty(empty);

                // add to empty free list
                this.AddOrRemoveToFreeList(true, empty, header, ref header.FreeEmptyPageID);
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Initialize new datafile with header page + lock reserved area zone
        /// </summary>
        public static void CreateDatabase(Stream stream, string password = null, long initialSize = 0)
        {
            // calculate how many empty pages will be added on disk
            var emptyPages = initialSize == 0 ? 0 : (initialSize - (2 * BasePage.PAGE_SIZE)) / BasePage.PAGE_SIZE;

            // if too small size (less than 2 pages), assume no initial size
            if (emptyPages < 0)
            {
                emptyPages = 0;
            }

            // create a new header page in bytes (keep second page empty)
            var header = new HeaderPage
            {
                LastPageID      = initialSize == 0 ? 1 : (uint)emptyPages + 1,
                FreeEmptyPageID = initialSize == 0 ? uint.MaxValue : 2
            };

            if (password != null)
            {
                header.Password = AesEncryption.HashSHA1(password);
                header.Salt     = AesEncryption.Salt();
            }

            // point to begin file
            stream.Seek(0, SeekOrigin.Begin);

            // get header page in bytes
            var buffer = header.WritePage();

            stream.Write(buffer, 0, BasePage.PAGE_SIZE);

            // write second page as an empty AREA (it's not a page) just to use as lock control
            stream.Write(new byte[BasePage.PAGE_SIZE], 0, BasePage.PAGE_SIZE);

            // create crypto class if has password
            var crypto = password != null ? new AesEncryption(password, header.Salt) : null;

            // if initial size is defined, lets create empty pages in a linked list
            if (emptyPages > 0)
            {
                stream.SetLength(initialSize);

                var pageID = 1u;

                while (++pageID < (emptyPages + 2))
                {
                    var empty = new EmptyPage(pageID)
                    {
                        PrevPageID = pageID == 2 ? 0 : pageID - 1,
                        NextPageID = pageID == emptyPages + 1 ? uint.MaxValue : pageID + 1
                    };

                    var bytes = empty.WritePage();

                    if (password != null)
                    {
                        bytes = crypto.Encrypt(bytes);
                    }

                    stream.Write(bytes, 0, BasePage.PAGE_SIZE);
                }
            }

            if (crypto != null)
            {
                crypto.Dispose();
            }
        }