Browse Source

Initial version (0.0.1)

master v0.0.1
Emanuele HF 2 years ago
parent
commit
2eafb8bab0
  1. 12
      README.md
  2. 3
      build.sh
  3. 83
      src/main.c
  4. 69
      src/minfs.c
  5. 38
      src/minfs.h
  6. 160
      src/operations.c
  7. 8
      src/operations.h
  8. 53
      src/utils.h

12
README.md

@ -2,3 +2,15 @@
### MinFS file system FUSE implementation
Read-only implementation of MinFS file system (found in some chinese devices) using FUSE.
## Build
```bash
git clone https://git.hackfront.eu/Hackfront/minfs-fuse.git
cd minfs-fuse
./build.sh
```
## Usage
```bash
minfs [<fuse options>] <mount point>
```

3
build.sh

@ -0,0 +1,3 @@
#!/bin/bash
gcc -Wall `pkg-config fuse3 --cflags --libs` -DFUSE_USE_VERSION=30 -o build/minfs src/*.c
exit 0

83
src/main.c

@ -0,0 +1,83 @@
#include <stdlib.h>
#include <string.h>
#include <fuse.h>
#include <unistd.h>
#include "minfs.h"
#include "operations.h"
#include "utils.h"
#define BLOCK_DEV "../extracted/ROOTFS.bin"
//#define BLOCK_DEV "./mnt1/ramdisk.iso"
int main(int argc, char **argv)
{
int rc = 1;
fs_data_t *fs_data = NULL;
int fd = open(BLOCK_DEV, O_RDONLY);
if (fd < 0) {
ERROR_PRINTF("Cannot open file\n");
goto cleanup;
}
fs_data = malloc(sizeof(fs_data_t));
if (fs_data == NULL) {
ERROR_PRINTF("Cannot allocate filesystem data buffer\n");
goto cleanup;
}
minfs_header_t header;
if (pread(fd, &header, sizeof(minfs_header_t), 0) != sizeof(minfs_header_t)) {
ERROR_PRINTF("Cannot read header\n");
goto cleanup;
}
PRINT_HEADER(header);
if (strcmp(header.magic, "MINFS")) {
ERROR_PRINTF("Invalid file system magic\n");
goto cleanup;
}
int file_size = lseek(fd, 0, SEEK_END);
if (file_size < 0) {
ERROR_PRINTF("Cannot estimate file size\n");
goto cleanup;
}
if (file_size < header.image_size) {
ERROR_PRINTF("Invalid file system size\n");
goto cleanup;
}
fs_data->fd = fd;
fs_data->tree_offset = header.tree_offset;
fs_data->tree_size = header.tree_size;
fs_data->root_size = header.root_size;
fs_data->tree_ptr = malloc(header.tree_size);
if (fs_data->tree_ptr == NULL) {
ERROR_PRINTF("Error allocating tree buffer\n");
goto cleanup;
}
if (pread(fd, fs_data->tree_ptr, header.tree_size, header.tree_offset) != header.tree_size) {
ERROR_PRINTF("Error reading tree\n");
goto cleanup;
}
rc = fuse_main(argc, argv, &fs_ops, fs_data);
cleanup:
if (fs_data && fs_data->tree_ptr) {
free(fs_data->tree_ptr);
}
if (fs_data) {
free(fs_data);
}
return rc;
}

69
src/minfs.c

@ -0,0 +1,69 @@
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include "minfs.h"
#include "utils.h"
minfs_entry_t *minfs_get_entry(const char *path, void *tree_ptr,
minfs_long_t tree_offset, minfs_long_t tree_size,
minfs_long_t root_size)
{
void *dentry_ptr = tree_ptr;
minfs_long_t dentry_offset = 0;
minfs_long_t dentry_size = root_size;
minfs_entry_t *cur_entry = NULL;
bool dir_flag = true;
search:
while (path[0] == '/') {
path++;
}
size_t part_length = 0;
while (path[part_length] != '/' && path[part_length] != '\0') {
part_length++;
}
if (part_length == 0) {
return cur_entry;
}
if (!dir_flag) {
return NULL;
}
while (dentry_offset + sizeof(minfs_entry_t) <= dentry_size) {
cur_entry = dentry_ptr + dentry_offset;
PRINT_ENTRY(cur_entry);
if ((dentry_offset + cur_entry->name_length) > dentry_size) {
break;
}
if (
cur_entry->name_length == part_length &&
!memcmp((char *)(cur_entry) + sizeof(minfs_entry_t), path, part_length)
) {
path += part_length;
dentry_ptr = tree_ptr + cur_entry->offset - tree_offset;
dentry_offset = 0;
dentry_size = cur_entry->raw_size;
dir_flag = !!(cur_entry->flags & MF_FLAG_DIR);
goto search;
}
dentry_offset += cur_entry->entry_length;
if (dentry_offset % 4) {
dentry_offset += 4 - (dentry_offset %4);
}
}
return NULL;
}

38
src/minfs.h

@ -0,0 +1,38 @@
#ifndef MF_MINFS
#define MF_MINFS
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#define MF_FLAG_DIR (1 << 0)
#define MF_FLAG_EXTRA (1 << 1)
#define MF_FLAG_COMPR (1 << 2)
typedef uint16_t minfs_short_t;
typedef uint32_t minfs_long_t;
typedef struct {
char magic[6];
minfs_short_t version;
minfs_long_t tree_offset;
minfs_long_t root_size;
minfs_long_t tree_entries;
minfs_long_t tree_size;
minfs_long_t fdata_length;
minfs_long_t image_size;
} minfs_header_t;
typedef struct {
minfs_long_t offset;
minfs_long_t raw_size;
minfs_long_t orig_size;
minfs_short_t entry_length;
minfs_short_t flags;
minfs_short_t name_length;
minfs_short_t extra_length;
} minfs_entry_t;
minfs_entry_t *minfs_get_entry(const char *, void *, minfs_long_t, minfs_long_t, minfs_long_t);
#endif /* end of include guard: MF_MINFS */

160
src/operations.c

@ -0,0 +1,160 @@
#include <errno.h>
#include <string.h>
#include <fuse.h>
#include <unistd.h>
#include "minfs.h"
#include "utils.h"
static int fs_getattr(const char *path, struct stat *stbuf,
struct fuse_file_info *fi)
{
struct fuse_context *context = fuse_get_context();
fs_data_t *fs_data = context->private_data;
if (path[0] == '/' && path[1] == '\0') {
stbuf->st_ino = (off_t)(fs_data->tree_offset);
stbuf->st_mode = S_IFDIR | 0555;
stbuf->st_nlink = 2;
return 0;
}
minfs_entry_t *entry = minfs_get_entry(path, fs_data->tree_ptr,
fs_data->tree_offset, fs_data->tree_size, fs_data->root_size);
if (entry == NULL) {
return -ENOENT;
}
memset(stbuf, 0, sizeof(struct stat));
stbuf->st_ino = (off_t)(entry) - (off_t)(fs_data->tree_ptr) + (off_t)(fs_data->tree_offset);
stbuf->st_size = entry->orig_size;
if (entry->flags & MF_FLAG_DIR) {
stbuf->st_mode = S_IFDIR | 0555;
stbuf->st_nlink = 2;
} else if (entry->flags & MF_FLAG_COMPR) {
stbuf->st_mode = S_IFREG | 0000;
stbuf->st_nlink = 1;
} else {
stbuf->st_mode = S_IFREG | 0444;
stbuf->st_nlink = 1;
}
return 0;
}
static int fs_open(const char *path, struct fuse_file_info *fi)
{
struct fuse_context *context = fuse_get_context();
fs_data_t *fs_data = context->private_data;
minfs_entry_t *entry = minfs_get_entry(path, fs_data->tree_ptr,
fs_data->tree_offset, fs_data->tree_size, fs_data->root_size);
if (entry == NULL) {
return -ENOENT;
}
if ((fi->flags & O_ACCMODE) != O_RDONLY) {
return -EACCES;
}
if (entry->flags & MF_FLAG_COMPR) {
return -EACCES;
}
return 0;
}
static int fs_read(const char *path, char *buf, size_t size, off_t offset,
struct fuse_file_info *fi)
{
struct fuse_context *context = fuse_get_context();
fs_data_t *fs_data = context->private_data;
minfs_entry_t *entry = minfs_get_entry(path, fs_data->tree_ptr,
fs_data->tree_offset, fs_data->tree_size, fs_data->root_size);
if (entry == NULL) {
return -ENOENT;
}
if (entry->flags & MF_FLAG_COMPR) {
return -EACCES;
}
if (offset >= entry->orig_size) {
return 0;
}
if (offset + size > entry->orig_size) {
size = entry->orig_size - offset;
}
return pread(fs_data->fd, buf, size, entry->offset + offset);
}
static int fs_readdir(const char *path, void *data, fuse_fill_dir_t filler,
off_t offset, struct fuse_file_info *fi, enum fuse_readdir_flags flags)
{
struct fuse_context *context = fuse_get_context();
fs_data_t *fs_data = context->private_data;
minfs_long_t entry_offset;
minfs_long_t dentry_size;
if (path[0] == '/' && path[1] == '\0') {
entry_offset = fs_data->tree_offset;
dentry_size = fs_data->root_size;
} else {
minfs_entry_t *entry = minfs_get_entry(path, fs_data->tree_ptr,
fs_data->tree_offset, fs_data->tree_size, fs_data->root_size);
if (entry == NULL) {
return -ENOENT;
}
entry_offset = entry->offset;
dentry_size = entry->raw_size;
}
filler(data, ".", NULL, 0, 0);
filler(data, "..", NULL, 0, 0);
char name_buffer[128];
struct stat stat_info;
void *dentry_ptr = fs_data->tree_ptr + entry_offset - fs_data->tree_offset;
minfs_long_t dentry_offset = 0;
while ((dentry_offset + sizeof(minfs_entry_t)) <= dentry_size) {
minfs_entry_t *cur_entry = (minfs_entry_t *)(dentry_ptr + dentry_offset);
size_t name_length = MIN_VAL(cur_entry->name_length, sizeof(name_buffer) - 1);
memcpy(name_buffer, (char *)(cur_entry) + sizeof(minfs_entry_t), name_length);
name_buffer[name_length] = '\0';
memset(&stat_info, 0, sizeof(struct stat));
stat_info.st_size = cur_entry->orig_size;
if (cur_entry->flags & MF_FLAG_DIR) {
stat_info.st_mode = S_IFDIR | 0555;
stat_info.st_nlink = 2;
} else {
stat_info.st_mode = S_IFREG | 0444;
stat_info.st_nlink = 1;
}
filler(data, name_buffer, &stat_info, 0, 0);
dentry_offset += cur_entry->entry_length;
if (dentry_offset % 4) {
dentry_offset += 4 - (dentry_offset % 4);
}
}
return 0;
}
struct fuse_operations fs_ops = {
.getattr = fs_getattr,
.open = fs_open,
.read = fs_read,
.readdir = fs_readdir,
};

8
src/operations.h

@ -0,0 +1,8 @@
#ifndef MF_OPERATIONS
#define MF_OPERATIONS
#include <fuse.h>
extern struct fuse_operations fs_ops;
#endif /* end of include guard: MF_OPERATIONS */

53
src/utils.h

@ -0,0 +1,53 @@
#ifndef MF_UTILS
#define MF_UTILS
#define DEBUG_PRINTF(_fmt, ...)
//#define DEBUG_PRINTF(_fmt, ...) printf(_fmt, ##__VA_ARGS__)
#define ERROR_PRINTF(_fmt, ...) printf(_fmt, ##__VA_ARGS__)
#define MIN_VAL(a, b) ((a < b) ? (a) : (b))
#define BTB_FMT "%c%c%c%c%c%c%c%c"
#define BTB_VALUES(value) \
(value & (1 << 7) ? '1': '0'), \
(value & (1 << 6) ? '1': '0'), \
(value & (1 << 5) ? '1': '0'), \
(value & (1 << 4) ? '1': '0'), \
(value & (1 << 3) ? '1': '0'), \
(value & (1 << 2) ? '1': '0'), \
(value & (1 << 1) ? '1': '0'), \
(value & (1 << 0) ? '1': '0')
#define PRINT_HEADER(header) DEBUG_PRINTF( \
"header = {\n" \
" .magic = %s,\n" \
" .version = %4x,\n" \
" .tree_offset = %8x,\n" \
" .root_size = %8x,\n" \
" .tree_entries = %8x,\n" \
" .tree_size = %8x,\n" \
" .fdata_length = %8x,\n" \
" .image_size = %8x,\n" \
"};\n", \
header.magic, header.version, header.tree_offset, header.root_size, \
header.tree_entries, header.tree_size, header.fdata_length, \
header.image_size \
);
#define PRINT_ENTRY(entry) DEBUG_PRINTF( \
"entry = { .offset = %5x, .raw_size = %5x, .orig_size = %5x, " \
".field_1 = %04x, .flags = %04x, .extra_length = %3x, " \
".name_data = \"%.*s\" };\n", entry->offset, entry->raw_size, \
entry->orig_size, entry->field_1, entry->flags, entry->extra_length, \
entry->name_length, (char *)(entry) + sizeof(minfs_entry_t) \
)
typedef struct {
int fd;
void *tree_ptr;
minfs_long_t tree_offset;
minfs_long_t tree_size;
minfs_long_t root_size;
} fs_data_t;
#endif /* end of include guard: MF_UTILS */
Loading…
Cancel
Save