summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2008-12-31 00:26:34 (GMT)
committerH. Peter Anvin <hpa@zytor.com>2008-12-31 00:26:34 (GMT)
commit140bf5601d8400846cbf844ab5a9aaf62bbfb784 (patch)
tree3561494a2b8540f40c9d0ac74e8b5aa9dc3f45a8
downloadabcdisk-140bf5601d8400846cbf844ab5a9aaf62bbfb784.zip
abcdisk-140bf5601d8400846cbf844ab5a9aaf62bbfb784.tar.gz
abcdisk-140bf5601d8400846cbf844ab5a9aaf62bbfb784.tar.bz2
abcdisk-140bf5601d8400846cbf844ab5a9aaf62bbfb784.tar.xz
Tool to write an UFD-DOS filesystem image
-rw-r--r--Makefile18
-rw-r--r--abcwrite.c404
2 files changed, 422 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..22625f8
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,18 @@
+CC = cc
+CFLAGS = -O -g
+LDFLAGS =
+ifneq (,$(findstring _NT,$(shell uname -s)))
+O = obj
+X = .exe
+else
+O = o
+X =
+endif
+
+all : abcwrite$(X)
+
+abcwrite$(X): abcwrite.c
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
+
+clean:
+ rm -f abcwrite$(X) *.$(O) *~
diff --git a/abcwrite.c b/abcwrite.c
new file mode 100644
index 0000000..c6373a1
--- /dev/null
+++ b/abcwrite.c
@@ -0,0 +1,404 @@
+/*
+ * abcwrite.c
+ *
+ * Program to build a populated ABC-DOS hard disk image
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+
+const char *program;
+
+unsigned char image[238*256*256];
+
+struct directory {
+ unsigned char *bitmap; /* Directory entry "bitmap" area */
+ unsigned char *dirsec; /* Actual directory sector */
+ unsigned int block; /* UFD block pointer (0 for MFD) */
+};
+
+/* Global bitmap */
+unsigned char *bitmap = image+(14*256);
+
+/* Master file directory */
+struct directory mfd = {
+ image+(14*256), /* Directory entry "bitmap" */
+ image+(16*256), /* Directory sectors */
+ 0
+};
+
+/* This is the next unassigned block number */
+int nextblock = 32;
+
+/*
+ * Set a bit in the bitmap
+ */
+void mark_used(int sector)
+{
+ bitmap[sector >> 8] |= (1 << ((sector >> 5) & 7));
+}
+
+/*
+ * Returns 0 for OK, -1 for failure
+ */
+int mangle_name(char *dst, const char *src)
+{
+ char *d = dst;
+ const char *s, *p;
+ char c;
+
+ if ( (p = strrchr(src,'/')) )
+ s = p+1;
+ else
+ s = src;
+
+ memset(dst, ' ', 11);
+ dst[11] = '\0';
+
+ while ( (c = *s++) && d < dst+11 ) {
+ const char *xstr = "ΙΕΔΦάιεδφό";
+ if ( (p = strchr(xstr, c)) ) {
+ c = "@][\\^@][\\^"[p-xstr];
+ }
+
+ if ( c == '.' )
+ d = dst+8;
+ else
+ *d++ = toupper((unsigned char)c);
+ }
+
+ return 0;
+}
+
+/*
+ * Get the contents of a file, and guess whether or not it's a text file
+ */
+
+unsigned char *read_file(const char *filename, int *sizep)
+{
+ FILE *f = fopen(filename, "rb");
+ unsigned char buffer[256];
+ int i, n;
+ int size = 0;
+ int binary = 0;
+ unsigned char *data, *dp;
+
+ if ( !f )
+ return NULL;
+
+ while ( (n = fread(buffer, 1, sizeof buffer, f)) ) {
+ if ( !binary )
+ for ( i = 0 ; i < n ; i++ ) {
+ if ( buffer[i] & 0x80 || buffer[i] == 0x00 ||
+ buffer[i] == 0x03 ) {
+ binary = 1;
+ break;
+ }
+ }
+
+ size += n;
+ }
+
+ rewind(f);
+
+ if ( binary ) {
+ data = malloc(size);
+ fread(data,size,1,f);
+ } else {
+ int blocks = (size+251)/252 + 1;
+ data = malloc(size = blocks*253);
+
+ dp = data;
+ while ( memset(buffer, 0, 253),
+ (n = fread(buffer, 1, 252, f)) ) {
+ for ( i = 0 ; i < n ; i++ ) {
+ if ( buffer[i] == '\n' )
+ buffer[i] = '\r';
+ }
+ buffer[n] = '\x03';
+
+ memcpy(dp, buffer, 253);
+ dp += 253;
+ }
+
+ /* Ending block */
+ memset(buffer, 0, 6);
+ buffer[6] = '\x03';
+ memcpy(dp, buffer, 253);
+ }
+
+ fclose(f);
+
+ *sizep = size;
+
+ return data;
+}
+
+/*
+ * Copy a file
+ */
+int copy_file(const char *filename, struct directory *dir)
+{
+ int size;
+ int nblocks, nclust;
+ char mangled_name[12];
+ int dirs, dirp; /* Directory (sector,position) */
+ unsigned char *dirent;
+ unsigned char *data;
+ int i;
+
+ data = read_file(filename, &size);
+
+ nblocks = (size+252)/253 + 1;
+ nclust = (nblocks+31)/32;
+
+ mangle_name(mangled_name, filename);
+
+ /* Find and create directory entry */
+
+ dirp = -1;
+ for ( dirs = 0 ; dirs < 16 ; dirs++ ) {
+ if ( dir->bitmap[0xEF+dirs] < 0x10 ) {
+ dirp = dir->bitmap[0xEF+dirs]++;
+ break;
+ }
+ }
+
+ if ( dirs == 16 ) {
+ free(data);
+ return -1;
+ }
+
+ dirent = dir->dirsec + dirs*256 + dirp*16;
+
+ memcpy(dirent+4, mangled_name, 11);
+ dirent[0] = nextblock >> 8;
+ dirent[1] = nextblock & 0xE0;
+ dirent[2] = nblocks & 0xFF;
+ dirent[3] = nblocks >> 8;
+
+ /* Create "file header" */
+ {
+ int block = nextblock;
+ int cleft = nclust;
+ unsigned char *header = image + nextblock*256;
+
+ memset(header, 0, 256);
+
+ *header++ = (dirp << 4) + dirs;
+ *header++ = 0;
+ *header++ = 0;
+ *header++ = 0xFF;
+
+ while ( cleft ) {
+ int nc = cleft > 32 ? 32 : cleft;
+ *header++ = block >> 8;
+ *header++ = (block & 0xE0) | (nc-1);
+ cleft -= nc;
+ block += nc;
+ }
+
+ *header++ = 0xFF;
+ *header++ = 0xFF;
+ }
+
+ /* Actually copy the file */
+ {
+ int blockno = 1;
+ unsigned char *target = image + (nextblock+1)*256;
+ unsigned char *dp = data;
+
+ while ( size ) {
+ int nbytes = (size > 253) ? 253 : size;
+ target[0] = (dirp << 4) + dirs;
+ target[1] = blockno & 0xFF;
+ target[2] = blockno >> 8;
+ memcpy(target+3, dp, nbytes);
+ memset(target+3+(253-nbytes), 0, 253-nbytes);
+
+ blockno++;
+ target += 256;
+ size -= nbytes;
+ dp += nbytes;
+ }
+ }
+
+ free(data);
+
+ for ( i = 0 ; i < nclust*32 ; i++ )
+ mark_used(nextblock++);
+
+ return 0;
+}
+
+/*
+ * Create a UFD
+ */
+struct directory *make_ufd(const char *filename, struct directory *dir)
+{
+ int nblocks, nclust;
+ char mangled_name[12];
+ int dirs, dirp; /* Directory (sector,position) */
+ unsigned char *dirent;
+ struct directory *ufd = malloc(sizeof(struct directory));
+ int i;
+
+ nblocks = 18;
+ nclust = (nblocks+31)/32;
+
+ mangle_name(mangled_name, filename);
+ memcpy(mangled_name+8, "Ufd", 4);
+
+ /* Find and create directory entry */
+
+ dirp = -1;
+ for ( dirs = 0 ; dirs < 16 ; dirs++ ) {
+ if ( dir->bitmap[0xEF+dirs] < 0x10 ) {
+ dirp = dir->bitmap[0xEF+dirs]++;
+ break;
+ }
+ }
+
+ if ( dirs == 16 ) {
+ free(ufd);
+ return NULL;
+ }
+
+ dirent = dir->dirsec + dirs*256 + dirp*16;
+
+ memcpy(dirent+4, mangled_name, 11);
+ dirent[0] = nextblock >> 8;
+ dirent[1] = nextblock & 0xE0;
+ dirent[2] = nblocks & 0xFF;
+ dirent[3] = nblocks >> 8;
+
+ /* Create "file header" */
+ {
+ int block = nextblock;
+ int cleft = nclust;
+ unsigned char *header = image + nextblock*256;
+
+ memset(header, 0, 256);
+
+ *header++ = (dirp << 4) + dirs;
+ *header++ = 0;
+ *header++ = 0;
+ *header++ = 0xFF;
+
+ while ( cleft ) {
+ int nc = cleft > 32 ? 32 : cleft;
+ *header++ = block >> 8;
+ *header++ = (block & 0xE0) | (nc-1);
+ cleft -= nc;
+ block += nc;
+ }
+
+ *header++ = 0xFF;
+ *header++ = 0xFF;
+ }
+
+ /* Create "bitmap" */
+ {
+ unsigned char *bitmap = image + (nextblock+1)*256;
+ int dirs_block = dir->block ? dir->block+2 : 0;
+
+ memset(bitmap, 0, 256);
+ bitmap[0] = (dirp << 4) + dirs;
+ bitmap[1] = 1;
+ bitmap[2] = 0;
+ bitmap[3] = dirs_block & 0xFF;
+ bitmap[4] = dirs_block >> 8;
+ bitmap[5] = (dirp << 4) + dirs;
+
+ ufd->bitmap = bitmap;
+ }
+
+ /* Create "data" */
+ ufd->dirsec = image + (nextblock+2)*256;
+ memset(ufd->dirsec, 0xFF, 16*256);
+
+ /* Pointer to this UFD */
+ ufd->block = nextblock;
+
+ /* Mark sectors used */
+ for ( i = 0 ; i < nclust*32 ; i++ )
+ mark_used(nextblock++);
+
+ return ufd;
+}
+
+/* Copy files as given by tree on stdin */
+int get_files(const char *dirpath, struct directory *ufd)
+{
+ struct stat st;
+ DIR *d;
+ struct dirent *de;
+ char filename[4096];
+ struct directory *subdir;
+
+ if ( !(d = opendir(dirpath)) ) {
+ perror(dirpath);
+ return -1;
+ }
+
+ while ( (de = readdir(d)) ) {
+ if ( !strcmp(de->d_name, ".") || !strcmp(de->d_name, "..") )
+ continue;
+
+ sprintf(filename, "%s/%s", dirpath, de->d_name);
+ if ( stat(filename, &st) ) {
+ perror(filename);
+ continue;
+ }
+ if ( S_ISDIR(st.st_mode) ) {
+ subdir = make_ufd(filename, ufd);
+ get_files(filename, subdir);
+ } else {
+ copy_file(filename, ufd);
+ }
+ }
+ closedir(d);
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int i;
+
+ program = argv[0];
+
+ memset(image, 0xe5, 238*256*256);
+
+ /* Create empty bitmap */
+ image[0xF00] = 0x80;
+ memset(image+0xF01, 0x00, 237);
+ image[0xFEE] = 0xFF;
+ memset(image+0xFEF, 0x01, 16);
+ image[0xFFF] = 0x00;
+
+ /* Copy empty bitmap to live bitmap */
+ memcpy(image+0xE00, image+0xF00, 256);
+
+ /* Create directory sectors */
+ for ( i = 16 ; i < 32 ; i++ ) {
+ memset(image+(i << 8), 0x00, 16);
+ memset(image+(i << 8)+16, 0xFF, 240);
+ }
+
+ /* Install files */
+ get_files(argv[1], &mfd);
+
+ /*** DO STUFF ***/
+
+ /* Finally, write out image */
+ fwrite(image, 1, 238*256*256, stdout);
+
+ return 0;
+}
+