Hello, I added DEC RT-11 filesystem support to makefs, working from manuals on bitsavers.org [1][2], sources of PUTR [3] and arff [4], and advice from those who actually used the PDP-11; the images are accepted by RT-11 5.3 in SIMH. It's still work in progress, please review it. I did not find documentation for certain features (the INIT/RESTORE data area, bad block relocation table, how to write boot blocks...). Number of directory segments is chosen automatically, depending on the size of filesystem, and is also settable via option. I'm not sure that 'extra words in directory entry' feature is useful, so it's not there. Filesystem is not autosized yet, '-s' option is required. Volume and Owner IDs are fixed (makefs doesn't support string options). Timestamps can be written with or without 'age' field, and if a date cannot be represented in RT-11 format, it is written as zero ('no date'). [1] AA-PD6PA-TC_RT-11_Volume_and_File_Formats_Manual_Aug91.pdf [2] AA-PE7VA-TC_RT-11_Device_Handlers_Manual_Aug91.pdf [3] http://www.dbit.com/pub/putr/putr.asm [4] ftp://ftp.mrynet.com/pub/os/UNIX/4.2BSD/etc/arff.c -- Sergey Svishchev
diff --exclude .git -ruN makefs/Makefile makefs1/Makefile --- makefs/Makefile 2011-07-19 02:52:37.000000000 +0400 +++ makefs1/Makefile 2013-04-20 19:10:45.000000000 +0400 @@ -6,7 +6,7 @@ .include <bsd.own.mk> PROG= makefs -SRCS= cd9660.c ffs.c v7fs.c \ +SRCS= cd9660.c ffs.c rt11fs.c v7fs.c \ getid.c \ makefs.c misc.c \ pack_dev.c \ @@ -22,6 +22,7 @@ .include "${.CURDIR}/cd9660/Makefile.inc" .include "${.CURDIR}/ffs/Makefile.inc" +.include "${.CURDIR}/rt11fs/Makefile.inc" .include "${.CURDIR}/v7fs/Makefile.inc" .if !defined(HOSTPROG) diff --exclude .git -ruN makefs/makefs.8 makefs1/makefs.8 --- makefs/makefs.8 2012-01-28 06:35:46.000000000 +0400 +++ makefs1/makefs.8 2013-04-20 17:27:49.000000000 +0400 @@ -201,6 +201,8 @@ ISO 9660 file system. .It Sy v7fs 7th Edition(V7) file system. +.It Sy rt11fs +RT-11 file system. .El .It Fl x Exclude file system nodes not explicitly listed in the specfile. diff --exclude .git -ruN makefs/makefs.c makefs1/makefs.c --- makefs/makefs.c 2012-01-28 06:35:46.000000000 +0400 +++ makefs1/makefs.c 2013-04-15 21:56:20.000000000 +0400 @@ -73,6 +73,8 @@ { "ffs", ffs_prep_opts, ffs_parse_opts, ffs_cleanup_opts, ffs_makefs }, { "cd9660", cd9660_prep_opts, cd9660_parse_opts, cd9660_cleanup_opts, cd9660_makefs}, + { "rt11fs", rt11fs_prep_opts, rt11fs_parse_opts, rt11fs_cleanup_opts, + rt11fs_makefs }, { "v7fs", v7fs_prep_opts, v7fs_parse_opts, v7fs_cleanup_opts, v7fs_makefs }, { .type = NULL }, diff --exclude .git -ruN makefs/makefs.h makefs1/makefs.h --- makefs/makefs.h 2012-01-28 06:35:46.000000000 +0400 +++ makefs1/makefs.h 2013-04-15 20:58:17.000000000 +0400 @@ -172,6 +172,11 @@ void cd9660_cleanup_opts(fsinfo_t *); void cd9660_makefs(const char *, const char *, fsnode *, fsinfo_t *); +void rt11fs_prep_opts(fsinfo_t *); +int rt11fs_parse_opts(const char *, fsinfo_t *); +void rt11fs_cleanup_opts(fsinfo_t *); +void rt11fs_makefs(const char *, const char *, fsnode *, fsinfo_t *); + void v7fs_prep_opts(fsinfo_t *); int v7fs_parse_opts(const char *, fsinfo_t *); void v7fs_cleanup_opts(fsinfo_t *); diff --exclude .git -ruN makefs/rt11fs/Makefile.inc makefs1/rt11fs/Makefile.inc --- makefs/rt11fs/Makefile.inc 1970-01-01 03:00:00.000000000 +0300 +++ makefs1/rt11fs/Makefile.inc 2013-04-19 00:51:15.000000000 +0400 @@ -0,0 +1,7 @@ +.PATH: ${.CURDIR}/rt11fs + +SRCS+= rt11fs_rad50.c +.if !defined(HOSTPROG) +LDADD+= -lz +DPADD+= ${LIBZ} +.endif diff --exclude .git -ruN makefs/rt11fs/rt11fs_rad50.c makefs1/rt11fs/rt11fs_rad50.c --- makefs/rt11fs/rt11fs_rad50.c 1970-01-01 03:00:00.000000000 +0300 +++ makefs1/rt11fs/rt11fs_rad50.c 2013-04-20 17:57:35.000000000 +0400 @@ -0,0 +1,101 @@ +/*- + * All rights reserved. + */ + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include <sys/param.h> +#include <sys/stat.h> + +#include <assert.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <zlib.h> + +#include "makefs.h" +#include "rt11fs_makefs.h" +#include "rt11fs/rt11fs_rad50.h" + +/* taken from 4.2BSD's arff.c */ + +static char table[256] = { +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, + 0, 29, 29, 29, 27, 29, 29, 29, 29, 29, 29, 29, 29, 29, 28, 29, +30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 29, 29, 29, 29, 29, 29, +29, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, +16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 29, 29, 29, 29, 29, +29, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, +16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, + 0, 29, 29, 29, 27, 29, 29, 29, 29, 29, 29, 29, 29, 29, 28, 29, +30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 29, 29, 29, 29, 29, 29, +29, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, +16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 29, 29, 29, 29, 29, +29, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, +16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 29, 29, 29, 29 }; + +#define Ain1 03100 +#define Ain2 050 + +void +rad50 (const char *cp, uint16_t *out) +{ + int m; + uint16_t temp; + + for (m = 0; *cp; m++) { + temp = Ain1 * table[(int)*cp++]; + if (*cp!=0) { + temp += Ain2 * table[(int)*cp++]; + if(*cp!=0) + temp += table[(int)*cp++]; + } + out[m] = htole16(temp); + } +} + +void +srad50 (char *name, uint16_t *rname) +{ + int m; + char *cp; + char file[7], ext[4]; + + /* + * Find end of pathname + */ + for (cp = name; *cp++; ) + ; + while (cp >= name && *--cp != '/') + ; + cp++; + /* + * Change to rad50 + */ + for (m = 0; *cp; ) { + file[m++] = *cp++; + if (*cp == '.') { + cp++; + break; + } + if (m > 5) { + break; + } + } + file[m] = 0; + for (m = 0; *cp; ) { + ext[m++] = *cp++; + if (*cp == '.' || m > 2) + break; + } + ext[m]=0; + rname[0] = rname[1] = rname[2] = 0; + rad50((const char *)file, rname); + rad50((const char *)ext, rname+2); +} diff --exclude .git -ruN makefs/rt11fs/rt11fs_rad50.h makefs1/rt11fs/rt11fs_rad50.h --- makefs/rt11fs/rt11fs_rad50.h 1970-01-01 03:00:00.000000000 +0300 +++ makefs1/rt11fs/rt11fs_rad50.h 2013-04-20 17:57:35.000000000 +0400 @@ -0,0 +1,13 @@ +/*- + * All rights reserved. + */ + +#ifndef _RT11FS_RAD50_H +#define _RT11FS_RAD50_H + +#include <sys/endian.h> + +void rad50 (const char *, uint16_t *); +void srad50 (char *, uint16_t *); + +#endif diff --exclude .git -ruN makefs/rt11fs.c makefs1/rt11fs.c --- makefs/rt11fs.c 1970-01-01 03:00:00.000000000 +0300 +++ makefs1/rt11fs.c 2013-04-25 23:33:28.000000000 +0400 @@ -0,0 +1,404 @@ +/*- + * All rights reserved. + */ + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include <sys/endian.h> +#include <sys/param.h> + +#include <assert.h> +#include <errno.h> +#include <fcntl.h> +#include <string.h> +#include <time.h> +#include <unistd.h> +#include <util.h> +#include <stdio.h> +#include <stdlib.h> + +#include "makefs.h" +#include "rt11fs_makefs.h" +#include "rt11fs/rt11fs_rad50.h" + +static int rt11fs_create_image(const char *, fsinfo_t *); +static int rt11fs_estimate(const char *, fsnode *, fsinfo_t *); +static int rt11fs_populate(const char *, fsnode *, fsinfo_t *); +void rt11fs_name(char *, uint16_t *, int *); +void rt11fs_date(time_t, uint16_t *, int *); + +rt11fs_opt_t rt11fs_opts; +static struct rt_dir rt11fs_dir[RT_DIRSEGS]; +static struct rt_home rt11fs_home; + +void +rt11fs_name(char *name, uint16_t * rtnamep, int *errp) +{ + srad50(name, rtnamep); + *errp = 0; +} + +void +rt11fs_date(time_t mtime, uint16_t * rtdatp, int *errp) +{ + struct tm *rtp; + + *errp = 0; + + rtp = localtime(&mtime); + if (!rtp) { + *errp = errno; + return; + } + if (rtp->tm_year < 72) { + *rtdatp = 0; + return; + } + if (rtp->tm_year > (rt11fs_opts.y2k_date ? 199 : 103)) { + *rtdatp = 0; + return; + } + + *rtdatp = (rtp->tm_year - 72) % 32; + *rtdatp |= rtp->tm_mday << 5; + *rtdatp |= (rtp->tm_mon + 1) << 10; + *rtdatp |= ((rtp->tm_year - 72) / 32) << 14; + /* + 15-14 :2 Age (0-3) + 13-10 :4 Month (1-12) + 9-5 :5 Day (1-31) + 4-0 :5 Year minus 1972 minus 32*Age + */ +} + +void +rt11fs_prep_opts(fsinfo_t * fsopts) +{ + + fsopts->fs_specific = &rt11fs_opts; +} + +void +rt11fs_cleanup_opts(fsinfo_t * fsopts) +{ + /* NO-OP */ +} + +int +rt11fs_parse_opts(const char *option, fsinfo_t * fsopts) +{ + static option_t rt11fs_options[] = { + {"sys_version", &rt11fs_opts.sys_version, 3, 5, + "Home block version"}, + {"dir_segments", &rt11fs_opts.dir_segments, 1, 31, + "Number of directory segments"}, + {"y2k_date", &rt11fs_opts.y2k_date, 0, 1, + "Y2K-aware date format"}, + {.name = NULL} + }; + + set_option(rt11fs_options, option, "1"); + + return 1; +} + +static int +rt11fs_create_image(const char *image, fsinfo_t * fsopts) +{ + uint16_t *p, sum; + int m; + char tmp[13]; + + assert(image != NULL); + assert(fsopts != NULL); + + rt11fs_home.rt_clsize = htole16(1); + rt11fs_home.rt_dirblk = htole16(RT_DIRBLK); + rad50("V3A", &rt11fs_home.rt_sysver); /* V05 and V4A also exist */ + snprintf(tmp, 13, "%-12s", "RT11A"); + memcpy(rt11fs_home.rt_volid, tmp, 12); + snprintf(tmp, 13, "%-12s", "DECRT11A"); + memcpy(rt11fs_home.rt_sysid, tmp, 12); + snprintf(tmp, 13, "%-12s", "makefs(8)"); + memcpy(rt11fs_home.rt_owner, tmp, 12); + + sum = 0; + p = (uint16_t *) (void *) &rt11fs_home; + for (m = 0; m < 255; m++) + sum += le16toh(*p++); + + rt11fs_home.rt_cksum = htole16(sum); + + if ((fsopts->fd = open(image, O_RDWR | O_CREAT | O_TRUNC, 0666)) == -1) { + warn("Can't open `%s' for writing", image); + return -1; + } + if (lseek(fsopts->fd, fsopts->maxsize - 1, SEEK_SET) == -1) { + warn("Can't seek `%s' to %lld", image, fsopts->size - 1); + return -1; + } + if (write(fsopts->fd, "\0", 1) != 1) { + warn("Can't write `%s'", image); + return -1; + } + if (lseek(fsopts->fd, RT_SECSIZE, SEEK_SET) == -1) { + warn("Can't seek `%s' to home block", image); + return -1; + } + if (write(fsopts->fd, (void *) &rt11fs_home, RT_SECSIZE) != RT_SECSIZE) { + warn("Can't write home block to `%s'", image); + return -1; + } + return fsopts->fd; +} + +static int +rt11fs_estimate(const char *dir, fsnode * root, fsinfo_t * fsopts) +{ + fsnode *cur; + int failed; + off_t size; + + assert(dir != NULL); + assert(root != NULL); + assert(fsopts != NULL); + + failed = 0; + + if (fsopts->maxsize > RT_MAXSIZE) { + errx(EXIT_FAILURE, "maxsize of %lld is greater than maximum supported of 32M.", + fsopts->maxsize); + } + +/* from PUTR.ASM: +rtnseg dw 512d ;Up to 512 blocks + dw 1 ;we get 1 segment. + dw 2048d ;Up to 2048 blocks + dw 4 ;we get 4 segments. + dw 12288d ;Up to 12288 blocks + dw 16d ;we get 16 segments. + dw -1 ;Over that + dw 31d ;we get 31 segments (max allowed). +*/ + if (rt11fs_opts.dir_segments == 0) { + if (fsopts->maxsize <= 512 * RT_SECSIZE) + rt11fs_opts.dir_segments = 1; + else if (fsopts->maxsize <= 2048 * RT_SECSIZE) + rt11fs_opts.dir_segments = 4; + else if (fsopts->maxsize <= 12288 * RT_SECSIZE) + rt11fs_opts.dir_segments = 16; + else + rt11fs_opts.dir_segments = 31; + }; + fsopts->size = RT_SECSIZE * (6 + 2 * rt11fs_opts.dir_segments); + + for (cur = root; cur != NULL; cur = cur->next) { + switch (cur->type & S_IFMT) { + case S_IFREG: + size = (cur->inode->st.st_size + 511) & ~511; + fsopts->size += size; + fsopts->inodes++; + break; + default: + break; + } + } + + /* leave 1 entry for EMPTY.FIL */ + if (fsopts->inodes > (rt11fs_opts.dir_segments * RT_DIRENTS - 1)) { + errx(EXIT_FAILURE, "`%s' inode count of %lld is larger than the maximum of %d.", + dir, fsopts->inodes, rt11fs_opts.dir_segments * RT_DIRENTS); + } + if (fsopts->maxsize > 0 && fsopts->size > fsopts->maxsize) { + errx(EXIT_FAILURE, "`%s' size of %lld is larger than the maxsize of %lld.", + dir, fsopts->size, fsopts->maxsize); + } + return failed ? 2 : 0; +} + +/* +- open 1st directory segment (populate word 4) +- for each file: + - fill directory entry (status word = E.PERM) + - write file data to image + - find next directory entry in this segment + - if none available, close this segment (populate word 1 and write + E.EOS into last word, if available) and open a new segment +- close last and 1st (populate words 0 and 2) directory segments +- write directory to disk +*/ +static int +rt11fs_populate(const char *dir, fsnode * root, fsinfo_t * fsopts) +{ + int error, failed, rt11fs_file, rt11fs_segment, fd, m, x; + size_t blk_nr, blocks; + char *name, empty_fil[10]; + uint8_t *buf; + off_t blk_offset, bytes_read, bytes_written; + fsnode *cur; + struct rt_ent *entry; + + assert(dir != NULL); + assert(root != NULL); + assert(fsopts != NULL); + + error = failed = rt11fs_file = rt11fs_segment = m = x = 0; + strncpy(empty_fil, "EMPTY.FIL", 10); + + buf = emalloc(RT_BUFSIZE); + name = emalloc(PATH_MAX); + + blk_nr = RT_DIRBLK + rt11fs_opts.dir_segments * 2; + if (debug & DEBUG_WALK_DIR) + printf("rt11fs_populate_dir: data starts at block %d\n", blk_nr); + + /* open 1st directory segment */ + rt11fs_dir[rt11fs_segment].rt_axhead.rt_numseg = rt11fs_opts.dir_segments; + rt11fs_dir[rt11fs_segment].rt_axhead.rt_stfile = blk_nr; + + for (cur = root; cur != NULL; cur = cur->next) { + switch (cur->type & S_IFMT) { + case S_IFREG: + blocks = ((size_t) cur->inode->st.st_size + RT_SECSIZE - 1) / RT_SECSIZE; + if (debug & DEBUG_WALK_DIR) + printf("rt11fs_populate_dir: <%s> %lld bytes (%d blocks)\n", + cur->name, cur->inode->st.st_size, blocks); + entry = &rt11fs_dir[rt11fs_segment].rt_ents[rt11fs_file]; + entry->rt_stat = RT_E_PERM; + if (!(cur->inode->st.st_mode & S_IWUSR)) + entry->rt_stat |= RT_E_READ; + entry->rt_len = (uint16_t) blocks; + rt11fs_name(cur->name, &entry->rt_name[0], &error); + if (error) + break; + rt11fs_date(cur->inode->st.st_mtime, &entry->rt_date, &error); + if (error) + break; + + /* ready to store the file */ + snprintf(name, PATH_MAX - 1, "%s/%s", dir, cur->name); + fd = open(name, O_RDONLY, 0444); + if (fd == -1) { + warn("rt11fs_populate: open"); + break; + } + blk_offset = blk_nr * RT_SECSIZE; + do { + bytes_read = read(fd, buf, RT_BUFSIZE); + if (bytes_read == -1) { + warn("rt11fs_populate: read"); + break; + } + bytes_written = pwrite(fsopts->fd, buf, RT_BUFSIZE, blk_offset); + if (bytes_written == -1) { + warn("rt11fs_populate: write"); + break; + } + blk_offset += bytes_written; + } while (bytes_read > 0); + close(fd); + + blk_nr += blocks; + if (debug & DEBUG_WALK_DIR) + printf("rt11fs_populate_dir: OK, seg %d (of %d) ent %d\n", + rt11fs_segment, rt11fs_opts.dir_segments, rt11fs_file); + + if (++rt11fs_file == RT_DIRENTS) { + /* close this segment */ + rt11fs_dir[rt11fs_segment].rt_eos = RT_E_EOS; + /* open next one, if available */ + if ((rt11fs_opts.dir_segments - rt11fs_segment) > 1) { + rt11fs_dir[rt11fs_segment].rt_axhead.rt_nxtseg = rt11fs_segment + 2; + rt11fs_segment += 1; + rt11fs_dir[rt11fs_segment].rt_axhead.rt_stfile = blk_nr; + rt11fs_file = 0; + } + } + break; + default: + if ((debug & DEBUG_WALK_DIR) && strcmp(cur->name, ".")) + printf("rt11fs_populate_dir: can't handle file <%s> of type %x\n", + cur->name, cur->type & S_IFMT); + break; + } + } + + /* add E.MPTY entry, if there's space for it, and then close the segment */ + if (rt11fs_segment < rt11fs_opts.dir_segments) { + rt11fs_dir[rt11fs_segment].rt_ents[rt11fs_file].rt_stat = RT_E_MPTY; + /* name is irrelevant */ + rt11fs_name(empty_fil, &rt11fs_dir[rt11fs_segment].rt_ents[rt11fs_file].rt_name[0], &error); + rt11fs_dir[rt11fs_segment].rt_ents[rt11fs_file].rt_len = (uint16_t) ((fsopts->maxsize / RT_SECSIZE) - blk_nr); + if (++rt11fs_file == RT_DIRENTS) + rt11fs_dir[rt11fs_segment].rt_eos = RT_E_EOS; + else + rt11fs_dir[rt11fs_segment].rt_ents[rt11fs_file].rt_stat = RT_E_EOS; + } + /* close 1st segment (populate word 2), write directory */ + rt11fs_dir[0].rt_axhead.rt_lstseg = rt11fs_segment + 1; + + /* byte-swap if necessary */ +#if BYTE_ORDER == BIG_ENDIAN + for (m = 0; m < rt11fs_opts.dir_segments; m++) { + HTOLE16(rt11fs_dir[m].rt_axhead.rt_numseg); + HTOLE16(rt11fs_dir[m].rt_axhead.rt_nxtseg); + HTOLE16(rt11fs_dir[m].rt_axhead.rt_lstseg); + HTOLE16(rt11fs_dir[m].rt_axhead.rt_entpad); + HTOLE16(rt11fs_dir[m].rt_axhead.rt_stfile); + HTOLE16(rt11fs_dir[m].rt_eos); + for (x = 0; x < RT_DIRENTS; x++) { + HTOLE16(rt11fs_dir[m].rt_ents[x].rt_stat); + HTOLE16(rt11fs_dir[m].rt_ents[x].rt_len); + HTOLE16(rt11fs_dir[m].rt_ents[x].rt_date); + } + } +#endif + + blocks = rt11fs_opts.dir_segments * sizeof(struct rt_dir); + if (pwrite(fsopts->fd, (void *) &rt11fs_dir, blocks, RT_SECSIZE * RT_DIRBLK) != blocks) { + warn("Can't write directory (%d, %p, %d, %d)", fsopts->fd, (void *) &rt11fs_dir, blocks, RT_SECSIZE * RT_DIRBLK); + failed = 1; + } + return failed ? 2 : 0; +} + +void +rt11fs_makefs(const char *image, const char *dir, fsnode * root, fsinfo_t * fsopts) +{ + struct timeval start; + + assert(image != NULL); + assert(dir != NULL); + assert(root != NULL); + assert(fsopts != NULL); + + printf("Estimating `%s'\n", image); + TIMER_START(start); + if (rt11fs_estimate(dir, root, fsopts)) { + warnx("Image file `%s' not estimated", image); + } + TIMER_RESULTS(start, "rt11fs_estimate"); + + printf("Creating `%s'\n", image); + TIMER_START(start); + if (rt11fs_create_image(image, fsopts) == -1) { + errx(EXIT_FAILURE, "Image file `%s' not created", image); + } + TIMER_RESULTS(start, "rt11fs_create_image"); + + printf("Populating `%s'\n", image); + TIMER_START(start); + if (rt11fs_populate(dir, root, fsopts)) { + errx(EXIT_FAILURE, "Image file `%s' not populated", image); + } + TIMER_RESULTS(start, "rt11fs_populate"); + + if (close(fsopts->fd) == -1) { + err(EXIT_FAILURE, "Closing `%s'", image); + } + fsopts->fd = -1; + + printf("Image `%s' complete\n", image); +} diff --exclude .git -ruN makefs/rt11fs_makefs.h makefs1/rt11fs_makefs.h --- makefs/rt11fs_makefs.h 1970-01-01 03:00:00.000000000 +0300 +++ makefs1/rt11fs_makefs.h 2013-04-20 22:00:24.000000000 +0400 @@ -0,0 +1,90 @@ +/*- + * All rights reserved. + */ + +#ifndef _RT11FS_MAKEFS_H +#define _RT11FS_MAKEFS_H + +typedef struct { + int dir_segments; + int sys_version; + int y2k_date; +} rt11fs_opt_t; + +#define RT_BUFSIZE 16384 + +#define RT_SECSIZE 512 /* block size */ +#define RT_MAXSIZE 65536*RT_SECSIZE/* actually 65535 */ + +#define RT_DIRBLK 6 /* directory's starting block */ +#define RT_DIRSEGS 31 /* max # of directory segments */ +#define RT_DIRENTS 72 /* # of directory entries per segment */ + +extern rt11fs_opt_t rt11fs_opts; + +#define RT_E_TENT 000400 /* Tentative file */ +#define RT_E_MPTY 001000 /* Empty area */ +#define RT_E_PERM 002000 /* Permanent file */ +#define RT_E_EOS 004000 /* End-of-segment marker */ +#define RT_E_READ 040000 /* 5.6+: Protected by monitor from write operations */ +#define RT_E_PROT 100000 /* Protected permanent file */ +#define RT_E_PRE 000020 /* ?.?+: Prefix block indicator */ + +struct rt_head { + int16_t rt_numseg; /* # of segments available */ + int16_t rt_nxtseg; /* # of next logical segment */ + int16_t rt_lstseg; /* highest seg currently open */ + int16_t rt_entpad; /* extra words/directory entry */ + int16_t rt_stfile; /* block # where files begin */ +} __packed; + +struct rt_ent { + uint16_t rt_stat; /* type of entry, or end of seg */ + uint16_t rt_name[3]; /* name, 3 words in rad50 form */ + uint16_t rt_len; /* length of file */ + char rt_chan; /* only used in temporary files */ + char rt_job; /* only used in temporary files */ + uint16_t rt_date; /* creation date; w/ Y2K support as of 5.7 */ +} __packed; + +struct rt_dir { + struct rt_head rt_axhead; + struct rt_ent rt_ents[RT_DIRENTS]; + uint16_t rt_eos; /* end of segment */ + char _dirpad[4]; +} __packed; + +/* +000-201 Bad block replacement table +202-203 ? +204-251 INITIALIZE/RESTORE data area +252-273 BUP information area +274-677 ? +700-701 (Reserved for Digital, must be zero) +702-703 (Reserved for Digital, must be zero) +704-721 ? +722-723 Pack cluster size (= 1) +724-725 Block number of first directory segment (= 6) +726-727 System version (RAD50 "V3A") +730-743 Volume Identification ("RT11A" and seven spaces) +744-757 Owner name +760-773 System Identification ("DECRT11A" and four spaces) +774-775 ? +776-777 Checksum (optional?) + +PDP-11 is little-endian in 16-bit words. +*/ +struct rt_home { + char rt_bbt[0202]; + char _pad1[0520]; + uint16_t rt_clsize; + uint16_t rt_dirblk; + uint16_t rt_sysver; + char rt_volid[12]; + char rt_owner[12]; + char rt_sysid[12]; + char _pad2[2]; + uint16_t rt_cksum; +} __packed; + +#endif
Attachment:
pgpY4zG0zmRvj.pgp
Description: PGP signature