#############################################################################*/
#include <errno.h>
+#include <fts.h>
#include <dirent.h>
#include <fcntl.h>
#include <linux/limits.h>
#include <stdio.h>
#include <stdlib.h>
+#include <sys/file.h>
#include <sys/mount.h>
#include <pakfire/logging.h>
PAKFIRE_SNAPSHOT_INIT = 0,
PAKFIRE_SNAPSHOT_MOUNTED,
PAKFIRE_SNAPSHOT_UMOUNTED,
+ PAKFIRE_SNAPSHOT_DESTROYED,
} state;
};
goto ERROR;
}
- // XXX Check and lock the snapshot
+ // Lock the snapshot
+ r = flock(s->fd, LOCK_SH);
+ if (r < 0) {
+ CTX_ERROR(s->ctx, "Could not lock %s: %m\n", s->path);
+ r = -errno;
+ goto ERROR;
+ }
// Return the snapshot
*snapshot = pakfire_snapshot_ref(s);
return 0;
}
+static int pakfire_snapshot_destroy(struct pakfire_snapshot* snapshot) {
+ int r;
+
+ // Check if the snapshot is mounted
+ switch (snapshot->state) {
+ case PAKFIRE_SNAPSHOT_MOUNTED:
+ CTX_DEBUG(snapshot->ctx, "Snapshot is mounted\n");
+ return -EBUSY;
+
+ default:
+ break;
+ }
+
+ /*
+ Try to get an exclusive lock on the directory.
+
+ If this fails, another process is using this snapshot.
+ */
+ r = flock(snapshot->fd, LOCK_EX|LOCK_NB);
+ if (r < 0) {
+ switch (errno) {
+ case EWOULDBLOCK:
+ return -EBUSY;
+
+ default:
+ CTX_DEBUG(snapshot->ctx,
+ "Could not acquire an exclusive lock on %s: %m\n", snapshot->path);
+ break;
+ }
+ }
+
+ CTX_INFO(snapshot->ctx, "Destroying snapshot %s\n", snapshot->path);
+
+ // Remove all files
+ r = pakfire_rmtree(snapshot->path, 0);
+ if (r < 0) {
+ CTX_ERROR(snapshot->ctx, "Could not destroy snapshot %s: %s\n",
+ snapshot->path, strerror(-r));
+ return r;
+ }
+
+ // Mark as destroyed
+ snapshot->state = PAKFIRE_SNAPSHOT_DESTROYED;
+
+ return 0;
+}
+
static int pakfire_snapshot_install_packages(struct pakfire* pakfire, const char** packages) {
struct pakfire_transaction* transaction = NULL;
int r;
return r;
}
+
+/*
+ Cleans up any unused snapshots
+*/
+int pakfire_snapshot_clean(struct pakfire* pakfire) {
+ struct pakfire_snapshot* snapshot = NULL;
+ char path[PATH_MAX];
+ FTS* f = NULL;
+ int r;
+
+ struct pakfire_ctx* ctx = pakfire_ctx(pakfire);
+
+ // Make the path
+ r = pakfire_cache_path(pakfire, path, "%s", "snapshots");
+ if (r < 0)
+ return r;
+
+ char* paths[] = {
+ path, NULL,
+ };
+
+ // Open the directory
+ f = fts_open(paths, FTS_PHYSICAL|FTS_NOCHDIR|FTS_NOSTAT, NULL);
+
+ for (;;) {
+ FTSENT* node = fts_read(f);
+ if (!node)
+ break;
+
+ // Skip the main directory
+ if (node->fts_level == 0) {
+ continue;
+
+ // Skip any subdirectories
+ } else if (node->fts_level > 1) {
+ fts_set(f, node, FTS_SKIP);
+ continue;
+ }
+
+ // We only care about directories
+ if (node->fts_info == FTS_D)
+ continue;
+
+ // Open the snapshot
+ r = pakfire_snapshot_create(&snapshot, ctx, node->fts_path);
+ if (r < 0)
+ goto ERROR;
+
+ // Destroy the snapshot
+ r = pakfire_snapshot_destroy(snapshot);
+ if (r < 0)
+ goto ERROR;
+
+ // Free the snapshot
+ snapshot = pakfire_snapshot_unref(snapshot);
+ }
+
+ERROR:
+ if (snapshot)
+ pakfire_snapshot_unref(snapshot);
+ if (ctx)
+ pakfire_ctx_unref(ctx);
+ if (f)
+ fts_close(f);
+
+ return r;
+}