From 03f408f868fb576d3c1a55047070ce8a58009f7b Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 31 Oct 2014 14:37:20 +0000 Subject: [PATCH] Standalone: Add the standalone utilities These are based off the UZI-WRS versions from Will Sowerbutts except for chmem which is new code. --- Standalone/Makefile | 21 + Standalone/chmem.c | 59 +++ Standalone/devio.c | 253 ++++++++++ Standalone/fsck.c | 757 ++++++++++++++++++++++++++++++ Standalone/fuzix_fs.h | 325 +++++++++++++ Standalone/mkfs.c | 131 ++++++ Standalone/ucp.c | 647 ++++++++++++++++++++++++++ Standalone/util.c | 45 ++ Standalone/xfs1.c | 401 ++++++++++++++++ Standalone/xfs1a.c | 157 +++++++ Standalone/xfs1b.c | 504 ++++++++++++++++++++ Standalone/xfs2.c | 1025 +++++++++++++++++++++++++++++++++++++++++ 12 files changed, 4325 insertions(+) create mode 100644 Standalone/Makefile create mode 100644 Standalone/chmem.c create mode 100644 Standalone/devio.c create mode 100644 Standalone/fsck.c create mode 100644 Standalone/fuzix_fs.h create mode 100644 Standalone/mkfs.c create mode 100644 Standalone/ucp.c create mode 100644 Standalone/util.c create mode 100644 Standalone/xfs1.c create mode 100644 Standalone/xfs1a.c create mode 100644 Standalone/xfs1b.c create mode 100644 Standalone/xfs2.c diff --git a/Standalone/Makefile b/Standalone/Makefile new file mode 100644 index 00000000..c94072fa --- /dev/null +++ b/Standalone/Makefile @@ -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 index 00000000..6429d79c --- /dev/null +++ b/Standalone/chmem.c @@ -0,0 +1,59 @@ +#include +#include +#include +#include + + +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 index 00000000..65a15750 --- /dev/null +++ b/Standalone/devio.c @@ -0,0 +1,253 @@ +#define DEVIO + +#include +#include +#include +#include +#include +#include +#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 index 00000000..a3ba201c --- /dev/null +++ b/Standalone/fsck.c @@ -0,0 +1,757 @@ +#include +#include +#include +#include +#include +#include +#include +#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 index 00000000..2a669f23 --- /dev/null +++ b/Standalone/fuzix_fs.h @@ -0,0 +1,325 @@ +#define __UZIFS_DOT_H__ + +#include + +#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 index 00000000..9aa1c24c --- /dev/null +++ b/Standalone/mkfs.c @@ -0,0 +1,131 @@ + +/************************************************** +UZI (Unix Z80 Implementation) Utilities: mkfs.c +***************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include "fuzix_fs.h" + +/* This makes a filesystem + * + * example use: + * ./mkfs ./blankfs.img 64 4096 + * (this will write a 2MB filesystem with 64 blocks of inodes to ./blankfs.img) + * + * */ + +char zero512[512]; + +direct dirbuf[64] = { {ROOTINODE,"."}, + {ROOTINODE,".."} }; +struct dinode inode[8]; + +void mkfs(uint16_t fsize, uint16_t isize); +void dwrite(uint16_t blk, char *addr); + +struct filesys fs_super; + +int main(int argc, char **argv) +{ + uint16_t fsize, isize; + + if (argc != 4) + { + printf("Usage: mkfs device isize fsize\n"); + return -1; + } + + if(sizeof(inode) != 512){ + printf("inode is the wrong size -- %d\n", (int)sizeof(inode)); + } + + isize = (uint16_t)atoi(argv[2]); + fsize = (uint16_t)atoi(argv[3]); + + if (fsize < 3 || isize < 2 || isize >= fsize) + { + printf("Bad parameter values\n"); + return -1; + } + + memset(zero512, 0, 512); + + printf("Making filesystem on device %s with isize %u fsize %u.\n", argv[1], isize, fsize); + + if (fd_open(argv[1])) + { + printf("Can't open device"); + return -1; + } + + mkfs(fsize, isize); + + return 0; +} + +void mkfs(uint16_t fsize, uint16_t isize) +{ + uint16_t j; + + /* Zero out the blocks */ + + for (j=0; j < fsize; ++j) + dwrite(j, zero512); + + /* Initialize the super-block */ + + fs_super.s_mounted = SMOUNTED; /* Magic number */ + fs_super.s_isize = isize; + fs_super.s_fsize = fsize; + fs_super.s_nfree = 1; + fs_super.s_free[0] = 0; + fs_super.s_tfree = 0; + fs_super.s_ninode = 0; + fs_super.s_tinode = 8 * (isize-2) - 2; + + /* Free each block, building the free list */ + for (j= fsize-1; j >= isize+1; --j) + { + if (fs_super.s_nfree == 50) + { + dwrite(j, (char *)&fs_super.s_nfree); + fs_super.s_nfree = 0; + } + + ++fs_super.s_tfree; + fs_super.s_free[(fs_super.s_nfree)++] = j; + } + + /* The inodes are already zeroed out */ + /* create the root dir */ + inode[ROOTINODE].i_mode = F_DIR | (0777 & MODE_MASK); + inode[ROOTINODE].i_nlink = 3; + inode[ROOTINODE].i_size = 64; + inode[ROOTINODE].i_addr[0] = isize; + + /* Reserve reserved inode */ + inode[0].i_nlink = 1; + inode[0].i_mode = ~0; + + dwrite(2, (char *)inode); + + dwrite(isize,(char *)dirbuf); + + /* Write out super block */ + dwrite(1,(char *)&fs_super); +} + +void dwrite(uint16_t blk, char *addr) +{ + lseek(dev_fd, ((int)blk) * 512, SEEK_SET); + if (write(dev_fd, addr, 512) != 512) { + perror("write"); + exit(1); + } +} diff --git a/Standalone/ucp.c b/Standalone/ucp.c new file mode 100644 index 00000000..a4a5daaf --- /dev/null +++ b/Standalone/ucp.c @@ -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 +#include +#include +#include +#include +#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 index 00000000..895bb9b1 --- /dev/null +++ b/Standalone/util.c @@ -0,0 +1,45 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#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 index 00000000..fd3883d3 --- /dev/null +++ b/Standalone/xfs1.c @@ -0,0 +1,401 @@ +/************************************************** +UZI (Unix Z80 Implementation) Utilities: xfs1.c +***************************************************/ + +/*LINTLIBRARY*/ +#include +#include +#include +#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 index 00000000..d2b07c72 --- /dev/null +++ b/Standalone/xfs1a.c @@ -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 +#include +#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 index 00000000..e0e6898b --- /dev/null +++ b/Standalone/xfs1b.c @@ -0,0 +1,504 @@ +/************************************************** + UZI (Unix Z80 Implementation) Utilities: xfs1a1.c + ***************************************************/ + +/*LINTLIBRARY*/ +#include +#include +#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 index 00000000..fac6f758 --- /dev/null +++ b/Standalone/xfs2.c @@ -0,0 +1,1025 @@ +/************************************************** +UZI (Unix Z80 Implementation) Utilities: xfs2.c +***************************************************/ + +/* Revisions: + * 25.2.96 Bug fix in i_deref() SN + */ + +/*LINTLIBRARY*/ +#include +#include +#include +#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"); +} -- 2.34.1