[Pkg-privacy-commits] [libgsecuredelete] 02/168: Added a generic asynchronous spawning class and used it.

Ulrike Uhlig u-guest at moszumanska.debian.org
Thu Jul 7 20:06:31 UTC 2016


This is an automated email from the git hooks/post-receive script.

u-guest pushed a commit to branch master
in repository libgsecuredelete.

commit ca67bf70aa868695191cf96f62910d8096684bdf
Author: Colomban Wendling <ban at herbesfolles.org>
Date:   Tue Sep 29 20:01:59 2009 +0200

    Added a generic asynchronous spawning class and used it.
    
    Added AsyncOperation that is a generic class for spawning processes and
    watch them. It supports progression and child return value reporting.
    DeleteOperation now is a subclass of it, and then is sligthly simplified.
---
 gsecuredelete/Makefile.am           |   3 +-
 gsecuredelete/async-operation.vala  | 264 ++++++++++++++++++++++++++++++++++++
 gsecuredelete/delete-operation.vala | 220 +++++-------------------------
 gsecuredelete/main.vala             |   2 +-
 4 files changed, 298 insertions(+), 191 deletions(-)

diff --git a/gsecuredelete/Makefile.am b/gsecuredelete/Makefile.am
index 151c3a1..d053a69 100644
--- a/gsecuredelete/Makefile.am
+++ b/gsecuredelete/Makefile.am
@@ -8,7 +8,8 @@ AM_LDFLAGS   = $(LIBGSECUREDELETE_LIBS)
 libgsecuredelete_la_includedir=$(includedir)/gsecuredelete
 
 libgsecuredelete_la_VALAFLAGS = $(AM_VALAFLAGS) --library=libgsecuredelete -H libgsecuredelete.h
-libgsecuredelete_la_SOURCES = delete-operation.vala \
+libgsecuredelete_la_SOURCES = async-operation.vala \
+                              delete-operation.vala \
                               fill-operation.vala \
                               utils.vala
 libgsecuredelete_la_include_HEADERS = libgsecuredelete.h \
diff --git a/gsecuredelete/async-operation.vala b/gsecuredelete/async-operation.vala
new file mode 100644
index 0000000..d2d6920
--- /dev/null
+++ b/gsecuredelete/async-operation.vala
@@ -0,0 +1,264 @@
+
+using GLib;
+
+namespace SecureDelete
+{
+  public errordomain AsyncOperationError {
+    ARGS_ERROR,
+    CHILD_FAILED
+  }
+  
+  /** AsyncOperation:
+   * 
+   * An asynchronous process spawner, with support for progression and succes
+   * report.
+   * This is a base class designed to be subclassed by actual spawners, with
+   * less efforts as possible.
+   * 
+   * To subclass this class, the only thing you need to implement is the
+   * argument builder, that gives the command to be spawned, and its arguments.
+   * This said, you may want to override get_max_progress() and get_progress()
+   * to add actual progress support; build_environ() to provide a specific
+   * environment to your command.
+   * 
+   * @n_passes: the maximum number of progress steps.
+   * @passes:   the current progress step
+   * @pid:      the subprocess PID
+   * @fd_in:    the subprocess' standard input
+   * @fd_out:   the subprocess' standard output
+   * @fd_err:   the subprocess' error output
+   */
+  /* TODO: implement the synchronous opreration */
+  public abstract class AsyncOperation : Object
+  {
+    /* fields for async operation */
+    protected uint  n_passes;
+    protected uint  passes;
+    protected Pid   pid;
+    protected int   fd_in;
+    protected int   fd_out;
+    protected int   fd_err;
+    
+    /* signals */
+    public signal void finished (bool     success,
+                                 string?  message);
+    public signal void progress (double   fraction);
+    
+    /* properties */
+    /* whether the operation object is busy */
+    public bool busy {
+      public    get;
+      protected set;
+      default = false;
+    }
+    
+    /* builds the command's arguments (argv) */
+    private abstract string?[] build_args ()
+      throws AsyncOperationError;
+    
+    /* builds the command's environment */
+    private virtual string?[]? build_environ ()
+    {
+      return null;
+    }
+    
+    /* returns the value at which the progress is full. When the progress reach
+     * this value, it will be considered to be at 100% (even if it has no impact
+     * other than reporting the current progress)
+     */
+    private virtual uint get_max_progress ()
+    {
+      return 0;
+    }
+    
+    /* gets the additional progress status of the child process.
+     * This function gets called from time to time to get the new additional
+     * progress of the operation, since last call.
+     */
+    private virtual uint get_progress ()
+    {
+      return 0;
+    }
+    
+    /* updates the progress status and emit DeleteOperation::progress if
+     * changed */
+    private void update_progress ()
+    {
+      uint progress = this.get_progress ();
+      if (progress > 0) {
+        this.passes += progress;
+        this.progress (this.passes / (this.n_passes * 1.0));
+      }
+    }
+    
+    /* checks if the child finished, and disatches related things.
+     * 
+     * It is meant to be called as a timeout function.
+     */
+    private bool do_wait_child ()
+    {
+      bool        finished = true;
+      bool        success  = false;
+      int         exit_status;
+      Posix.pid_t wait_rv;
+      string?     message  = null;
+      
+      /* FIXME: 1 = WNOHANG, buf WNOHANG doesn't seems to be accessible from
+       * Vala */
+      wait_rv = Posix.waitpid ((Posix.pid_t)this.pid, out exit_status, 1);
+      if ((int)wait_rv < 0) {
+        critical ("waitpid() failed: %s", strerror (errno));
+        /* if we cannot watch the child, try to kill it */
+        if (Posix.kill ((Posix.pid_t)this.pid, 15) < 0) {
+          critical ("kill() failed: %s", strerror (errno));
+        }
+      } else if ((int)wait_rv == 0) {
+        /* nothing to do, just wait until next call */
+        this.update_progress ();
+        finished = false;
+      } else {
+        /* FIXME: the error output read may not block if empty? */
+        if (! Process.if_exited (exit_status)) {
+          message = "Subprocess crashed: " + FD.read_string (this.fd_err);
+        } else if (Process.exit_status (exit_status) != 0) {
+          /* get errors reported by the child */
+          message = "Subprocess failed: " + FD.read_string (this.fd_err);
+        } else {
+          success = true;
+        }
+      }
+      
+      if (finished) {
+        this.finished (success, message);
+        
+        Process.close_pid (this.pid);
+        Posix.close (this.fd_err);
+        Posix.close (this.fd_out);
+        Posix.close (this.fd_in);
+        /*lock (this.busy)*/ {
+          this.busy = false;
+        }
+      }
+      
+      return ! finished;
+    }
+    
+    /** run:
+     * @working_directory: the working directory of the child process, or null
+     *                     to use the parent's one.
+     * @spawn_flags: %SpawnFlags. You may only use the SEARCH_PATH and
+     *               CHILD_INHERITS_STDIN flags, others may conflict.
+     * @watch_interval: time (in milliseconds) between two check for subprocess
+     *                  status. A too short value may use too much CPU and a too
+     *                  big may be less responsive.
+     * 
+     * Launches an operation asynchronously.
+     * 
+     * Returns: whether asynchronous operation was successfully started.
+     */
+    public bool run (string?    working_directory = null,
+                     SpawnFlags spawn_flags = 0,
+                     uint       watch_interval = 100)
+      throws SpawnError, AsyncOperationError
+      requires (! this.busy)
+    {
+      bool      success = true;
+      string?[] args;
+      
+      /*lock (this.busy)*/ {
+        this.busy = true;
+      }
+      try {
+        args = this.build_args ();
+      } catch (AsyncOperationError e) {
+        throw e;
+      }
+      this.fd_err = -1;
+      this.fd_out = -1;
+      this.n_passes = this.get_max_progress ();
+      this.passes = 0;
+      try {
+        Process.spawn_async_with_pipes (working_directory,
+                                        args, this.build_environ (),
+                                        spawn_flags | SpawnFlags.DO_NOT_REAP_CHILD,
+                                        null,
+                                        out this.pid, out this.fd_in,
+                                        out this.fd_out, out this.fd_err);
+      } catch (SpawnError e) {
+        success = false;
+        throw e;
+      }
+      if (success) {
+        Timeout.add (watch_interval, this.do_wait_child);
+      }
+      
+      return success;
+    }
+    
+    /** run_sync:
+     * @working_directory: the working directory of the child process, or null
+     *                     to use the parent's one.
+     * spawn_flags: %SpawnFlags. You may only use the SEARCH_PATH and
+     *               CHILD_INHERITS_STDIN flags, others may conflict.
+     * @standard_output: return location for the subprocess' standard output,
+     *                   or null to ignore it.
+     * 
+     * Launches an operation synchronously.
+     * 
+     * Returns: %true if all worked properly, and %false if something failed.
+     *          An error is thrown if something fails. It can be the subprocess
+     *          spawning (SpawnError) or the child that failed
+     *          (AsyncOperationError.CHILD_FAILED) or the generation of
+     *          arguments that failed (AsyncOperationError.ARGS_ERROR).
+     */
+    public bool run_sync (string?    working_directory = null,
+                          SpawnFlags spawn_flags = 0,
+                          out string standard_output)
+      throws SpawnError, AsyncOperationError
+      requires (! this.busy)
+    {
+      bool      success = true;
+      string    error_output;
+      int       exit_status;
+      string?[] args;
+      
+      /*lock (this.busy)*/ {
+        this.busy = true;
+      }
+      try {
+        args = this.build_args ();
+      } catch (AsyncOperationError e) {
+        throw e;
+      }
+      try {
+        Process.spawn_sync (working_directory, args, this.build_environ (),
+                            spawn_flags, null,
+                            out standard_output, out error_output, out exit_status);
+      } catch (SpawnError e) {
+        success = false;
+        throw e;
+      }
+      if (success) {
+        string? message = null;
+        
+        success = false;
+        if (! Process.if_exited (exit_status)) {
+          message = "Subprocess crashed: " + error_output;
+        } else if (Process.exit_status (exit_status) != 0) {
+          message = "Subprocess failed: " + error_output;
+        } else {
+          success = true;
+        }
+        this.finished (success, message);
+        if (message != null) {
+          throw new AsyncOperationError.CHILD_FAILED ("%s", message);
+        }
+      }
+      /*lock (this.busy)*/ {
+        this.busy = false;
+      }
+      
+      return success;
+    }
+  }
+}
diff --git a/gsecuredelete/delete-operation.vala b/gsecuredelete/delete-operation.vala
index 24147d1..e51db51 100644
--- a/gsecuredelete/delete-operation.vala
+++ b/gsecuredelete/delete-operation.vala
@@ -3,33 +3,12 @@ using GLib;
 
 namespace SecureDelete
 {
-  public errordomain DeleteOperationError {
-    CHILD_FAILED,
-    NO_FILES
-  }
-  
-  public class DeleteOperation : Object
+  public class DeleteOperation : AsyncOperation
   {
     private List<string>  pathes;
-    /* fields for async deletion */
-    private size_t        n_passes;
-    private size_t        passes;
-    private Pid           pid;
-    private int           fd_out;
-    private int           fd_err;
-    
-    /* signals */
-    public signal void finished (bool     success,
-                                 string?  message);
-    public signal void progress (double   fraction);
+    private uint          n_files = 0;
     
     /* properties */
-    /* whether the operation object is busy */
-    public bool busy {
-      public get;
-      private set;
-      default = false;
-    }
     /* whether to use fast and insecure mode */
     public bool fast {
       get; set; default = false;
@@ -60,10 +39,9 @@ namespace SecureDelete
     }
     
     /* builds the command's arguments (argv) */
-    private string?[] build_args (out size_t n_files)
-      throws DeleteOperationError
+    private override string?[] build_args ()
+      throws AsyncOperationError
     {
-      size_t n = 0;
       string?[] args = {
         "srm",
         "-rv"
@@ -72,26 +50,35 @@ namespace SecureDelete
       if (this.fast) {
         args += "-f";
       }
+      this.n_files = 0;
       foreach (string path in this.pathes) {
         args += path;
-        n++;
+        this.n_files++;
       }
       args += null;
       
-      n_files = n;
-      if (n == 0) {
-        throw new DeleteOperationError.NO_FILES ("Nothing to remove");
+      if (this.n_files == 0) {
+        throw new AsyncOperationError.ARGS_ERROR ("Nothing to remove");
       }
       
       return args;
     }
     
+    private override uint get_max_progress ()
+    {
+      /* FIXME: 38 is the standard SRM pass number, but may change with options
+       * like -l. If we support it one day, we need to fix this value (by
+       * getting the one SRM reports) in order to get a meaningful progress
+       * information */
+      return 38 * this.n_files;
+    }
+    
     /* gets the progress status of the child process */
-    private uint get_progress (int    fd,
-                               size_t bufisze = 16)
-      throws FDError
+    private override uint get_progress ()
     {
-      uint progress = 0;
+      int     fd = this.fd_out;
+      size_t  bufisze = 16;
+      uint    progress = 0;
       
       try {
         if (FD.read_ready (fd)) {
@@ -111,179 +98,34 @@ namespace SecureDelete
           } while (read_rv == bufisze);
         }
       } catch (FDError e) {
-        throw e;
-      }
-      
-      return progress;
-    }
-    
-    /* updates the progress status and emit DeleteOperation::progress if
-     * changed */
-    private void update_progress ()
-    {
-      uint progress = 0;
-      
-      try {
-        progress = this.get_progress (this.fd_out);
-      } catch (FDError e) {
         warning ("Progression check failed: %s", e.message);
       }
-      if (progress > 0) {
-        this.passes += progress;
-        this.progress (this.passes / (this.n_passes * 1.0));
-      }
-    }
-    
-    /* checks if the chils finished, and disatches related things.
-     * 
-     * It is meant to be called as a timeout function.
-     */
-    private bool do_wait_child ()
-    {
-      bool        finished = true;
-      bool        success  = false;
-      int         exit_status;
-      Posix.pid_t wait_rv;
-      string?     message  = null;
-      
-      /* FIXME: 1 = WNOHANG, buf WNOHANG doesn't seems to be accessible from
-       * Vala */
-      wait_rv = Posix.waitpid ((Posix.pid_t)this.pid, out exit_status, 1);
-      if ((int)wait_rv < 0) {
-        critical ("waitpid() failed: %s", strerror (errno));
-        /* if we cannot watch the child, try to kill it */
-        if (Posix.kill ((Posix.pid_t)this.pid, 15) < 0) {
-          critical ("kill() failed: %s", strerror (errno));
-        }
-      } else if ((int)wait_rv == 0) {
-        /* nothing to do, just wait until next call */
-        this.update_progress ();
-        finished = false;
-      } else {
-        if (! Process.if_exited (exit_status)) {
-          message = "Subprocess crashed";
-        } else if (Process.exit_status (exit_status) != 0) {
-          /* get errors reported by the child */
-          message = FD.read_string (this.fd_err);
-        } else {
-          success = true;
-        }
-      }
       
-      if (finished) {
-        this.finished (success, message);
-        
-        Process.close_pid (this.pid);
-        Posix.close (this.fd_err);
-        Posix.close (this.fd_out);
-        /*lock (this.busy)*/ {
-          this.busy = false;
-        }
-      }
-      
-      return ! finished;
+      return progress;
     }
     
-    /** delete_async:
-     * @watch_interval: time (in milliseconds) between two check for subprocess
-     *                  status. A too short value may use too much CPU and a too
-     *                  big may be less responsive.
-     * 
+    /** run_sync:
      * Launches a secure deletion asynchronously.
      * 
-     * Returns: whether asynchronous deletion was successfully started.
+     * Returns: whether subprocess started successfully.
      */
-    public bool delete_async (uint watch_interval = 100)
-      throws SpawnError, DeleteOperationError
+    public new bool run (uint watch_interval = 100)
+      throws SpawnError, AsyncOperationError
       requires (! this.busy)
     {
-      bool      success = true;
-      string?[] args;
-      size_t    n_files;
-      
-      /*lock (this.busy)*/ {
-        this.busy = true;
-      }
-      try {
-        args = this.build_args (out n_files);
-      } catch (DeleteOperationError e) {
-        throw e;
-      }
-      this.fd_err = -1;
-      this.fd_out = -1;
-      /* FIXME: 38 is the standard SRM pass number, but may change with options
-       * like -l. If we support it one day, we need to fix this value (by
-       * getting the one SRM reports) in order to get a meaningful progress
-       * information */
-      this.n_passes = 38 * n_files;
-      this.passes = 0;
-      try {
-        Process.spawn_async_with_pipes (null, args, null,
-                                        SpawnFlags.SEARCH_PATH | SpawnFlags.DO_NOT_REAP_CHILD,
-                                        null,
-                                        out this.pid,
-                                        null, out this.fd_out, out this.fd_err);
-      } catch (SpawnError e) {
-        success = false;
-        throw e;
-      }
-      if (success) {
-        Timeout.add (watch_interval, this.do_wait_child);
-      }
-      
-      return success;
+      return base.run (null, SpawnFlags.SEARCH_PATH, watch_interval);
     }
     
-    /** delete_sync:
+    /** run_sync:
      * Launches a secure deletion synchronously.
      * 
      * Returns: whether deletion was successful.
      */
-    public bool delete_sync ()
-      throws SpawnError, DeleteOperationError
+    public new bool run_sync ()
+      throws SpawnError, AsyncOperationError
       requires (! this.busy)
     {
-      bool      success = true;
-      string    error_output;
-      int       exit_status;
-      string?[] args;
-      
-      /*lock (this.busy)*/ {
-        this.busy = true;
-      }
-      try {
-        /* FIXME: how to make an out parameter optional? */
-        size_t n_files;
-        
-        args = this.build_args (out n_files);
-      } catch (DeleteOperationError e) {
-        throw e;
-      }
-      try {
-        Process.spawn_sync (null, args, null,
-                            SpawnFlags.SEARCH_PATH, null,
-                            null, out error_output, out exit_status);
-      } catch (SpawnError e) {
-        success = false;
-        throw e;
-      }
-      if (success) {
-        string? message = null;
-        
-        if (! Process.if_exited (exit_status) ||
-              Process.exit_status (exit_status) != 0) {
-          message = error_output;
-        }
-        this.finished (success, message);
-        if (message != null) {
-          throw new DeleteOperationError.CHILD_FAILED ("%s", message);
-        }
-      }
-      /*lock (this.busy)*/ {
-        this.busy = false;
-      }
-      
-      return success;
+      return base.run_sync (null, SpawnFlags.SEARCH_PATH, null);
     }
   }
 }
diff --git a/gsecuredelete/main.vala b/gsecuredelete/main.vala
index 484fb2e..2e227b6 100644
--- a/gsecuredelete/main.vala
+++ b/gsecuredelete/main.vala
@@ -49,7 +49,7 @@ public class Test
         op.add_path (arg);
     }
     try {
-      op.delete_async ();
+      op.run ();
       
       this.main_loop = new MainLoop (null, false);
       main_loop.run ();

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-privacy/packages/libgsecuredelete.git



More information about the Pkg-privacy-commits mailing list