aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarvin Borner2022-01-02 18:37:51 +0100
committerMarvin Borner2022-01-02 18:37:51 +0100
commite4b01ac99b3d13c5d1057eacc04757cea957cbd7 (patch)
tree5bc2a7af3a788047aab8482959eddc306831adfe
parent6a1f4e4d394b3c5ff7a7d1c58a8775a645275e4a (diff)
Read/write maybe more
-rw-r--r--README.md4
-rw-r--r--inc/spec.h21
-rw-r--r--makefile2
-rw-r--r--src/fuse.c200
-rw-r--r--src/mkfs.c28
5 files changed, 208 insertions, 47 deletions
diff --git a/README.md b/README.md
index b82800e..686ce64 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,8 @@
# MarFS
-> This is a sub-project of Melvix and shouldn't be used otherwise.
+> This is a sub-project of Melvix and shouldn't be used otherwise. It's not fast and 32-bit only.
-As of right now, there are two utility programs in this project:
+As of right now, there are two utility programs for GNU/Linux in this project:
* `mkfs` creates an empty MarFS filesystem on a specified image
* `fuse` mounts a specified MarFS-formatted image onto a specified directory
diff --git a/inc/spec.h b/inc/spec.h
index b13534c..5012789 100644
--- a/inc/spec.h
+++ b/inc/spec.h
@@ -16,6 +16,7 @@
#define MARFS_NAME_LENGTH 32
#define MARFS_ENTRY_SIZE 1024
+#define MARFS_EMPTY_ENTRY 0
#define MARFS_DIR_ENTRY 1
#define MARFS_FILE_ENTRY 2
@@ -29,8 +30,9 @@ struct marfs_header {
char magic[6];
u32 version;
u32 entry_size;
+ u32 entry_count;
struct marfs_pointer main;
- u8 padding[MARFS_ENTRY_SIZE - 22];
+ u8 padding[MARFS_ENTRY_SIZE - 26];
} PACKED;
struct marfs_entry_header {
@@ -45,18 +47,27 @@ struct marfs_dir_entry_data {
struct marfs_pointer pointer;
} PACKED;
-struct marfs_dir_entry {
+struct marfs_dir_entry_info {
struct marfs_entry_header header;
u32 count;
+} PACKED;
+
+struct marfs_dir_entry {
+ struct marfs_dir_entry_info info;
struct marfs_dir_entry_data entries[MARFS_DIR_ENTRY_COUNT];
- u8 padding[MARFS_ENTRY_SIZE - sizeof(struct marfs_entry_header) - sizeof(u32) -
+ u8 padding[MARFS_ENTRY_SIZE - sizeof(struct marfs_dir_entry_info) -
(MARFS_DIR_ENTRY_COUNT * sizeof(struct marfs_dir_entry_data))];
} PACKED;
-struct marfs_file_entry {
+struct marfs_file_entry_info {
struct marfs_entry_header header;
+ u32 parent;
u32 size;
- u8 data[MARFS_ENTRY_SIZE - sizeof(struct marfs_entry_header) - sizeof(u32)];
+} PACKED;
+
+struct marfs_file_entry {
+ struct marfs_file_entry_info info;
+ u8 data[MARFS_ENTRY_SIZE - sizeof(struct marfs_file_entry_info)];
} PACKED;
#endif
diff --git a/makefile b/makefile
index 3793b61..857a080 100644
--- a/makefile
+++ b/makefile
@@ -47,7 +47,7 @@ $(MNT):
mount: disk $(MNT)
@DEV=$$(losetup -a | grep $(BUILD)/disk.img | grep -m 1 -o '/dev/loop[[:digit:]]*') && \
PART="p1" && \
- ($(SU) $(BUILD)/marfs_fuse "$$DEV$$PART" -f $(MNT) &) && \
+ ($(SU) $(BUILD)/marfs_fuse "$$DEV$$PART" -f $(MNT) -o allow_other &) && \
echo "Mounted $$DEV$$PART"
umount:
diff --git a/src/fuse.c b/src/fuse.c
index 9cfd2bf..4876f36 100644
--- a/src/fuse.c
+++ b/src/fuse.c
@@ -31,26 +31,57 @@ static void debug(const char *fmt, ...)
printf("\n");
}
-static void sector(u32 index, u32 size, void *buf)
+static void read_sector(u32 index, u32 size, void *buf)
{
- fseek(image, index * header.entry_size, SEEK_SET);
+ assert(index < header.entry_count);
+ assert(fseek(image, index * header.entry_size, SEEK_SET) == 0);
assert(fread(buf, 1, size, image) == size);
}
+static void write_sector(u32 index, u32 size, void *buf)
+{
+ assert(index < header.entry_count);
+ assert(fseek(image, index * header.entry_size, SEEK_SET) == 0);
+ assert(fwrite(buf, 1, size, image) == size);
+}
+
+static u32 find_free_sector(void)
+{
+ static u32 start = 1;
+
+ struct marfs_entry_header h;
+ for (u32 i = start; i < header.entry_count - start; i++) {
+ read_sector(i, sizeof(h), &h);
+ if (h.type == MARFS_EMPTY_ENTRY) {
+ start = i;
+ return i;
+ }
+ }
+
+ fprintf(stderr, "error: no free sector left\n");
+ exit(1);
+}
+
// first -> start = header.main.head
+// TODO: Improve
static u8 read_entry_header(const char *path, u32 start, struct marfs_entry_header *entry_header)
{
+ struct marfs_entry_header h;
+ read_sector(start, sizeof(h), &h);
+
+ if (*path == '/' && *(path + 1) == 0) {
+ *entry_header = h;
+ return 1;
+ }
+
while (*path && *path == '/')
path++;
- struct marfs_entry_header h;
- sector(start, sizeof(h), &h);
-
if (h.type == MARFS_DIR_ENTRY) {
struct marfs_dir_entry entry;
- sector(start, sizeof(entry), &entry);
- assert(entry.count <= MARFS_DIR_ENTRY_COUNT);
- for (u32 i = 0; i < entry.count; i++) {
+ read_sector(start, sizeof(entry), &entry);
+ assert(entry.info.count <= MARFS_DIR_ENTRY_COUNT);
+ for (u32 i = 0; i < entry.info.count; i++) {
struct marfs_dir_entry_data *data = &entry.entries[i];
if (!strncmp(path, data->name, data->length)) {
if (path[data->length] == '/') {
@@ -58,14 +89,17 @@ static u8 read_entry_header(const char *path, u32 start, struct marfs_entry_head
entry_header);
}
if (!path[data->length]) {
- *entry_header = h;
+ struct marfs_entry_header sub;
+ read_sector(data->pointer.head, sizeof(sub), &sub);
+ *entry_header = sub;
return 1;
}
}
}
- if (entry.header.next != MARFS_END)
- return read_entry_header(path, entry.header.next, entry_header);
+ if (entry.info.header.next != MARFS_END)
+ return read_entry_header(path, entry.info.header.next, entry_header);
+ *entry_header = h;
} else if (h.type == MARFS_FILE_ENTRY) {
*entry_header = h;
return 1;
@@ -91,8 +125,10 @@ static void marfs_destroy(void *data)
debug("destroy()");
UNUSED(data);
- if (image)
+ if (image) {
+ write_sector(0, sizeof(header), &header);
fclose(image);
+ }
}
static int marfs_open(const char *file_path, struct fuse_file_info *file_info)
@@ -113,13 +149,21 @@ static int marfs_getattr(const char *path, struct stat *stat, struct fuse_file_i
UNUSED(info);
memset(stat, 0, sizeof(*stat));
- if (strcmp(path, "/") == 0) {
- stat->st_mode = S_IFDIR | 0000;
- } else if (strcmp(path + 1, "aah") == 0) {
- stat->st_mode = S_IFREG | 0000;
- stat->st_size = 0;
- } else {
+
+ struct marfs_entry_header h;
+ u8 aah = read_entry_header(path, header.main.head, &h);
+ if (!aah)
return -ENOENT;
+
+ if (h.type == MARFS_DIR_ENTRY) {
+ stat->st_mode = S_IFDIR;
+ } else if (h.type == MARFS_FILE_ENTRY) {
+ struct marfs_file_entry_info i;
+ read_sector(h.id, sizeof(i), &i);
+ stat->st_mode = S_IFREG;
+ stat->st_size = i.size;
+ } else {
+ return -EINVAL;
}
return 0;
@@ -129,29 +173,29 @@ static int marfs_readdir(const char *path, void *buf, fuse_fill_dir_t fill, off_
struct fuse_file_info *file_info, enum fuse_readdir_flags flags)
{
debug("readdir() on %s and offset %lu", path, offset);
-
UNUSED(offset);
UNUSED(file_info);
UNUSED(flags);
- if (strcmp(path, "/") != 0)
+
+ struct marfs_entry_header h;
+ u8 aah = read_entry_header(path, header.main.head, &h);
+ if (!aah)
return -ENOENT;
+ if (h.type != MARFS_DIR_ENTRY)
+ return -EINVAL;
+
fill(buf, ".", NULL, 0, 0);
fill(buf, "..", NULL, 0, 0);
- fill(buf, "aah", NULL, 0, 0);
- return 0;
-}
+ struct marfs_dir_entry d;
+ u32 sector = h.id;
+ do {
+ read_sector(sector, sizeof(d), &d);
+ for (u32 i = 0; i < d.info.count; i++)
+ fill(buf, d.entries[i].name, NULL, 0, 0);
+ } while ((sector = h.next) != MARFS_END);
-static int marfs_release(const char *path, struct fuse_file_info *file_info)
-{
- debug("release() on %s", path);
- return 0;
-}
-
-static int marfs_releasedir(const char *path, struct fuse_file_info *file_info)
-{
- debug("releasedir() on %s", path);
return 0;
}
@@ -159,6 +203,24 @@ static int marfs_read(const char *path, char *buf, size_t to_read, off_t offset,
struct fuse_file_info *file_info)
{
debug("read() on %s, %lu", path, to_read);
+ UNUSED(offset);
+ UNUSED(file_info);
+
+ struct marfs_entry_header h;
+ u8 aah = read_entry_header(path, header.main.head, &h);
+ if (!aah)
+ return -ENOENT;
+
+ if (h.type != MARFS_FILE_ENTRY)
+ return -EISDIR;
+
+ struct marfs_file_entry f;
+
+ // TODO: Multiple sector read
+ read_sector(h.id, sizeof(f), &f);
+ to_read = MIN(to_read, f.info.size);
+ memcpy(buf, f.data, MIN(sizeof(f.data), to_read));
+
return to_read;
}
@@ -166,12 +228,82 @@ static int marfs_write(const char *path, const char *buf, size_t to_write, off_t
struct fuse_file_info *file_info)
{
debug("write() on %s", path);
+ UNUSED(offset);
+ UNUSED(file_info);
+
+ struct marfs_entry_header h;
+ u8 aah = read_entry_header(path, header.main.head, &h);
+ if (!aah)
+ return -ENOENT;
+
+ if (h.type != MARFS_FILE_ENTRY)
+ return -EISDIR;
+
+ struct marfs_file_entry f;
+
+ // TODO: Multiple sector write
+ read_sector(h.id, sizeof(f), &f);
+ memcpy(f.data, buf, MIN(sizeof(f.data), to_write));
+ f.info.size = to_write; // TODO: Append??
+ write_sector(h.id, sizeof(f), &f);
+
return to_write;
}
static int marfs_create(const char *path, mode_t mode, struct fuse_file_info *file_info)
{
debug("create() on %s", path);
+ UNUSED(mode);
+ UNUSED(file_info);
+
+ struct marfs_entry_header parent = { .type = 0 };
+ u8 aah = read_entry_header(path, header.main.head, &parent);
+ if (aah) {
+ debug("%s already exists\n", path);
+ errno = EEXIST;
+ return -1;
+ }
+ if (parent.type != MARFS_DIR_ENTRY) {
+ debug("%s could not get created\n", path);
+ return -1;
+ }
+
+ u32 sector = find_free_sector();
+ struct marfs_file_entry_info info = {
+ .header.type = MARFS_FILE_ENTRY,
+ .header.id = sector,
+ .header.prev = MARFS_END,
+ .header.next = MARFS_END,
+ .size = 0,
+ };
+ write_sector(sector, sizeof(info), &info);
+
+ char *base = strrchr(path, '/');
+ if (!(base++))
+ return -EINVAL;
+
+ u32 last = parent.id;
+ while (parent.next != MARFS_END)
+ last = parent.next;
+
+ struct marfs_dir_entry dir;
+ read_sector(last, sizeof(dir), &dir);
+
+ assert(dir.info.count + 1 < MARFS_DIR_ENTRY_COUNT); // TODO: Create new dir entry at end
+
+ struct marfs_dir_entry_data data = (struct marfs_dir_entry_data){
+ .length = strlen(base),
+ .pointer = MARFS_POINT(sector, sector),
+ };
+
+ if (data.length > MARFS_NAME_LENGTH)
+ return -EINVAL;
+
+ strcpy(data.name, base);
+ dir.entries[dir.info.count++] = data;
+
+ write_sector(last, sizeof(dir), &dir);
+
return 0;
}
@@ -219,8 +351,6 @@ static struct fuse_operations operations = {
.opendir = marfs_opendir,
.getattr = marfs_getattr,
.readdir = marfs_readdir,
- .release = marfs_release,
- .releasedir = marfs_releasedir,
.read = marfs_read,
.write = marfs_write,
.create = marfs_create,
@@ -244,7 +374,7 @@ int main(int argc, char **argv)
argv++;
argc--;
- image = fopen(path, "r");
+ image = fopen(path, "r+");
if (!image) {
fprintf(stderr, "error: invalid image path '%s' specified: %s\n", path,
strerror(errno));
diff --git a/src/mkfs.c b/src/mkfs.c
index 5d539d0..960fedd 100644
--- a/src/mkfs.c
+++ b/src/mkfs.c
@@ -20,16 +20,35 @@ int main(int argc, char *argv[])
return 1;
}
+ printf("Formatting %s...\n", argv[1]);
+
FILE *image = fopen(argv[1], "r+");
if (!image) {
fprintf(stderr, "%s: error: no valid image specified\n", argv[0]);
return 1;
}
+ fseek(image, 0, SEEK_END);
+ size_t size = ftell(image);
+
+ if (size < 2 * MARFS_ENTRY_SIZE) {
+ fprintf(stderr, "%s: error: too small image size: %luB but at least %dB needed\n",
+ argv[0], size, 2 * MARFS_ENTRY_SIZE);
+ return 1;
+ }
+
+ struct marfs_entry_header entry_header = { 0 };
+ for (u32 i = 0; i < size / MARFS_ENTRY_SIZE; i++) {
+ fseek(image, i * MARFS_ENTRY_SIZE, SEEK_SET);
+ assert(fwrite(&entry_header, 1, sizeof(entry_header), image) ==
+ sizeof(entry_header));
+ }
+
struct marfs_header header = {
.magic = MARFS_MAGIC,
.version = MARFS_SPEC_VERSION,
.entry_size = MARFS_ENTRY_SIZE,
+ .entry_count = size / MARFS_ENTRY_SIZE,
.main = MARFS_POINT(1, 1),
.padding = { 0 },
};
@@ -40,15 +59,16 @@ int main(int argc, char *argv[])
fprintf(stderr, "%s: error: header write failed: %lu bytes written\n", argv[0],
write);
- struct marfs_dir_entry main = {
+ struct marfs_dir_entry_info info = {
.header.type = MARFS_DIR_ENTRY,
+ .header.id = 1,
.header.prev = MARFS_END,
.header.next = MARFS_END,
+ .count = 0,
};
- main.entries[0].name[0] = 0;
- write = fwrite(&main, 1, sizeof(main), image);
- if (write != sizeof(main))
+ write = fwrite(&info, 1, sizeof(info), image);
+ if (write != sizeof(info))
fprintf(stderr, "%s: error: main directory write failed: %lu bytes written\n",
argv[0], write);