Skip to content

Commit

Permalink
Implement fakefs rebuilding
Browse files Browse the repository at this point in the history
  • Loading branch information
tbodt committed Jan 12, 2018
1 parent a9aaa2c commit 1f58d2f
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 6 deletions.
111 changes: 111 additions & 0 deletions fs/fake-rebuild.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <gdbm.h>
#include "kernel/fs.h"
#include "kernel/errno.h"
#include "util/list.h"

// ad hoc hashtable
struct entry {
ino_t inode;
char *path;
struct list chain;
};

#define PREFIX_INO "inode "

int fakefs_rebuild(struct mount *mount, const char *db_path) {
char new_db_path[MAX_PATH];
strcpy(new_db_path, db_path);
strcat(new_db_path, ".new");
GDBM_FILE new_db = gdbm_open(new_db_path, 0, GDBM_NEWDB, 0666, NULL);
if (new_db == NULL)
return errno_map();

struct list hashtable[2000];
#define HASH_SIZE (sizeof(hashtable)/sizeof(hashtable[0]))
for (unsigned i = 0; i < HASH_SIZE; i++)
list_init(&hashtable[i]);

char keydata[strlen(PREFIX_INO) + MAX_PATH];
datum dkey = {.dptr = keydata};
char valuedata[30];
datum dvalue = {.dptr = valuedata};

for (datum key = gdbm_firstkey(mount->db), nextkey; key.dptr != NULL;
nextkey = gdbm_nextkey(mount->db, key), free(key.dptr), key = nextkey) {
if (strncmp(key.dptr, PREFIX_INO, strlen(PREFIX_INO)) != 0)
continue;

// fetch the inode from the value
datum value_datum = gdbm_fetch(mount->db, key);
char *value = strndup(value_datum.dptr, value_datum.dsize);
free(value_datum.dptr);
char *end;
ino_t inode = strtol(value, &end, 10);
if (*end != '\0') {
free(value);
continue;
}

// extract the path from the key
char *path = strndup(key.dptr + strlen(PREFIX_INO), key.dsize - strlen(PREFIX_INO));
struct stat stat;
int err = fstatat(mount->root_fd, fix_path(path), &stat, 0);
if (err < 0)
goto next;
ino_t real_inode = stat.st_ino;

// restore hardlinks
struct list *bucket = &hashtable[inode % HASH_SIZE];
struct entry *entry;
bool found = false;
list_for_each_entry(bucket, entry, chain) {
if (entry->inode == inode) {
unlinkat(mount->root_fd, fix_path(path), 0);
linkat(mount->root_fd, fix_path(entry->path), mount->root_fd, fix_path(path), 0);
found = true;
break;
}
}
if (!found) {
entry = malloc(sizeof(struct entry));
entry->inode = inode;
entry->path = strdup(path);
list_add(bucket, &entry->chain);
}

// extract the stat data from the appropriate stat key
dkey.dsize = sprintf(dkey.dptr, "stat %lu", inode);
datum stat_data = gdbm_fetch(mount->db, dkey);
if (stat_data.dptr == NULL)
goto next;

// store all the information in the new database
dkey.dsize = sprintf(dkey.dptr, "inode %s", path);
dvalue.dsize = sprintf(dvalue.dptr, "%lu", real_inode);
gdbm_store(new_db, dkey, dvalue, GDBM_REPLACE);
dkey.dsize = sprintf(dkey.dptr, "stat %lu", real_inode);
gdbm_store(new_db, dkey, stat_data, GDBM_REPLACE);
free(stat_data.dptr);

next:
free(path);
}

for (unsigned i = 0; i < HASH_SIZE; i++) {
struct entry *entry, *tmp;
list_for_each_entry_safe(&hashtable[i], entry, tmp, chain) {
list_remove(&entry->chain);
free(entry->path);
free(entry);
}
}

if (rename(new_db_path, db_path) < 0)
return errno_map();
gdbm_close(mount->db);
mount->db = new_db;
return 0;
}
21 changes: 16 additions & 5 deletions fs/fake.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ static void write_stat(struct mount *mount, const char *path, struct ish_stat *s
}

static struct fd *fakefs_open(struct mount *mount, const char *path, int flags, int mode) {
struct fd *fd = realfs.open(mount, path, flags, 0644);
struct fd *fd = realfs.open(mount, path, flags, 0666);
if (IS_ERR(fd))
return fd;
if (flags & O_CREAT_) {
Expand Down Expand Up @@ -163,7 +163,7 @@ static int fakefs_rename(struct mount *mount, const char *src, const char *dst)

static int fakefs_symlink(struct mount *mount, const char *target, const char *link) {
// create a file containing the target
int fd = openat(mount->root_fd, fix_path(link), O_WRONLY | O_CREAT | O_EXCL, 0644);
int fd = openat(mount->root_fd, fix_path(link), O_WRONLY | O_CREAT | O_EXCL, 0666);
if (fd < 0)
return errno_map();
ssize_t res = write(fd, target, strlen(target));
Expand Down Expand Up @@ -239,7 +239,7 @@ static int fakefs_fsetattr(struct fd *fd, struct attr attr) {
}

static int fakefs_mkdir(struct mount *mount, const char *path, mode_t_ mode) {
int err = realfs.mkdir(mount, path, 0755);
int err = realfs.mkdir(mount, path, 0777);
if (err < 0)
return err;
struct ish_stat ishstat;
Expand Down Expand Up @@ -273,6 +273,8 @@ static ssize_t fakefs_readlink(struct mount *mount, const char *path, char *buf,
return err;
}

int fakefs_rebuild(struct mount *mount, const char *db_path);

static int fakefs_mount(struct mount *mount) {
char db_path[PATH_MAX];
strcpy(db_path, mount->source);
Expand All @@ -285,6 +287,11 @@ static int fakefs_mount(struct mount *mount) {
return _EINVAL;
}

// do this now so fakefs_rebuild can use mount->root_fd
int err = realfs.mount(mount);
if (err < 0)
return err;

// after the filesystem is compressed, transmitted, and uncompressed, the
// inode numbers will be different. to detect this, the inode of the
// database file is stored inside the database and compared with the actual
Expand All @@ -295,15 +302,19 @@ static int fakefs_mount(struct mount *mount) {
datum value = gdbm_fetch(mount->db, key);
if (value.dptr != NULL && atol(value.dptr) != stat.st_ino) {
free(value.dptr);
TODO("rebuild database");
int err = fakefs_rebuild(mount, db_path);
if (err < 0) {
close(mount->root_fd);
return err;
}
}

char keydata[30];
value = make_datum(keydata, "%lu", (unsigned long) stat.st_ino);
value.dsize++; // make sure to null terminate
gdbm_store(mount->db, key, value, GDBM_REPLACE);

return realfs.mount(mount);
return 0;
}

static int fakefs_umount(struct mount *mount) {
Expand Down
2 changes: 2 additions & 0 deletions fs/tty.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@ static int tty_get(int type, int num, struct tty **tty_out) {
// TODO default termios
memset(&tty->winsize, 0, sizeof(tty->winsize));
lock_init(tty->lock);
lock_init(tty->fds_lock);
pthread_cond_init(&tty->produced, NULL);
pthread_cond_init(&tty->consumed, NULL);
tty->bufsize = 0;

tty->driver = &tty_drivers[type];
if (tty->driver->open) {
Expand Down
1 change: 1 addition & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ src = [
'fs/path.c',
'fs/real.c',
'fs/fake.c',
'fs/fake-rebuild.c',
'fs/poll.c',
'fs/adhoc.c',

Expand Down
1 change: 0 additions & 1 deletion xX_main_Xx.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ static inline int xX_main_Xx(int argc, char *const argv[]) {
else
fs = &fakefs;
break;

}
}

Expand Down

0 comments on commit 1f58d2f

Please sign in to comment.