[gnome-games] utils: Add Archive



commit 295ffb3aeb661f303e13fa6df7be3316dad7cc50
Author: Adwait Rawat <adwait rawat gmail com>
Date:   Wed May 8 01:47:45 2019 +0900

    utils: Add Archive
    
    It contains functions for creating and extracting archives.
    
    This will be used in the next commit to implement Backup & Restore page in
    preferences.

 po/POTFILES.in         |   1 +
 src/meson.build        |   1 +
 src/utils/archive.vala | 146 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 148 insertions(+)
---
diff --git a/po/POTFILES.in b/po/POTFILES.in
index d24e59cb..0af8c955 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -75,4 +75,5 @@ src/ui/preferences-page-platforms.vala
 src/ui/preferences-page-video.vala
 src/ui/preferences-subpage-gamepad.vala
 src/ui/preferences-subpage-keyboard.vala
+src/utils/archive.vala
 src/utils/cue-sheet/cue-sheet.vala
diff --git a/src/meson.build b/src/meson.build
index 6f17d9eb..3f635d53 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -181,6 +181,7 @@ vala_sources = [
   'ui/shortcuts-window.vala',
   'ui/ui-view.vala',
 
+  'utils/archive.vala',
   'utils/archive-error.vala',
   'utils/composite-cover.vala',
   'utils/composite-title.vala',
diff --git a/src/utils/archive.vala b/src/utils/archive.vala
new file mode 100644
index 00000000..775f7c29
--- /dev/null
+++ b/src/utils/archive.vala
@@ -0,0 +1,146 @@
+// This file is part of GNOME Games. License: GPL-3.0+.
+
+namespace Games {
+       private void compress_dir (string name, File parent_dir, File export_data, string[]? exclude_files = 
null) throws ArchiveError {
+               var archive = new Archive.Write ();
+               archive.add_filter_gzip ();
+               archive.set_format_pax_restricted ();
+               archive.open_filename (name);
+
+               backup_data (parent_dir, export_data, archive, exclude_files);
+               if (archive.close () != Archive.Result.OK) {
+                       var error_message = _("Error: %s (%d)").printf (archive.error_string (), 
archive.errno ());
+                       throw new ArchiveError.COMPRESSION_FAILED (error_message);
+               }
+       }
+
+       private void backup_data (File parent, File dir, Archive.Write archive, string[] exclusions) throws 
ArchiveError {
+               var dtype = dir.query_file_type (FileQueryInfoFlags.NOFOLLOW_SYMLINKS);
+
+               if (dtype == FileType.DIRECTORY) {
+                       try {
+                               var dir_children = dir.enumerate_children (FileAttribute.STANDARD_NAME, 0);
+                               FileInfo dir_info;
+                               while ((dir_info = dir_children.next_file ()) != null) {
+                                       var file = dir.get_child (dir_info.get_name ());
+                                       backup_data (parent, file, archive, exclusions);
+                               }
+                       }
+                       catch (Error e) {
+                               throw new ArchiveError.COMPRESSION_FAILED (e.message);
+                       }
+               }
+               else {
+                       foreach (var filename in exclusions)
+                               if (dir.get_parse_name () == filename)
+                                       return;
+                       compress_files (parent, dir, archive);
+               }
+       }
+
+       private void compress_files (File parent_working_dir, File export_dir, Archive.Write export_archive) 
throws ArchiveError {
+               FileInfo export_info;
+               FileInputStream input_stream;
+               DataInputStream data_input_stream;
+
+               try {
+                       var attributes = ("%s,%s").printf (FileAttribute.STANDARD_SIZE 
,FileAttribute.TIME_MODIFIED);
+                       export_info = export_dir.query_info (attributes, FileQueryInfoFlags.NONE);
+                       input_stream = export_dir.read ();
+                       data_input_stream = new DataInputStream (input_stream);
+               }
+               catch (Error e) {
+                       throw new ArchiveError.INITIALIZATION_FAILED (e.message);
+               }
+
+               var entry = new Archive.Entry ();
+               var timeval = export_info.get_modification_time ();
+               entry.set_pathname (parent_working_dir.get_relative_path (export_dir));
+               entry.set_size ((Archive.int64_t) export_info.get_size ());
+               entry.set_mtime ((time_t) timeval.tv_sec, 0);
+               entry.set_filetype ((Archive.FileType) Posix.S_IFREG);
+               entry.set_perm (0644);
+               if (export_archive.write_header (entry) != Archive.Result.OK) {
+                       var error_msg = _("Error writing '%s': %s (%d)").printf (export_dir.get_path (), 
export_archive.error_string (), export_archive.errno ());
+                       throw new ArchiveError.COMPRESSION_FAILED (error_msg);
+               }
+
+               size_t bytes_read;
+               uint8[] buffer = new uint8[64];
+               try {
+                       while (data_input_stream.read_all (buffer, out bytes_read)) {
+                               if (bytes_read <= 0)
+                                       break;
+
+                               export_archive.write_data (buffer);
+                       }
+               }
+               catch (Error e) {
+                       throw new ArchiveError.FILE_HANDLING (e.message);
+               }
+       }
+
+       private void delete_files (File file, string[] exclusions) throws Error {
+               var dtype = file.query_file_type (FileQueryInfoFlags.NOFOLLOW_SYMLINKS);
+
+               if (dtype == FileType.DIRECTORY) {
+                       try     {
+                               var file_children = file.enumerate_children (FileAttribute.STANDARD_NAME, 0);
+                               FileInfo file_info;
+                               while ((file_info = file_children.next_file ()) != null) {
+                                       var child = file.get_child (file_info.get_name ());
+                                       delete_files (child, exclusions);
+                               }
+                       }
+                       catch (Error e) {
+                               throw e;
+                       }
+               }
+               else {
+                       foreach (var filename in exclusions)
+                               if (file.get_parse_name () == filename)
+                                       return;
+                       file.delete ();
+               }
+       }
+
+       private void extract_archive (string archive_path, string extract_dir, string[] exclude) throws 
ArchiveError {
+               try {
+                       var file_dir = File.new_for_path (extract_dir);
+                       delete_files (file_dir, exclude);
+               }
+               catch (Error e) {
+                       throw new ArchiveError.DELETION_FAILED (e.message);
+               }
+
+               var restore_archive = new Archive.Read ();
+               restore_archive.support_format_all ();
+               restore_archive.support_filter_all ();
+
+               var flags = Archive.ExtractFlags.TIME | Archive.ExtractFlags.PERM;
+
+               var extractor_archive = new Archive.WriteDisk ();
+               extractor_archive.set_options (flags);
+               extractor_archive.set_standard_lookup ();
+
+               restore_archive.open_filename (archive_path, /* block_size */ 10240);
+
+               unowned Archive.Entry entry;
+               Archive.Result last_result;
+               while ((last_result = restore_archive.next_header (out entry)) == Archive.Result.OK) {
+                       var dir_pathname = ("%s/%s").printf (extract_dir, entry.pathname ());
+                       entry.set_pathname (dir_pathname);
+                       if (extractor_archive.write_header (entry) != Archive.Result.OK)
+                               throw new ArchiveError.EXTRACTION_FAILED ("%s\n", 
extractor_archive.error_string ());
+
+                       uint8[] buffer = new uint8[64];
+                       size_t buffer_length;
+                       while (restore_archive.read_data_block (out buffer, out buffer_length) == 
Archive.Result.OK)
+                               if (extractor_archive.write_data_block (buffer, buffer_length) != 
Archive.Result.OK)
+                                       break;
+               }
+
+               if (last_result != Archive.Result.EOF)
+                       throw new ArchiveError.EXTRACTION_FAILED ("%s (%d)", restore_archive.error_string (), 
restore_archive.errno ());
+       }
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]