--- /dev/null
+#define _GNU_SOURCE
+#define _FILE_OFFSET_BITS 64
+
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <talloc.h>
+#include <lafs/lafs.h>
+#include "internal.h"
+
+static int csum_ok(struct lafs_state *st, int size)
+{
+ u32 crc, crc2;
+ crc = st->checksum;
+ st->checksum = 0;
+ crc2 = crc32(0, (uint32_t*)st, size);
+ st->checksum = crc;
+ return crc == crc2;
+}
+
+char *lafs_mount(struct lafs *fs, int force)
+{
+ char *err = NULL;
+ struct lafs_device *dv;
+ struct lafs_state *st;
+ struct lafs_snapshot **ssp;
+ int s;
+
+ if (fs->blocksize == 0)
+ return strdup("mount: no devices loaded");
+
+ if (fs->loaded_devs != fs->devices) {
+ asprintf(&err,
+ "need %d devices, only %d loaded",
+ fs->devices, fs->loaded_devs);
+ return err;
+ }
+ /* - check that the loaded devices don't overlap.
+ * - Choose and load a state block
+ * - fill in data in 'lafs': e..g ss, max_segment, checkpoint_cluster,
+ * youth
+ */
+
+ if (fs->ss.root || fs->ss.root_addr) {
+ asprintf(&err, "LaFS is already mounted");
+ return err;
+ }
+
+ /* FIXME check seq number is OK. */
+ for (dv = fs->devs; dv; dv = dv->next) {
+ struct lafs_device *dv2;
+ for (dv2 = dv->next; dv2; dv2= dv->next) {
+ if (dv->start < dv2->start + dv2->size &&
+ dv->start + dv->size <= dv2->start)
+ continue;
+ if (dv2->start < dv->start + dv->size &&
+ dv2->start + dv2->size <= dv->start)
+ continue;
+ asprintf(&err, "devices %s and %s overlap",
+ dv->name, dv2->name);
+ return err;
+ }
+ }
+ st = malloc(fs->statesize);
+ for (dv = fs->devs; dv; dv = dv->next)
+ if (lseek64(dv->fd, dv->stateaddr[dv->recent_state], 0)
+ == dv->stateaddr[dv->recent_state]
+ && read(dv->fd, st, fs->statesize) == fs->statesize)
+ break;
+ if (!dv) {
+ asprintf(&err, "Couldn't load a state block from any device");
+ free(st);
+ return err;
+ }
+ /* The state block has already been checked by lafs_load, but just
+ * to be sure...
+ */
+ if (memcmp(st->idtag, "LaFS-State-Block", 16) != 0 ||
+ memcmp(st->uuid, fs->uuid, 16) != 0 ||
+ !csum_ok(st, fs->statesize)) {
+ asprintf(&err, "state block nolonger looks correct");
+ free(st);
+ return err;
+ }
+ /* OK, let-her-rip. */
+ fs->seq = __le32_to_cpu(st->seq);
+// fs->levels = __le32_to_cpu(st->levels);
+ fs->checkpoint_cluster = __le64_to_cpu(st->checkpointcluster);
+ fs->youth_next = __le16_to_cpu(st->nextyouth);
+ fs->ss.root_addr = __le64_to_cpu(st->root_inodes[0]);
+ fs->ss.next = NULL;
+
+ ssp = &fs->ss.next;
+ for (s = 1; s < __le32_to_cpu(st->maxsnapshot); s++) {
+ struct lafs_snapshot *ss = talloc(fs, struct lafs_snapshot);
+ ss->next = NULL;
+ ss->root_addr = __le64_to_cpu(st->root_inodes[s]);
+ ss->root = NULL;
+ ss->rootdir = NULL;
+ *ssp = ss;
+ ssp = &ss->next;
+ }
+
+ fs->max_segment = 0;
+ for (dv = fs->devs ; dv; dv=dv->next)
+ if (fs->max_segment < dv->segment_size)
+ fs->max_segment = dv->segment_size;
+
+ fs->checkpointing = 0;
+ free(st);
+ return NULL;
+}
}
}
+/****** MOUNT ******/
+static char help_mount[] = "Coalesce loaded devices into a filesystem";
+static struct args args_mount[] = {
+ { "DEVNAME", external, -1, {NULL}, "Device to load and mount"},
+ { "-file", external, 0, {NULL}, "File to load and mount"},
+ { "-force", flag, -1, {NULL}, "Try to mount even if there are problems"},
+ TERMINAL_ARG
+};
+static void c_mount(struct state *st, void **args)
+{
+ char *err;
+ if (args[1]) {
+ /* Load the device first, then mount */
+ char *devname = args[1];
+ long long device_bytes = 0;
+ int fd;
+ struct lafs_device *dev;
+ if (st->lafs->blocksize) {
+ printf("mount: lafs already initialised - cannot load %s\n",
+ devname);
+ return;
+ }
+ fd = open_device(devname, &device_bytes, args[2] != NULL, &err);
+ if (fd < 0) {
+ printf("mount: %s\n", err);
+ free(err);
+ return;
+ }
+ dev = lafs_load(fd, device_bytes, &err);
+ if (err) {
+ printf("mount: Cannot load %s: %s\n", devname, err);
+ if (dev)
+ talloc_free(dev);
+ close(fd);
+ return;
+ }
+ dev->name = talloc_strdup(dev, devname);
+ if (lafs_include_dev(st->lafs, dev, &err) != 0) {
+ printf("mount: Cannot use %s: %s\n", devname, err);
+ talloc_free(dev);
+ return;
+ }
+ printf("loaded device %s\n", devname);
+ }
+ err = lafs_mount(st->lafs, args[3] != NULL);
+ if (err) {
+ printf("mount: cannot mount filesystem: %s\n", err);
+ free(err);
+ }
+}
+
/****** SHOW *****/
static struct cmd show_cmds[];
CMD(exit),
CMD(help),
CMD(load_dev),
+ CMD(mount),
CMD(newfs),
CMD(quit),
CMD(reset),