From: Arvin Schnell Date: Fri, 29 Jul 2011 14:33:06 +0000 (+0200) Subject: - moved filesystem depended code new classes X-Git-Tag: v0.1.3~339 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=70190350d30ba2b494f0568ab8570e43d067525b;p=thirdparty%2Fsnapper.git - moved filesystem depended code new classes - renamed baseDir to infoDir - added some code for ext4 snapshots --- diff --git a/LIBVERSION b/LIBVERSION index 7dea76ed..9084fa2f 100644 --- a/LIBVERSION +++ b/LIBVERSION @@ -1 +1 @@ -1.0.1 +1.1.0 diff --git a/snapper/Compare.cc b/snapper/Compare.cc index 02b6c145..9bb81a36 100644 --- a/snapper/Compare.cc +++ b/snapper/Compare.cc @@ -238,7 +238,7 @@ namespace snapper bool filter(const string& name) { - if (name == "/snapshots") + if (name == "/.snapshots" || name == "/.snapshots-info") return true; return false; diff --git a/snapper/File.cc b/snapper/File.cc index a4bf2c55..da205120 100644 --- a/snapper/File.cc +++ b/snapper/File.cc @@ -119,6 +119,9 @@ namespace snapper if (getSnapper()->getCompareCallback()) getSnapper()->getCompareCallback()->start(); + comparison->getSnapshot1()->mountFilesystemSnapshot(); + comparison->getSnapshot2()->mountFilesystemSnapshot(); + #if 1 cmpdirs_cb_t cb = AppendHelper(comparison, entries); #else @@ -154,7 +157,7 @@ namespace snapper if (invert) swap(num1, num2); - string input = getSnapper()->snapshotsDir() + "/" + decString(num2) + "/filelist-" + + string input = getSnapper()->infosDir() + "/" + decString(num2) + "/filelist-" + decString(num1) + ".txt"; try @@ -209,7 +212,7 @@ namespace snapper if (invert) swap(num1, num2); - string output = getSnapper()->snapshotsDir() + "/" + decString(num2) + "/filelist-" + + string output = getSnapper()->infosDir() + "/" + decString(num2) + "/filelist-" + decString(num1) + ".txt"; string tmp_name = output + ".tmp-XXXXXX"; diff --git a/snapper/Filesystem.cc b/snapper/Filesystem.cc new file mode 100644 index 00000000..d74fcda0 --- /dev/null +++ b/snapper/Filesystem.cc @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2011 Novell, Inc. + * + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, contact Novell, Inc. + * + * To contact Novell about this file by physical or electronic mail, you may + * find current contact information at www.novell.com. + */ + + +#include +#include + +#include "snapper/Filesystem.h" +#include "snapper/Snapper.h" +#include "snapper/SnapperTmpl.h" +#include "snapper/SystemCmd.h" +#include "snapper/SnapperDefines.h" + + +namespace snapper +{ + + string + Btrfs::infosDir() const + { + return snapper->subvolumeDir() + "/.snapshots"; + } + + + string + Ext4::infosDir() const + { + return snapper->subvolumeDir() + "/.snapshots-info"; + } + + + string + Btrfs::snapshotDir(unsigned int num) const + { + return snapper->subvolumeDir() + "/.snapshots/" + decString(num) + "/snapshot"; + } + + + string + Ext4::snapshotDir(unsigned int num) const + { + return snapper->subvolumeDir() + "@" + decString(num); + } + + + void + Btrfs::createFilesystemSnapshot(unsigned int num) const + { + SystemCmd cmd(BTRFSBIN " subvolume snapshot " + snapper->subvolumeDir() + " " + snapshotDir(num)); + if (cmd.retcode() != 0) + throw CreateSnapshotFailedException(); + } + + + void + Ext4::createFilesystemSnapshot(unsigned int num) const + { + SystemCmd cmd1(TOUCHBIN " " "/mnt/.snapshots/" + decString(num)); + if (cmd1.retcode() != 0) + throw CreateSnapshotFailedException(); + + SystemCmd cmd2(CHSNAPBIN " +S " "/mnt/.snapshots/" + decString(num)); + if (cmd2.retcode() != 0) + throw CreateSnapshotFailedException(); + } + + + void + Btrfs::deleteFilesystemSnapshot(unsigned int num) const + { + SystemCmd cmd(BTRFSBIN " subvolume delete " + snapshotDir(num)); + if (cmd.retcode() != 0) + throw DeleteSnapshotFailedException(); + } + + + void + Ext4::deleteFilesystemSnapshot(unsigned int num) const + { + // TODO + } + + + void + Btrfs::mountFilesystemSnapshot(unsigned int num) const + { + } + + + void + Ext4::mountFilesystemSnapshot(unsigned int num) const + { + SystemCmd cmd1(CHSNAPBIN " +n " "/mnt/.snapshots/" + decString(num)); + if (cmd1.retcode() != 0) + throw CreateSnapshotFailedException(); + + mkdir(("/mnt@" + decString(num)).c_str(), 0666); + + SystemCmd cmd2(MOUNTBIN " -t ext4 -r -o loop,noload " "/mnt/.snapshots/" + decString(num) + " " + "/mnt@" + decString(num)); + if (cmd2.retcode() != 0) + throw CreateSnapshotFailedException(); + } + + + void + Btrfs::umountFilesystemSnapshot(unsigned int num) const + { + } + + + void + Ext4::umountFilesystemSnapshot(unsigned int num) const + { + // TODO + } + + + bool + Btrfs::checkFilesystemSnapshot(unsigned int num) const + { + return checkDir(snapshotDir(num)); + } + + + bool + Ext4::checkFilesystemSnapshot(unsigned int num) const + { + // TODO + + return true; + } + +} diff --git a/snapper/Filesystem.h b/snapper/Filesystem.h new file mode 100644 index 00000000..9afd9690 --- /dev/null +++ b/snapper/Filesystem.h @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2011 Novell, Inc. + * + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, contact Novell, Inc. + * + * To contact Novell about this file by physical or electronic mail, you may + * find current contact information at www.novell.com. + */ + + +#ifndef FILESYSTEM_H +#define FILESYSTEM_H + + +#include + + +namespace snapper +{ + using std::string; + + + class Snapper; + + + class Filesystem + { + public: + + Filesystem(Snapper* snapper) : snapper(snapper) {} + virtual ~Filesystem() {} + + virtual string name() const = 0; + + virtual string infosDir() const = 0; + virtual string snapshotDir(unsigned int num) const = 0; + + virtual void createFilesystemSnapshot(unsigned int num) const = 0; + virtual void deleteFilesystemSnapshot(unsigned int num) const = 0; + + virtual void mountFilesystemSnapshot(unsigned int num) const = 0; + virtual void umountFilesystemSnapshot(unsigned int num) const = 0; + + virtual bool checkFilesystemSnapshot(unsigned int num) const = 0; + + protected: + + Snapper* snapper; + + }; + + + class Btrfs : public Filesystem + { + public: + + Btrfs(Snapper* snapper) : Filesystem(snapper) {} + + virtual string name() const { return "btrfs"; } + + virtual string infosDir() const; + virtual string snapshotDir(unsigned int num) const; + + virtual void createFilesystemSnapshot(unsigned int num) const; + virtual void deleteFilesystemSnapshot(unsigned int num) const; + + virtual void mountFilesystemSnapshot(unsigned int num) const; + virtual void umountFilesystemSnapshot(unsigned int num) const; + + virtual bool checkFilesystemSnapshot(unsigned int num) const; + + }; + + + class Ext4 : public Filesystem + { + public: + + Ext4(Snapper* snapper) : Filesystem(snapper) {} + + virtual string name() const { return "ext4"; } + + virtual string infosDir() const; + virtual string snapshotDir(unsigned int num) const; + + virtual void createFilesystemSnapshot(unsigned int num) const; + virtual void deleteFilesystemSnapshot(unsigned int num) const; + + virtual void mountFilesystemSnapshot(unsigned int num) const; + virtual void umountFilesystemSnapshot(unsigned int num) const; + + virtual bool checkFilesystemSnapshot(unsigned int num) const; + + }; + +} + + +#endif diff --git a/snapper/Makefile.am b/snapper/Makefile.am index 8fd1d93a..a5e8252a 100644 --- a/snapper/Makefile.am +++ b/snapper/Makefile.am @@ -11,6 +11,7 @@ libsnapper_la_SOURCES = \ Snapper.cc Snapper.h \ Snapshot.cc Snapshot.h \ Comparison.cc Comparison.h \ + Filesystem.cc Filesystem.h \ File.cc File.h \ XmlFile.cc XmlFile.h \ Enum.cc Enum.h \ diff --git a/snapper/Snapper.cc b/snapper/Snapper.cc index 32086578..2099e068 100644 --- a/snapper/Snapper.cc +++ b/snapper/Snapper.cc @@ -30,8 +30,8 @@ #include "snapper/Snapper.h" #include "snapper/Comparison.h" #include "snapper/AppUtil.h" -#include "snapper/XmlFile.h" #include "snapper/Enum.h" +#include "snapper/Filesystem.h" #include "snapper/SnapperTmpl.h" #include "snapper/SystemCmd.h" #include "snapper/SnapperDefines.h" @@ -46,8 +46,8 @@ namespace snapper Snapper::Snapper(const string& config_name, bool disable_filters) - : config_name(config_name), config(NULL), subvolume("/"), snapshots(this), - compare_callback(NULL), rollback_callback(NULL) + : config_name(config_name), config(NULL), subvolume("/"), filesystem(NULL), + snapshots(this), compare_callback(NULL), rollback_callback(NULL) { y2mil("Snapper constructor"); y2mil("libsnapper version " VERSION); @@ -69,6 +69,10 @@ namespace snapper y2mil("subvolume:" << subvolume); + filesystem = new Btrfs(this); + + y2mil("filesystem:" << filesystem->name()); + if (!disable_filters) loadIgnorePatterns(); @@ -80,6 +84,7 @@ namespace snapper { y2mil("Snapper destructor"); + delete filesystem; delete config; } @@ -115,15 +120,13 @@ namespace snapper } - // Directory containing directories for all snapshots, e.g. "/snapshots" - // or "/home/snapshots". + // Directory that contains the per snapshot directory with info files. + // For btrfs e.g. "/.snapshots" or "/home/.snapshots". + // For ext4 e.g. "/.snapshots-info" or "/home/.snapshots-info". string - Snapper::snapshotsDir() const + Snapper::infosDir() const { - if (subvolumeDir() == "/") - return SNAPSHOTSDIR; - else - return subvolumeDir() + SNAPSHOTSDIR; + return filesystem->infosDir(); } @@ -174,6 +177,9 @@ namespace snapper y2mil("num1:" << snapshot1->getNum() << " num2:" << snapshot2->getNum()); + snapshot1->mountFilesystemSnapshot(); + snapshot2->mountFilesystemSnapshot(); + bool invert = snapshot1->getNum() > snapshot2->getNum(); if (invert) @@ -182,7 +188,7 @@ namespace snapper string dir1 = snapshot1->snapshotDir(); string dir2 = snapshot2->snapshotDir(); - string output = snapshot2->baseDir() + "/filelist-" + decString(snapshot1->getNum()) + + string output = snapshot2->infoDir() + "/filelist-" + decString(snapshot1->getNum()) + ".txt"; SystemCmd(NICEBIN " -n 19 " IONICEBIN " -c 3 " COMPAREDIRSBIN " " + quote(dir1) + " " + @@ -595,7 +601,7 @@ namespace snapper throw AddConfigFailedException("modifying config failed"); } - SystemCmd cmd2(BTRFSBIN " subvolume create " + subvolume + SNAPSHOTSDIR); + SystemCmd cmd2(BTRFSBIN " subvolume create " + subvolume + "/.snapshots"); if (cmd2.retcode() != 0) { throw AddConfigFailedException("creating snapshot failed"); diff --git a/snapper/Snapper.h b/snapper/Snapper.h index 53b43343..2f8eee00 100644 --- a/snapper/Snapper.h +++ b/snapper/Snapper.h @@ -35,6 +35,7 @@ namespace snapper class SysconfigFile; + class Filesystem; struct CompareCallback @@ -109,7 +110,7 @@ namespace snapper ~Snapper(); string subvolumeDir() const; - string snapshotsDir() const; + string infosDir() const; Snapshots& getSnapshots() { return snapshots; } const Snapshots& getSnapshots() const { return snapshots; } @@ -141,6 +142,8 @@ namespace snapper static void addConfig(const string& config_name, const string& subvolume, const string& template_name); + const Filesystem* getFilesystem() const { return filesystem; } + private: void filter1(list& tmp, time_t min_age); @@ -154,6 +157,8 @@ namespace snapper string subvolume; + Filesystem* filesystem; + vector ignore_patterns; Snapshots snapshots; diff --git a/snapper/SnapperDefines.h b/snapper/SnapperDefines.h index 51a2ba0d..e379142e 100644 --- a/snapper/SnapperDefines.h +++ b/snapper/SnapperDefines.h @@ -31,19 +31,20 @@ #define FILTERSDIR "/etc/snapper/filters" -#define SNAPSHOTDIR "/snapshot" -#define SNAPSHOTSDIR "/.snapshots" - #define BTRFSBIN "/sbin/btrfs" +#define CHSNAPBIN "/sbin/chsnap" + #define COMPAREDIRSBIN "/usr/lib/snapper/bin/compare-dirs" #define NICEBIN "/usr/bin/nice" #define IONICEBIN "/usr/bin/ionice" #define CPBIN "/bin/cp" - +#define TOUCHBIN "/usr/bin/touch" #define DIFFBIN "/usr/bin/diff" +#define MOUNTBIN "/bin/mount" + #endif diff --git a/snapper/Snapshot.cc b/snapper/Snapshot.cc index 3aed2ab7..73629633 100644 --- a/snapper/Snapshot.cc +++ b/snapper/Snapshot.cc @@ -31,6 +31,7 @@ #include "snapper/Snapper.h" #include "snapper/AppUtil.h" #include "snapper/XmlFile.h" +#include "snapper/Filesystem.h" #include "snapper/Enum.h" #include "snapper/SnapperTmpl.h" #include "snapper/SystemCmd.h" @@ -62,28 +63,32 @@ namespace snapper } - // Directory where the info file is saved, e.g. "/snapshots/1" or - // "/home/snapshots/1". Obviously not available for current. + // Directory where the info file is saved. Obviously not available for + // current. + // For btrfs e.g. "/.snapshots/1" or "/home/.snapshots/1". + // For ext4 e.g. "/.snapshots-info/1" or "/home/.snapshots-info/1". string - Snapshot::baseDir() const + Snapshot::infoDir() const { if (isCurrent()) throw IllegalSnapshotException(); - return snapper->snapshotsDir() + "/" + decString(num); + return snapper->infosDir() + "/" + decString(num); } - // Directory containing the actual snapshot, e.g. "/" or "/home" for - // current and "/snapshots/1/snapshot" or "/home/snapshots/1/snapshot" + // Directory containing the actual content of the snapshot. + // For btrfs , e.g. "/" or "/home" for current and + // "/.snapshots/1/snapshot" or "/home/.snapshots/1/snapshot" otherwise. + // For ext4 , e.g. "/" or "/home" for current and "/@1" or "/home@1" // otherwise. string Snapshot::snapshotDir() const { - if (num == 0) + if (isCurrent()) return snapper->subvolumeDir(); - else - return baseDir() + SNAPSHOTDIR; + + return snapper->getFilesystem()->snapshotDir(num); } @@ -106,11 +111,11 @@ namespace snapper void Snapshots::read() { - list infos = glob(snapper->snapshotsDir() + "/*/info.xml", GLOB_NOSORT); + list infos = glob(snapper->infosDir() + "/*/info.xml", GLOB_NOSORT); for (list::const_iterator it = infos.begin(); it != infos.end(); ++it) { unsigned int num; - it->substr(snapper->snapshotsDir().length() + 1) >> num; + it->substr(snapper->infosDir().length() + 1) >> num; XmlFile file(*it); const xmlNode* root = file.getRootElement(); @@ -144,9 +149,9 @@ namespace snapper getChildValue(node, "cleanup", snapshot.cleanup); - if (!checkDir(snapshot.snapshotDir())) + if (!snapper->getFilesystem()->checkFilesystemSnapshot(num)) { - y2err("snapshot directory does not exist. not adding snapshot " << num); + y2err("snapshot check failed. not adding snapshot " << num); continue; } @@ -275,7 +280,7 @@ namespace snapper num = entries.rbegin()->num + 1; int r; - while ((r = mkdir((snapper->snapshotsDir() + "/" + decString(num)).c_str(), 0777)) == -1 && + while ((r = mkdir((snapper->infosDir() + "/" + decString(num)).c_str(), 0777)) == -1 && errno == EEXIST) ++num; @@ -311,27 +316,37 @@ namespace snapper if (!cleanup.empty()) setChildValue(node, "cleanup", cleanup); - xml.save(baseDir() + "/info.xml"); + xml.save(infoDir() + "/info.xml"); return true; } + void + Snapshot::mountFilesystemSnapshot() const + { + snapper->getFilesystem()->mountFilesystemSnapshot(num); + } + + + void + Snapshot::umountFilesystemSnapshot() const + { + snapper->getFilesystem()->umountFilesystemSnapshot(num); + } + + void Snapshot::createFilesystemSnapshot() const { - SystemCmd cmd(BTRFSBIN " subvolume snapshot " + snapper->subvolumeDir() + " " + snapshotDir()); - if (cmd.retcode() != 0) - throw CreateSnapshotFailedException(); + snapper->getFilesystem()->createFilesystemSnapshot(num); } void Snapshot::deleteFilesystemSnapshot() const { - SystemCmd cmd(BTRFSBIN " subvolume delete " + snapshotDir()); - if (cmd.retcode() != 0) - throw DeleteSnapshotFailedException(); + snapper->getFilesystem()->deleteFilesystemSnapshot(num); } @@ -394,18 +409,18 @@ namespace snapper snapshot->deleteFilesystemSnapshot(); - unlink((snapshot->baseDir() + "/info.xml").c_str()); + unlink((snapshot->infoDir() + "/info.xml").c_str()); - list tmp1 = glob(snapshot->baseDir() + "/filelist-*.txt", GLOB_NOSORT); + list tmp1 = glob(snapshot->infoDir() + "/filelist-*.txt", GLOB_NOSORT); for (list::const_iterator it = tmp1.begin(); it != tmp1.end(); ++it) unlink(it->c_str()); - list tmp2 = glob(snapper->snapshotsDir() + "/*/filelist-" + + list tmp2 = glob(snapper->infosDir() + "/*/filelist-" + decString(snapshot->getNum()) + ".txt", GLOB_NOSORT); for (list::const_iterator it = tmp2.begin(); it != tmp2.end(); ++it) unlink(it->c_str()); - rmdir(snapshot->baseDir().c_str()); + rmdir(snapshot->infoDir().c_str()); entries.erase(snapshot); } diff --git a/snapper/Snapshot.h b/snapper/Snapshot.h index 82a11ee0..c361e143 100644 --- a/snapper/Snapshot.h +++ b/snapper/Snapshot.h @@ -78,9 +78,12 @@ namespace snapper void setCleanup(const string& cleanup); string getCleanup() const { return cleanup; } - string baseDir() const; + string infoDir() const; string snapshotDir() const; + void mountFilesystemSnapshot() const; + void umountFilesystemSnapshot() const; + friend std::ostream& operator<<(std::ostream& s, const Snapshot& snapshot); private: @@ -100,6 +103,7 @@ namespace snapper string cleanup; bool writeInfo() const; + void createFilesystemSnapshot() const; void deleteFilesystemSnapshot() const; diff --git a/testsuite-real/common.cc b/testsuite-real/common.cc index 3052a0e8..6e35ff32 100644 --- a/testsuite-real/common.cc +++ b/testsuite-real/common.cc @@ -60,7 +60,7 @@ RollbackCallbackImpl rollback_callback_impl; void setup() { - system("/usr/bin/find " SUBVOLUME " -mindepth 1 -maxdepth 1 -not -path " SUBVOLUME SNAPSHOTSDIR " " + system("/usr/bin/find " SUBVOLUME " -mindepth 1 -maxdepth 1 -not -path " SUBVOLUME "/.snapshots " "-exec rm -r {} \\;"); initDefaultLogger();