mfsreader/readmfs.c

222 lines
5.7 KiB
C

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#define BLOCKSIZE 512
#define ALLOCBLOCKSIZE 1024
uint16_t allocBM[1024] = { 0 };
typedef struct __attribute__((packed)) {
uint16_t drSigWord;
uint32_t drCrDate;
uint32_t drLsBkUp;
uint16_t drAtrb;
uint16_t drNmFls;
uint16_t drDirSt;
uint16_t drBlLen;
uint16_t drNmAlBlks;
uint32_t drAlBlkSiz;
uint32_t drClpSiz;
uint16_t drAlBlSt;
uint32_t drNxtFNum;
uint16_t drFreeBks;
uint8_t drVN;
char drVName[255];
} mfs_vol_info;
typedef struct __attribute__((packed)) {
uint8_t flFlags; // bit 7 = 1 if entry used, bit 0 = 1 if file locks
uint8_t flTyp; // version number
uint8_t flUsrWds[16]; // Finder info
uint32_t flFlNum; // file number
uint16_t flStBlk; // first allocaion block of data fork
uint32_t flLgLen; // logical end-of-file of data fork
uint32_t flPyLen; // physical end-of-file of data fork
uint16_t flRStBlk; // first allocaion block of resource fork
uint32_t flRLgLen; // logical end-of-file of resource fork
uint32_t flRPyLen; // physical end-of-file of resource fork
uint32_t flCrDat; // date and time of creation
uint32_t flMdDat; // date and time of modification
uint8_t flNam; // length of file name
char flName[255]; // file name bytes
} mfs_dir_entry;
uint32_t b2l32(uint32_t num) {
return ((num>>24)&0xff) | ((num<<8)&0xff0000) | ((num>>8)&0xff00) | ((num<<24)&0xff000000);
}
uint16_t b2l16(uint16_t num) {
return ((num>>8)&0xff) | ((num<<8)&0xff00);
}
void writeFile(uint8_t *im, int fd, uint16_t nFirstAllocBlk, uint16_t firstBlock, uint32_t len) {
int nextBlock = firstBlock;
int blkn = nFirstAllocBlk * BLOCKSIZE;
uint8_t *pos;
int size = len;
while (nextBlock >= 2) {
pos = im + blkn + ALLOCBLOCKSIZE * (nextBlock - 2);
write(fd, pos, (size < ALLOCBLOCKSIZE) ? size : ALLOCBLOCKSIZE);
nextBlock = allocBM[nextBlock];
size = size - ALLOCBLOCKSIZE;
}
}
void readdir(uint8_t *im, uint16_t nFirstAllocBlk, uint16_t firstBlock, uint16_t nBlocks, uint16_t nFiles) {
uint32_t pos;
mfs_dir_entry *d;
int n = 0;
char fn[256];
int fd;
char exfn[256+5];
pos = firstBlock * BLOCKSIZE;
while (n < nBlocks) {
d = (mfs_dir_entry *)(im + pos);
memcpy(fn, &(d->flName), d->flNam);
fn[d->flNam] = '\0';
printf("Pos: %d = 0x%08x used = %s\n", pos, pos, (d->flFlags & 0x80) ? "yes":"no");
printf("File %02d length %d: >>%s<<\n", n, d->flNam, fn);
printf("DATA fork: first block %d log eof %d phys eof %d\n",
b2l16(d->flStBlk), b2l32(d->flLgLen), b2l32(d->flPyLen));
printf("RSRC fork: first block %d log eof %d phys eof %d\n",
b2l16(d->flRStBlk), b2l32(d->flRLgLen), b2l32(d->flRPyLen));
printf("\n");
pos = pos + 51 + ((d->flNam % 2) ? d->flNam : d->flNam+1);
// write file only if entry is used
if (d->flFlags & 0x80) {
// write data and resource forks
snprintf(exfn, 256+5, "%s.DATA", fn);
fd = open(exfn, O_CREAT|O_WRONLY, 0666);
if (fd < 0) {
fprintf(stderr, "open(%s) failed\n", exfn);
exit(1);
}
writeFile(im, fd, nFirstAllocBlk, b2l16(d->flStBlk), b2l32(d->flLgLen));
close(fd);
snprintf(exfn, 256+5, "%s.RSRC", fn);
fd = open(exfn, O_CREAT|O_WRONLY, 0666);
if (fd < 0) {
fprintf(stderr, "open(%s) failed\n", exfn);
exit(1);
}
writeFile(im, fd, nFirstAllocBlk, b2l16(d->flRStBlk), b2l32(d->flRLgLen));
close(fd);
}
if (pos % BLOCKSIZE > BLOCKSIZE - 51) {
printf("Skipping to next block\n");
pos = (pos + BLOCKSIZE) / BLOCKSIZE * BLOCKSIZE;
n++;
}
}
}
int main(int argc, char **argv) {
if (argc < 2) {
fprintf(stderr, "Usage: %s disk.img\n", argv[0]);
exit(1);
}
struct stat st;
if (stat(argv[1], &st) < 0) {
fprintf(stderr, "stat(%s) failed\n", argv[1]);
exit(1);
}
uint8_t *im = malloc(st.st_size);
if (im == (uint8_t *)0) {
fprintf(stderr, "malloc(%lld) failed\n", st.st_size);
exit(1);
}
int fd;
fd = open(argv[1], O_RDONLY);
if (fd < 0) {
fprintf(stderr, "open(%s) failed\n", argv[1]);
exit(1);
}
size_t n;
n = read(fd, im, st.st_size);
if (n != st.st_size) {
fprintf(stderr, "short read, expected %zu, got %lld bytes\n", n, st.st_size);
exit(1);
}
close(fd);
printf("Image %s loaded into memory\n", argv[1]);
mfs_vol_info *vol;
vol = (mfs_vol_info *)(im + 2 * BLOCKSIZE);
if (vol->drSigWord != 0xd7d2) {
printf("Volume signature invalid: %04x, expected 0xd2d7\n", vol->drSigWord);
}
char vn[256];
memcpy(vn, vol->drVName, 256);
vn[vol->drVN] = '\0';
printf("Volume name: %s\n", vn);
uint16_t nFiles;
nFiles = b2l16(vol->drNmFls);
printf("Number of files: %d\n", nFiles);
uint16_t firstBlock;
firstBlock = b2l16(vol->drDirSt);
printf("First block of directory: %d\n", firstBlock);
uint16_t nBlocks;
nBlocks = b2l16(vol->drBlLen);
printf("Length of dir: %d blocks\n", nBlocks);
uint16_t nFirstAllocBlk;
nFirstAllocBlk = b2l16(vol->drAlBlSt);
printf("First alloc block: %d\n", nFirstAllocBlk);
uint16_t nAllocBlks;
nAllocBlks = b2l16(vol->drNmAlBlks);
printf("Number of alloc blocks: %d\n", nAllocBlks);
printf("Allocation bitmap at %08x:\n\n", 2 * BLOCKSIZE + 36 + vol->drVN + 1);
uint8_t *bm;
uint16_t blkn1;
uint16_t blkn2;
int nb = 2; // first block in alloc bitmap is 2
bm = im + 2 * BLOCKSIZE + 64;
while (nb < b2l16(vol->drNmAlBlks) + 2) {
// 12 bit per entry!
blkn1 = (*(bm+0) << 4) + ((*(bm+1) & 0xF0) >> 4);
blkn2 = (*(bm+1) & 0x0F << 8) + *(bm+2);
printf("%d %d ", blkn1, blkn2);
bm += 3;
allocBM[nb] = blkn1;
allocBM[nb+1] = blkn2;
nb += 2;
}
printf("\n\n");
readdir(im, nFirstAllocBlk, firstBlock, nBlocks, nFiles);
}