foxdos/tool/mfstool.c

239 lines
5.7 KiB
C

#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <fs.h> // structs for mothfs
#include <mfs_hdr.h> // bootcode
#define setbit(x, y) x[y >> 3] |= 1 << (y & 7)
#define NUM_MULTICALL 1
typedef struct {
char* name;
int (*fn)(int, char**);
} multicall;
int pstrlen(char* d, char* typ) {
int i = 0;
while((d[i] ^ '/') && d[i] != 0) i++; // slash or null terminated
*typ = d[i] ? 1 : 0;
return i;
}
char** psplit(char* path, int* i) {
int l, a = 8;
char** rpth = malloc(sizeof(char*)*a);
*i = 0;
char x = 1, dir = 0;
if(*path == '/') {
rpth[(*i)++] = memcpy(malloc(2), "/", 2);
path++;
}
if(path[strlen(path) - 1] == '/') dir = 1;
while(1) {
while(*path == '/') path++;
l = pstrlen(path, &x);
if(l < 3 && *path == '.') {
if(path[1] == '.' && *i != 0) free(rpth[*i--]);
} else {
rpth[*i] = memcpy(malloc(l + 1), path, l);
rpth[(*i)++][l] = 0;
path += l + x; // prevent buffer overrun
}
if(!x) break;
if(*i >= a) rpth = realloc(rpth, sizeof(char*)*(a += 4));
}
if(dir) {
if(*i + 1 >= a) rpth = realloc(rpth, sizeof(char*)*(a += 4));
rpth[(*i)++] = memcpy(malloc(2), "/", 2);
}
return rpth;
}
int xstrlen(char* s) {
int i = strlen(s) - 1;
for(;s[i] != '.' && i; i--);
return i;
}
// s: passed path
// d: path in fs to check against
// TODO does this even work
int nmatch(char* s, char* d) {
int x = xstrlen(s);
for(int i = 0; i < (x > 8 ? 8 : x); i++) {
if(
(s[i] & ((s[i] >= 'a' && s[i] <= 'z') ? 0xDF: 0xFF)) != d[i]
) return 0;
}
s = s + x + 1;
x = strlen(s);
for(int i = 0; i < (x > 3 ? 3 : x); i++) {
if(
(s[i] & ((s[i] >= 'a' && s[i] <= 'z') ? 0xDF: 0xFF)) != d[i]
) return 0;
}
}
// returns sector of file or directory
uint32_t mfs_traverse(int fd, uint32_t from, char* name) {
uint64_t r = 0; // sector to return?
mothfs_file d, next;
int sz;
char** rpth = psplit(name, &sz);
uint32_t* ns = malloc(512);
int i = 0;
if(!strcmp(*rpth, "/")) {
lseek(fd, 0, SEEK_SET);
read(fd, &d, 512);
mothfs_header* e = (mothfs_header*)&d; // reuse buffer
from = e->reserved + e->abm + 1;
i++;
}
for(; i < sz; i++) { // TODO . and ..
lseek(fd, ((uint64_t)from) << 9, SEEK_SET);
read(fd, &d, 512);
switch(d.type) {
case 0: // file
r = strcmp(rpth[sz - 1], "/") ? from : 0; // fail if last element of path is a /
if(sz - !strcmp(rpth[sz - 1], "/") - 1 != i) r = 0; // TODO does this work. fail if the current element is not the last one, excluding a possible "/"
goto ret;
break;
case 1: // directory
uint32_t* sp = d.data + 121;
for(int c = 0; c < 121; c++) {
if(!d.data[c]) {
r = 0;
goto ret;
}
lseek(fd, ((uint64_t)d.data[c]) << 9, SEEK_SET);
read(fd, &next, 512);
if(nmatch(next.name, rpth[i])) {
// TODO set r if last element
if(i == sz - 1 - !strcmp(rpth[sz - 1], "/")) {
r = d.data[c];
goto ret;
}
from = d.data[c];
break;
}
} // else check linked sector:
cls: lseek(fd, ((uint64_t)(*sp)) << 9, SEEK_SET);
read(fd, ns, 512);
for(int c = 0; c < 127; c++) {
if(!ns[c]) {
r = 0;
goto ret;
}
lseek(fd, ((uint64_t)d.data[c]) << 9, SEEK_SET);
read(fd, &next, 512);
if(nmatch(next.name, rpth[i])) {
// TODO set r if last element
if(i == sz - 1 - !strcmp(rpth[sz - 1], "/")) {
r = d.data[c];
goto ret;
}
from = d.data[c];
break;
}
} // else go to next linked sector:
sp = ns + 127;
goto cls;
break;
}
}
ret: for(; i < sz; i++) free(rpth[i]);
free(rpth);
free(ns);
return r;
}
#define LFIL argv[1]
#define SIZE argv[2]
#define SKIP argv[3]
int mfs_new(int argc, char** argv) {
if(argc < 4) return !!printf("need arguments: [file] [size] [sector offset]\n");
int fd;
if((fd = open(LFIL, O_RDWR|O_CREAT, 0644)) < 0) return !!printf("could not open %s\n", LFIL);
uint64_t sz = atol(SIZE);
sz = (sz + ((sz & 0x1FF) ? 512 : 0)) >> 9; // round up to number of sectors
uint64_t skip = atol(SKIP);
ftruncate(fd, sz << 9);
mothfs_header* header = (mothfs_header*)mfs_hdr;
header->size = sz;
header->offset = skip;
header->reserved = 127;
// currently uses 1/8 of the partition but that isnt too bad for now
header->abm = (sz + ((sz & 7) ? 8 : 0)) >> 3;
write(fd, header, 512); // write bootloader
// start writing initial abm
lseek(fd, 512*(header->reserved + 1), SEEK_SET);
// volume name
memcpy(header->volname, "mothfs\0????????", 15); // this will look really funny if parsed wrong
// reserve the boot sector, bootcode area, and abm
uint8_t* rsv = malloc(header->abm << 9);
memset(rsv, 0, header->abm << 9);
for(unsigned long i = 0; i < 1 + header->reserved + header->abm; i++) setbit(rsv, i);
write(fd, rsv, header->abm << 9);
free(rsv);
mothfs_file root;
memset(&root, 0, sizeof(mothfs_file));
root.type = MFS_DIR;
root.ext = 0;
*root.data = 0; // no files yet - that is the user's job
// set root to itself
root.dir = ((uint64_t)lseek(fd, 0, SEEK_CUR)) >> 9;
write(fd, &root, 512);
}
int mfs_insert(int argc, char** argv) {
if(argc < 3) return !!printf("need arguments: [mothfs file] [file to insert]\n");
}
multicall mc[NUM_MULTICALL] = {
{"new", mfs_new},
// {"insert", mfs_insert},
};
int main(int argc, char** argv) {
int y;
char** x = psplit("//doc/toc////foc//", &y);
printf("%i\n", y);
for(int i = 0; i < y; i++) printf("%s\n", x[i]);
if(argc < 2) err: {
printf("valid functions:");
for(int i = 0; i < NUM_MULTICALL; i++) printf(" %s%c", mc[i].name, ((NUM_MULTICALL - i) ^ 1) ? ',' : '\n');
return 1;
}
for(int i = 0; i < NUM_MULTICALL; i++) if(!strcmp(argv[1], mc[i].name)) return mc[i].fn(argc - 1, argv + 1);
goto err;
}