/// <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; } }