예제 #1
0
        /// <summary>
        /// Tests the FileNameRegistration class. Retrieve names for some
        /// files, delete nodes, add nodes, and perform a compact operation.
        /// </summary>
        public void test_FileNameRegistration()
        {
            Console.WriteLine("About to test the FileNameRegistration. Attempt to get a "
                              + "few alternative file names. Then delete some files to trigger "
                              + "compaction.  Press any key to continue, or ESC to skip.");
            if (hit_esc_key())
            {
                return;
            }

            // Add files to the file name registration tree.
            var file_name_reg = new FileNameRegistration(file_name_reg_xml);

            Console.WriteLine();
            Console.WriteLine("The test now creates a basic directory structure and "
                              + "print information about it.");

            // Create a basic directory structure.
            var path_status = file_name_reg.get_path_status(@"E:\a");

            if (path_status == null)
            {
                // .add_file(...) can only happen once per file, so this block
                // should run just once.
                Console.WriteLine(file_name_reg.add_file(@"E:\a"));
                Console.WriteLine(file_name_reg.add_file(@"E:\a1\b"));
                Console.WriteLine(file_name_reg.add_file(@"E:\a1\c"));

                Console.WriteLine(file_name_reg.add_file(@"E:\a1\c2\cc2"));
                Console.WriteLine(file_name_reg.add_file(@"E:\a1\c2\cc2b"));
                Console.WriteLine(file_name_reg.add_file(@"E:\a1\c2\cc2c"));
                Console.WriteLine(file_name_reg.add_file(@"E:\a1\c2\cc2dd\c2a"));
                Console.WriteLine(file_name_reg.add_file(@"E:\a1\c2\cc2dd\c2b"));

                Console.WriteLine(file_name_reg.add_file(@"E:\a1\c3"));
            }

            // print how things look so far
            file_name_reg.print();
            file_name_reg.print(@"E:\temp\temp\fnr.txt");
            Console.WriteLine();

            // Test the .get_path_status(...)
            string[] paths = { @"E:\a1\c2", @"E:\a1\b", @"E:\a1\no_such_thing" };
            foreach (string path in paths)
            {
                var path_info = file_name_reg.get_path_status(path);
                if (path_info == null)
                {
                    Console.WriteLine(path + " does not exist.");
                }
                else
                {
                    Console.WriteLine(path);
                    Console.WriteLine("is_file = " + path_info.is_file
                                      + "; alt_file_name = " + path_info.alt_file_name
                                      + "; modified_time = " + path_info.modified_time);
                }
                Console.WriteLine();
            }

            // Test the .get_names(...)
            List <string> sub_dir_names = null, file_names = null, alt_file_names = null;
            string        path2 = @"E:\a1\c2";

            file_name_reg.get_names(path2, ref sub_dir_names, ref file_names, ref alt_file_names);

            if (sub_dir_names != null)
            {
                Console.Write(path2 + " sub directory names: ");
                foreach (var name in sub_dir_names)
                {
                    Console.Write(name + ", ");
                }
                Console.WriteLine();
            }

            if (file_names != null)
            {
                Console.Write(path2 + " file names: ");
                foreach (var name in file_names)
                {
                    Console.Write(name + ", ");
                }
                Console.WriteLine();
            }

            if (alt_file_names != null)
            {
                Console.Write(path2 + " alternative file names: ");
                foreach (var name in alt_file_names)
                {
                    Console.Write(name + ", ");
                }
                Console.WriteLine();
            }

            pause();

            // Delete
            Console.WriteLine(@"Delete E:\a1\c2");
            file_name_reg.delete(@"E:\a1\c2");
            file_name_reg.print();
            pause();

            file_name_reg.Dispose();

            // Reload from file to trigger compaction
            file_name_reg = new FileNameRegistration(file_name_reg_xml);

            // Get modified time
            Console.WriteLine("Test changing the modified time.");
            Console.WriteLine(@"E:\a1\b modified time = " +
                              file_name_reg.get_modified_time(@"E:\a1\b"));

            // Set modified time
            file_name_reg.set_modified_time(@"E:\a1\b", DateTime.Now);
            Console.WriteLine(@"E:\a1\b modified time = " +
                              file_name_reg.get_modified_time(@"E:\a1\b"));

            pause();

            // Try a bigger directory
            Console.WriteLine("Attaching files from " + @"E:\temp\temp");

            string[] file_paths = Directory.GetFiles(@"E:\temp\temp", "*",
                                                     SearchOption.AllDirectories);

            if (file_name_reg.get_path_status(file_paths[0]) == null)
            {
                foreach (string path in file_paths)
                {
                    Console.Write(file_name_reg.add_file(path) + " ");
                }
            }


            Console.WriteLine();
            file_name_reg.print();
            pause();

            // Try reload from disk
            Console.WriteLine("Reload from disk.");
            file_name_reg.Dispose();

            file_name_reg = new FileNameRegistration(file_name_reg_xml);
            file_name_reg.print();

            // Try to create files using explicit file IDs. This is necessary
            // for the restoration process. The file IDs need to be >= 1000
            // per design spec.
            pause();
            file_name_reg.Dispose();

            Console.WriteLine("Adding new files with explicit file IDs\n");
            file_name_reg = new FileNameRegistration(file_name_reg_xml);

            if (file_name_reg.get_path_status(@"c:\test\whatever\123.txt") == null)
            {
                file_name_reg.add_file(@"c:\test\whatever\123.txt", "a", 2123, 0);
                file_name_reg.add_file(@"c:\test\whatever\67.txt", "a", 2067, 0);
                file_name_reg.add_file(@"c:\test\whatever2\320.txt", "a", 2320, 0);
                file_name_reg.set_modified_time(@"c:\test\whatever2\320.txt", DateTime.Now);
                file_name_reg.add_file(@"c:\test\whatever\999.txt", "b", 2999, 0);
            }
            file_name_reg.Dispose();

            file_name_reg = new FileNameRegistration(file_name_reg_xml);

            path_status = file_name_reg.get_path_status(@"c:\test\whatever\999.txt");
            Console.WriteLine(@"c:\test\whatever\999.txt");
            Console.WriteLine("is_file = " + path_status.is_file
                              + "; alt_file_name = " + path_status.alt_file_name
                              + "; modified_time = " + path_status.modified_time);

            file_name_reg.Dispose();
            Console.WriteLine();
        }
        public void restore(string restore_destination_base,
                            Dictionary <string, string> restore_destination_lookup,
                            List <string> prefix_filter, FileNameRegistration file_name_reg)
        {
            // The following variables are not used directly in this function,
            // but they are used in restore_handler(...)
            this.restore_destination_base   = restore_destination_base;
            this.restore_destination_lookup = restore_destination_lookup;
            this.prefix_filter = prefix_filter;

            // Get a list of alt_file_names. These look like "a1000.bin"
            string[] alt_file_names = get_alt_file_names();

            // Each file restore happens in two steps. In the first step, only the
            // start of a file is read / downloaded.
            const int starting_bytes = 1024;

            byte[] buffer = new byte[starting_bytes];

            int files_processed = 0; // report progress to the GUI

            // loop over all files
            foreach (var alt_file_name in alt_file_names)
            {
                // identify the file's prefix and file ID
                string prefix = null;
                UInt32 id;
                break_down_alt_file_name(alt_file_name, ref prefix, out id);

                if (prefix == null)
                {
                    continue;
                }

                // setup for the decryption
                decrypt_stream.reset(null, restore_handler);
                handler_called      = false;
                file_modified_time  = null;
                continue_download   = false;
                restore_destination = null;

                if (cloud_backup == null)
                {
                    using (var fs = new FileStream(alt_file_name, FileMode.Open, FileAccess.Read))
                    {
                        // decrypt from alt_file_name
                        int bytes_read = fs.Read(buffer, 0, starting_bytes);
                        decrypt_stream.Write(buffer, 0, bytes_read);

                        if (continue_download)
                        {
                            fs.CopyTo(decrypt_stream);
                            decrypt_stream.Flush();
                        }
                    }
                }
                else
                {
                    // download from the cloud
                    cloud_backup.download(backup_destination_base, alt_file_name,
                                          decrypt_stream, 0, starting_bytes);

                    if (continue_download)
                    {
                        // The following does not work for GCP:
                        // cloud_backup.download(backup_destination_base, alt_file_name,
                        //      decrypt_stream, starting_bytes, file_pre_encrypt_size);

                        // GCP error: Request range not satisfiable
                        // GCP seems to require the starting byte location of the
                        // download to be valid.

                        if (total_file_length > starting_bytes)
                        {
                            cloud_backup.download(backup_destination_base, alt_file_name,
                                                  decrypt_stream, starting_bytes,
                                                  total_file_length - starting_bytes);
                        }

                        decrypt_stream.Flush();
                    }
                }

                // check for "handler_called" errors?
                // if (handler_called == false) ??
                // This kind of error should have been filtered out when the GUI used
                // get_info(...). An exception now will interrupt the restore
                // operation. So for now just quietly skip the file??

                // Change file modified time to what it use to be.
                if (continue_download && file_modified_time != null)
                {
                    File.SetLastWriteTimeUtc(restore_destination, file_modified_time.Value);
                }

                // Update file_name_reg.
                if (continue_download)
                {
                    long file_mod_time_ticks = 0;
                    if (file_modified_time != null)
                    {
                        file_mod_time_ticks = file_modified_time.Value.Ticks;
                    }

                    file_name_reg.add_file(restore_destination, prefix, id, file_mod_time_ticks);

                    // report progress to the user
                    files_processed++;
                    if (report_event != null)
                    {
                        if (files_processed == 5)
                        {
                            report_event(AppEventType.FILES_PROCESSED, files_processed);
                            files_processed = 0;
                        }
                    }
                }
            } // end of: foreach (var alt_file_name in alt_file_names)

            if (report_event != null)
            {
                report_event(AppEventType.FILES_PROCESSED, files_processed);
                files_processed = 0;
            }
        }