[deja-dup/f18] tmp on tmpfs patch. resolves rhbz#892063
Rahul Sundaram
sundaram at fedoraproject.org
Tue Mar 19 04:17:41 UTC 2013
commit e6c80c3c543df8c07c233a8135861e7d4fb584b7
Author: Rahul Sundaram <sundaram at fedoraproject.org>
Date: Tue Mar 19 00:17:26 2013 -0400
tmp on tmpfs patch. resolves rhbz#892063
deja-dup.spec | 9 +-
duplicity-tempdir.patch | 509 +++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 516 insertions(+), 2 deletions(-)
---
diff --git a/deja-dup.spec b/deja-dup.spec
index 335e688..42e1eb3 100644
--- a/deja-dup.spec
+++ b/deja-dup.spec
@@ -1,12 +1,13 @@
Name: deja-dup
Version: 24.0
-Release: 1%{?dist}
+Release: 2%{?dist}
Summary: Simple backup tool and frontend for duplicity
Group: Applications/Archiving
License: GPLv3+
URL: https://launchpad.net/deja-dup
Source0: http://launchpad.net/%{name}/24/%{version}/+download/%{name}-%{version}.tar.xz
+Patch0: duplicity-tempdir.patch
BuildRequires: gettext desktop-file-utils intltool scrollkeeper
BuildRequires: yelp-tools pango-devel cairo-devel vala-devel
@@ -33,13 +34,14 @@ Features:
%prep
%setup -q
+%patch0 -b .tempdir
%build
%configure --disable-static --with-nautilus --with-gnu-ld
make %{?_smp_mflags}
%install
-make install DESTDIR=%{buildroot}
+%make_install
rm -f %{buildroot}/%{_libdir}/deja-dup/*.la
rm -f %{buildroot}/%{_libdir}/nautilus/extensions-3.0/*.la
@@ -85,6 +87,9 @@ glib-compile-schemas %{_datadir}/glib-2.0/schemas &> /dev/null || :
%{_datadir}/icons/hicolor/scalable/devices/deja-dup-cloud.svg
%changelog
+* Mon Mar 18 2013 Rahul Sundaram <sundaram at fedoraproject.org> - 24.0-2
+- tmp on tmpfs patch. resolves rhbz#892063
+
* Wed Sep 26 2012 Matthias Clasen <mclasen at redhat.com> - 24.0-1
- Update to 24.0
diff --git a/duplicity-tempdir.patch b/duplicity-tempdir.patch
new file mode 100644
index 0000000..773d968
--- /dev/null
+++ b/duplicity-tempdir.patch
@@ -0,0 +1,509 @@
+--- common/CommonUtils.vala 2012-08-20 01:16:15 +0000
++++ common/CommonUtils.vala 2013-03-17 23:50:06 +0000
+@@ -444,6 +444,9 @@
+ var unused_backend = DejaDup.Backend.get_default();
+ unused_backend = null;
+
++ // And cleanup from any previous runs
++ clean_tempdirs.begin();
++
+ return true;
+ }
+
+@@ -582,5 +585,127 @@
+ return date;
+ }
+
++public bool ensure_directory_exists(string path)
++{
++ var gfile = File.new_for_path(path);
++ try {
++ if (gfile.make_directory_with_parents())
++ return true;
++ }
++ catch (IOError.EXISTS e) {
++ return true; // ignore
++ }
++ catch (Error e) {
++ warning("%s\n", e.message);
++ }
++ return false;
++}
++
++// By default, duplicity uses normal tmp folders like /tmp to store its
++// in-process files. These can get quite large, especially when restoring.
++// You may need up to twice the size of the largest source file.
++// Because /tmp may not be super large, especially on systems that use
++// tmpfs by default (e.g. Fedora 18), we try to use a tempdir that is on
++// the same partition as the source files.
++public async string get_tempdir()
++{
++ var tempdirs = get_tempdirs();
++
++ // First, decide the "main include". Assume that if $HOME
++ // is present, that is it. Else, the first include we find decides it.
++ // This is admittedly fast and loose, but our primary concern is just
++ // avoiding silly choices like tmpfs or tiny special /tmp partitions.
++ var settings = get_settings();
++ var include_val = settings.get_value(INCLUDE_LIST_KEY);
++ var include_list = parse_dir_list(include_val.get_strv());
++ File main_include = null;
++ var home = File.new_for_path(Environment.get_home_dir());
++ foreach (var include in include_list) {
++ if (include.equal(home)) {
++ main_include = include;
++ break;
++ }
++ else if (main_include == null)
++ main_include = include;
++ }
++ if (main_include == null)
++ return tempdirs[0];
++
++ // Grab that include's fs ID
++ string filesystem_id;
++ try {
++ var info = yield main_include.query_info_async(FileAttribute.ID_FILESYSTEM,
++ FileQueryInfoFlags.NONE);
++ filesystem_id = info.get_attribute_string(FileAttribute.ID_FILESYSTEM);
++ }
++ catch (Error e) {
++ return tempdirs[0];
++ }
++
++ // Then, see which of our possible tempdirs matches that partition.
++ foreach (var tempdir in tempdirs) {
++ string temp_id;
++ ensure_directory_exists(tempdir);
++ try {
++ var gfile = File.new_for_path(tempdir);
++ var info = yield gfile.query_info_async(FileAttribute.ID_FILESYSTEM,
++ FileQueryInfoFlags.NONE);
++ temp_id = info.get_attribute_string(FileAttribute.ID_FILESYSTEM);
++ }
++ catch (Error e) {
++ continue;
++ }
++ if (temp_id == filesystem_id)
++ return tempdir;
++ }
++
++ // Fallback to simply using the highest preferred tempdir
++ return tempdirs[0];
++}
++
++public string[] get_tempdirs()
++{
++ var tempdir = Environment.get_variable("DEJA_DUP_TEMPDIR");
++ if (tempdir != null && tempdir != "")
++ return {tempdir};
++ // Prefer directories that have their own cleanup logic in case ours isn't
++ // run for a while. (e.g. /tmp every boot, /var/tmp every now and then)
++ return {Environment.get_tmp_dir(), "/var/tmp",
++ Path.build_filename(Environment.get_user_cache_dir(), Config.PACKAGE,
++ "tmp")};
++}
++
++public async void clean_tempdirs()
++{
++ var tempdirs = get_tempdirs();
++ const int NUM_ENUMERATED = 16;
++ foreach (var tempdir in tempdirs) {
++ var gfile = File.new_for_path(tempdir);
++
++ // Now try to find and delete all files that start with "duplicity-"
++ try {
++ var enumerator = yield gfile.enumerate_children_async(
++ FileAttribute.STANDARD_NAME,
++ FileQueryInfoFlags.NOFOLLOW_SYMLINKS,
++ Priority.DEFAULT, null);
++ while (true) {
++ var infos = yield enumerator.next_files_async(NUM_ENUMERATED,
++ Priority.DEFAULT, null);
++ foreach (FileInfo info in infos) {
++ if (info.get_name().has_prefix("duplicity-")) {
++ var child = gfile.get_child(info.get_name());
++ yield new DejaDup.RecursiveDelete(child).start_async();
++ }
++ }
++ if (infos.length() != NUM_ENUMERATED)
++ break;
++ }
++ }
++ catch (Error e) {
++ // No worries
++ }
++ }
++}
++
+ } // end namespace
+
+--- common/Operation.vala 2012-08-20 01:16:15 +0000
++++ common/Operation.vala 2013-03-17 23:50:06 +0000
+@@ -223,6 +223,7 @@
+ finished = true;
+
+ unclaim_bus();
++ yield DejaDup.clean_tempdirs();
+
+ done(success, cancelled, detail);
+ }
+--- common/OperationBackup.vala 2012-08-13 19:59:00 +0000
++++ common/OperationBackup.vala 2013-03-17 23:50:06 +0000
+@@ -116,11 +116,11 @@
+ rv.append(Path.build_filename(dir, ".xsession-errors"));
+ }
+
+- // Some problematic directories like /tmp and /proc should be left alone
+- dir = Environment.get_tmp_dir();
+- if (dir != null)
+- rv.append(dir);
+-
++ // Skip all of our temporary directories
++ foreach (var tempdir in DejaDup.get_tempdirs())
++ rv.append(tempdir);
++
++ // Skip kernel directories
+ rv.append("/proc");
+ rv.append("/sys");
+
+--- tests/runner/runner.vala 2012-08-21 01:29:56 +0000
++++ tests/runner/runner.vala 2013-03-18 00:15:03 +0000
+@@ -51,7 +51,14 @@
+ Environment.set_variable("DEJA_DUP_TOOLS_PATH", "../../tools/duplicity", true);
+ Environment.set_variable("DEJA_DUP_TEST_MOCKSCRIPT", Path.build_filename(dir, "mockscript"), true);
+ Environment.set_variable("XDG_CACHE_HOME", cachedir, true);
+- Environment.set_variable("PATH", "./mock:" + Environment.get_variable("PATH"), true);
++ Environment.set_variable("PATH",
++ "./mock:" +
++ Environment.get_variable("DEJA_DUP_TEST_PATH"),
++ true);
++
++ var tempdir = Path.build_filename(dir, "tmp");
++ DejaDup.ensure_directory_exists(tempdir);
++ Environment.set_variable("DEJA_DUP_TEMPDIR", tempdir, true);
+
+ var settings = DejaDup.get_settings();
+ settings.set_string(DejaDup.BACKEND_KEY, "file");
+@@ -61,11 +68,9 @@
+
+ void backup_teardown()
+ {
+- var path = Environment.get_variable("PATH");
+- if (path.has_prefix("./mock:")) {
+- path = path.substring(7);
+- Environment.set_variable("PATH", path, true);
+- }
++ Environment.set_variable("PATH",
++ Environment.get_variable("DEJA_DUP_TEST_PATH"),
++ true);
+
+ var file = File.new_for_path(Environment.get_variable("DEJA_DUP_TEST_MOCKSCRIPT"));
+ if (file.query_exists(null)) {
+@@ -112,14 +117,22 @@
+
+ var archive = tmp_archive ? "?" : "%s/deja-dup".printf(cachedir);
+
++ string enc_str = "";
++ if (!encrypted)
++ enc_str = "--no-encryption ";
++
++ var tempdir = Path.build_filename(test_home, "tmp");
++
++ var end_str = "%s'--verbosity=9' '--gpg-options=--no-use-agent' '--archive-dir=%s' '--tempdir=%s' '--log-fd=?'".printf(enc_str, archive, tempdir);
++
+ if (mode == Mode.CLEANUP)
+- return "cleanup '--force' 'file://%s' '--gio' %s'--verbosity=9' '--gpg-options=--no-use-agent' '--archive-dir=%s' '--log-fd=?'".printf(backupdir, encrypted ? "" : "'--no-encryption' ", archive);
++ return "cleanup '--force' 'file://%s' '--gio' %s".printf(backupdir, end_str);
+ else if (mode == Mode.RESTORE)
+- return "'restore' '--gio' '--force' 'file://%s' '%s' %s'--verbosity=9' '--gpg-options=--no-use-agent' '--archive-dir=%s' '--log-fd=?'".printf(backupdir, restoredir, encrypted ? "" : "'--no-encryption' ", archive);
++ return "'restore' '--gio' '--force' 'file://%s' '%s' %s".printf(backupdir, restoredir, end_str);
+ else if (mode == Mode.VERIFY)
+- return "'restore' '--file-to-restore=%s/deja-dup/metadata' '--gio' '--force' 'file://%s' '%s/deja-dup/metadata' %s'--verbosity=9' '--gpg-options=--no-use-agent' '--archive-dir=%s' '--log-fd=?'".printf(cachedir.substring(1), backupdir, cachedir, encrypted ? "" : "'--no-encryption' ", archive);
++ return "'restore' '--file-to-restore=%s/deja-dup/metadata' '--gio' '--force' 'file://%s' '%s/deja-dup/metadata' %s".printf(cachedir.substring(1), backupdir, cachedir, end_str);
+ else if (mode == Mode.LIST)
+- return "'list-current-files' '--gio' 'file://%s' %s'--verbosity=9' '--gpg-options=--no-use-agent' '--archive-dir=%s' '--log-fd=?'".printf(backupdir, encrypted ? "" : "'--no-encryption' ", archive);
++ return "'list-current-files' '--gio' 'file://%s' %s".printf(backupdir, end_str);
+
+ string source_str = "";
+ if (mode == Mode.DRY || mode == Mode.BACKUP)
+@@ -129,10 +142,6 @@
+ if (mode == Mode.DRY)
+ dry_str = "--dry-run ";
+
+- string enc_str = "";
+- if (!encrypted)
+- enc_str = "--no-encryption ";
+-
+ string args = "";
+
+ if (br.is_full && !br.is_first && (mode == Mode.BACKUP || mode == Mode.DRY))
+@@ -147,7 +156,7 @@
+ string[] excludes1 = {"~/Downloads", "~/.local/share/Trash", "~/.xsession-errors", "~/.thumbnails", "~/.Private", "~/.gvfs", "~/.adobe/Flash_Player/AssetCache"};
+
+ var user = Environment.get_user_name();
+- string[] excludes2 = {"/home/.ecryptfs/%s/.Private".printf(user), "/sys", "/proc", "/tmp"};
++ string[] excludes2 = {"/home/.ecryptfs/%s/.Private".printf(user), "/sys", "/proc", tempdir};
+
+ foreach (string ex in excludes1) {
+ ex = ex.replace("~", Environment.get_home_dir());
+@@ -166,7 +175,7 @@
+ args += "'--exclude=%s/deja-dup' '--exclude=%s' '--exclude=**' ".printf(cachedir, cachedir);
+ }
+
+- args += "%s%s'--gio' %s'file://%s' %s'--verbosity=9' '--gpg-options=--no-use-agent' '--archive-dir=%s' '--log-fd=?'".printf(extra, dry_str, source_str, backupdir, enc_str, archive);
++ args += "%s%s'--gio' %s'file://%s' %s".printf(extra, dry_str, source_str, backupdir, end_str);
+
+ return args;
+ }
+@@ -175,6 +184,8 @@
+ {
+ public delegate void OpCallback (DejaDup.Operation op);
+ public DejaDup.Operation op = null;
++ public string path = null;
++ public string script = null;
+ public string? init_error = null;
+ public bool success = true;
+ public bool cancelled = false;
+@@ -188,6 +199,12 @@
+
+ public void run()
+ {
++ if (script != null)
++ run_script(script);
++
++ if (path != null)
++ Environment.set_variable("PATH", path, true);
++
+ string header, msg;
+ if (!DejaDup.initialize(out header, out msg)) {
+ if (header + "\n" + msg != init_error)
+@@ -298,9 +315,13 @@
+ string replace_keywords(string in)
+ {
+ var home = Environment.get_home_dir();
++ var mockdir = "./mock";
+ var cachedir = Environment.get_variable("XDG_CACHE_HOME");
+ var test_home = Environment.get_variable("DEJA_DUP_TEST_HOME");
++ var path = Environment.get_variable("PATH");
+ return in.replace("@HOME@", home).
++ replace("@MOCK_DIR@", mockdir).
++ replace("@PATH@", path).
+ replace("@XDG_CACHE_HOME@", cachedir).
+ replace("@TEST_HOME@", test_home);
+ }
+@@ -351,6 +372,10 @@
+ br.error_detail = keyfile.get_string(group, "ErrorDetail");
+ if (keyfile.has_key(group, "Passphrases"))
+ br.passphrases = keyfile.get_integer(group, "Passphrases");
++ if (keyfile.has_key(group, "Path"))
++ br.path = replace_keywords(keyfile.get_string(group, "Path"));
++ if (keyfile.has_key(group, "Script"))
++ br.script = replace_keywords(keyfile.get_string(group, "Script"));
+ if (keyfile.has_key(group, "Settings")) {
+ var settings_list = keyfile.get_string_list(group, "Settings");
+ var settings = DejaDup.get_settings();
+@@ -449,10 +474,15 @@
+ };
+ }
+
+- if (script != null)
+- dupscript += "\n" + "SCRIPT: " + script;
+- else if (mode == Mode.VERIFY)
+- dupscript += "\n" + "SCRIPT: mkdir -p %s/deja-dup/metadata; echo 'This folder can be safely deleted.\\n0' > %s/deja-dup/metadata/README".printf(cachedir, cachedir);
++ var verify_script = "mkdir -p %s/deja-dup/metadata && echo 'This folder can be safely deleted.\\n0' > %s/deja-dup/metadata/README".printf(cachedir, cachedir);
++ if (mode == Mode.VERIFY)
++ dupscript += "\n" + "SCRIPT: " + verify_script;
++ if (script != null) {
++ if (mode == Mode.VERIFY)
++ dupscript += " && " + script;
++ else
++ dupscript += "\n" + "SCRIPT: " + script;
++ }
+
+ if (passphrase)
+ dupscript += "\n" + "PASSPHRASE: test";
+@@ -523,6 +553,10 @@
+ script = args[1];
+ Environment.set_variable("DEJA_DUP_TEST_SCRIPT", script, true);
+
++ // Save PATH, as tests might reset it on us
++ Environment.set_variable("DEJA_DUP_TEST_PATH",
++ Environment.get_variable("PATH"), true);
++
+ var parts = script.split("/");
+ var suitename = parts[parts.length - 2];
+ var testname = parts[parts.length - 1].split(".")[0];
+--- tests/scripts/clean-tempdir.test 1970-01-01 00:00:00 +0000
++++ tests/scripts/clean-tempdir.test 2013-03-17 23:50:25 +0000
+@@ -0,0 +1,12 @@
++# Make sure we clean up the tempdir that we give to duplicity after we're done
++
++[Operation]
++Type=backup
++Script=mkdir -p @TEST_HOME@/tmp/duplicity-blarg @TEST_HOME@/tmp/nope
++
++[Duplicity]
++Runs=status;dry;backup;status-restore;list;verify;
++
++# Check at end of everything that we cleared the temp files
++[Duplicity verify]
++Script=test ! -e @TEST_HOME@/tmp/duplicity-blarg -a -d @TEST_HOME@/tmp/nope
+--- tests/scripts/instance-error.test 1970-01-01 00:00:00 +0000
++++ tests/scripts/instance-error.test 2013-03-18 00:21:57 +0000
+@@ -0,0 +1,21 @@
++# Make sure we correctly bubble up an error message from
++# DuplicityInstance.start(). In this case, an error about spawning duplicity.
++
++[Operation]
++Type=backup
++# Delete mockscript ourselves, because the runner will notice that it is still
++# there and fail. Since we never run our mock duplicity, it is never cleaned
++# naturally. Also symlink python since the mock duplicity needs it
++Script=mkdir -p @TEST_HOME@/mockcopy && cp -r @MOCK_DIR@/* @TEST_HOME@/mockcopy && ln -s `which python` @TEST_HOME@/mockcopy/python
++Path=@TEST_HOME@/mockcopy
++Success=false
++Error=Failed to execute child process "duplicity" (No such file or directory)
++
++[Duplicity]
++Runs=status;dry;
++
++[Duplicity status]
++# We let duplicity go for one operation to let it get initialized (i.e. we
++# don't want to mess up any of its early calls like --version).
++# Also clean the mockscript out since our mock won't be doing it.
++Script=/bin/rm @TEST_HOME@/mockcopy/duplicity @TEST_HOME@/mockscript
+--- tests/scripts/verify.test 2012-08-10 18:33:29 +0000
++++ tests/scripts/verify.test 2013-03-17 23:50:25 +0000
+@@ -7,4 +7,4 @@
+ Runs=status;dry;backup;status-restore;list;verify;
+
+ [Duplicity verify]
+-Script=mkdir -p @XDG_CACHE_HOME@/deja-dup/metadata; echo 'Nope' > @XDG_CACHE_HOME@/deja-dup/metadata/README
++Script=echo 'Nope' > @XDG_CACHE_HOME@/deja-dup/metadata/README
+--- tools/duplicity/DuplicityInstance.vala 2012-08-20 01:16:15 +0000
++++ tools/duplicity/DuplicityInstance.vala 2013-03-17 23:50:25 +0000
+@@ -29,8 +29,30 @@
+ public bool verbose {get; private set; default = false;}
+ public string forced_cache_dir {get; set; default = null;}
+
+- public virtual void start(List<string> argv_in, List<string>? envp_in,
+- bool as_root = false) throws Error
++ public async void start(List<string> argv_in, List<string>? envp_in,
++ bool as_root = false)
++ {
++ try {
++ /* Make deep copies of the lists, so if our caller doesn't yield, the
++ lists won't be invalidated. */
++ var argv = new List<string>();
++ foreach (var arg in argv_in)
++ argv.append(arg);
++ var envp = new List<string>();
++ foreach (var env in envp_in)
++ envp.append(env);
++ if (!yield start_internal(argv, envp, as_root))
++ done(false, false);
++ }
++ catch (Error e) {
++ // Fake a generic message from duplicity
++ message({"ERROR", "1"}, null, e.message);
++ done(false, false);
++ }
++ }
++
++ async bool start_internal(List<string> argv_in, List<string>? envp_in,
++ bool as_root) throws Error
+ {
+ var verbose_str = Environment.get_variable("DEJA_DUP_DEBUG");
+ if (verbose_str != null && int.parse(verbose_str) > 0)
+@@ -76,46 +98,29 @@
+ if (cache_dir == null)
+ cache_dir = Environment.get_user_cache_dir();
+ if (cache_dir != null) {
+- bool add_dir = false;
+- var cache_file = File.new_for_path(cache_dir);
+- cache_file = cache_file.get_child(Config.PACKAGE);
+- try {
+- if (cache_file.make_directory_with_parents(null))
+- add_dir = true;
+- }
+- catch (IOError.EXISTS e) {
+- add_dir = true; // ignore
+- }
+- catch (Error e) {
+- warning("%s\n", e.message);
+- }
+- if (add_dir)
+- argv.append("--archive-dir=" + cache_file.get_path());
++ cache_dir = Path.build_filename(cache_dir, Config.PACKAGE);
++ if (DejaDup.ensure_directory_exists(cache_dir))
++ argv.append("--archive-dir=" + cache_dir);
+ }
+-
++
++ // Specify tempdir
++ var tempdir = yield DejaDup.get_tempdir();
++ if (DejaDup.ensure_directory_exists(tempdir))
++ argv.append("--tempdir=%s".printf(tempdir));
++
+ // Add logging argument
+ if (as_root) {
+ // Make log file
+ int logfd = 0;
+- try {
+- string logname;
+- logfd = FileUtils.open_tmp(Config.PACKAGE + "-XXXXXX", out logname);
+- logfile = File.new_for_path(logname);
+- }
+- catch (Error e) {
+- warning("%s\n", e.message);
+- done(false, false);
+- return;
+- }
+-
++ string logname;
++ logfd = FileUtils.open_tmp(Config.PACKAGE + "-XXXXXX", out logname);
++ logfile = File.new_for_path(logname);
+ argv.append("--log-file=%s".printf(logfile.get_path()));
+ }
+ else {
+ // Open pipes to communicate with subprocess
+- if (Posix.pipe(pipes) != 0) {
+- done(false, false);
+- return;
+- }
++ if (Posix.pipe(pipes) != 0)
++ return false;
+
+ argv.append("--log-fd=%d".printf(pipes[1]));
+ }
+@@ -195,9 +200,10 @@
+ if (pipes[1] != -1)
+ Posix.close(pipes[1]);
+
+- read_log.begin();
++ yield read_log();
++ return true;
+ }
+-
++
+ public bool is_started()
+ {
+ return (int)child_pid > 0;
+--- tools/duplicity/DuplicityJob.vala 2012-08-21 01:27:58 +0000
++++ tools/duplicity/DuplicityJob.vala 2013-03-17 23:50:25 +0000
+@@ -1459,13 +1459,7 @@
+ }
+
+ /* Start duplicity instance */
+- try {
+- inst.start(argv, envp, needs_root);
+- }
+- catch (Error e) {
+- show_error(e.message);
+- done(false, false, null);
+- }
++ inst.start.begin(argv, envp, needs_root);
+ }
+ }
+
More information about the scm-commits
mailing list