#include "snapper/SnapperTmpl.h"
#include "snapper/SnapperDefines.h"
#include "snapper/Acls.h"
+#include "snapper/Regex.h"
namespace snapper
#endif
+#ifdef ENABLE_ROLLBACK
+
+ unsigned int
+ Btrfs::getDefault() const
+ {
+ try
+ {
+ SDir subvolume_dir = openSubvolumeDir();
+ unsigned long long id = get_default_id(subvolume_dir.fd());
+ string name = get_subvolume(subvolume_dir.fd(), id);
+
+ if (name.empty())
+ return 0;
+
+ Regex rx("^.snapshots/([0-9]*)/snapshot");
+ if (!rx.match(name))
+ throw IOErrorException();
+
+ int num = 0;
+ rx.cap(1) >> num;
+ return num;
+ }
+ catch (const runtime_error& e)
+ {
+ throw IOErrorException();
+ }
+ }
+
+
+ void
+ Btrfs::setDefault(unsigned int num) const
+ {
+ try
+ {
+ if (num == 0)
+ {
+ SDir subvolume_dir = openSubvolumeDir();
+ unsigned long long id = get_id(subvolume_dir.fd());
+ set_default_id(subvolume_dir.fd(), id);
+ }
+ else
+ {
+ SDir snapshot_dir = openSnapshotDir(num);
+ unsigned long long id = get_id(snapshot_dir.fd());
+
+ SDir subvolume_dir = openSubvolumeDir();
+ set_default_id(subvolume_dir.fd(), id);
+ }
+ }
+ catch (const runtime_error& e)
+ {
+ throw IOErrorException();
+ }
+ }
+
+#else
+
+ unsigned int
+ Btrfs::getDefault() const
+ {
+ throw std::logic_error("not implemented");
+ }
+
+
+ void
+ Btrfs::setDefault(unsigned int num) const
+ {
+ throw std::logic_error("not implemented");
+ }
+
+#endif
+
+
#ifdef ENABLE_ROLLBACK
void
virtual void cmpDirs(const SDir& dir1, const SDir& dir2, cmpdirs_cb_t cb) const;
+ virtual unsigned int getDefault() const;
+ virtual void setDefault(unsigned int num) const;
+
private:
void addToFstab() const;
#endif
+#ifndef BTRFS_IOC_SUBVOL_GETFLAGS
+#define BTRFS_IOC_SUBVOL_GETFLAGS _IOR(BTRFS_IOCTL_MAGIC, 25, __u64)
+#endif
+
namespace snapper
{
+
// See btrfsprogs source code for references.
bool
+ is_subvolume_read_only(int fd, bool& read_only)
+ {
+ __u64 flags;
+ if (ioctl(fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags) != 0)
+ throw runtime_error_with_errno("ioctl(BTRFS_IOC_SUBVOL_GETFLAGS) failed", errno);
+
+ return flags & BTRFS_SUBVOL_RDONLY;
+ }
+
+
+ void
create_subvolume(int fddst, const string& name)
{
struct btrfs_ioctl_vol_args args;
#ifdef ENABLE_ROLLBACK
+ void
+ set_default_id(int fd, unsigned long long id)
+ {
+ if (ioctl(fd, BTRFS_IOC_DEFAULT_SUBVOL, &id) != 0)
+ throw runtime_error_with_errno("ioctl(BTRFS_IOC_DEFAULT_SUBVOL) failed", errno);
+ }
+
+
+ unsigned long long
+ get_default_id(int fd)
+ {
+ struct btrfs_ioctl_search_args args;
+ memset(&args, 0, sizeof(args));
+
+ struct btrfs_ioctl_search_key* sk = &args.key;
+ sk->tree_id = BTRFS_ROOT_TREE_OBJECTID;
+ sk->nr_items = 1;
+ sk->max_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
+ sk->min_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
+ sk->max_type = BTRFS_DIR_ITEM_KEY;
+ sk->min_type = BTRFS_DIR_ITEM_KEY;
+ sk->max_offset = (__u64) -1;
+ sk->max_transid = (__u64) -1;
+
+ if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) != 0)
+ throw runtime_error_with_errno("ioctl(BTRFS_IOC_TREE_SEARCH) failed", errno);
+
+ if (sk->nr_items == 0)
+ throw std::runtime_error("sk->nr_items == 0");
+
+ struct btrfs_ioctl_search_header* sh = (struct btrfs_ioctl_search_header*) args.buf;
+ if (sh->type != BTRFS_DIR_ITEM_KEY)
+ throw std::runtime_error("sh->type != BTRFS_DIR_ITEM_KEY");
+
+ struct btrfs_dir_item* di = (struct btrfs_dir_item*)(sh + 1);
+ int name_len = btrfs_stack_dir_name_len(di);
+ const char* name = (const char*)(di + 1);
+ if (strncmp("default", name, name_len) != 0)
+ throw std::runtime_error("name != default");
+
+ return btrfs_disk_key_objectid(&di->location);
+ }
+
+
string
get_subvolume(int fd, unsigned long long id)
{
bool is_subvolume(const struct stat& stat);
+ bool is_subvolume_read_only(int fd);
+
void create_subvolume(int fddst, const string& name);
void create_snapshot(int fd, int fddst, const string& name, bool read_only);
void delete_subvolume(int fd, const string& name);
+ void set_default_id(int fd, unsigned long long id);
+ unsigned long long get_default_id(int fd);
+
string get_subvolume(int fd, unsigned long long id);
unsigned long long get_id(int fd);
snapper::cmpDirs(dir1, dir2, cb);
}
+
+ unsigned int
+ Filesystem::getDefault() const
+ {
+ throw std::logic_error("not implemented");
+ }
+
+
+ void
+ Filesystem::setDefault(unsigned int num) const
+ {
+ throw std::logic_error("not implemented");
+ }
+
}
virtual void cmpDirs(const SDir& dir1, const SDir& dir2, cmpdirs_cb_t cb) const;
+ virtual unsigned int getDefault() const;
+ virtual void setDefault(unsigned int num) const;
+
protected:
const string subvolume;