Standalone: Add the standalone utilities
authorAlan Cox <alan@etchedpixels.co.uk>
Fri, 31 Oct 2014 14:37:20 +0000 (14:37 +0000)
committerAlan Cox <alan@etchedpixels.co.uk>
Fri, 31 Oct 2014 14:37:20 +0000 (14:37 +0000)
These are based off the UZI-WRS versions from Will Sowerbutts except for
chmem which is new code.

12 files changed:
Standalone/Makefile [new file with mode: 0644]
Standalone/chmem.c [new file with mode: 0644]
Standalone/devio.c [new file with mode: 0644]
Standalone/fsck.c [new file with mode: 0644]
Standalone/fuzix_fs.h [new file with mode: 0644]
Standalone/mkfs.c [new file with mode: 0644]
Standalone/ucp.c [new file with mode: 0644]
Standalone/util.c [new file with mode: 0644]
Standalone/xfs1.c [new file with mode: 0644]
Standalone/xfs1a.c [new file with mode: 0644]
Standalone/xfs1b.c [new file with mode: 0644]
Standalone/xfs2.c [new file with mode: 0644]

diff --git a/Standalone/Makefile b/Standalone/Makefile
new file mode 100644 (file)
index 0000000..c94072f
--- /dev/null
@@ -0,0 +1,21 @@
+CC=gcc
+CCOPTS=-O2 -g -Wall -Wno-char-subscripts -Wno-deprecated-declarations
+TARGETS=mkfs fsck ucp
+UTILS=util.o devio.o xfs1.o xfs1a.o xfs1b.o xfs2.o
+
+all:   $(TARGETS)
+
+clean:
+       rm -f $(TARGETS) *.o *~
+
+mkfs:  mkfs.o util.o
+       $(CC) $(CCOPTS) -o $@ $< util.o
+
+fsck:  fsck.o util.o
+       $(CC) $(CCOPTS) -o $@ $< util.o
+
+ucp:   ucp.o $(UTILS)
+       $(CC) $(CCOPTS) -o $@ $< $(UTILS)
+
+%.o:   %.c
+       $(CC) $(CCOPTS) -c -o $@ $<
diff --git a/Standalone/chmem.c b/Standalone/chmem.c
new file mode 100644 (file)
index 0000000..6429d79
--- /dev/null
@@ -0,0 +1,59 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+int main(int argc, char *argv[])
+{
+  int v;
+  FILE *fp;
+  unsigned char buf[8];
+
+  if (argc != 2 && argc != 3) {
+    fprintf(stderr, "%s [executable] {size}\n", argv[0]);
+    exit(1);
+  }
+  if (argc == 2)
+    fp = fopen(argv[1], "r");
+  else
+    fp = fopen(argv[1], "r+");
+  if (fp == NULL) {
+    perror(argv[1]);
+    exit(1);
+  }
+  if (fread(buf, 8, 1, fp) != 1) {
+    fprintf(stderr, "%s: too short ?\n", argv[0]);
+    exit(1);
+  }
+  if (buf[0] != 0xC3 || buf[3] != 'U' || buf[4] != 'Z') {
+    fprintf(stderr, "%s: not an UZI binary format.\n", argv[1]);
+    exit(1);
+  }
+  if (argc == 2) {
+    if (buf[5] == 'I')
+      printf("classic UZI binary.\n");
+    else if (buf[5] & 0x80)
+      printf("chmem UZI binary set at %d bytes.\n", 
+        (buf[5] & 0x7F) << 9);
+    else
+      printf("UZI binary with unknown tail byte %d\n", buf[5]);
+    exit(0);
+  }
+      
+  if (sscanf(argv[2], "%d", &v) != 1 || v < 0 || v > 65536) {
+    fprintf(stderr, "%s: invalid chmem value '%s'.\n", argv[0], argv[2]);
+    exit(1);
+  }
+  if (v == 0)
+    buf[5] = 'I';
+  else
+    buf[5] = ((v + 511) >> 9) | 0x80;
+  rewind(fp);
+  if(fwrite(buf, 8, 1, fp) != 1) {
+    fprintf(stderr, "%s: write error.\n", argv[0]);
+    exit(1);
+  }
+  fclose(fp);
+  exit(0);
+}
diff --git a/Standalone/devio.c b/Standalone/devio.c
new file mode 100644 (file)
index 0000000..65a1575
--- /dev/null
@@ -0,0 +1,253 @@
+#define DEVIO
+
+#include <string.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include "fuzix_fs.h"
+
+/* Buffer pool management */
+/*********************************************************************
+The high-level interface is through bread() and bfree().
+Bread() is given a device and block number, and a rewrite flag.  If
+rewrite is 0, the block is actually read if it is not already in the
+buffer pool. If rewrite is set, it is assumed that the caller plans to
+rewrite the entire contents of the block, and it will not be read in,
+but only have a buffer named after it.
+
+Bfree() is given a buffer pointer and a dirty flag.  If the dirty flag
+is 0, the buffer is made available for further use.  If the flag is 1,
+the buffer is marked "dirty", and it will eventually be written out to
+disk.  If the flag is 2, it will be immediately written out.
+
+Zerobuf() returns a buffer of zeroes not belonging to any device.  It
+must be bfree'd after use, and must not be dirty. It is used when a
+read() wants to read an unallocated block of a file.
+
+Bufsync() write outs all dirty blocks.
+
+Note that a pointer to a buffer structure is the same as a pointer to
+the data.  This is very important.
+**********************************************************************/
+
+uint16_t bufclock = 0;         /* Time-stamp counter for LRU */
+struct blkbuf bufpool[NBUFS];
+
+char *bread(int dev, blkno_t blk, int rewrite)
+{
+    register bufptr bp;
+
+/*printf("Reading block %d\n", blk);*/
+
+    bp = bfind (dev, blk);
+    if (bp)
+    {
+        if (bp->bf_busy)
+            panic ("want busy block");
+        goto done;
+    }
+    bp = freebuf();
+    bp->bf_dev = dev;
+    bp->bf_blk = blk;
+
+    /* If rewrite is set, we are about to write over the entire block,
+       so we don't need the previous contents */
+
+    ifnot (rewrite)
+        if (bdread (bp) == -1)
+        {
+            udata.u_error = EIO;
+            return 0;
+        }
+
+/*--    if (rewrite == 2)--*/
+/*--        bzero (bp->bf_data, 512);--*/
+
+done:
+    bp->bf_busy = 1;
+    bp->bf_time = ++bufclock;  /* Time stamp it */
+    return (bp->bf_data);
+}
+
+
+void brelse(bufptr bp)
+{
+/*printf("Releasing block %d (0)\n", bp->bf_blk);*/
+    bfree (bp, 0);
+}
+
+void bawrite(bufptr bp)
+{
+/*printf("Releasing block %d (1)\n", bp->bf_blk);*/
+    bfree (bp, 1);
+}
+
+int bfree(bufptr bp, int dirty)
+{
+/*printf("Releasing block %d (%d)\n", bp->bf_blk, dirty);*/
+    bp->bf_dirty |= dirty;
+    bp->bf_busy = 0;
+
+    if (dirty == 2)   /* Extra dirty */
+    {
+        if (bdwrite (bp) == -1)
+            udata.u_error = EIO;
+        bp->bf_dirty = 0;
+        return (-1);
+    }
+    return (0);
+}
+
+
+/* This returns a busy block not belonging to any device, with
+ * garbage contents.  It is essentially a malloc for the kernel.
+ * Free it with brelse()!
+ */
+char *
+tmpbuf ()
+{
+    bufptr bp;
+    bufptr freebuf();
+
+/*printf("Allocating temp block\n");*/
+    bp = freebuf();
+    bp->bf_dev = -1;
+    bp->bf_busy = 1;
+    bp->bf_time = ++bufclock;   /* Time stamp it */
+    return (bp->bf_data);
+}
+
+
+char *zerobuf (void)
+{
+    char *b;
+    char *tmpbuf();
+
+    b = tmpbuf();
+    bzero (b, 512);
+    return (b);
+}
+
+
+void bufsync (void)
+{
+    register bufptr bp;
+
+    for (bp=bufpool; bp < bufpool+NBUFS; ++bp)
+    {
+        if (bp->bf_dev != -1 && bp->bf_dirty)
+        {
+            bdwrite (bp);
+            if (!bp->bf_busy)
+                bp->bf_dirty = 0;
+        }
+    }
+}
+
+#ifndef ASM_BUFIO
+
+bufptr bfind (int dev, blkno_t blk)
+{
+    register bufptr bp;
+
+    for (bp=bufpool; bp < bufpool+NBUFS; ++bp)
+    {
+        if (bp->bf_dev == dev && bp->bf_blk == blk)
+            return (bp);
+    }
+    return (NULL);
+}
+
+
+bufptr freebuf(void)
+{
+    register bufptr bp;
+    register bufptr oldest;
+    register int oldtime;
+
+    /* Try to find a non-busy buffer and write out the data if it is dirty */
+    oldest = NULL;
+    oldtime = 0;
+    for (bp=bufpool; bp < bufpool+NBUFS; ++bp)
+    {
+        if (bufclock - bp->bf_time >= oldtime && !bp->bf_busy)
+        {
+            oldest = bp;
+            oldtime = bufclock - bp->bf_time;
+        }
+    }
+    ifnot (oldest)
+        panic ("no free buffers");
+
+    if (oldest->bf_dirty)
+    {
+        if (bdwrite (oldest) == -1)
+            udata.u_error = EIO;
+        oldest->bf_dirty = 0;
+    }
+    return (oldest);
+}
+
+#endif
+        
+
+void bufinit (void)
+{
+    register bufptr bp;
+
+    for (bp=bufpool; bp < bufpool+NBUFS; ++bp)
+    {
+        bp->bf_dev = -1;
+    }
+}
+
+
+void bufdump (void)
+{
+    register bufptr j;
+
+    printf ("\ndev\tblock\tdirty\tbusy\ttime clock %d\n", bufclock);
+    for (j=bufpool; j < bufpool+NBUFS; ++j)
+        printf ("%d\t%u\t%d\t%d\t%u\n",
+            j->bf_dev,j->bf_blk,j->bf_dirty,j->bf_busy,j->bf_time);
+}
+
+
+/*********************************************************************
+Bdread() and bdwrite() are the block device interface routines.  they
+are given a buffer pointer, which contains the device, block number,
+and data location.  They basically validate the device and vector the
+call.
+
+Cdread() and cdwrite are the same for character (or "raw") devices,
+and are handed a device number.  Udata.u_base, count, and offset have
+the rest of the data.
+**********************************************************************/
+
+int bdread (bufptr bp)
+{
+//    printf("bdread(fd=%d, block %d)\n", dev_fd, bp->bf_blk);
+
+    udata.u_buf = bp;
+    if (lseek(dev_fd, dev_offset + (((int)bp->bf_blk) * 512), SEEK_SET) == -1)
+        perror("lseek");
+    if(read(dev_fd, bp->bf_data, 512) != 512)
+        panic("read() failed");
+
+    return 0;
+}
+
+
+int bdwrite (bufptr bp)
+{
+    udata.u_buf = bp;
+
+    lseek(dev_fd, dev_offset + (((int)bp->bf_blk) * 512), SEEK_SET);
+    if(write(dev_fd, bp->bf_data, 512) != 512)
+        panic("write() failed");
+    return 0;
+}
+
+
diff --git a/Standalone/fsck.c b/Standalone/fsck.c
new file mode 100644 (file)
index 0000000..a3ba201
--- /dev/null
@@ -0,0 +1,757 @@
+#include <stdio.h>
+#include <strings.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include "fuzix_fs.h"
+
+#define MAXDEPTH 20    /* Maximum depth of directory tree to search */
+
+/* This checks a filesystem */
+
+int dev = 0;
+struct filesys superblock;
+
+char *bitmap;
+int16_t *linkmap;
+char *daread(uint16_t blk);
+void dwrite(uint16_t blk, char *addr);
+void iread(uint16_t ino, struct dinode *buf);
+void iwrite(uint16_t ino, struct dinode *buf);
+void setblkno(struct dinode *ino, blkno_t num, blkno_t dnum);
+void ckdir(uint16_t inum, uint16_t pnum, char *name);
+void dirread(struct dinode *ino, uint16_t j, struct direct *dentry);
+void dirwrite(struct dinode *ino, uint16_t j, struct direct *dentry);
+void mkentry(uint16_t inum);
+
+void pass1(void);
+void pass2(void);
+void pass3(void);
+void pass4(void);
+void pass5(void);
+
+int yes(void)
+{
+    printf("YESYES!\n");
+    return 1;
+}
+
+
+int main(int argc, char **argv)
+{
+    char *buf;
+
+    if(argc != 2){
+        fprintf(stderr, "syntax: fsck [devfile]\n");
+        return 1;
+    }
+    
+    if(fd_open(argv[1])){
+        printf("Cannot open file\n");
+        return -1;
+    }
+
+    buf = daread(1);
+    bcopy(buf, (char *) &superblock, sizeof(struct filesys));
+
+    /* Verify the fsize and isize parameters */
+
+    if (superblock.s_mounted != SMOUNTED) {
+        printf("Device %d has invalid magic number %d. Fix? ", dev, superblock.s_mounted);
+        if (!yes())
+            exit(-1);
+        superblock.s_mounted = SMOUNTED;
+        dwrite((blkno_t) 1, (char *) &superblock);
+    }
+    printf("Device %d has fsize = %d and isize = %d. Continue? ",
+            dev, superblock.s_fsize, superblock.s_isize);
+    if (!yes())
+        exit(-1);
+
+    bitmap = calloc(superblock.s_fsize, sizeof(char));
+    linkmap = (int16_t *) calloc(8 * superblock.s_isize, sizeof(int16_t));
+
+    if (!bitmap || !linkmap) {
+        fprintf(stderr, "Not enough memory.\n");
+        exit(-1);
+    }
+
+    printf("Pass 1: Checking inodes...\n");
+    pass1();
+
+    printf("Pass 2: Rebuilding free list...\n");
+    pass2();
+
+    printf("Pass 3: Checking block allocation...\n");
+    pass3();
+
+    printf("Pass 4: Checking directory entries...\n");
+    pass4();
+
+    printf("Pass 5: Checking link counts...\n");
+    pass5();
+
+    printf("Done.\n");
+
+    exit(0);
+}
+
+
+/*
+ *  Pass 1 checks each inode independently for validity, zaps bad block
+ *  numbers in the inodes, and builds the block allocation map.
+ */
+
+void pass1(void)
+{
+    uint16_t n;
+    struct dinode ino;
+    uint16_t mode;
+    blkno_t b;
+    blkno_t bno;
+    uint16_t icount;
+    blkno_t *buf;
+
+    blkno_t getblkno();
+    int yes();                 /* 1.4.98 - HFB */
+
+    icount = 0;
+
+    for (n = ROOTINODE; n < 8 * (superblock.s_isize - 2); ++n) {
+        iread(n, &ino);
+        linkmap[n] = -1;
+        if (ino.i_mode == 0)
+            continue;
+
+        mode = ino.i_mode & F_MASK;
+
+        /* Check mode */
+        if (mode != F_REG && mode != F_DIR && mode != F_BDEV && mode != F_CDEV) {
+            printf("Inode %d with mode 0%o is not of correct type. Zap? ",
+                    n, ino.i_mode);
+            if (yes()) {
+                ino.i_mode = 0;
+                ino.i_nlink = 0;
+                iwrite(n, &ino);
+                continue;
+            }
+        }
+        linkmap[n] = 0;
+        ++icount;
+        /* Check size */
+
+        if (ino.i_size < 0) {
+            printf("Inode %d offset is negative with value of %ld. Fix? ",
+                    n, (long)ino.i_size);
+            if (yes()) {
+                ino.i_size = 0;
+                iwrite(n, &ino);
+            }
+        }
+        /* Check blocks and build free block map */
+        if (mode == F_REG || mode == F_DIR) {
+            /* Check singly indirect blocks */
+
+            for (b = 18; b < 20; ++b) {
+                if (ino.i_addr[b] != 0 && (ino.i_addr[b] < superblock.s_isize ||
+                            ino.i_addr[b] >= superblock.s_fsize)) {
+                    printf("Inode %d singly ind. blk %d out of range, val = %u. Zap? ",
+                            n, b, ino.i_addr[b]);
+                    if (yes()) {
+                        ino.i_addr[b] = 0;
+                        iwrite(n, &ino);
+                    }
+                }
+                if (ino.i_addr[b] != 0 && ino.i_size < 18*512) {
+                    printf("Inode %d singly ind. blk %d past end of file, val = %u. Zap? ",
+                            n, b, ino.i_addr[b]);
+                    if (yes()) {
+                        ino.i_addr[b] = 0;
+                        iwrite(n, &ino);
+                    }
+                }
+                if (ino.i_addr[b] != 0)
+                    bitmap[ino.i_addr[b]] = 1;
+            }
+
+            /* Check the double indirect blocks */
+            if (ino.i_addr[19] != 0) {
+                buf = (blkno_t *) daread(ino.i_addr[19]);
+                for (b = 0; b < 256; ++b) {
+                    if (buf[b] != 0 && (buf[b] < superblock.s_isize ||
+                                buf[b] >= superblock.s_fsize)) {
+                        printf("Inode %d doubly ind. blk %d is ", n, b);
+                        printf("out of range, val = %u. Zap? ", buf[b]);
+                        /* 1.4.98 - line split.  HFB */
+                        if (yes()) {
+                            buf[b] = 0;
+                            dwrite(b, (char *) buf);
+                        }
+                    }
+                    if (buf[b] != 0)
+                        bitmap[buf[b]] = 1;
+                }
+            }
+            /* Check the rest */
+            for (bno = 0; bno <= ino.i_size/512; ++bno) {
+                b = getblkno(&ino, bno);
+
+                if (b != 0 && (b < superblock.s_isize || b >= superblock.s_fsize)) {
+                    printf("Inode %d block %d out of range, val = %u. Zap? ",
+                            n, bno, b);
+                    if (yes()) {
+                        setblkno(&ino, bno, 0);
+                        iwrite(n, &ino);
+                    }
+                }
+                if (b != 0)
+                    bitmap[b] = 1;
+            }
+        }
+    }
+    /* Fix free inode count in superblock block */
+    if (superblock.s_tinode != 8 * (superblock.s_isize - 2) - ROOTINODE - icount) {
+        printf("Free inode count in superblock block is %u, should be %u. Fix? ",
+                superblock.s_tinode, 8 * (superblock.s_isize - 2) - ROOTINODE - icount);
+
+        if (yes()) {
+            superblock.s_tinode = 8 * (superblock.s_isize - 2) - ROOTINODE - icount;
+            dwrite((blkno_t) 1, (char *) &superblock);
+        }
+    }
+}
+
+
+/* Clear inode free list, rebuild block free list using bit map. */
+
+void pass2(void)
+{
+    blkno_t j;
+    blkno_t oldtfree;
+    int yes();
+
+    printf("Rebuild free list? ");
+    if (!yes())
+        return;
+
+    oldtfree = superblock.s_tfree;
+
+    /* Initialize the superblock-block */
+
+    superblock.s_ninode = 0;
+    superblock.s_nfree = 1;
+    superblock.s_free[0] = 0;
+    superblock.s_tfree = 0;
+
+    /* Free each block, building the free list */
+
+    for (j = superblock.s_fsize - 1; j >= superblock.s_isize; --j) {
+        if (bitmap[j] == 0) {
+            if (superblock.s_nfree == 50) {
+                dwrite(j, (char *) &superblock.s_nfree);
+                superblock.s_nfree = 0;
+            }
+            ++superblock.s_tfree;
+            superblock.s_free[(superblock.s_nfree)++] = j;
+        }
+    }
+
+    dwrite((blkno_t) 1, (char *) &superblock);
+
+    if (oldtfree != superblock.s_tfree)
+        printf("During free list regeneration s_tfree was changed to %d from %d.\n",
+                superblock.s_tfree, oldtfree);
+
+}
+
+
+/* Pass 3 finds and fixes multiply allocated blocks. */
+
+void pass3(void)
+{
+    uint16_t n;
+    struct dinode ino;
+    uint16_t mode;
+    blkno_t b;
+    blkno_t bno;
+    blkno_t newno;
+    blkno_t blk_alloc0();
+    /*--- was blk_alloc ---*/
+    blkno_t getblkno();
+    int yes();
+
+    for (b = superblock.s_isize; b < superblock.s_fsize; ++b)
+        bitmap[b] = 0;
+
+    for (n = ROOTINODE; n < 8 * (superblock.s_isize - 2); ++n) {
+        iread(n, &ino);
+
+        mode = ino.i_mode & F_MASK;
+        if (mode != F_REG && mode != F_DIR)
+            continue;
+
+        /* Check singly indirect blocks */
+
+        for (b = 18; b < 20; ++b) {
+            if (ino.i_addr[b] != 0) {
+                if (bitmap[ino.i_addr[b]] != 0) {
+                    printf("Indirect block %d in inode %u value %u multiply allocated. Fix? ",
+                            b, n, ino.i_addr[b]);
+                    if (yes()) {
+                        newno = blk_alloc0(&superblock);
+                        if (newno == 0)
+                            printf("Sorry... No more free blocks.\n");
+                        else {
+                            dwrite(newno, daread(ino.i_addr[b]));
+                            ino.i_addr[b] = newno;
+                            iwrite(n, &ino);
+                        }
+                    }
+                } else
+                    bitmap[ino.i_addr[b]] = 1;
+            }
+        }
+
+        /* Check the rest */
+        for (bno = 0; bno <= ino.i_size/512; ++bno) {
+            b = getblkno(&ino, bno);
+
+            if (b != 0) {
+                if (bitmap[b] != 0) {
+                    printf("Block %d in inode %u value %u multiply allocated. Fix? ",
+                            bno, n, b);
+                    if (yes()) {
+                        newno = blk_alloc0(&superblock);
+                        if (newno == 0)
+                            printf("Sorry... No more free blocks.\n");
+                        else {
+                            dwrite(newno, daread(b));
+                            setblkno(&ino, bno, newno);
+                            iwrite(n, &ino);
+                        }
+                    }
+                } else
+                    bitmap[b] = 1;
+            }
+        }
+
+    }
+
+}
+
+int depth;
+
+/*
+ *  Pass 4 traverses the directory tree, fixing bad directory entries
+ *  and finding the actual number of references to each inode.
+ */
+
+void pass4(void)
+{
+    depth = 0;
+    linkmap[ROOTINODE] = 1;
+    ckdir(ROOTINODE, ROOTINODE, "/");
+    if (depth != 0)
+        panic("Inconsistent depth");
+}
+
+
+/* This recursively checks the directories */
+
+void ckdir(uint16_t inum, uint16_t pnum, char *name)
+{
+    struct dinode ino;
+    struct direct dentry;
+    uint16_t j;
+    int c;
+    int nentries;
+    char ename[150];
+
+    iread(inum, &ino);
+    if ((ino.i_mode & F_MASK) != F_DIR)
+        return;
+    ++depth;
+
+    if (ino.i_size % 32 != 0) {
+        printf("Directory inode %d has improper length. Fix? ", inum);
+        if (yes()) {
+            ino.i_size &= (~0x1f);
+            iwrite(inum, &ino);
+        }
+    }
+    nentries = ino.i_size/32;
+
+    for (j = 0; j < nentries; ++j) {
+        dirread(&ino, j, &dentry);
+
+#if 1 /**HP**/
+        {
+            int i;
+
+            for (i = 0; i < 14; ++i) if (dentry.d_name[i] == '\0') break;
+            for (     ; i < 14; ++i) dentry.d_name[i] = '\0';
+            dirwrite(&ino, j, &dentry);
+        }
+#endif
+
+        if (dentry.d_ino == 0)
+            continue;
+
+        if (dentry.d_ino < ROOTINODE || dentry.d_ino >= 8 * superblock.s_isize) {
+            printf("Directory entry %s%-1.14s has out-of-range inode %u. Zap? ",
+                    name, dentry.d_name, dentry.d_ino);
+            if (yes()) {
+                dentry.d_ino = 0;
+                dentry.d_name[0] = '\0';
+                dirwrite(&ino, j, &dentry);
+                continue;
+            }
+        }
+        if (dentry.d_ino && linkmap[dentry.d_ino] == -1) {
+            printf("Directory entry %s%-1.14s points to bogus inode %u. Zap? ",
+                    name, dentry.d_name, dentry.d_ino);
+            if (yes()) {
+                dentry.d_ino = 0;
+                dentry.d_name[0] = '\0';
+                dirwrite(&ino, j, &dentry);
+                continue;
+            }
+        }
+        ++linkmap[dentry.d_ino];
+
+        for (c = 0; c < 14 && dentry.d_name[c]; ++c) {
+            if (dentry.d_name[c] == '/') {
+                printf("Directory entry %s%-1.14s contains slash. Fix? ",
+                        name, dentry.d_name);
+                if (yes()) {
+                    dentry.d_name[c] = 'X';
+                    dirwrite(&ino, j, &dentry);
+                }
+            }
+        }
+
+        if (strncmp(dentry.d_name, ".", 14) == 0 && dentry.d_ino != inum) {
+            printf("Dot entry %s%-1.14s points to wrong place. Fix? ",
+                    name, dentry.d_name);
+            if (yes()) {
+                dentry.d_ino = inum;
+                dirwrite(&ino, j, &dentry);
+            }
+        }
+        if (strncmp(dentry.d_name, "..", 14) == 0 && dentry.d_ino != pnum) {
+            printf("DotDot entry %s%-1.14s points to wrong place. Fix? ",
+                    name, dentry.d_name);
+            if (yes()) {
+                dentry.d_ino = pnum;
+                dirwrite(&ino, j, &dentry);
+            }
+        }
+        if (dentry.d_ino != pnum && dentry.d_ino != inum && depth < MAXDEPTH) {
+            strcpy(ename, name);
+            strcat(ename, dentry.d_name);
+            strcat(ename, "/");
+            ckdir(dentry.d_ino, inum, ename);
+        }
+    }
+    --depth;
+}
+
+
+/* Pass 5 compares the link counts found in pass 4 with the inodes. */
+
+void pass5(void)
+{
+    uint16_t n;
+    struct dinode ino;
+    int yes();
+
+    for (n = ROOTINODE; n < 8 * (superblock.s_isize - 2); ++n) {
+        iread(n, &ino);
+
+        if (ino.i_mode == 0) {
+            if (linkmap[n] != -1)
+                panic("Inconsistent linkmap");
+            continue;
+        }
+
+        if (linkmap[n] == -1 && ino.i_mode != 0)
+            panic("Inconsistent linkmap");
+
+        if (linkmap[n] > 0 && ino.i_nlink != linkmap[n]) {
+            printf("Inode %d has link count %d should be %d. Fix? ",
+                    n, ino.i_nlink, linkmap[n]);
+            if (yes()) {
+                ino.i_nlink = linkmap[n];
+                iwrite(n, &ino);
+            }
+        }
+
+        if (linkmap[n] == 0) {
+            if ((ino.i_mode & F_MASK) == F_BDEV ||
+                    (ino.i_mode & F_MASK) == F_CDEV ||
+                    (ino.i_size == 0)) {
+                printf("Useless inode %d with mode 0%o has become detached. Link count is %d. Zap? ",
+                        n, ino.i_mode, ino.i_nlink);
+                if (yes()) {
+                    ino.i_nlink = 0;
+                    ino.i_mode = 0;
+                    iwrite(n, &ino);
+                    ++superblock.s_tinode;
+                    dwrite((blkno_t) 1, (char *) &superblock);
+                }
+            } else {
+#if 0
+                printf("Inode %d has become detached. Link count is %d. Fix? ",
+                        n, ino.i_nlink);
+                if (yes()) {
+                    ino.i_nlink = 1;
+                    iwrite(n, &ino);
+                    mkentry(n);
+                }
+#else
+                printf("Inode %d has become detached. Link count is %d. ",
+                        n, ino.i_nlink);
+                if (ino.i_nlink == 0)
+                    printf("Zap? ");
+                else
+                    printf("Fix? ");
+                if (yes()) {
+                    if (ino.i_nlink == 0) {
+                        ino.i_nlink = 0;
+                        ino.i_mode = 0;
+                        iwrite(n, &ino);
+                        ++superblock.s_tinode;
+                        dwrite((blkno_t) 1, (char *) &superblock);
+                    } else {
+                        ino.i_nlink = 1;
+                        iwrite(n, &ino);
+                        mkentry(n);
+                    }
+                }
+#endif
+            }
+        }
+
+    }
+}
+
+
+/* This makes an entry in "lost+found" for inode n */
+
+void mkentry(uint16_t inum)
+{
+    struct dinode rootino;
+    struct direct dentry;
+    uint16_t d;
+
+    iread(ROOTINODE, &rootino);
+    for (d = 0; d < rootino.i_size/32; ++d) {
+        dirread(&rootino, d, &dentry);
+        if (dentry.d_ino == 0 && dentry.d_name[0] == '\0') {
+            dentry.d_ino = inum;
+            sprintf(dentry.d_name, "l+f%d", inum);
+            dirwrite(&rootino, d, &dentry);
+            return;
+        }
+    }
+    printf("Sorry... No empty slots in root directory.\n");
+}
+
+/* Beginning of fsck1.c */
+
+/*
+ *  Getblkno gets a pointer index, and a number of a block in the file.
+ *  It returns the number of the block on the disk.  A value of zero
+ *  means an unallocated block.
+ */
+
+    blkno_t
+getblkno(ino, num)
+    struct dinode *ino;
+    blkno_t num;
+{
+    blkno_t indb;
+    blkno_t dindb;
+    blkno_t *buf;
+
+    if (num < 18) {            /* Direct block */
+        return (ino->i_addr[num]);
+    }
+    if (num < 256 + 18) {      /* Single indirect */
+        indb = ino->i_addr[18];
+        if (indb == 0)
+            return (0);
+        buf = (blkno_t *) daread(indb);
+        return (buf[num - 18]);
+    }
+    /* Double indirect */
+    indb = ino->i_addr[19];
+    if (indb == 0)
+        return (0);
+
+    buf = (blkno_t *) daread(indb);
+
+    dindb = buf[(num - (18 + 256)) >> 8];
+    buf = (blkno_t *) daread(dindb);
+
+    return (buf[(num - (18 + 256)) & 0x00ff]);
+}
+
+
+/*
+ *  Setblkno sets the given block number of the given file to the given
+ *  disk block number, possibly creating or modifiying the indirect blocks.
+ *  A return of zero means there were no blocks available to create an 
+ *  indirect block. This should never happen in fsck.
+ */
+
+void setblkno(struct dinode *ino, blkno_t num, blkno_t dnum)
+{
+    blkno_t indb;
+    blkno_t dindb;
+    blkno_t *buf;
+    /*--    char *zerobuf();--*/
+
+
+    if (num < 18) {                    /* Direct block */
+        ino->i_addr[num] = dnum;
+    } else if (num < 256 + 18) {       /* Single indirect */
+        indb = ino->i_addr[18];
+        if (indb == 0)
+            panic("Missing indirect block");
+
+        buf = (blkno_t *) daread(indb);
+        buf[num - 18] = dnum;
+        dwrite(indb, (char *) buf);
+    } else {                           /* Double indirect */
+        indb = ino->i_addr[19];
+        if (indb == 0)
+            panic("Missing indirect block");
+
+        buf = (blkno_t *) daread(indb);
+        dindb = buf[(num - (18 + 256)) >> 8];
+        if (dindb == 0)
+            panic("Missing indirect block");
+
+        buf = (blkno_t *) daread(dindb);
+        buf[(num - (18 + 256)) & 0x00ff] = num;
+        dwrite(indb, (char *) buf);
+    }
+}
+
+
+/*
+ *  blk_alloc0 allocates an unused block.
+ *  A returned block number of zero means no more blocks.
+ */
+
+/*--- was blk_alloc ---*/
+
+blkno_t blk_alloc0(struct filesys *filesys)
+{
+    blkno_t newno;
+    blkno_t *buf;
+    int16_t j;
+
+    newno = filesys->s_free[--filesys->s_nfree];
+    ifnot (newno) {
+        ++filesys->s_nfree;
+        return (0);
+    }
+
+    /* See if we must refill the s_free array */
+
+    ifnot (filesys->s_nfree) {
+        buf = (blkno_t *) daread(newno);
+        filesys->s_nfree = buf[0];
+        for (j = 0; j < 50; j++) {
+            filesys->s_free[j] = buf[j + 1];
+        }
+    }
+
+    --filesys->s_tfree;
+
+    if (newno < filesys->s_isize || newno >= filesys->s_fsize) {
+        printf("Free list is corrupt.  Did you rebuild it?\n");
+        return (0);
+    }
+    dwrite((blkno_t) 1, (char *) filesys);
+    return (newno);
+}
+
+
+char *daread(uint16_t blk)
+{
+    static char da_buf[512];
+    if (lseek(dev_fd, blk * 512L, 0) == -1) {
+        perror("lseek");
+        exit(1);
+    }
+    if(read(dev_fd, da_buf, 512) != 512) {
+        perror("read");
+        exit(1);
+    }
+    return da_buf;
+}
+
+
+void dwrite(uint16_t blk, char *addr)
+{
+    if (lseek(dev_fd, blk * 512L, 0) == -1) {
+        perror("lseek");
+        exit(1);
+    }
+    if(write(dev_fd, addr, 512) != 512) {
+        perror("write");
+        exit(1);
+    }
+}
+
+
+void iread(uint16_t ino, struct dinode *buf)
+{
+    struct dinode *addr;
+
+    addr = (struct dinode *) daread((ino >> 3) + 2);
+    bcopy((char *) &addr[ino & 7], (char *) buf, sizeof(struct dinode));
+}
+
+
+void iwrite(uint16_t ino, struct dinode *buf)
+{
+    struct dinode *addr;
+
+    addr = (struct dinode *) daread((ino >> 3) + 2);
+    bcopy((char *) buf, (char *) &addr[ino & 7], sizeof(struct dinode));
+    dwrite((ino >> 3) + 2, (char *) addr);
+}
+
+
+void dirread(struct dinode *ino, uint16_t j, struct direct *dentry)
+{
+    blkno_t blkno;
+    char *buf;
+
+    blkno = getblkno(ino, (blkno_t) j / 16);
+    if (blkno == 0)
+        panic("Missing block in directory");
+    buf = daread(blkno);
+    bcopy(buf + 32 * (j % 16), (char *) dentry, 32);
+}
+
+
+void dirwrite(struct dinode *ino, uint16_t j, struct direct *dentry)
+{
+    blkno_t blkno;
+    char *buf;
+
+    blkno = getblkno(ino, (blkno_t) j / 16);
+    if (blkno == 0)
+        panic("Missing block in directory");
+    buf = daread(blkno);
+    bcopy((char *) dentry, buf + 32 * (j % 16), 32);
+    dwrite(blkno, buf);
+}
+
diff --git a/Standalone/fuzix_fs.h b/Standalone/fuzix_fs.h
new file mode 100644 (file)
index 0000000..2a669f2
--- /dev/null
@@ -0,0 +1,325 @@
+#define __UZIFS_DOT_H__
+
+#include <stdio.h>
+
+#define ROOTDEV 0
+#define ROOTINODE 1
+#define SMOUNTED 12742   /* Magic number to specify mounted filesystem */
+#define CMAGIC   24721
+#define UFTSIZE 10
+#define NSIGS 16
+#define NDEVS 1
+#define NBUFS 10
+#define OFTSIZE 15
+#define ITABSIZE 20
+#define _NSIG NSIGS
+#define NULLINODE ((inoptr)NULL)
+#define NULLBLK ((blkno_t)-1)
+#define NULLINOPTR ((inoptr*)NULL)
+
+/* Flags for setftime() */
+#define A_TIME 1
+#define M_TIME 2
+#define C_TIME 4
+
+
+#define FO_RDONLY        0
+#define FO_WRONLY        1
+#define FO_RDWR          2
+
+#define ifnot(x) if(!(x))
+
+extern int dev_fd;
+extern int dev_offset;
+int fd_open(char *name);
+int d_close(void);
+void xfs_init();
+void panic(char *s);
+void bufsync (void);
+char *zerobuf (void);
+int super();
+
+
+typedef struct s_queue {
+    char *q_base;    /* Pointer to data */
+    char *q_head;    /* Pointer to addr of next char to read. */
+    char *q_tail;    /* Pointer to where next char to insert goes. */
+    int   q_size;    /* Max size of queue */
+    int   q_count;   /* How many characters presently in queue */
+    int   q_wakeup;  /* Threshold for waking up processes waiting on queue */
+} queue_t;
+
+struct  uzi_stat    /* Really only used by users */
+{
+    int16_t   st_dev;
+    uint16_t  st_ino;
+    uint16_t  st_mode;
+    uint16_t  st_nlink;
+    uint16_t  st_uid;
+    uint16_t  st_gid;
+    uint16_t  st_rdev;
+    uint32_t  st_size;
+    uint32_t  fst_atime;
+    uint32_t  fst_mtime;
+    uint32_t  fst_ctime;
+};
+
+typedef struct direct {
+        uint16_t   d_ino;
+        char     d_name[30];
+} direct;
+
+typedef uint16_t blkno_t;    /* Can have 65536 512-byte blocks in filesystem */
+
+typedef struct blkbuf {
+    char        bf_data[512];    /* This MUST be first ! */
+    char        bf_dev;
+    blkno_t     bf_blk;
+    char        bf_dirty;
+    char        bf_busy;
+    uint16_t      bf_time;         /* LRU time stamp */
+} blkbuf;
+
+typedef blkbuf *bufptr;
+
+typedef struct dinode {
+    uint16_t i_mode;
+    uint16_t i_nlink;
+    uint16_t i_uid;
+    uint16_t i_gid;
+    uint32_t    i_size;
+    uint32_t   i_atime;
+    uint32_t   i_mtime;
+    uint32_t   i_ctime;
+    blkno_t  i_addr[20];
+} dinode;               /* Exactly 64 bytes long! */
+
+/* Bit masks for i_mode and st_mode */
+
+#define OTH_EX  0001
+#define OTH_WR  0002
+#define OTH_RD  0004
+#define GRP_EX  0010
+#define GRP_WR  0020
+#define GRP_RD  0040
+#define OWN_EX  0100
+#define OWN_WR  0200
+#define OWN_RD  0400
+
+#define SAV_TXT 01000
+#define SET_GID 02000
+#define SET_UID 04000
+
+#define MODE_MASK 07777
+
+#define F_REG   0100000
+#define F_DIR   040000
+#define F_PIPE  010000
+#define F_BDEV  060000
+#define F_CDEV  020000
+
+#define F_MASK  0170000
+
+typedef struct cinode {
+    int        c_magic;           /* Used to check for corruption. */
+    int        c_dev;             /* Inode's device */
+    unsigned   c_num;             /* Inode # */
+    dinode     c_node;
+    char       c_refs;            /* In-core reference count */
+    char       c_dirty;           /* Modified flag. */
+} cinode, *inoptr;
+
+typedef struct filesys {
+    int16_t       s_mounted;
+    uint16_t      s_isize;
+    uint16_t      s_fsize;
+    int16_t       s_nfree;
+    blkno_t     s_free[50];
+    int16_t       s_ninode;
+    uint16_t      s_inode[50];
+    uint8_t       s_fmod;
+    uint8_t    s_timeh;        /* top bits of time */
+    uint32_t      s_time;
+    blkno_t     s_tfree;
+    uint16_t      s_tinode;
+    inoptr      s_mntpt;
+} filesys, *fsptr;
+
+typedef struct u_data {
+    struct p_tab *u_ptab;       /* Process table pointer */
+    char        u_insys;        /* True if in kernel */
+    char        u_callno;       /* sys call being executed. */
+    char        *u_retloc;      /* Return location from sys call */
+    int         u_retval;       /* Return value from sys call */
+    int         u_error;                /* Last error number */
+    char        *u_sp;          /* Used when a process is swapped. */
+    char        *u_bc;          /* Place to save user's frame pointer */
+    int         u_cursig;       /* Signal currently being caught */
+    int         u_argn;         /* Last system call arg */
+    int         u_argn1;        /* This way because args on stack backwards */
+    int         u_argn2;
+    int         u_argn3;        /* args n-3, n-2, n-1, and n */
+
+    char *      u_base;         /* Source or dest for I/O */
+    unsigned    u_count;        /* Amount for I/O */
+    uint32_t       u_offset;       /* Place in file for I/O */
+    struct blkbuf *u_buf;
+    char        u_sysio;        /* True if I/O is to system data space   280*/
+
+    int         u_gid;
+    int         u_euid;
+    int         u_egid;
+    int         u_mask;         /* umask: file creation mode mask */
+    uint32_t      u_time;         /* Start time */
+    char        u_files[UFTSIZE];       /* Process file table:
+                                           contains indexes into open file table. */
+    inoptr      u_cwd;          /* Index into inode table of cwd. */
+    unsigned    u_break;        /* Top of data space */
+    inoptr      u_ino;          /* Used during execve() */
+    char        *u_isp;         /* Value of initial sp (argv) */
+
+    int         (*u_sigvec[NSIGS])();   /* Array of signal vectors */
+    char        u_name[8];      /* Name invoked with */
+    uint32_t      u_utime;        /* Elapsed ticks in user mode */
+    uint32_t      u_stime;        /* Ticks in system mode */
+    uint32_t      u_cutime;       /* Total childrens ticks */
+    uint32_t      u_cstime;
+} u_data;
+
+
+extern inoptr root;
+extern struct cinode i_tab[ITABSIZE];
+extern struct filesys fs_tab[1];
+extern struct blkbuf bufpool[NBUFS];
+extern struct u_data udata; /* MUST BE FIRST */
+#define PTABSIZE 20
+// extern struct p_tab ptab[PTABSIZE];
+
+#define EPERM           1               /* Not owner */
+#define ENOENT          2               /* No such file or directory */
+#define ESRCH           3               /* No such process */
+#define EINTR           4               /* Interrupted System Call */
+#define EIO             5               /* I/O Error */
+#define ENXIO           6               /* No such device or address */
+#define E2BIG           7               /* Arg list too long */
+#define ENOEXEC         8               /* Exec format error */
+#define EBADF           9               /* Bad file number */
+#define ECHILD          10              /* No children */
+#define EAGAIN          11              /* No more processes */
+#define ENOMEM          12              /* Not enough core */
+#define EACCES          13              /* Permission denied */
+#define EFAULT          14              /* Bad address */
+#define ENOTBLK         15              /* Block device required */
+#define EBUSY           16              /* Mount device busy */
+#define EEXIST          17              /* File exists */
+#define EXDEV           18              /* Cross-device link */
+#define ENODEV          19              /* No such device */
+#define ENOTDIR         20              /* Not a directory */
+#define EISDIR          21              /* Is a directory */
+#define EINVAL          22              /* Invalid argument */
+#define ENFILE          23              /* File table overflow */
+#define EMFILE          24              /* Too many open files */
+#define ENOTTY          25              /* Not a typewriter */
+#define ETXTBSY         26              /* Text file busy */
+#define EFBIG           27              /* File too large */
+#define ENOSPC          28              /* No space left on device */
+#define ESPIPE          29              /* Illegal seek */
+#define EROFS           30              /* Read-only file system */
+#define EMLINK          31              /* Too many links */
+#define EPIPE           32              /* Broken pipe */
+
+typedef struct oft {
+    uint32_t     o_ptr;      /* File position point16_ter */
+    inoptr    o_inode;    /* Pointer into in-core inode table */
+    char      o_access;   /* O_RDONLY, O_WRONLY, or O_RDWR */
+    char      o_refs;     /* Reference count: depends on # of active children*/
+} oft;
+
+// extern struct cinode i_tab[ITABSIZE];    /* In-core inode table */
+extern struct oft of_tab[OFTSIZE]; /* Open File Table */
+
+void brelse(bufptr bp);
+void bawrite(bufptr bp);
+int bfree(bufptr bp, int dirty);
+int bdwrite(bufptr bp);
+int bdread(bufptr bp);
+void bufinit(void);
+void bufdump(void);
+bufptr bfind(int dev, blkno_t blk);
+bufptr freebuf(void);
+int insq (struct s_queue *q, char c);
+int remq (struct s_queue *q, char *cp);
+int uninsq (struct s_queue *q, char *cp);
+int fullq (struct s_queue *q);
+void clrq (struct s_queue *q);
+char *bread(int dev, blkno_t blk, int rewrite);
+int fmount(int dev, inoptr ino);
+void i_ref(inoptr ino);
+void xfs_end(void);
+int doclose(int16_t uindex);
+int _open(char *name, int16_t flag);
+int _creat(char *name, int16_t mode);
+int _close(int16_t uindex);
+int _link( char *name1, char *name2);
+int _unlink(char *path);
+int _read( int16_t d, char *buf, uint16_t nbytes);
+int _write( int16_t d, char *buf, uint16_t nbytes);
+int _mknod( char *name, int16_t mode, int16_t dev);
+blkno_t bmap(inoptr ip, blkno_t bn, int rwflg);
+inoptr rwsetup( int rwflag, int d, char *buf, int nbytes);
+int psize(inoptr ino);
+void oft_deref(int of);
+void i_deref(inoptr ino);
+void f_trunc(inoptr ino);
+void setftime(inoptr ino, int flag);
+void wr_inode(inoptr ino);
+int _seek( int16_t file, uint16_t offset, int16_t flag);
+void readi( inoptr ino );
+void writei( inoptr ino);
+void addoff( uint32_t *ofptr, int amount);
+void updoff(int d);
+inoptr getinode(int uindex);
+inoptr n_open( register char *name, register inoptr *parent );
+inoptr srch_dir(inoptr wd, register char *compname);
+inoptr srch_mt( inoptr ino);
+inoptr i_open( register int dev, register unsigned ino);
+int ch_link( inoptr wd, char *oldname, char *newname, inoptr nindex);
+char * filename( char *path);
+int namecomp( char *n1, char *n2);
+inoptr newfile( inoptr pino, char *name);
+fsptr getdev( int devno);
+unsigned i_alloc(int devno);
+void i_free( int devno, unsigned ino);
+blkno_t blk_alloc( int devno );
+void blk_free( int devno, blkno_t blk);
+int oft_alloc(void);
+void _sync(void);
+int _chdir(char *dir);
+int min(int a, int b);
+int _access( char *path, int16_t mode);
+int _chmod( char *path, int16_t mode);
+int _chown( char *path, int owner, int group);
+int _stat( char *path, struct uzi_stat *buf);
+int _fstat( int16_t fd, struct uzi_stat *buf);
+void stcpy( inoptr ino, struct uzi_stat *buf);
+int _dup( int16_t oldd);
+int _dup2( int16_t oldd, int16_t newd);
+int _umask( int mask);
+int _getfsys(int dev,char * buf);
+int _ioctl( int fd, int request, char *data);
+int getperm(inoptr ino);
+int _mount( char *spec, char *dir, int rwflag);
+int _time( int tvec[]);
+int getmode(inoptr ino);
+void bawrite(bufptr bp);
+int isdevice(inoptr ino);
+int bfree(bufptr bp, int dirty);
+void magic(inoptr ino);
+int baddev(fsptr dev);
+void validblk(int dev, blkno_t num);
+int uf_alloc(void);
+void i_ref( inoptr ino);
+void freeblk(int dev, blkno_t blk, int level);
+int valadr(char *base, uint16_t size);
+int _umount(char *spec);
+
diff --git a/Standalone/mkfs.c b/Standalone/mkfs.c
new file mode 100644 (file)
index 0000000..9aa1c24
--- /dev/null
@@ -0,0 +1,131 @@
+\r
+/**************************************************\r
+UZI (Unix Z80 Implementation) Utilities:  mkfs.c\r
+***************************************************/\r
+\r
+#include <stdio.h>\r
+#include <stdint.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <sys/types.h>\r
+#include <unistd.h>\r
+#include <sys/stat.h>\r
+#include "fuzix_fs.h"\r
+\r
+/* This makes a filesystem \r
+ *\r
+ * example use:\r
+ *   ./mkfs ./blankfs.img 64 4096\r
+ * (this will write a 2MB filesystem with 64 blocks of inodes to ./blankfs.img)\r
+ *\r
+ * */\r
+\r
+char zero512[512];\r
+\r
+direct dirbuf[64] = { {ROOTINODE,"."},\r
+                      {ROOTINODE,".."} };\r
+struct dinode inode[8];\r
+\r
+void mkfs(uint16_t fsize, uint16_t isize);\r
+void dwrite(uint16_t blk, char *addr);\r
+\r
+struct filesys fs_super;\r
+\r
+int main(int argc, char **argv)\r
+{\r
+    uint16_t fsize, isize;\r
+\r
+    if (argc != 4)\r
+    {\r
+        printf("Usage: mkfs device isize fsize\n");\r
+        return -1;\r
+    }\r
+\r
+    if(sizeof(inode) != 512){\r
+        printf("inode is the wrong size -- %d\n", (int)sizeof(inode));\r
+    }\r
+\r
+    isize = (uint16_t)atoi(argv[2]);\r
+    fsize = (uint16_t)atoi(argv[3]);\r
+\r
+    if (fsize < 3 || isize < 2 || isize >= fsize)\r
+    {\r
+        printf("Bad parameter values\n");\r
+        return -1;\r
+    }\r
+\r
+    memset(zero512, 0, 512);\r
+\r
+    printf("Making filesystem on device %s with isize %u fsize %u.\n", argv[1], isize, fsize);\r
+\r
+    if (fd_open(argv[1]))\r
+    {\r
+        printf("Can't open device");\r
+        return -1;\r
+    }\r
+\r
+    mkfs(fsize, isize);\r
+\r
+    return 0;\r
+}\r
+\r
+void mkfs(uint16_t fsize, uint16_t isize)\r
+{\r
+    uint16_t j;\r
+\r
+    /* Zero out the blocks */\r
+\r
+    for (j=0; j < fsize; ++j)\r
+        dwrite(j, zero512);\r
+\r
+    /* Initialize the super-block */\r
+\r
+    fs_super.s_mounted = SMOUNTED; /* Magic number */\r
+    fs_super.s_isize =  isize;\r
+    fs_super.s_fsize =  fsize;\r
+    fs_super.s_nfree =  1;\r
+    fs_super.s_free[0] =  0;\r
+    fs_super.s_tfree =  0;\r
+    fs_super.s_ninode = 0;\r
+    fs_super.s_tinode =  8 * (isize-2) - 2;\r
+\r
+    /* Free each block, building the free list */\r
+    for (j= fsize-1; j >= isize+1; --j)\r
+    {\r
+        if (fs_super.s_nfree == 50)\r
+        {\r
+            dwrite(j, (char *)&fs_super.s_nfree);\r
+            fs_super.s_nfree = 0;\r
+        }\r
+\r
+        ++fs_super.s_tfree;\r
+        fs_super.s_free[(fs_super.s_nfree)++] = j;\r
+    }\r
+\r
+    /* The inodes are already zeroed out */\r
+    /* create the root dir */\r
+    inode[ROOTINODE].i_mode = F_DIR | (0777 & MODE_MASK);\r
+    inode[ROOTINODE].i_nlink = 3;\r
+    inode[ROOTINODE].i_size = 64;\r
+    inode[ROOTINODE].i_addr[0] = isize;\r
+\r
+    /* Reserve reserved inode */\r
+    inode[0].i_nlink = 1;\r
+    inode[0].i_mode = ~0;\r
+\r
+    dwrite(2, (char *)inode);\r
+\r
+    dwrite(isize,(char *)dirbuf);\r
+\r
+    /* Write out super block */\r
+    dwrite(1,(char *)&fs_super);\r
+}\r
+\r
+void dwrite(uint16_t blk, char *addr)\r
+{\r
+    lseek(dev_fd, ((int)blk) * 512, SEEK_SET);\r
+    if (write(dev_fd, addr, 512) != 512) {\r
+        perror("write");\r
+        exit(1);\r
+    }\r
+}\r
diff --git a/Standalone/ucp.c b/Standalone/ucp.c
new file mode 100644 (file)
index 0000000..a4a5daa
--- /dev/null
@@ -0,0 +1,647 @@
+/**************************************************
+  UZI (Unix Z80 Implementation) Utilities:  ucp.c
+Modifications:
+14 June 1998 - Reformatted, restructured command
+switch, sense Ctrl-Z in type.   HFB
+21 Sept 1999 - Corrected the 'constant expression'
+problem, added some missing breaks.
+HP
+ ***************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <time.h>
+#include "fuzix_fs.h"
+
+#define UCP_VERSION  "1.1ac"
+
+int16_t *syserror = (int16_t*)&udata.u_error;
+static char cwd[100];
+static char line[128];
+char *month[] =
+{ "Jan", "Feb", "Mar", "Apr",
+    "May", "Jun", "Jul", "Aug",
+    "Sep", "Oct", "Nov", "Dec" };
+
+
+int match(char *cmd);
+void usage(void);
+void prmode(int mode);
+int ls(char *path);
+int chmod( char *path, char *modes);
+int mknod( char *path, char *modes, char *devs);
+int mkdir(char *path);
+int get( char *arg, int binflag);
+int put( char *arg, int binflag);
+int type( char *arg);
+int fdump(char *arg);
+int unlink( char *path);
+int rmdir(char *path);
+
+int main(argc, argval)
+    int argc;
+    char *argval[];
+{
+    int  rdev;
+    char cmd[30], arg1[30], arg2[30], arg3[30];
+    int  count;
+    struct filesys fsys;
+    int  j, retc;
+    /*--    char *argv[5];--*/
+
+    /*
+       if (argc < 2)
+       rdev = 0;
+       else
+       rdev = atoi(argval[1]);
+       */
+    if (argc > 1) 
+        fd_open(argval[1]);
+    rdev = 0;
+
+    xfs_init(rdev);
+    strcpy(cwd, "/");
+
+    printf("Fuzix UCP version " UCP_VERSION ". Type ? for help.\n");
+
+    for (;;) {
+        printf("unix: ");
+        if (fgets(line, 128, stdin) == NULL) {
+            xfs_end();
+            exit(1);
+        }
+        cmd[0] = '\0';
+        *arg1 = '\0';
+        arg2[0] = '\0';
+        arg3[0] = '\0';
+        count = sscanf(line, "%s %s %s %s", cmd, arg1, arg2, arg3);
+        if (count == 0 || cmd[0] == '\0')
+            continue;
+
+        _sync();
+
+        if (strcmp(cmd, "\n") == 0)
+            continue;
+        switch (match(cmd)) {
+            case 0:         /* exit */
+                xfs_end();
+                exit(1);
+
+            case 1:         /* ls */
+                if (*arg1)
+                    ls(arg1);
+                else
+                    ls(".");
+                break;
+
+            case 2:         /* cd */
+                if (*arg1) {
+                    strcpy(cwd, arg1);
+                    if (_chdir(arg1) != 0) {
+                        printf("cd: error number %d\n", *syserror);
+                    }
+                }
+                break;
+
+            case 3:         /* mkdir */
+                if (*arg1)
+                    mkdir(arg1);
+                break;
+
+            case 4:         /* mknod */
+                if (*arg1 && *arg2 && *arg3)
+                    mknod(arg1, arg2, arg3);
+                break;
+
+            case 5:         /* chmod */
+                if (*arg1 && *arg2)
+                    chmod(arg1, arg2);
+                break;
+
+            case 6:         /* get */
+                if (*arg1)
+                    get(arg1, 0);
+                break;
+
+            case 7:         /* bget */
+                if (*arg1)
+                    get(arg1, 1);
+                break;
+
+            case 8:         /* put */
+                if (*arg1)
+                    put(arg1, 0);
+                break;
+
+            case 9:         /* bput */
+                if (*arg1)
+                    put(arg1, 1);
+                break;
+
+            case 10:        /* type */
+                if (*arg1)
+                    type(arg1);
+                break;
+
+            case 11:        /* dump */
+                if (*arg1)
+                    fdump(arg1);
+                break;
+
+            case 12:        /* rm */
+                if (*arg1)
+                    unlink(arg1);
+                break;
+
+            case 13:        /* df */
+                for (j = 0; j < 4; ++j) {
+                    retc = _getfsys(j, (char*)&fsys);
+                    if (retc == 0 && fsys.s_mounted) {
+                        printf("%d:  %u blks used, %u free;  ", j,
+                                (fsys.s_fsize - fsys.s_isize) - fsys.s_tfree,
+                                fsys.s_tfree);
+                        printf("%u inodes used, %u free\n",
+                                (8 * (fsys.s_isize - 2) - fsys.s_tinode),
+                                fsys.s_tinode);
+                    }
+                }
+                break;
+
+            case 14:        /* rmdir */
+                if (*arg1)
+                    rmdir(arg1);
+                break;
+
+            case 15:        /* mount */
+                if (*arg1 && *arg2)
+                    if (_mount(arg1, arg2, 0) != 0) {
+                        printf("Mount error: %d\n", *syserror);
+                    }
+                break;
+
+            case 16:        /* umount */
+                if (*arg1)
+                    if (_umount(arg1) != 0) {
+                        printf("Umount error: %d\n", *syserror);
+                    }
+                break;
+
+            case 50:        /* help */
+                usage();
+                break;
+
+            default:        /* ..else.. */
+                printf("Unknown command, type ? for help.\n");
+                break;
+        }           /* End Switch */
+    }
+}
+
+
+int match(char *cmd)
+{
+    if (strcmp(cmd, "exit") == 0)
+        return (0);
+    else if (strcmp(cmd, "quit") == 0)
+        return (0);
+    else if (strcmp(cmd, "ls") == 0)
+        return (1);
+    else if (strcmp(cmd, "dir") == 0)
+        return (1);
+    else if (strcmp(cmd, "cd") == 0)
+        return (2);
+    else if (strcmp(cmd, "mkdir") == 0)
+        return (3);
+    else if (strcmp(cmd, "mknod") == 0)
+        return (4);
+    else if (strcmp(cmd, "chmod") == 0)
+        return (5);
+    else if (strcmp(cmd, "get") == 0)
+        return (6);
+    else if (strcmp(cmd, "bget") == 0)
+        return (7);
+    else if (strcmp(cmd, "put") == 0)
+        return (8);
+    else if (strcmp(cmd, "bput") == 0)
+        return (9);
+    else if (strcmp(cmd, "type") == 0)
+        return (10);
+    else if (strcmp(cmd, "cat") == 0)
+        return (10);
+    else if (strcmp(cmd, "dump") == 0)
+        return (11);
+    else if (strcmp(cmd, "rm") == 0)
+        return (12);
+    else if (strcmp(cmd, "df") == 0)
+        return (13);
+    else if (strcmp(cmd, "rmdir") == 0)
+        return (14);
+    else if (strcmp(cmd, "mount") == 0)
+        return (15);
+    else if (strcmp(cmd, "umount") == 0)
+        return (16);
+    else if (strcmp(cmd, "help") == 0)
+        return (50);
+    else if (strcmp(cmd, "?") == 0)
+        return (50);
+    else
+        return (-1);
+}
+
+
+void usage(void)
+{
+    printf("UCP commands:\n");
+    printf("?|help\n");
+    printf("exit|quit\n");
+    printf("dir|ls [path]\n");
+    printf("cd path\n");
+    printf("mkdir dirname\n");
+    printf("mknod name mode dev#\n");
+    printf("chmod mode path\n");
+    printf("[b]get cpmfile\n");
+    printf("[b]put uzifile\n");
+    printf("type|cat filename\n");
+    printf("dump filename\n");
+    printf("rm path\n");
+    printf("rmdir dirname\n");
+    printf("df\n");
+    printf("mount dev# path\n");
+    printf("umount path\n");
+}
+
+void prmode(int mode)
+{
+    if (mode & 4)
+        printf("r");
+    else
+        printf("-");
+
+    if (mode & 2)
+        printf("w");
+    else
+        printf("-");
+
+    if (mode & 1)
+        printf("x");
+    else
+        printf("-");
+}
+
+int ls(char *path)
+{
+    struct direct buf;
+    struct uzi_stat statbuf;
+    char dname[128];
+    int d, st;
+
+    /*
+       if (_stat(path, &statbuf) != 0 || (statbuf.st_mode & F_MASK) != F_DIR) {
+       printf("ls: can't stat %s\n", path);
+       return -1;
+       }
+       */
+
+    d = _open(path, 0);
+    if (d < 0) {
+        printf("ls: can't open %s\n", path);
+        return -1;
+    }
+    while (_read(d, (char *) &buf, 16) == 16) {
+        if (buf.d_name[0] == '\0')
+            continue;
+
+        if (path[0] != '.' || path[1]) {
+            strcpy(dname, path);
+            strcat(dname, "/");
+        } else {
+            dname[0] = '\0';
+        }
+
+        strcat(dname, buf.d_name);
+
+        if (_stat(dname, &statbuf) != 0) {
+            printf("ls: can't stat %s\n", dname);
+            break;
+        }
+        st = (statbuf.st_mode & F_MASK);
+
+        if ((st & F_MASK) == F_DIR) /* & F_MASK is redundant */
+            printf("d");
+        else if ((st & F_MASK) == F_CDEV)
+            printf("c");
+        else if ((st & F_MASK) == F_BDEV)
+            printf("b");
+        else if ((st & F_MASK) == F_PIPE)
+            printf("p");
+        else if ((st & F_REG) == 0)
+            printf("l");
+        else
+            printf("-");
+
+        prmode(statbuf.st_mode >> 6);
+        prmode(statbuf.st_mode >> 3);
+        prmode(statbuf.st_mode);
+
+        printf("%4d %5d", statbuf.st_nlink, statbuf.st_ino);
+
+        if ((statbuf.st_mode & F_MASK) == F_DIR)
+            strcat(dname, "/");
+
+        printf("%12u ",
+                (statbuf.st_mode & F_CDEV) ?
+                statbuf.st_rdev :
+                statbuf.st_size);
+
+        if (statbuf.fst_mtime == 0) { /* st_mtime? */
+            /*printf("--- -- ----   --:--");*/
+            printf("                   ");
+        } else {
+            time_t t = statbuf.fst_mtime;
+            struct tm *tm = gmtime(&t);
+            printf("%s %02d %4d   ",
+                    month[tm->tm_mon],
+                    tm->tm_mday,
+                    tm->tm_year);
+
+            printf("%2d:%02d",
+                    tm->tm_hour,
+                    tm->tm_min);
+        }
+
+        printf("  %-15s\n", dname);
+    }
+    _close(d);
+    return 0;
+}
+
+int chmod( char *path, char *modes)
+{
+    int mode;
+
+    printf("chmod %s to %s\n", path, modes);
+    mode = -1;
+    sscanf(modes, "%o", &mode);
+    if (mode == -1) {
+        printf("chmod: bad mode\n");
+        return (-1);
+    }
+    /* Preserve the type if not specified */
+    if (mode < 10000) {
+        struct uzi_stat st;
+        if (_stat(path, &st) != 0) {
+            printf("chmod: can't stat file %d\n", *syserror);
+            return -1;
+        }
+        mode = (st.st_mode & ~0x7777) | mode;
+    }
+    if (_chmod(path, mode)) {
+        printf("chmod: error %d\n", *syserror);
+        return (-1);
+    }
+    return 0;
+}
+
+
+int mknod( char *path, char *modes, char *devs)
+{
+    int mode;
+    int dev;
+
+    mode = -1;
+    sscanf(modes, "%o", &mode);
+    if (mode == -1) {
+        printf("mknod: bad mode\n");
+        return (-1);
+    }
+    if ((mode & F_MASK) != F_BDEV && (mode & F_MASK) != F_CDEV) {
+        printf("mknod: mode is not device\n");
+        return (-1);
+    }
+    dev = -1;
+    sscanf(devs, "%d", &dev);
+    if (dev == -1) {
+        printf("mknod: bad device\n");
+        return (-1);
+    }
+    if (_mknod(path, mode, dev) != 0) {
+        printf("_mknod: error %d\n", *syserror);
+        return (-1);
+    }
+    return (0);
+}
+
+
+
+int mkdir(char *path)
+{
+    char dot[100];
+
+    if (_mknod(path, 040000 | 0777, 0) != 0) {
+        printf("mkdir: mknod error %d\n", *syserror);
+        return (-1);
+    }
+    strcpy(dot, path);
+    strcat(dot, "/.");
+    if (_link(path, dot) != 0) {
+        printf("mkdir: link \".\" error %d\n", *syserror);
+        return (-1);
+    }
+    strcpy(dot, path);
+    strcat(dot, "/..");
+    if (_link(".", dot) != 0) {
+        printf("mkdir: link \"..\" error %d\n", *syserror);
+        return (-1);
+    }
+    return (0);
+}
+
+
+
+int get( char *arg, int binflag)
+{
+    FILE *fp;
+    int d;
+    char cbuf[512];
+    int nread;
+
+    fp = fopen(arg, binflag ? "rb" : "r");
+    if (fp == NULL) {
+        printf("Source file not found\n");
+        return (-1);
+    }
+    d = _creat(arg, 0666);
+    if (d < 0) {
+        printf("Cant open unix file error %d\n", *syserror);
+        return (-1);
+    }
+    for (;;) {
+        nread = fread(cbuf, 1, 512, fp);
+        if (nread == 0)
+            break;
+        if (_write(d, cbuf, nread) != nread) {
+            printf("_write error %d\n", *syserror);
+            fclose(fp);
+            _close(d);
+            return (-1);
+        }
+    }
+    fclose(fp);
+    _close(d);
+    _sync();
+    return (0);
+}
+
+
+int put( char *arg, int binflag)
+{
+    FILE *fp;
+    int d;
+    char cbuf[512];
+    int nread;
+
+    fp = fopen(arg, binflag ? "wb" : "w");
+    if (fp == NULL) {
+        printf("Cant open destination file.\n");
+        return (-1);
+    }
+    d = _open(arg, 0);
+    if (d < 0) {
+        printf("Cant open unix file error %d\n", *syserror);
+        return (-1);
+    }
+    for (;;) {
+        if ((nread = _read(d, cbuf, 512)) == 0)
+            break;
+        if (fwrite(cbuf, 1, nread, fp) != nread) {
+            printf("fwrite error");
+            fclose(fp);
+            _close(d);
+            return (-1);
+        }
+    }
+    fclose(fp);
+    _close(d);
+    return (0);
+}
+
+
+int type( char *arg)
+{
+    int d, i;
+    char cbuf[512];
+    int nread;
+
+    d = _open(arg, 0);
+    if (d < 0) {
+        printf("Cant open unix file error %d\n", *syserror);
+        return (-1);
+    }
+    for (;;) {
+        if ((nread = _read(d, cbuf, 512)) == 0)
+            break;
+
+        for (i = 0; i < nread; i++) {
+            if (cbuf[i] == 0x1a)
+                break;
+            fputc(cbuf[i], stdout);
+        }
+    }
+    fputc('\n', stdout);
+    _close(d);
+    return (0);
+}
+
+
+int fdump(char *arg)
+{
+    int d;
+    char cbuf[512];
+    int nread;
+
+    printf("Dump starting.\n");
+    d = _open(arg, 0);
+    if (d < 0) {
+        printf("Cant open unix file error %d\n", *syserror);
+        return (-1);
+    }
+    for (;;) {
+        if ((nread = _read(d, cbuf, 512)) == 0)
+            break;
+    }
+    _close(d);
+    printf("Dump done.\n");
+    return (0);
+}
+
+
+int unlink( char *path)
+{
+    struct uzi_stat statbuf;
+
+    if (_stat(path, &statbuf) != 0) {
+        printf("unlink: can't stat %s\n", path);
+        return (-1);
+    }
+    if ((statbuf.st_mode & F_MASK) == F_DIR) {
+        printf("unlink: %s is a directory\n", path);
+        return (-1);
+    }
+    if (_unlink(path) != 0) {
+        printf("unlink: _unlink errn=or %d\n", *syserror);
+        return (-1);
+    }
+    return (0);
+}
+
+
+int rmdir(char *path)
+{
+    struct uzi_stat statbuf;
+    char newpath[100];
+    struct direct dir;
+    int fd;
+
+    if (_stat(path, &statbuf) != 0) {
+        printf("rmdir: can't stat %s\n", path);
+        return (-1);
+    }
+    if ((statbuf.st_mode & F_DIR) == 0) {
+        /*-- Constant expression !!!  HFB --*/
+        printf("rmdir: %s is not a directory\n", path);
+        return (-1);
+    }
+    if ((fd = _open(path, 0)) < 0) {
+        printf("rmdir: %s is unreadable\n", path);
+        return (-1);
+    }
+    while (_read(fd, (char *) &dir, sizeof(dir)) == sizeof(dir)) {
+        if (dir.d_ino == 0)
+            continue;
+        if (!strcmp(dir.d_name, ".") || !strcmp(dir.d_name, ".."))
+            continue;
+        printf("rmdir: %s is not empty\n", path);
+        _close(fd);
+        return (-1);
+    }
+    _close(fd);
+
+    strcpy(newpath, path);
+    strcat(newpath, "/.");
+    if (_unlink(newpath) != 0) {
+        printf("rmdir: can't unlink \".\"  error %d\n", *syserror);
+        /*return (-1); */
+    }
+    strcat(newpath, ".");
+    if (_unlink(newpath) != 0) {
+        printf("rmdir: can't unlink \"..\"  error %d\n", *syserror);
+        /*return (-1); */
+    }
+    if (_unlink(path) != 0) {
+        printf("rmdir: _unlink error %d\n", *syserror);
+        return (-1);
+    }
+    return (0);
+}
diff --git a/Standalone/util.c b/Standalone/util.c
new file mode 100644 (file)
index 0000000..895bb9b
--- /dev/null
@@ -0,0 +1,45 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "fuzix_fs.h"
+
+int dev_fd;
+int dev_offset;
+struct u_data udata;
+
+int fd_open(char *name)
+{
+    char *namecopy, *sd;
+    int subdev = 0;
+
+    namecopy=strdup(name);
+    sd = index(namecopy, ':');
+    if(sd){
+        *sd = 0;
+        sd++;
+        subdev=atoi(sd);
+    }
+
+    printf("Opening %s sd%d\n", namecopy, subdev);
+    dev_offset = subdev << 25; // * 32MB
+    dev_fd = open(namecopy, O_RDWR | O_CREAT, 0666);
+    free(namecopy);
+
+    if(dev_fd < 0)
+        return -1;
+    printf("fd=%d, dev_offset = %d\n", dev_fd, dev_offset);
+    return 0;
+}
+
+
+void panic(char *s)
+{
+    fprintf(stderr, "panic: %s\n", s);
+    exit(1);
+}
diff --git a/Standalone/xfs1.c b/Standalone/xfs1.c
new file mode 100644 (file)
index 0000000..fd3883d
--- /dev/null
@@ -0,0 +1,401 @@
+/**************************************************
+UZI (Unix Z80 Implementation) Utilities:  xfs1.c
+***************************************************/
+
+/*LINTLIBRARY*/
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include "fuzix_fs.h"
+
+void fs_init(void)
+{
+    udata.u_euid = 0;
+    udata.u_insys = 1;
+}
+
+void xfs_init(int bootdev)
+{
+    register char *j;
+    inoptr i_open();
+
+    fs_init();
+    bufinit();
+
+    /* User's file table */
+    for (j=udata.u_files; j < (udata.u_files+UFTSIZE); ++j)
+        *j = -1;
+
+    /* Mount the root device */
+    if (fmount(ROOTDEV, NULLINODE))
+        panic("no filesys");
+
+    ifnot (root = i_open(ROOTDEV,ROOTINODE))
+        panic("no root");
+
+    i_ref(udata.u_cwd = root);
+}
+
+
+void xfs_end(void)
+{
+    register int16_t j;
+
+    for (j=0; j < UFTSIZE; ++j)
+    {
+        ifnot (udata.u_files[j] & 0x80)  /* Portable equivalent of == -1 */
+            doclose(j);
+    }
+}
+
+
+int _open(char *name, int16_t flag)
+{
+    int16_t uindex;
+    register int16_t oftindex;
+    register inoptr ino;
+    register int16_t perm;
+    inoptr n_open();
+    int    getperm(), getmode(), isdevice(), d_open();
+    int    uf_alloc(), oft_alloc();
+
+    udata.u_error = 0;
+
+    if (flag < 0 || flag > 2)
+    {
+        udata.u_error = EINVAL;
+        return (-1);
+    }
+    if ((uindex = uf_alloc()) == -1)
+        return (-1);
+
+    if ((oftindex = oft_alloc()) == -1)
+        goto nooft;
+
+    ifnot(ino = n_open(name,NULLINOPTR))
+        goto cantopen;
+
+    of_tab[oftindex].o_inode = ino;
+
+    perm = getperm(ino);
+    if (((flag == FO_RDONLY || flag == FO_RDWR) && !(perm & OTH_RD)) ||
+            ((flag == FO_WRONLY || flag == FO_RDWR) && !(perm & OTH_WR)))
+    {
+        udata.u_error = EPERM;
+        goto cantopen;
+    }
+
+    if (getmode(ino) == F_DIR &&
+            (flag == FO_WRONLY || flag == FO_RDWR))
+    {
+        udata.u_error = EISDIR;
+        goto cantopen;
+    }
+
+    if (isdevice(ino)) // && d_open((int)ino->c_node.i_addr[0]) != 0)
+    {
+        udata.u_error = ENXIO;
+        goto cantopen;
+    }
+
+    udata.u_files[uindex] = oftindex;
+
+    of_tab[oftindex].o_ptr = 0;
+    of_tab[oftindex].o_access = flag;
+
+    return (uindex);
+
+cantopen:
+    oft_deref(oftindex);  /* This will call i_deref() */
+nooft:
+    udata.u_files[uindex] = -1;
+    return (-1);
+}
+
+
+
+
+
+int doclose(int16_t uindex)
+{
+    register int16_t oftindex;
+    inoptr ino;
+    inoptr getinode();
+    int    isdevice();
+
+    udata.u_error = 0;
+    ifnot(ino = getinode(uindex))
+        return(-1);
+    oftindex = udata.u_files[uindex];
+
+    //if (isdevice(ino)
+    //        /* && ino->c_refs == 1 && of_tab[oftindex].o_refs == 1 */ )
+    //    d_close((int)(ino->c_node.i_addr[0]));
+
+    udata.u_files[uindex] = -1;
+    oft_deref(oftindex);
+
+    return(0);
+}
+
+int _close(int16_t uindex)
+{
+    udata.u_error = 0;
+    return(doclose(uindex));
+}
+
+
+
+int _creat(char *name, int16_t mode)
+{
+    register inoptr ino;
+    register int16_t uindex;
+    register int16_t oftindex;
+    inoptr parent;
+    register int16_t j;
+    inoptr n_open();
+    inoptr newfile();
+    int    getperm(), getmode(), uf_alloc(), oft_alloc();
+
+    udata.u_error = 0;
+    parent = NULLINODE;
+
+    if ((uindex = uf_alloc()) == -1)
+        return (-1);
+    if ((oftindex = oft_alloc()) == -1)
+        return (-1);
+
+    ino = n_open(name,&parent);
+    if (ino)
+    {
+        i_deref(parent);
+        if (getmode(ino) == F_DIR)
+        {
+            i_deref(ino);
+            udata.u_error = EISDIR;
+            goto nogood;
+        }
+        ifnot (getperm(ino) & OTH_WR)
+        {
+            i_deref(ino);
+            udata.u_error = EACCES;
+            goto nogood;
+        }
+        if (getmode(ino) == F_REG)
+        {
+            /* Truncate the file to zero length */
+            f_trunc(ino);
+            /* Reset any oft pointers */
+            for (j=0; j < OFTSIZE; ++j)
+                if (of_tab[j].o_inode == ino)
+                    of_tab[j].o_ptr = 0;
+        }
+    }
+    else
+    {
+        if (parent && (ino = newfile(parent,name)))
+            /* Parent was derefed in newfile */
+        {
+            ino->c_node.i_mode = (F_REG | (mode & MODE_MASK & ~udata.u_mask));
+            setftime(ino, A_TIME|M_TIME|C_TIME);
+            /* The rest of the inode is initialized in newfile() */
+            wr_inode(ino);
+        }
+        else
+        {
+            /* Doesn't exist and can't make it */
+            if (parent)
+                i_deref(parent);
+            goto nogood;
+        }
+    }
+    udata.u_files[uindex] = oftindex;
+
+    of_tab[oftindex].o_ptr = 0;
+    of_tab[oftindex].o_inode = ino;
+    of_tab[oftindex].o_access = FO_WRONLY;
+
+    return (uindex);
+
+nogood:
+    oft_deref(oftindex);
+    return (-1);
+}
+
+
+
+int _link( char *name1, char *name2)
+{
+    register inoptr ino;
+    register inoptr ino2;
+    inoptr parent2;
+    char *filename();
+    inoptr n_open();
+    int    ch_link(), getmode(), super();
+
+    udata.u_error = 0;
+    ifnot (ino = n_open(name1,NULLINOPTR))
+        return(-1);
+
+    if (getmode(ino) == F_DIR && !super())
+    {
+        udata.u_error = EPERM;
+        goto nogood;
+    }
+
+    /* Make sure file2 doesn't exist, and get its parent */
+    if ((ino2 = n_open(name2,&parent2)))
+    {
+        i_deref(ino2);
+        i_deref(parent2);
+        udata.u_error = EEXIST;
+        goto nogood;
+    }
+
+    ifnot (parent2)
+        goto nogood;
+
+    if (ino->c_dev != parent2->c_dev)
+    {
+        i_deref(parent2);
+        udata.u_error = EXDEV;
+        goto nogood;
+    }
+
+    if (ch_link(parent2,"",filename(name2),ino) == 0)
+        goto nogood;
+
+    /* Update the link count. */
+    ++ino->c_node.i_nlink;
+    wr_inode(ino);
+    setftime(ino, C_TIME);
+
+    i_deref(parent2);
+    i_deref(ino);
+    return(0);
+
+nogood:
+    i_deref(ino);
+    return(-1);
+}
+
+
+
+int _unlink(char *path)
+{
+    register inoptr ino;
+    inoptr pino;
+    char *filename();
+    /*--    inoptr i_open();--*/
+    inoptr n_open();
+    int    getmode(), ch_link(), super();
+
+    udata.u_error = 0;
+    ino = n_open(path,&pino);
+
+    ifnot (pino && ino)
+    {
+        udata.u_error = ENOENT;
+        return (-1);
+    }
+
+    if (getmode(ino) == F_DIR && !super())
+    {
+        udata.u_error = EPERM;
+        goto nogood;
+    }
+
+    /* Remove the directory entry */
+
+    if (ch_link(pino,filename(path),"",NULLINODE) == 0)
+        goto nogood;
+
+    /* Decrease the link count of the inode */
+
+    ifnot (ino->c_node.i_nlink--)
+    {
+        ino->c_node.i_nlink += 2;
+        printf("_unlink: bad nlink\n");
+    }
+    setftime(ino, C_TIME);
+    i_deref(pino);
+    i_deref(ino);
+    return(0);
+nogood:
+    i_deref(pino);
+    i_deref(ino);
+    return(-1);
+}
+
+
+
+int _read( int16_t d, char *buf, uint16_t nbytes)
+{
+    register inoptr ino;
+    inoptr rwsetup();
+
+    udata.u_error = 0;
+    /* Set up u_base, u_offset, ino; check permissions, file num. */
+    if ((ino = rwsetup(1, d, buf, nbytes)) == NULLINODE)
+        return (-1);   /* bomb out if error */
+
+    readi(ino);
+    updoff(d);
+
+    return (udata.u_count);
+}
+
+
+
+int _write( int16_t d, char *buf, uint16_t nbytes)
+{
+    register inoptr ino;
+    /*--    off_t *offp;--*/
+    inoptr rwsetup();
+
+    udata.u_error = 0;
+    /* Set up u_base, u_offset, ino; check permissions, file num. */
+    if ((ino = rwsetup(0, d, buf, nbytes)) == NULLINODE)
+        return (-1);   /* bomb out if error */
+
+    writei(ino);
+    updoff(d);
+
+    return (udata.u_count);
+}
+
+
+
+inoptr rwsetup( int rwflag, int d, char *buf, int nbytes)
+{
+    register inoptr ino;
+    register struct oft *oftp;
+    inoptr getinode();
+
+    udata.u_base = buf;
+    udata.u_count = nbytes;
+
+    if ((ino = getinode(d)) == NULLINODE)
+        return (NULLINODE);
+
+    oftp = of_tab + udata.u_files[d];
+    if (oftp->o_access == (rwflag ? FO_WRONLY : FO_RDONLY))
+    {
+        udata.u_error = EBADF;
+        return (NULLINODE);
+    }
+
+    setftime(ino, rwflag ? A_TIME : (A_TIME | M_TIME | C_TIME));
+
+    /* Initialize u_offset from file pointer */
+    udata.u_offset = oftp->o_ptr;
+
+    return (ino);
+}
+
+
+
+int psize(inoptr ino)
+{
+    return (ino->c_node.i_size);
+}
diff --git a/Standalone/xfs1a.c b/Standalone/xfs1a.c
new file mode 100644 (file)
index 0000000..d2b07c7
--- /dev/null
@@ -0,0 +1,157 @@
+/**************************************************
+  UZI (Unix Z80 Implementation) Utilities:  xfs1a.c
+ ***************************************************/
+/* Revisions:
+ *  1.4.98 - Split xfs.c into parts for compilation with Hi-Tech C.   HFB
+ */
+
+/*LINTLIBRARY*/
+#include <stdint.h>
+#include <strings.h>
+#include "fuzix_fs.h"
+
+int32_t _lseek( int16_t file, int32_t offset, int16_t flag)
+{
+    register inoptr ino;
+    register int32_t retval;
+    register int    oftno;
+
+    udata.u_error = 0;
+    if ((ino = getinode(file)) == NULLINODE)
+        return(-1);
+
+    oftno = udata.u_files[file];
+
+    retval = of_tab[oftno].o_ptr;
+
+    switch(flag)
+    {
+        case 0:
+            of_tab[oftno].o_ptr = offset;
+            break;
+        case 1:
+            of_tab[oftno].o_ptr += offset;
+            break;
+        case 2:
+            of_tab[oftno].o_ptr = ino->c_node.i_size + offset;
+            break;
+        default:
+            udata.u_error = EINVAL;
+            return(-1);
+    }
+    retval = of_tab[oftno].o_ptr;
+    return retval;
+}
+
+
+
+void readi( inoptr ino )
+{
+    register uint16_t amount;
+    register uint16_t toread;
+    register blkno_t pblk;
+    register char *bp;
+    int dev;
+
+    dev = ino->c_dev;
+    switch (getmode(ino))
+    {
+
+        case F_DIR:
+        case F_REG:
+
+            /* See of end of file will limit read */
+            toread = udata.u_count =
+                min(udata.u_count, ino->c_node.i_size-udata.u_offset);
+            goto loop;
+
+        case F_BDEV:
+            toread = udata.u_count;
+            dev = *(ino->c_node.i_addr);
+
+loop:
+            while (toread)
+            {
+                if ((pblk = bmap(ino, udata.u_offset>>9, 1)) != NULLBLK)
+                    bp = bread(dev, pblk, 0);
+                else
+                    bp = zerobuf();
+
+                bcopy(bp+(udata.u_offset&511), udata.u_base,
+                        (amount = min(toread, 512 - (udata.u_offset&511))));
+                brelse((bufptr)bp);
+
+                udata.u_base += amount;
+                udata.u_offset += amount;
+                toread -= amount;
+            }
+            break;
+
+        default:
+            udata.u_error = ENODEV;
+    }
+}
+
+
+
+/* Writei (and readi) need more i/o error handling */
+
+void writei( inoptr ino)
+{
+    register uint16_t amount;
+    register uint16_t towrite;
+    register char *bp;
+    blkno_t pblk;
+    int dev;
+
+    dev = ino->c_dev;
+
+    switch (getmode(ino))
+    {
+
+        case F_BDEV:
+            dev = *(ino->c_node.i_addr);
+        case F_DIR:
+        case F_REG:
+            towrite = udata.u_count;
+            goto loop;
+
+loop:
+            while (towrite)
+            {
+                amount = min(towrite, 512 - (udata.u_offset&511));
+
+                if ((pblk = bmap(ino, udata.u_offset>>9, 0)) == NULLBLK)
+                    break;    /* No space to make more blocks */
+
+                /* If we are writing an entire block, we don't care
+                   about its previous contents */
+                bp = bread(dev, pblk, (amount == 512));
+
+                bcopy(udata.u_base, bp+(udata.u_offset&511), amount);
+                bawrite((bufptr)bp);
+
+                udata.u_base += amount;
+                udata.u_offset += amount;
+                towrite -= amount;
+            }
+
+            /* Update size if file grew */
+            if ( udata.u_offset > ino->c_node.i_size) {
+                ino->c_node.i_size = udata.u_offset;
+                ino->c_dirty = 1;
+            }
+            break;
+
+        default:
+            udata.u_error = ENODEV;
+    }
+}
+
+
+
+void updoff(int d)
+{
+    /* Update current file pointer */
+    of_tab[udata.u_files[d]].o_ptr = udata.u_offset;
+}
diff --git a/Standalone/xfs1b.c b/Standalone/xfs1b.c
new file mode 100644 (file)
index 0000000..e0e6898
--- /dev/null
@@ -0,0 +1,504 @@
+/**************************************************
+  UZI (Unix Z80 Implementation) Utilities:  xfs1a1.c
+ ***************************************************/
+
+/*LINTLIBRARY*/
+#include <stdint.h>
+#include <strings.h>
+#include "fuzix_fs.h"
+
+struct cinode i_tab[ITABSIZE];
+struct filesys fs_tab[1];
+
+int valadr(char *base, uint16_t size)
+{
+        return(1);
+}
+
+
+int _mknod( char *name, int16_t mode, int16_t dev)
+{
+    register inoptr ino;
+    inoptr parent;
+
+    udata.u_error = 0;
+    ifnot (super())
+    {
+        udata.u_error = EPERM;
+        return(-1);
+    }
+
+    if ((ino = n_open(name,&parent)))
+    {
+        udata.u_error = EEXIST;
+        goto nogood;
+    }
+
+    ifnot (parent)
+    {
+        udata.u_error = ENOENT;
+        return(-1);
+    }
+
+    ifnot (ino = newfile(parent,name))
+        goto nogood2;
+
+    /* Initialize mode and dev */
+    ino->c_node.i_mode = mode & ~udata.u_mask;
+    ino->c_node.i_addr[0] = isdevice(ino) ? dev : 0;
+    setftime(ino, A_TIME|M_TIME|C_TIME);
+    wr_inode(ino);
+
+    i_deref(ino);
+    return (0);
+
+nogood:
+    i_deref(ino);
+nogood2:
+    i_deref(parent);
+    return (-1);
+}
+
+
+
+void _sync(void)
+{
+    int j;
+    inoptr ino;
+    char *buf;
+
+    /* Write out modified inodes */
+
+    udata.u_error = 0;
+    for (ino=i_tab; ino < i_tab+ITABSIZE; ++ino)
+        if ((ino->c_refs) > 0 && ino->c_dirty != 0)
+        {
+            wr_inode(ino);
+            ino->c_dirty = 0;
+        }
+
+    /* Write out modified super blocks */
+    /* This fills the rest of the super block with garbage. */
+
+    for (j=0; j < NDEVS; ++j)
+    {
+        if (fs_tab[j].s_mounted == SMOUNTED && fs_tab[j].s_fmod)
+        {
+            fs_tab[j].s_fmod = 0;
+            buf = bread(j, 1, 1);
+            bcopy((char *)&fs_tab[j], buf, 512);
+            bfree((bufptr)buf, 2);
+        }
+    }
+    bufsync();   /* Clear buffer pool */
+}
+
+
+
+int _chdir(char *dir)
+{
+    register inoptr newcwd;
+    inoptr n_open();
+    int    getmode();
+
+    udata.u_error = 0;
+    ifnot (newcwd = n_open(dir,NULLINOPTR))
+        return(-1);
+
+    if (getmode(newcwd) != F_DIR)
+    {
+        udata.u_error = ENOTDIR;
+        i_deref(newcwd);
+        return(-1);
+    }
+    i_deref(udata.u_cwd);
+    udata.u_cwd = newcwd;
+    return(0);
+}
+
+
+
+int min(int a, int b)
+{
+    return ( a < b ? a : b);
+}
+
+
+
+int _access( char *path, int16_t mode)
+{
+    register inoptr ino;
+    register int16_t euid;
+    register int16_t egid;
+    register int16_t retval;
+    inoptr n_open();
+    int    getperm();
+
+    udata.u_error = 0;
+    if ((mode & 07) && !*(path))
+    {
+        udata.u_error = ENOENT;
+        return (-1);
+    }
+
+    /* Temporarily make eff. id real id. */
+    euid = udata.u_euid;
+    egid = udata.u_egid;
+    udata.u_euid = 0; // udata.u_ptab->p_uid;
+    udata.u_egid = 0; // udata.u_gid;
+
+    ifnot (ino = n_open(path,NULLINOPTR))
+    {
+        retval = -1;
+        goto nogood;
+    }
+
+    retval = 0;
+    if (~getperm(ino) & (mode&07))
+    {
+        udata.u_error = EPERM;
+        retval = -1;
+    }
+
+    i_deref(ino);
+nogood:
+    udata.u_euid = euid;
+    udata.u_egid = egid;
+
+    return(retval);
+}
+
+
+int _chmod( char *path, int16_t mode)
+{
+    inoptr ino;
+    inoptr n_open();
+    int    super();
+
+    udata.u_error = 0;
+    ifnot (ino = n_open(path,NULLINOPTR))
+        return (-1);
+
+    if (ino->c_node.i_uid != udata.u_euid && !super())
+    {
+        i_deref(ino);
+        udata.u_error = EPERM;
+        return(-1);
+    }
+    ino->c_node.i_mode = (mode & MODE_MASK) | (ino->c_node.i_mode & F_MASK);
+    setftime(ino, C_TIME);
+    i_deref(ino);
+    return(0);
+}
+
+
+int _chown( char *path, int owner, int group)
+{
+    register inoptr ino;
+    inoptr n_open();
+    int    super();
+
+    udata.u_error = 0;
+    ifnot (ino = n_open(path,NULLINOPTR))
+        return (-1);
+
+    if (ino->c_node.i_uid != udata.u_euid && !super())
+    {
+        i_deref(ino);
+        udata.u_error = EPERM;
+        return(-1);
+    }
+
+    ino->c_node.i_uid = owner;
+    ino->c_node.i_gid = group;
+    setftime(ino, C_TIME);
+    i_deref(ino);
+    return(0);
+}
+
+
+
+int _stat( char *path, struct uzi_stat *buf)
+{
+    register inoptr ino;
+
+    udata.u_error = 0;
+    ifnot(valadr((char*)buf,sizeof(struct uzi_stat)) && (ino = n_open(path,NULLINOPTR)))
+    {
+        return (-1);
+    }
+    stcpy(ino,buf);
+    i_deref(ino);
+    return(0);
+}
+
+
+
+int _fstat( int16_t fd, struct uzi_stat *buf)
+{
+    register inoptr ino;
+
+    udata.u_error = 0;
+    ifnot(valadr((char*)buf,sizeof(struct uzi_stat)))
+        return(-1);
+
+    if ((ino = getinode(fd)) == NULLINODE)
+        return(-1);
+
+    stcpy(ino,buf);
+    return(0);
+}
+
+
+
+/* Utility for stat and fstat */
+void stcpy( inoptr ino, struct uzi_stat *buf)
+{
+    struct uzi_stat *b = (struct uzi_stat *)buf;
+
+    b->st_dev = ino->c_dev;
+    b->st_ino = ino->c_num;
+    b->st_mode = ino->c_node.i_mode;
+    b->st_nlink = ino->c_node.i_nlink;
+    b->st_uid = ino->c_node.i_uid;
+    b->st_gid = ino->c_node.i_gid;
+
+    b->st_rdev = ino->c_node.i_addr[0];
+
+    b->st_size = ino->c_node.i_size;
+    b->fst_atime = ino->c_node.i_atime;
+    b->fst_mtime = ino->c_node.i_mtime;
+    b->fst_ctime = ino->c_node.i_ctime;
+}
+
+
+
+int _dup( int16_t oldd)
+{
+    register int newd;
+    inoptr getinode();
+    int    uf_alloc();
+
+    udata.u_error = 0;
+    if (getinode(oldd) == NULLINODE)
+        return(-1);
+
+    if ((newd = uf_alloc()) == -1)
+        return (-1);
+
+    udata.u_files[newd] = udata.u_files[oldd];
+    ++of_tab[udata.u_files[oldd]].o_refs;
+
+    return(newd);
+}
+
+
+
+int _dup2( int16_t oldd, int16_t newd)
+{
+    inoptr getinode();
+
+    udata.u_error = 0;
+    if (getinode(oldd) == NULLINODE)
+        return(-1);
+
+    if (newd < 0 || newd >= UFTSIZE)
+    {
+        udata.u_error = EBADF;
+        return (-1);
+    }
+
+    ifnot (udata.u_files[newd] & 0x80)
+        doclose(newd);
+
+    udata.u_files[newd] = udata.u_files[oldd];
+    ++of_tab[udata.u_files[oldd]].o_refs;
+
+    return(0);
+}
+
+
+
+int _umask( int mask)
+{
+    register int omask;
+
+    udata.u_error = 0;
+    omask = udata.u_mask;
+    udata.u_mask = mask & 0777;
+    return(omask);
+}
+
+
+
+/* Special system call returns super-block of given filesystem for
+ * users to determine free space, etc.  Should be replaced with a
+ * sync() followed by a read of block 1 of the device.
+ */
+
+int _getfsys(int dev,char * buf)
+{
+    udata.u_error = 0;
+    if (dev < 0 || dev >= NDEVS || fs_tab[dev].s_mounted != SMOUNTED)
+    {
+        udata.u_error = ENXIO;
+        return(-1);
+    }
+
+    bcopy((char *)&fs_tab[dev],(char *)buf,sizeof(struct filesys));
+    return(0);
+}
+
+
+
+int _ioctl( int fd, int request, char *data)
+{
+    register inoptr ino;
+    // register int dev;
+
+    udata.u_error = 0;
+    if ((ino = getinode(fd)) == NULLINODE)
+        return(-1);
+
+    ifnot (isdevice(ino))
+    {
+        udata.u_error = ENOTTY;
+        return(-1);
+    }
+
+    ifnot (getperm(ino) & OTH_WR)
+    {
+        udata.u_error = EPERM;
+        return(-1);
+    }
+
+    // dev = ino->c_node.i_addr[0];
+
+    // if (d_ioctl(dev, request,data))
+    //     return(-1);
+
+    return(0);
+}
+
+
+
+int _mount( char *spec, char *dir, int rwflag)
+{
+    register inoptr sino, dino;
+    register int dev;
+
+    udata.u_error = 0;
+    ifnot(super())
+    {
+        udata.u_error = EPERM;
+        return (-1);
+    }
+    ifnot (sino = n_open(spec,NULLINOPTR))
+        return (-1);
+
+    ifnot (dino = n_open(dir,NULLINOPTR))
+    {
+        i_deref(sino);
+        return (-1);
+    }
+    if (getmode(sino) != F_BDEV)
+    {
+        udata.u_error = ENOTBLK;
+        goto nogood;
+    }
+    if (getmode(dino) != F_DIR)
+    {
+        udata.u_error = ENOTDIR;
+        goto nogood;
+    }
+    dev = (int)sino->c_node.i_addr[0];
+
+    if ( dev >= NDEVS ) // || d_open(dev))
+    {
+        udata.u_error = ENXIO;
+        goto nogood;
+    }
+    if (fs_tab[dev].s_mounted || dino->c_refs != 1 || dino->c_num == ROOTINODE)
+    {
+        udata.u_error = EBUSY;
+        goto nogood;
+    }
+    _sync();
+
+    if (fmount(dev,dino))
+    {
+        udata.u_error = EBUSY;
+        goto nogood;
+    }
+    i_deref(dino);
+    i_deref(sino);
+    return(0);
+nogood:
+    i_deref(dino);
+    i_deref(sino);
+    return (-1);
+}
+
+
+
+int _umount(char *spec)
+{
+    register inoptr sino;
+    register int dev;
+    register inoptr ptr;
+
+    udata.u_error = 0;
+    ifnot(super())
+    {
+        udata.u_error = EPERM;
+        return (-1);
+    }
+
+    ifnot (sino = n_open(spec,NULLINOPTR))
+        return (-1);
+
+    if (getmode(sino) != F_BDEV)
+    {
+        udata.u_error = ENOTBLK;
+        goto nogood;
+    }
+
+    dev = (int)sino->c_node.i_addr[0];
+    //ifnot (validdev(dev))
+    //{
+    //    udata.u_error = ENXIO;
+    //    goto nogood;
+    //}
+
+    if (!fs_tab[dev].s_mounted)
+    {
+        udata.u_error = EINVAL;
+        goto nogood;
+    }
+
+    for (ptr = i_tab; ptr < i_tab+ITABSIZE; ++ptr)
+        if (ptr->c_refs > 0 && ptr->c_dev == dev)
+        {
+            udata.u_error = EBUSY;
+            goto nogood;
+        }
+    _sync();
+    fs_tab[dev].s_mounted = 0;
+    i_deref(fs_tab[dev].s_mntpt);
+
+    i_deref(sino);
+    return(0);
+
+nogood:
+    i_deref(sino);
+    return (-1);
+}
+
+
+
+int _time( int tvec[])
+{
+    udata.u_error = 0;
+    // rdtime(tvec);  /* In machdep.c */
+    return(0);
+}
diff --git a/Standalone/xfs2.c b/Standalone/xfs2.c
new file mode 100644 (file)
index 0000000..fac6f75
--- /dev/null
@@ -0,0 +1,1025 @@
+/**************************************************
+UZI (Unix Z80 Implementation) Utilities:  xfs2.c
+***************************************************/
+
+/* Revisions:
+ *  25.2.96      Bug fix in i_deref()     SN
+ */
+
+/*LINTLIBRARY*/
+#include <stdio.h>
+#include <strings.h>
+#include <stdint.h>
+#include "fuzix_fs.h"
+
+/* UZI180 NOTE: This file is basically the FILESYS.C module.   HFB */
+
+/* N_open is given a string containing a path name, and returns
+ * an inode table pointer.  If it returns NULL, the file did not
+ * exist.  If the parent existed, and parent is not null, parent
+ * will be filled in with the parents inoptr. Otherwise, parent
+ * will be set to NULL.
+ */
+
+inoptr root;
+struct oft of_tab[OFTSIZE];
+
+inoptr n_open( register char *name, register inoptr *parent )
+{
+    register inoptr wd;     /* the directory we are currently searching. */
+    register inoptr ninode;
+    register inoptr temp;
+
+    if (*name == '/')
+        wd = root;
+    else
+        wd = udata.u_cwd;
+
+    i_ref(ninode = wd);
+    i_ref(ninode);
+
+    for(;;)
+    {
+        if (ninode)
+            magic(ninode);
+
+        /* See if we are at a mount point */
+        if (ninode)
+            ninode = srch_mt(ninode);
+
+        while (*name == '/')    /* Skip (possibly repeated) slashes */
+            ++name;
+        ifnot (*name)           /* No more components of path? */
+            break;
+        ifnot (ninode)
+        {
+            udata.u_error = ENOENT;
+            goto nodir;
+        }
+        i_deref(wd);
+        wd = ninode;
+        if (getmode(wd) != F_DIR)
+        {
+            udata.u_error = ENOTDIR;
+            goto nodir;
+        }
+        ifnot (getperm(wd) & OTH_EX)
+        {
+            udata.u_error = EPERM;
+            goto nodir;
+        }
+
+        /* See if we are going up through a mount point */
+        if ( wd->c_num == ROOTINODE && wd->c_dev != ROOTDEV && name[1] == '.')
+        {
+           temp = fs_tab[wd->c_dev].s_mntpt;
+           ++temp->c_refs;
+           i_deref(wd);
+           wd = temp;
+        }
+
+        ninode = srch_dir(wd,name);
+
+        while (*name != '/' && *name )
+            ++name;
+    }
+
+    if (parent)
+        *parent = wd;
+    else
+        i_deref(wd);
+    ifnot (parent || ninode)
+        udata.u_error = ENOENT;
+    return (ninode);
+
+nodir:
+    if (parent)
+        *parent = NULLINODE;
+    i_deref(wd);
+    return(NULLINODE);
+
+}
+
+
+
+/* Srch_dir is given a inode pointer of an open directory and a string
+ * containing a filename, and searches the directory for the file.  If
+ * it exists, it opens it and returns the inode pointer, otherwise NULL.
+ * This depends on the fact that ba_read will return unallocated blocks
+ * as zero-filled, and a partially allocated block will be padded with
+ * zeroes.
+ */
+
+inoptr srch_dir(inoptr wd, register char *compname)
+{
+    register int curentry;
+    register blkno_t curblock;
+    register struct direct *buf;
+    register int nblocks;
+    unsigned inum;
+
+    nblocks = (wd->c_node.i_size + 511) >> 9;
+
+    for (curblock=0; curblock < nblocks; ++curblock)
+    {
+        buf = (struct direct *)bread( wd->c_dev, bmap(wd, curblock, 1), 0);
+        for (curentry = 0; curentry < 16; ++curentry)
+        {
+            if (namecomp(compname,buf[curentry].d_name))
+            {
+                inum = buf[curentry&0x0f].d_ino;
+                brelse((bufptr)buf);
+                return(i_open(wd->c_dev, inum));
+            }
+        }
+        brelse((bufptr)buf);
+    }
+    return(NULLINODE);
+}
+
+
+/* Srch_mt sees if the given inode is a mount point. If so it
+ * dereferences it, and references and returns a pointer to the
+ * root of the mounted filesystem.
+ */
+
+inoptr srch_mt( inoptr ino)
+{
+    register int j;
+    inoptr i_open();
+
+    for (j=0; j < NDEVS; ++j)
+        if (fs_tab[j].s_mounted == SMOUNTED && fs_tab[j].s_mntpt == ino)
+        {
+            i_deref(ino);
+            return(i_open(j,ROOTINODE));
+        }
+
+    return(ino);
+}
+
+
+/* I_open is given an inode number and a device number,
+ * and makes an entry in the inode table for them, or
+ * increases it reference count if it is already there.
+ * An inode # of zero means a newly allocated inode.
+ */
+
+inoptr i_open( register int dev, register unsigned ino)
+{
+
+    struct dinode *buf;
+    register inoptr nindex;
+    int i;
+    register inoptr j;
+    int new;
+    static inoptr nexti = i_tab;       /* added inoptr. 26.12.97  HFB */
+    unsigned i_alloc();
+
+    if (dev<0 || dev>=NDEVS)
+        panic("i_open: Bad dev");
+
+    new = 0;
+    ifnot (ino)         /* Want a new one */
+    {
+        new = 1;
+        ifnot (ino = i_alloc(dev))
+        {
+            udata.u_error = ENOSPC;
+            return (NULLINODE);
+        }
+    }
+
+    if (ino < ROOTINODE || ino >= (fs_tab[dev].s_isize-2)*8)
+    {
+        printf("i_open: bad inode number\n");
+        return (NULLINODE);
+    }
+
+
+    nindex = NULLINODE;
+    j = (inoptr) nexti;
+    for (i=0; i < ITABSIZE; ++i)
+    {
+        nexti = (inoptr)j;
+        if (++j >= i_tab+ITABSIZE)
+            j = i_tab;
+
+        ifnot (j->c_refs)
+           nindex = j;
+
+        if (j->c_dev == dev && j->c_num == ino)
+        {
+            nindex = j;
+            goto found;
+        }
+    }
+
+    /* Not already in table. */
+
+    ifnot (nindex)       /* No unrefed slots in inode table */
+    {
+        udata.u_error = ENFILE;
+        return(NULLINODE);
+    }
+
+    buf = (struct dinode *)bread(dev, (ino>>3)+2, 0);
+    bcopy((char *)&(buf[ino & 0x07]), (char *)&(nindex->c_node), 64);
+    brelse((bufptr)buf);
+
+    nindex->c_dev = dev;
+    nindex->c_num = ino;
+    nindex->c_magic = CMAGIC;
+
+found:
+    if (new)
+    {
+        if (nindex->c_node.i_nlink || nindex->c_node.i_mode & F_MASK)
+            goto badino;
+    }
+    else
+    {
+        ifnot (nindex->c_node.i_nlink && nindex->c_node.i_mode & F_MASK)
+            goto badino;
+    }
+
+    ++nindex->c_refs;
+    return(nindex);
+
+badino:
+    printf("i_open: bad disk inode\n");
+    return (NULLINODE);
+}
+
+
+
+/* Ch_link modifies or makes a new entry in the directory for the name
+ * and inode pointer given. The directory is searched for oldname.  When
+ * found, it is changed to newname, and it inode # is that of *nindex.
+ * A oldname of "" matches a unused slot, and a nindex of NULLINODE
+ * means an inode # of 0.  A return status of 0 means there was no
+ * space left in the filesystem, or a non-empty oldname was not found,
+ * or the user did not have write permission.
+ */
+
+int ch_link( inoptr wd, char *oldname, char *newname, inoptr nindex)
+{
+    struct direct curentry;
+
+    ifnot (getperm(wd) & OTH_WR)
+    {
+        udata.u_error = EPERM;
+        return (0);
+    }
+
+    /* Search the directory for the desired slot. */
+
+    udata.u_offset = 0;
+
+    for (;;)
+    {
+        udata.u_count = 32;
+        udata.u_base  = (char *)&curentry;
+//        udata.u_sysio = 1;                                   /*280*/
+        readi(wd);
+
+        /* Read until EOF or name is found */
+        /* readi() advances udata.u_offset */
+        if (udata.u_count == 0 || namecomp(oldname, curentry.d_name))
+            break;
+    }
+
+    if (udata.u_count == 0 && *oldname)
+        return (0);                  /* Entry not found */
+
+    bcopy(newname, curentry.d_name, 30);
+
+#if 1
+    {
+    int i;
+
+    for (i = 0; i < 30; ++i) if (curentry.d_name[i] == '\0') break;
+    for (     ; i < 30; ++i) curentry.d_name[i] = '\0';
+    }
+#endif
+
+    if (nindex)
+        curentry.d_ino = nindex->c_num;
+    else
+        curentry.d_ino = 0;
+
+    /* If an existing slot is being used, we must back up the file offset */
+    if (udata.u_count)
+        udata.u_offset -= 32;
+
+    udata.u_count = 32;
+    udata.u_base  = (char *)&curentry;
+    udata.u_sysio = 1;                                         /*280*/
+    writei(wd);
+
+    if (udata.u_error)
+        return (0);
+
+    setftime(wd, A_TIME|M_TIME|C_TIME);     /* Sets c_dirty */
+
+    /* Update file length to next block */
+    if (wd->c_node.i_size&511)
+        wd->c_node.i_size += 512 - (wd->c_node.i_size&511);
+
+    return (1);
+}
+
+
+
+/* Filename is given a path name, and returns a pointer to the
+ * final component of it.
+ */
+
+char * filename( char *path)
+{
+    register char *ptr;
+
+    ptr = path;
+    while (*ptr)
+        ++ptr;
+    while (*ptr != '/' && ptr-- > path)
+        ;
+    return (ptr+1);
+}
+
+
+/* Namecomp compares two strings to see if they are the same file name.
+ * It stops at 14 chars or a null or a slash. It returns 0 for difference.
+ */
+
+int namecomp( char *n1, char *n2)
+{
+    register int n;
+
+    n = 30;
+    while (*n1 && *n1 != '/')
+    {
+        if (*n1++ != *n2++)
+            return(0);
+        ifnot (--n)
+            return(-1);
+    }
+    return(*n2 == '\0' || *n2 == '/');
+}
+
+
+/* Newfile is given a pointer to a directory and a name, and creates
+ * an entry in the directory for the name, dereferences the parent,
+ * and returns a pointer to the new inode.  It allocates an inode
+ * number, and creates a new entry in the inode table for the new
+ * file, and initializes the inode table entry for the new file.
+ * The new file will have one reference, and 0 links to it.  Better
+ * Better make sure there isn't already an entry with the same name.
+ */
+
+inoptr newfile( inoptr pino, char *name)
+{
+    register inoptr nindex;
+    register int j;
+
+    /* First see if parent is writeable */                     /*280*/
+    ifnot (getperm(pino) & OTH_WR)                             /*280*/
+        goto nogood;                                           /*280*/
+
+    ifnot (nindex = i_open(pino->c_dev, 0))
+        goto nogood;
+
+    /* BIG FIX:  user/group setting was missing  SN */         /*280*/
+    nindex->c_node.i_uid = udata.u_euid;                       /*280*/
+    nindex->c_node.i_gid = udata.u_egid;                       /*280*/
+
+    nindex->c_node.i_mode = F_REG;   /* For the time being */
+    nindex->c_node.i_nlink = 1;
+    nindex->c_node.i_size = 0;
+    for (j=0; j <20; j++)
+        nindex->c_node.i_addr[j] = 0;
+    wr_inode(nindex);
+
+    ifnot (ch_link(pino,"",filename(name),nindex))
+    {
+        i_deref(nindex);
+        goto nogood;
+    }
+
+    i_deref (pino);
+    return(nindex);
+
+nogood:
+    i_deref (pino);
+    return (NULLINODE);
+}
+
+
+/* Check the given device number, and return its address in the mount
+ * table.  Also time-stamp the superblock of dev, and mark it modified.
+ * Used when freeing and allocating blocks and inodes.
+ */
+
+fsptr getdev( int devno)
+{
+    register fsptr dev;
+
+    dev = fs_tab + devno;
+    if (devno < 0 || devno >= NDEVS || !dev->s_mounted)
+        panic("getdev: bad dev");
+    dev->s_fmod = 1;
+    return (dev);
+}
+
+
+/* Returns true if the magic number of a superblock is corrupt.
+ */
+
+int baddev(fsptr dev)
+{
+    return (dev->s_mounted != SMOUNTED);
+}
+
+
+/* I_alloc finds an unused inode number, and returns it, or 0
+ * if there are no more inodes available.
+ */
+
+unsigned i_alloc(int devno)
+{
+    fsptr dev;
+    blkno_t blk;
+    struct dinode *buf;
+    register int j;
+    register int k;
+    unsigned ino;
+    int      baddev();
+    /* struct  dinode *bread();  -- HP */      /*?????  HFB  26.12.97 */
+
+    if (baddev(dev = getdev(devno)))
+        goto corrupt;
+
+tryagain:
+    if (dev->s_ninode)
+    {
+        ifnot (dev->s_tinode)
+            goto corrupt;
+        ino = dev->s_inode[--dev->s_ninode];
+        if (ino < 2 || ino >= (dev->s_isize-2)*8)
+            goto corrupt;
+        --dev->s_tinode;
+        return(ino);
+    }
+
+    /* We must scan the inodes, and fill up the table */
+
+    _sync();           /* Make on-disk inodes consistent */
+    k = 0;
+    for (blk = 2; blk < dev->s_isize; blk++)
+    {
+        buf = (struct dinode *)bread(devno, blk, 0);
+        for (j=0; j < 8; j++)
+        {
+            ifnot (buf[j].i_mode || buf[j].i_nlink)
+                dev->s_inode[k++] = 8*(blk-2) + j;
+            if (k==50)
+            {
+                brelse((bufptr)buf);
+                goto done;
+            }
+        }
+        brelse((bufptr)buf);
+    }
+
+done:
+    ifnot (k)
+    {
+        if (dev->s_tinode)
+            goto corrupt;
+        udata.u_error = ENOSPC;
+        return(0);
+    }
+
+    dev->s_ninode = k;
+    goto tryagain;
+
+corrupt:
+    printf("i_alloc: corrupt superblock\n");
+    dev->s_mounted = 1;
+    udata.u_error = ENOSPC;
+    return(0);
+}
+
+
+/* I_free is given a device and inode number, and frees the inode.
+ * It is assumed that there are no references to the inode in the
+ * inode table or in the filesystem.
+ */
+
+void i_free( int devno, unsigned ino)
+{
+    register fsptr dev;
+
+    if (baddev(dev = getdev(devno)))
+        return;
+
+    if (ino < 2 || ino >= (dev->s_isize-2)*8)
+        panic("i_free: bad ino");
+
+    ++dev->s_tinode;
+    if (dev->s_ninode < 50)
+        dev->s_inode[dev->s_ninode++] = ino;
+}
+
+
+/* Blk_alloc is given a device number, and allocates an unused block
+ * from it. A returned block number of zero means no more blocks.
+ */
+
+blkno_t blk_alloc( int devno )
+{
+    register fsptr dev;
+    register blkno_t newno;
+    blkno_t *buf; /*, *bread(); -- HP */
+    register int j;
+
+    if (baddev(dev = getdev(devno)))
+        goto corrupt2;
+
+    if (dev->s_nfree <= 0 || dev->s_nfree > 50)
+        goto corrupt;
+
+    newno = dev->s_free[--dev->s_nfree];
+    ifnot (newno)
+    {
+        if (dev->s_tfree != 0)
+            goto corrupt;
+        udata.u_error = ENOSPC;
+        ++dev->s_nfree;
+        return(0);
+    }
+
+    /* See if we must refill the s_free array */
+
+    ifnot (dev->s_nfree)
+    {
+        buf = (blkno_t *)bread(devno,newno, 0);
+        dev->s_nfree = buf[0];
+        for (j=0; j < 50; j++)
+        {
+            dev->s_free[j] = buf[j+1];
+        }
+        brelse((bufptr)buf);
+    }
+
+    validblk(devno, newno);
+
+    ifnot (dev->s_tfree)
+        goto corrupt;
+    --dev->s_tfree;
+
+    /* Zero out the new block */
+    buf = (blkno_t *)bread(devno, newno, 2);
+    bzero(buf, 512);
+    bawrite((bufptr)buf);
+    return(newno);
+
+corrupt:
+    printf("blk_alloc: corrupt\n");
+    dev->s_mounted = 1;
+corrupt2:
+    udata.u_error = ENOSPC;
+    return(0);
+}
+
+
+/* Blk_free is given a device number and a block number,
+and frees the block. */
+
+void blk_free( int devno, blkno_t blk)
+{
+    register fsptr dev;
+    register char *buf;
+
+    ifnot (blk)
+        return;
+
+    if (baddev(dev = getdev(devno)))
+        return;
+
+    validblk(devno, blk);
+
+    if (dev->s_nfree == 50)
+    {
+        buf = bread(devno, blk, 1);
+        bcopy((char *)&(dev->s_nfree), buf, 512);
+        bawrite((bufptr)buf);
+        dev->s_nfree = 0;
+    }
+
+    ++dev->s_tfree;
+    dev->s_free[(dev->s_nfree)++] = blk;
+}
+
+
+/* Oft_alloc and oft_deref allocate and dereference (and possibly free)
+ * entries in the open file table.
+ */
+
+int oft_alloc(void)
+{
+    register int j;
+
+    for (j=0; j < OFTSIZE ; ++j)
+    {
+        ifnot (of_tab[j].o_refs)
+        {
+            of_tab[j].o_refs = 1;
+            of_tab[j].o_inode = NULLINODE;
+            return (j);
+        }
+    }
+    udata.u_error = ENFILE;
+    return(-1);
+}
+
+
+void oft_deref(int of)
+{
+    register struct oft *ofptr;
+
+    ofptr = of_tab + of;
+    if (!(--ofptr->o_refs) && ofptr->o_inode)
+    {
+        i_deref(ofptr->o_inode);
+        ofptr->o_inode = NULLINODE;
+    }
+}
+
+
+/* Uf_alloc finds an unused slot in the user file table.
+ */
+
+int uf_alloc(void)
+{
+    register int j;
+
+    for (j=0; j < UFTSIZE ; ++j)
+    {
+        if (udata.u_files[j] & 0x80)  /* Portable, unlike  == -1 */
+        {
+            return (j);
+        }
+    }
+    udata.u_error = ENFILE;
+    return(-1);
+}
+
+
+/* I_ref increases the reference count of the given inode table entry.
+ */
+
+void i_ref( inoptr ino)
+{
+    if (++(ino->c_refs) == 2*ITABSIZE)       /* Arbitrary limit. */
+    {                                                  /*280*/
+        printf("inode %u,",ino->c_num);                        /*280*/
+        panic("too many i-refs");
+    }                                                  /*280*/
+}
+
+
+/* I_deref decreases the reference count of an inode, and frees it from
+ * the table if there are no more references to it.  If it also has no
+ * links, the inode itself and its blocks (if not a device) is freed.
+ */
+
+void i_deref(inoptr ino)
+{
+    magic(ino);
+
+    ifnot (ino->c_refs)
+        panic("inode freed.");
+
+    /* If the inode has no links and no refs, it must have
+       its blocks freed. */
+
+    ifnot (--ino->c_refs || ino->c_node.i_nlink)
+/*
+ SN  (mcy)
+*/
+        if (((ino->c_node.i_mode & F_MASK) == F_REG) ||
+            ((ino->c_node.i_mode & F_MASK) == F_DIR) ||
+            ((ino->c_node.i_mode & F_MASK) == F_PIPE))
+                f_trunc(ino);
+
+    /* If the inode was modified, we must write it to disk. */
+    if (!(ino->c_refs) && ino->c_dirty)
+    {
+        ifnot (ino->c_node.i_nlink)
+        {
+            ino->c_node.i_mode = 0;
+            i_free(ino->c_dev, ino->c_num);
+        }
+        wr_inode(ino);
+    }
+}
+
+
+/* Wr_inode writes out the given inode in the inode table out to disk,
+ * and resets its dirty bit.
+ */
+
+void wr_inode(inoptr ino)
+{
+    struct dinode *buf;
+    register blkno_t blkno;
+
+    magic(ino);
+
+    blkno = (ino->c_num >> 3) + 2;
+    buf = (struct dinode *)bread(ino->c_dev, blkno,0);
+    bcopy((char *)(&ino->c_node),
+          (char *)((char **)&buf[ino->c_num & 0x07]), 64);
+    bfree((bufptr)buf, 2);
+    ino->c_dirty = 0;
+}
+
+
+/* isdevice(ino) returns true if ino points to a device */
+int isdevice(inoptr ino)
+{
+    return (ino->c_node.i_mode & 020000);
+}
+
+
+/* This returns the device number of an inode representing a device */
+int devnum(inoptr ino)
+{
+    return (*(ino->c_node.i_addr));
+}
+
+
+/* F_trunc frees all the blocks associated with the file, if it
+ * is a disk file.
+ */
+
+void f_trunc(inoptr ino)
+{
+    int dev;
+    int j;
+
+    dev = ino->c_dev;
+
+    /* First deallocate the double indirect blocks */
+    freeblk(dev, ino->c_node.i_addr[19], 2);
+
+    /* Also deallocate the indirect blocks */
+    freeblk(dev, ino->c_node.i_addr[18], 1);
+
+    /* Finally, free the direct blocks */
+    for (j=17; j >= 0; --j)
+        freeblk(dev, ino->c_node.i_addr[j], 0);
+
+    bzero((char *)ino->c_node.i_addr, sizeof(ino->c_node.i_addr));
+
+    ino->c_dirty = 1;
+    ino->c_node.i_size = 0;
+}
+
+
+/* Companion function to f_trunc(). */
+void freeblk(int dev, blkno_t blk, int level)
+{
+    blkno_t *buf;
+    int j;
+
+    ifnot (blk)
+        return;
+
+    if (level)
+    {
+        buf = (blkno_t *)bread(dev, blk, 0);
+        for (j=255; j >= 0; --j)
+            freeblk(dev, buf[j], level-1);
+        brelse((bufptr)buf);
+    }
+
+    blk_free(dev,blk);
+}
+
+
+
+/* Changes: blk_alloc zeroes block it allocates */
+/*
+ * Bmap defines the structure of file system storage by returning
+ * the physical block number on a device given the inode and the
+ * logical block number in a file.  The block is zeroed if created.
+ */
+blkno_t bmap(inoptr ip, blkno_t bn, int rwflg)
+{
+        register int i;
+        register bufptr bp;
+        register int j;
+        register blkno_t nb;
+        int sh;
+        int dev;
+
+        if (getmode(ip) == F_BDEV)
+            return (bn);
+
+        dev = ip->c_dev;
+
+        /*
+         * blocks 0..17 are direct blocks
+         */
+        if(bn < 18) {
+                nb = ip->c_node.i_addr[bn];
+                if(nb == 0) {
+                        if(rwflg || (nb = blk_alloc(dev))==0)
+                                return(NULLBLK);
+                        ip->c_node.i_addr[bn] = nb;
+                        ip->c_dirty = 1;
+                }
+                return(nb);
+        }
+
+        /*
+         * addresses 18 and 19 have single and double indirect blocks.
+         * the first step is to determine how many levels of indirection.
+         */
+        bn -= 18;
+        sh = 0;
+        j = 2;
+        if (bn & 0xff00)        /* bn > 255  so double indirect */
+        {
+            sh = 8;
+            bn -= 256;
+            j = 1;
+        }
+
+        /*
+         * fetch the address from the inode
+         * Create the first indirect block if needed.
+         */
+        ifnot (nb = ip->c_node.i_addr[20-j])
+        {
+                if(rwflg || !(nb = blk_alloc(dev)))
+                        return(NULLBLK);
+                ip->c_node.i_addr[20-j] = nb;
+                ip->c_dirty = 1;
+        }
+
+        /*
+         * fetch through the indirect blocks
+         */
+        for(; j<=2; j++) {
+                bp = (bufptr)bread(dev, nb, 0);
+                /******
+                if(bp->bf_error) {
+                        brelse(bp);
+                        return((blkno_t)0);
+                }
+                ******/
+                i = (bn>>sh) & 0xff;
+                if ((nb = ((blkno_t *)bp)[i]))
+                    brelse(bp);
+                else
+                {
+                        if(rwflg || !(nb = blk_alloc(dev))) {
+                                brelse(bp);
+                                return(NULLBLK);
+                        }
+                        ((blkno_t *)bp)[i] = nb;
+                        bawrite(bp);
+                }
+                sh -= 8;
+        }
+        return(nb);
+}
+
+
+
+/* Validblk panics if the given block number is not a valid
+ *  data block for the given device.
+ */
+void validblk(int dev, blkno_t num)
+{
+    register fsptr devptr;
+
+    devptr = fs_tab + dev;
+
+    if (devptr->s_mounted == 0)
+        panic("validblk: not mounted");
+
+    if (num < devptr->s_isize || num >= devptr->s_fsize)
+        panic("validblk: invalid blk");
+}
+
+
+/* This returns the inode pointer associated with a user's file
+ * descriptor, checking for valid data structures.
+ */
+inoptr getinode(int uindex)
+{
+    register int oftindex;
+    register inoptr inoindex;
+
+    if (uindex < 0 || uindex >= UFTSIZE || udata.u_files[uindex] & 0x80 )
+    {
+        udata.u_error = EBADF;
+        return (NULLINODE);
+    }
+
+    if ((oftindex = udata.u_files[uindex]) < 0 || oftindex >= OFTSIZE)
+        panic("Getinode: bad desc table");
+
+    if ((inoindex = of_tab[oftindex].o_inode) < i_tab ||
+                inoindex >= i_tab+ITABSIZE)
+        panic("Getinode: bad OFT");
+
+    magic(inoindex);
+
+    return(inoindex);
+}
+
+
+/* Super returns true if we are the superuser */
+int super()
+{
+    return(udata.u_euid == 0);
+}
+
+
+/* Getperm looks at the given inode and the effective user/group ids,
+ * and returns the effective permissions in the low-order 3 bits.
+ */
+int getperm(inoptr ino)
+{
+    int mode;
+
+    if (super())
+        return(07);
+
+    mode = ino->c_node.i_mode;
+    if (ino->c_node.i_uid == udata.u_euid)
+        mode >>= 6;
+    else if (ino->c_node.i_gid == udata.u_egid)
+        mode >>= 3;
+
+    return(mode & 07);
+}
+
+
+/* This sets the times of the given inode, according to the flags.
+ */
+void setftime(inoptr ino, int flag)
+{
+    ino->c_dirty = 1;
+
+    //if (flag & A_TIME)
+    //    rdtime(&(ino->c_node.i_atime));
+    //if (flag & M_TIME)
+    //    rdtime(&(ino->c_node.i_mtime));
+    //if (flag & C_TIME)
+    //    rdtime(&(ino->c_node.i_ctime));
+}
+
+
+int getmode(inoptr ino)
+{
+    return( ino->c_node.i_mode & F_MASK);
+}
+
+
+/* Fmount places the given device in the mount table with mount point ino.
+ */
+int fmount(int dev, inoptr ino)
+{
+    char *buf;
+    register struct filesys *fp;
+
+    /* Dev 0 blk 1 */
+    fp = fs_tab + dev;
+    buf = bread(dev, 1, 0);
+    bcopy(buf, (char *)fp, sizeof(struct filesys));
+    brelse((bufptr)buf);
+    
+    /* See if there really is a filesystem on the device */
+    if (fp->s_mounted != SMOUNTED ||
+         fp->s_isize >= fp->s_fsize)
+        return (-1);
+
+    fp->s_mntpt = ino;
+    if (ino)
+        ++ino->c_refs;
+
+    return (0);
+}
+
+
+void magic(inoptr ino)
+{
+    if (ino->c_magic != CMAGIC)
+        panic("Corrupt inode");
+}