[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