summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2012-08-06 04:16:04 (GMT)
committerH. Peter Anvin <hpa@zytor.com>2012-08-06 04:16:04 (GMT)
commitf8417ee35616999a9291df6b21e054659c157598 (patch)
treebd60f6a181e6f51b255b29c5109cdd0e4e5ee023
parent824bef23cdb7a31074dc40976079cadc19803fca (diff)
downloadabcdisk-f8417ee35616999a9291df6b21e054659c157598.zip
abcdisk-f8417ee35616999a9291df6b21e054659c157598.tar.gz
abcdisk-f8417ee35616999a9291df6b21e054659c157598.tar.bz2
abcdisk-f8417ee35616999a9291df6b21e054659c157598.tar.xz
Add program abcread to extract the contents of an UFD-DOS filesystem
-rw-r--r--Makefile7
-rw-r--r--abcread.c174
-rw-r--r--abcwrite.c71
-rw-r--r--util.c41
-rw-r--r--util.h29
5 files changed, 249 insertions, 73 deletions
diff --git a/Makefile b/Makefile
index fa25b23..3cfd225 100644
--- a/Makefile
+++ b/Makefile
@@ -9,7 +9,7 @@ O = o
X =
endif
-all : abcwrite$(X)
+all : abcwrite$(X) abcread$(X)
.c.$(O):
$(CC) $(CFLAGS) -c -o $@ $<
@@ -17,5 +17,8 @@ all : abcwrite$(X)
abcwrite$(X): abcwrite.$(O) util.$(O) formats.$(O)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^
+abcread$(X): abcread.$(O) util.$(O) formats.$(O)
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^
+
clean:
- rm -f abcwrite$(X) *.$(O) *~
+ rm -f abcwrite$(X) abcread$(X) *.$(O) *~
diff --git a/abcread.c b/abcread.c
new file mode 100644
index 0000000..fc6f08f
--- /dev/null
+++ b/abcread.c
@@ -0,0 +1,174 @@
+/*
+ * abcread.c
+ *
+ * Program to extract the contents from an ABC/UFD-DOS filesystem
+ */
+#include <ctype.h>
+#include <dirent.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <wchar.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include "util.h"
+
+static void unmangle_filename(char *out, const unsigned char *in)
+{
+ static const wchar_t my_tolower[256] =
+ L"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017"
+ L"\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
+ L" !\"#¤%&'()*+,-./0123456789:;<=>?"
+ L"éabcdefghijklmnopqrstuvwxyzäöåü_"
+ L"éabcdefghijklmnopqrstuvwxyzäöåü\377"
+ L"\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ L"\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237"
+ L"\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257"
+ L"\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277"
+ L"\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317"
+ L"\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337"
+ L"\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357"
+ L"\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377";
+ int i;
+
+ wctomb(NULL, 0);
+
+ for (i = 0; i < 8; i++) {
+ if (*in != ' ')
+ out += wctomb(out, my_tolower[*in]);
+ in++;
+ }
+
+ if (memcmp(in, " ", 3) && memcmp(in, "Ufd", 3)) {
+ out += wctomb(out, L'.');
+ for (i = 0; i < 3; i++) {
+ if (*in != ' ')
+ out += wctomb(out, my_tolower[*in]);
+ in++;
+ }
+ }
+
+ *out = '\0';
+}
+
+/* Copy files as given by tree on stdin */
+static int
+extract_dir_sector(struct disk *disk, const char *dirpath, int sectnr)
+{
+ char filename[4096], *p;
+ unsigned char *sector;
+ unsigned char *header;
+ int i, hsect, dsect, len;
+ int ufd, skip, cleft;
+ FILE *f;
+
+ /* 16 directory entries per sector */
+ sector = disk->image + (sectnr << 8);
+
+ for (i = 0; i < 16; i++, sector += 16) {
+ hsect = (sector[0] << 3) + (sector[1] >> 5);
+ hsect <<= disk->fmt->cluster_shift;
+ if (!hsect || (sector[0] & sector[1]) == 0xff ||
+ sector[4] == 0x00 || sector[4] == 0xff)
+ continue; /* Empty slot */
+
+ header = disk->image + (hsect << 8);
+
+ /* Length of file in sectors, including header block */
+ len = sector[2] + (sector[3] << 8);
+
+ ufd = !memcmp(sector+12, "Ufd", 3);
+ p = filename + sprintf(filename, "%s/", dirpath);
+ unmangle_filename(p, sector + 4);
+
+ if (ufd)
+ mkdir(filename, 0777);
+ else
+ f = fopen(filename, "wb");
+
+ /* Skip the header block for a file, header block and bitmap for UFD */
+ skip = 1 + ufd;
+ cleft = 0;
+ dsect = -1;
+ header += 4;
+
+ while (len--) {
+ if (cleft) {
+ dsect++;
+ } else {
+ if ((header[0] & header[1]) == 0xff)
+ break; /* Premature end of data */
+
+ dsect = (header[0] << 3) + (header[1] >> 5);
+ dsect <<= disk->fmt->cluster_shift;
+ cleft = ((header[1] & 31) + 1) << disk->fmt->cluster_shift;
+
+ header += 2;
+ }
+ cleft--;
+
+ if (skip) {
+ skip--;
+ } else if (ufd) {
+ extract_dir_sector(disk, filename, dsect);
+ } else {
+ fwrite(disk->image + (dsect << 8) + 3, 1, 253, f);
+ }
+ }
+
+ if (!ufd)
+ fclose(f);
+ }
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ struct disk *disk;
+ const struct diskfmt *fmt;
+ const char *fmt_name;
+ char * const *argp;
+ FILE *f;
+ int i;
+
+ setlocale(LC_ALL, "");
+
+ program = argv[0];
+
+ if (argc > 1 && argv[1][0] == '-') {
+ fmt_name = argv[1]+1;
+ argp = argv + 2;
+ argc -= 2;
+ } else {
+ fmt_name = "";
+ argp = argv + 1;
+ argc--;
+ }
+
+ fmt = get_format(fmt_name);
+ if (!fmt) {
+ fprintf(stderr, "%s: unknown format: %s\n", program, fmt_name);
+ exit(1);
+ }
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s [-format] file outdir\n", program);
+ exit(1);
+ }
+
+ disk = allocate_disk(fmt);
+
+ f = fopen(argp[0], "rb");
+ fread(disk->image, 1, fmt->ntracks << (fmt->track_shift + 8), f);
+ fclose(f);
+
+ /* Extract files */
+ for (i = 0; i < 16; i++)
+ extract_dir_sector(disk, argp[1], i+16);
+
+ return 0;
+}
diff --git a/abcwrite.c b/abcwrite.c
index 4dcbde2..27b2e9f 100644
--- a/abcwrite.c
+++ b/abcwrite.c
@@ -16,77 +16,6 @@
#include <sys/types.h>
#include "util.h"
-struct disk;
-
-struct directory {
- struct disk *disk; /* This directory belongs to... */
- unsigned char *bitmap; /* Directory entry "bitmap" area */
- unsigned char *dirsec; /* Actual directory sector */
- unsigned int block; /* UFD block pointer (0 for MFD) */
-};
-
-struct disk {
- const struct diskfmt *fmt; /* Format descriptor */
- unsigned char *image; /* Image of the disk */
- unsigned char *bitmap; /* Pointer to the bitmap inside the disk */
- struct directory mfd; /* MFD directory descriptor */
-};
-
-/*
- * Set a bit in the bitmap
- */
-static void mark_used(struct disk *disk, unsigned int cluster)
-{
- disk->bitmap[cluster >> 3] |= (0x80 >> (cluster & 7));
-}
-
-static int is_used(struct disk *disk, unsigned int cluster)
-{
- return !!(disk->bitmap[cluster >> 3] & (0x80 >> (cluster & 7)));
-}
-
-static struct disk *allocate_disk(const struct diskfmt *fmt)
-{
- struct disk *disk = xmalloc(sizeof(struct disk));
- size_t size = (fmt->ntracks) << (fmt->track_shift + 8);
- int i, starter;
-
- memset(disk, 0, sizeof *disk);
-
- disk->fmt = fmt;
- disk->image = xmalloc(size);
- disk->bitmap = disk->image + 14*256;
- disk->mfd.disk = disk;
- disk->mfd.bitmap = disk->image + 14*256;
- disk->mfd.dirsec = disk->image + 16*256;
- disk->mfd.block = 0; /* This is the MFD */
-
- /* Post-formatting content? */
- memset(disk->image, 0xe5, size);
-
- /* Create empty bitmap */
- memset(disk->bitmap, 0, fmt->ntracks);
- memset(disk->bitmap+fmt->ntracks, 0xff, 239-fmt->ntracks);
- memset(disk->bitmap+239, 0x01, 16); /* MFD bitmap */
- disk->bitmap[0xff] = 0x00;
-
- /* Mark the first 32 sectors used */
- starter = 32 >> fmt->cluster_shift;
- for (i = 0; i < starter; i++)
- mark_used(disk, i);
-
- /* Copy bitmap to backup empty bitmap */
- memcpy(disk->bitmap + 256, disk->bitmap, 256);
-
- /* Create MFD directory sectors */
- for ( i = 16 ; i < 32 ; i++ ) {
- memset(disk->image+(i << 8), 0x00, 16);
- memset(disk->image+(i << 8)+16, 0xFF, 240);
- }
-
- return disk;
-}
-
/*
* Find a free cluster in the bitmap; return the cluster number
*/
diff --git a/util.c b/util.c
index e6dfd4c..74f9ffb 100644
--- a/util.c
+++ b/util.c
@@ -17,3 +17,44 @@ void *xmalloc(size_t len)
return p;
}
+struct disk *allocate_disk(const struct diskfmt *fmt)
+{
+ struct disk *disk = xmalloc(sizeof(struct disk));
+ size_t size = (fmt->ntracks) << (fmt->track_shift + 8);
+ int i, starter;
+
+ memset(disk, 0, sizeof *disk);
+
+ disk->fmt = fmt;
+ disk->image = xmalloc(size);
+ disk->bitmap = disk->image + 14*256;
+ disk->mfd.disk = disk;
+ disk->mfd.bitmap = disk->image + 14*256;
+ disk->mfd.dirsec = disk->image + 16*256;
+ disk->mfd.block = 0; /* This is the MFD */
+
+ /* Post-formatting content? */
+ memset(disk->image, 0xe5, size);
+
+ /* Create empty bitmap */
+ memset(disk->bitmap, 0, fmt->ntracks);
+ memset(disk->bitmap+fmt->ntracks, 0xff, 239-fmt->ntracks);
+ memset(disk->bitmap+239, 0x01, 16); /* MFD bitmap */
+ disk->bitmap[0xff] = 0x00;
+
+ /* Mark the first 32 sectors used */
+ starter = 32 >> fmt->cluster_shift;
+ for (i = 0; i < starter; i++)
+ mark_used(disk, i);
+
+ /* Copy bitmap to backup empty bitmap */
+ memcpy(disk->bitmap + 256, disk->bitmap, 256);
+
+ /* Create MFD directory sectors */
+ for ( i = 16 ; i < 32 ; i++ ) {
+ memset(disk->image+(i << 8), 0x00, 16);
+ memset(disk->image+(i << 8)+16, 0xFF, 240);
+ }
+
+ return disk;
+}
diff --git a/util.h b/util.h
index 52dcf3e..bd2dcf3 100644
--- a/util.h
+++ b/util.h
@@ -10,8 +10,37 @@ struct diskfmt {
unsigned int cluster_shift; /* Size of a cluster (typically track/8) */
};
+struct disk;
+
+struct directory {
+ struct disk *disk; /* This directory belongs to... */
+ unsigned char *bitmap; /* Directory entry "bitmap" area */
+ unsigned char *dirsec; /* Actual directory sector */
+ unsigned int block; /* UFD block pointer (0 for MFD) */
+};
+
+struct disk {
+ const struct diskfmt *fmt; /* Format descriptor */
+ unsigned char *image; /* Image of the disk */
+ unsigned char *bitmap; /* Pointer to the bitmap inside the disk */
+ struct directory mfd; /* MFD directory descriptor */
+};
+
const struct diskfmt *get_format(const char *);
+struct disk *allocate_disk(const struct diskfmt *fmt);
+
extern const char *program;
void *xmalloc(size_t);
+static inline void mark_used(struct disk *disk, unsigned int cluster)
+{
+ disk->bitmap[cluster >> 3] |= (0x80 >> (cluster & 7));
+}
+
+static inline int is_used(struct disk *disk, unsigned int cluster)
+{
+ return !!(disk->bitmap[cluster >> 3] & (0x80 >> (cluster & 7)));
+}
+
+
#endif /* UTIL_H */