# This is a shell archive. # Remove everything above and including the cut line. # Then run the rest of the file through sh. #----cut here-----cut here-----cut here-----cut here----# #!/bin/sh # shar: Shell Archiver # Run the following text with /bin/sh to create: # README # xenixfs.patch # This archive created: Tue Aug 18 14:30:11 1992 cat << \SHAR_EOF > README README for xenixfs.patch This patch provides an implementation of the Xenix filesystem for Linux. The implementation isn't complete in the sense that the following things are missing: - divvy partitions - badtrk table support - mkfs - fsck - fsdb To use this code with Linux, you must boot Xenix and run mkfs on a full partition. EG: mkfs /dev/hd03 ... This code can also be used with floppies (boot Xenix and do mkdev fd). In fact, I recommend testing the patch out on floppies first. I have my Linux system running on Xenix partitions as follows: 200 MB IDE 30MB MSDOS 50MB Xenix root + swap 60MB Linux root + swap 65MB /usr/spool (Xenix + Linux) 1 GIG SCSI 100MB MSDOS 300MB /home 300MB /src (Xenix + Linux) 360MB /u (Xenix + Linux) This patch must be applied to Linux 0.97 Patch Level 1: Apply it with (assuming the Linux source tree is in /usr/src/linux): cd /usr/src patch -p0 &1 | tee patch.log Doug Evans, dje@sspiff.UUCP or dje@sspiff.ampr.ab.ca, 92Aug18 SHAR_EOF cat << \SHAR_EOF > xenixfs.patch *** linux.pl1/Makefile Tue Aug 18 12:51:49 1992 --- linux/Makefile Mon Aug 17 13:54:30 1992 *************** *** 84,90 **** AR =ar ARCHIVES =kernel/kernel.o mm/mm.o fs/fs.o net/net.o ! FILESYSTEMS =fs/minix/minix.o fs/ext/ext.o fs/msdos/msdos.o DRIVERS =kernel/blk_drv/blk_drv.a kernel/chr_drv/chr_drv.a \ kernel/blk_drv/scsi/scsi.a MATH =kernel/math/math.a --- 84,90 ---- AR =ar ARCHIVES =kernel/kernel.o mm/mm.o fs/fs.o net/net.o ! FILESYSTEMS =fs/xenix/xenix.o fs/minix/minix.o fs/msdos/msdos.o DRIVERS =kernel/blk_drv/blk_drv.a kernel/chr_drv/chr_drv.a \ kernel/blk_drv/scsi/scsi.a MATH =kernel/math/math.a *** linux.pl1/fs/Makefile Sat Aug 1 15:44:01 1992 --- linux/fs/Makefile Sat Aug 8 00:02:15 1992 *************** *** 7,13 **** # # Note 2! The CFLAGS definitions are now in the main makefile... ! SUBDIRS =minix ext msdos .c.s: $(CC) $(CFLAGS) -S $< --- 7,13 ---- # # Note 2! The CFLAGS definitions are now in the main makefile... ! SUBDIRS =minix ext msdos xenix .c.s: $(CC) $(CFLAGS) -S $< *** linux.pl1/fs/super.c Sat Aug 1 13:09:35 1992 --- linux/fs/super.c Mon Aug 17 13:54:39 1992 *************** *** 12,17 **** --- 12,18 ---- #include #include #include + #include #include #include #include *************** *** 35,42 **** /* Move into include file later */ static struct file_system_type file_systems[] = { {minix_read_super,"minix"}, ! {ext_read_super,"ext"}, {msdos_read_super,"msdos"}, {NULL,NULL} }; --- 37,45 ---- /* Move into include file later */ static struct file_system_type file_systems[] = { + {xenix_read_super,"xenix"}, {minix_read_super,"minix"}, ! /*{ext_read_super,"ext"},*/ {msdos_read_super,"msdos"}, {NULL,NULL} }; *** linux.pl1/fs/xenix/alloc.c Wed Aug 12 15:09:56 1992 --- linux/fs/xenix/alloc.c Fri Aug 7 16:11:03 1992 *************** *** 0 **** --- 1,308 ---- + /* + * linux/fs/xenix/alloc.c + * + * (C) 1991 Linus Torvalds + * + * Taken from minix/bitmap.c, modified by Doug Evans, dje@sspiff.UUCP, 92Jun04. + * + * This file contains code for allocating/freeing blocks and inodes. + */ + + #include + #include + #include + #include + #include + + #define clear_block(addr) \ + __asm__("cld\n\t" \ + "rep\n\t" \ + "stosl" \ + ::"a" (0),"c" (BLOCK_SIZE/4),"D" ((long) (addr)):"cx","di") + + #ifndef MIN + #define MIN(a,b) ((a) < (b) ? (a) : (b)) + #endif + + int + xenix_free_block(int dev, int block) + { + struct super_block * sb; + struct buffer_head * bh; + struct xenix_free_block * xfb; + + if (!(sb = get_super(dev))) + panic("xenix_free_block: trying to free block on nonexistent device"); + + DEBUGPK(xenix_blocks, + ("xenix_free_block: dev 0x%x, block %d, s_nfree %d, s_tfree %d\n", + dev, block, sb->s_xenix_nfree, + #ifdef XENIX_GOT_PACK_2 + sb->s_xenix_tfree + #else + *(daddr_t *) sb->s_xenix_tfree + #endif + )); + + lock_super(sb); + if (block < sb->s_xenix_isize || block >= sb->s_xenix_fsize) { + printk("xenix_free_block: block=%d, isize=%d, fsize=%d\n", + block, sb->s_xenix_isize, sb->s_xenix_fsize); + panic("xenix_free_block: trying to free block not in datazone"); + } + if (sb->s_xenix_nfree > 100) + panic("xenix_free_block: s_nfree > 100"); + + /* + * If the cached free list is full, it's copied to this block ... + */ + + if (sb->s_xenix_nfree == 100) { + if (!(bh = getblk(dev, block, BLOCK_SIZE))) + panic("xenix_free_block: getblk() failed"); + if (bh->b_count > 1) { + brelse(bh); + free_super(sb); + return(0); /* FIXME: that's it? */ + } + xfb = (struct xenix_free_block *) bh->b_data; + xfb->xfb_nfree = 100; + memcpy(xfb->xfb_free, sb->s_xenix_free, 100 * sizeof(long)); + sb->s_xenix_nfree = 0; + bh->b_dirt = 1; + bh->b_uptodate = 1; /* FIXME: ok? */ + if (bh->b_count == 1) + brelse(bh); + } else { + bh = get_hash_table(dev, block, BLOCK_SIZE); + if (bh) { + if (bh->b_count > 1) { + brelse(bh); + free_super(sb); + return(0); /* FIXME: that's it? */ + } + bh->b_dirt = 0; + bh->b_uptodate = 0; + if (bh->b_count == 1) + brelse(bh); + } + } + #ifdef XENIX_GOT_PACK_2 + sb->s_xenix_free[sb->s_xenix_nfree] = block; + #else + *((daddr_t *) sb->s_xenix_free + sb->s_xenix_nfree) = block; + #endif + sb->s_xenix_nfree++; + #ifdef XENIX_GOT_PACK_2 + sb->s_xenix_tfree++; + #else + ++*((daddr_t *) sb->s_xenix_tfree); + #endif + sb->s_xenix_bh->b_dirt = 1; + free_super(sb); + return(1); + } + + int + xenix_new_block(int dev) + { + struct buffer_head * bh; + struct super_block * sb; + struct xenix_free_block * xfb; + int block; + + if (!(sb = get_super(dev))) + panic("xenix_new_block: trying to get new block from nonexistant device"); + + DEBUGPK(xenix_blocks, ("xenix_new_block: dev 0x%x, s_nfree %d, s_tfree %d\n", + dev, sb->s_xenix_nfree, + #ifdef XENIX_GOT_PACK_2 + sb->s_xenix_tfree + #else + *(daddr_t *) sb->s_xenix_tfree + #endif + )); + + if (sb->s_xenix_nfree == 0) /* FIXME: review */ + return(0); /* no blocks available */ + lock_super(sb); + #ifdef XENIX_GOT_PACK_2 + block = sb->s_xenix_free[--sb->s_xenix_nfree]; + #else + block = *((daddr_t *) sb->s_xenix_free + --sb->s_xenix_nfree); + #endif + if (block == 0) { + sb->s_xenix_nfree++; + free_super(sb); + return(0); /* no blocks available */ + } + if (sb->s_xenix_nfree == 0) { + if (!(bh = bread(dev, block, BLOCK_SIZE))) { + /* FIXME: was panic() */ + printk("xenix_new_block: cannot read free-list block\n"); + sb->s_xenix_nfree++; + free_super(sb); + return(0); + } + xfb = (struct xenix_free_block *) bh->b_data; + if (xfb->xfb_nfree <= 1 || xfb->xfb_nfree > 100) + panic("xenix_new_block: free-list block with 0 or >100 entries"); + sb->s_xenix_nfree = xfb->xfb_nfree; + memcpy(sb->s_xenix_free, xfb->xfb_free, xfb->xfb_nfree * sizeof(daddr_t)); + brelse(bh); + } + if (!(bh = getblk(dev, block, BLOCK_SIZE))) + panic("xenix_new_block: getblk() failed"); + if (bh->b_count > 1) + panic("xenix_new_block: count > 1"); + bh->b_count = 1; /* could have been 0 (brelse() above called) */ + clear_block(bh->b_data); + bh->b_uptodate = 1; + bh->b_dirt = 1; + brelse(bh); + #ifdef XENIX_GOT_PACK_2 + sb->s_xenix_tfree--; + #else + --*((daddr_t *) sb->s_xenix_tfree); + #endif + sb->s_xenix_bh->b_dirt = 1; + free_super(sb); + return(block); + } + + unsigned long + xenix_count_free_blocks(struct super_block * sb) + { + #ifdef XENIX_GOT_PACK_2 + return(sb->s_xenix_tfree); + #else + return(*(daddr_t *) sb->s_xenix_tfree); + #endif + } + + void + xenix_free_inode(struct inode * inode) + { + struct buffer_head * bh; + struct xenix_inode * raw_inode; + struct super_block * sb; + + if (!inode) + return; + if (!inode->i_dev) { + memset(inode, 0, sizeof(*inode)); + return; + } + if (inode->i_count > 1) { + printk("xenix_free_inode: inode has count=%d\n", inode->i_count); + return; + } + if (inode->i_nlink) { + printk("xenix_free_inode: inode has nlink=%d\n", inode->i_nlink); + return; + } + if (!(sb = inode->i_sb)) { + printk("xenix_free_inode: inode on nonexistent device\n"); + return; + } + + DEBUGPK(xenix_inodes, + ("xenix_free_inode: dev 0x%x, inode %d, s_ninode %d, s_tinode %d\n", + inode->i_dev, inode->i_ino, sb->s_xenix_ninode, sb->s_xenix_tinode + )); + + if (inode->i_ino <= XENIX_ROOT_INO || + inode->i_ino > sb->s_xenix_isize * XENIX_INODES_PER_BLOCK) { + printk("xenix_free_inode: inode 0,1,2 or nonexistent inode\n"); + return; + } + if (sb->s_xenix_ninode < 100) + sb->s_xenix_inode[sb->s_xenix_ninode++] = inode->i_ino; + /* FIXME: #define 31, 16 */ + if (!(bh = bread(inode->i_dev, (inode->i_ino + 31) / 16, BLOCK_SIZE))) { + panic("xenix_free_inode: unable to read inode block"); + /* FIXME: too severe? */ + return; + } + /* FIXME: #define 31, 15 */ + raw_inode = (struct xenix_inode *) bh->b_data + (inode->i_ino + 31 & 15); + if (raw_inode->i_nlink == 0) + printk("xenix_free_inode: inode already free\n"); + memset(raw_inode, 0, sizeof(*raw_inode)); + memset(inode, 0, sizeof(*inode)); + bh->b_dirt = 1; + sb->s_xenix_tinode++; + sb->s_xenix_bh->b_dirt = 1; + } + + struct inode * + xenix_new_inode(int dev) + { + struct inode * inode; + struct buffer_head * bh; + struct super_block * sb; + struct xenix_inode * raw_inode; + int i,j,ino,block,max_alloc; + + if (!(inode = get_empty_inode())) + return NULL; + if (!(inode->i_sb = sb = get_super(dev))) { + printk("xenix_new_inode: unknown device\n"); + iput(inode); + return(NULL); + } + inode->i_flags = inode->i_sb->s_flags; + + DEBUGPK(xenix_inodes, + ("xenix_new_inode: dev 0x%x, s_ninode %d, s_tinode %d\n", + dev, sb->s_xenix_ninode, sb->s_xenix_tinode + )); + + if (sb->s_xenix_ninode == 0) { + for (i = 0, ino = 3, block = 2, max_alloc = MIN(100, sb->s_xenix_tinode); + i < max_alloc && block < sb->s_xenix_isize; + ) { + if (!(bh = bread(dev, block, BLOCK_SIZE))) { + printk("xenix_new_inode: unable to read inode table\n"); + iput(inode); + return(NULL); + } + raw_inode = (struct xenix_inode *) bh->b_data; + for (j = ino == 3 ? 2 : 0; j < 16 && i < max_alloc; j++, ino++) { + if (raw_inode[j].i_nlink == 0) + sb->s_xenix_inode[i++] = ino; + } + brelse(bh); + block++; + } + if (i == 0) { + iput(inode); + return(NULL); /* no inodes available */ + } + sb->s_xenix_ninode = i; + } + ino = sb->s_xenix_inode[--sb->s_xenix_ninode]; + inode->i_count = 1; + inode->i_nlink = 1; + inode->i_dev = dev; + inode->i_uid = current->euid; + inode->i_gid = current->egid; + inode->i_dirt = 1; + inode->i_ino = ino; + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; + inode->i_op = NULL; + inode->i_mode = 0; /* for xenix_write_inode() */ + inode->i_size = 0; /* ditto */ + xenix_write_inode(inode); /* ensure inode not allocated again */ + /* FIXME: caller may call this too. */ + inode->i_dirt = 1; /* cleared by xenix_write_inode() */ + sb->s_xenix_tinode--; + sb->s_xenix_bh->b_dirt = 1; + return(inode); + } + + unsigned long + xenix_count_free_inodes(struct super_block * sb) + { + return(sb->s_xenix_tinode); + } *** linux.pl1/fs/xenix/blkdev.c Wed Aug 12 15:09:56 1992 --- linux/fs/xenix/blkdev.c Fri Aug 7 15:16:54 1992 *************** *** 0 **** --- 1,70 ---- + /* + * linux/fs/xenix/blkdev.c + * + * (C) 1991 Linus Torvalds + * + * Taken from minix/blkdev.c, modified by Doug Evans, dje@sspiff.UUCP, 92Jun04. + * + * This file contains code for block device nodes. + */ + + #include + #include + #include + #include + #include + #include + #include + + /* + * Called every time a xenix block special file is opened. + */ + + static int + blkdev_open(struct inode * inode, struct file * filp) + { + int i; + + /*check_disk_change(inode->i_rdev); - removed in 0.96a.pl2 */ + i = MAJOR(inode->i_rdev); + if (i < MAX_BLKDEV) { + filp->f_op = blkdev_fops[i]; + if (filp->f_op && filp->f_op->open) + return(filp->f_op->open(inode, filp)); + } + return(0); + } + + /* + * Dummy default file-operations: the only thing this does + * is contain the open that then fills in the correct operations + * depending on the special file... + */ + + static struct file_operations def_blk_fops = { + NULL, /* lseek */ + NULL, /* read */ + NULL, /* write */ + NULL, /* readdir */ + NULL, /* select */ + NULL, /* ioctl */ + blkdev_open, /* open */ + NULL, /* release */ + }; + + struct inode_operations xenix_blkdev_inode_operations = { + &def_blk_fops, /* default file operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + xenix_bmap, /* bmap */ + xenix_truncate /* truncate */ + }; *** linux.pl1/fs/xenix/chrdev.c Wed Aug 12 15:09:56 1992 --- linux/fs/xenix/chrdev.c Fri Aug 7 15:17:02 1992 *************** *** 0 **** --- 1,69 ---- + /* + * linux/fs/xenix/chrdev.c + * + * (C) 1991 Linus Torvalds + * + * Taken from minix/chrdev.c, modified by Doug Evans, dje@sspiff.UUCP, 92Jun04. + * + * This file contains code for character device nodes. + */ + + #include + #include + #include + #include + #include + #include + #include + + /* + * Called every time a xenix character special file is opened. + */ + + static int + chrdev_open(struct inode * inode, struct file * filp) + { + int i; + + i = MAJOR(inode->i_rdev); + if (i < MAX_CHRDEV) { + filp->f_op = chrdev_fops[i]; + if (filp->f_op && filp->f_op->open) + return(filp->f_op->open(inode, filp)); + } + return(0); + } + + /* + * Dummy default file-operations: the only thing this does + * is contain the open that then fills in the correct operations + * depending on the special file... + */ + + static struct file_operations def_chr_fops = { + NULL, /* lseek */ + NULL, /* read */ + NULL, /* write */ + NULL, /* readdir */ + NULL, /* select */ + NULL, /* ioctl */ + chrdev_open, /* open */ + NULL, /* release */ + }; + + struct inode_operations xenix_chrdev_inode_operations = { + &def_chr_fops, /* default file operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + xenix_bmap, /* bmap */ + xenix_truncate /* truncate */ + }; *** linux.pl1/fs/xenix/dir.c Wed Aug 12 15:09:56 1992 --- linux/fs/xenix/dir.c Fri Aug 7 15:17:46 1992 *************** *** 0 **** --- 1,95 ---- + /* + * linux/fs/xenix/dir.c + * + * (C) 1991 Linus Torvalds + * + * Taken from minix/dir.c, modified by Doug Evans, dje@sspiff.UUCP, 92Jun04. + * + * This file contains xenix directory handling functions. + */ + + #include + + #include + #include + #include + #include + + static int xenix_readdir(struct inode *, struct file *, struct dirent *, int); + + static struct file_operations xenix_dir_operations = { + NULL, /* lseek - default */ + xenix_file_read, /* read */ + NULL, /* write - bad */ + xenix_readdir, /* readdir */ + NULL, /* select - default */ + NULL, /* ioctl - default */ + NULL, /* no special open code */ + NULL /* no special release code */ + }; + + /* + * directories can handle most operations... + */ + + struct inode_operations xenix_dir_inode_operations = { + &xenix_dir_operations, /* default directory file-ops */ + xenix_create, /* create */ + xenix_lookup, /* lookup */ + xenix_link, /* link */ + xenix_unlink, /* unlink */ + xenix_symlink, /* symlink */ + xenix_mkdir, /* mkdir */ + xenix_rmdir, /* rmdir */ + xenix_mknod, /* mknod */ + xenix_rename, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + xenix_bmap, /* bmap */ + xenix_truncate /* truncate */ + }; + + static int + xenix_readdir(struct inode * inode, struct file * filp, + struct dirent * dirent, int count) + { + unsigned int block,offset,i; + char c; + struct buffer_head * bh; + struct xenix_dir_entry * de; + + if (!inode || !S_ISDIR(inode->i_mode)) + return(-EBADF); + if (filp->f_pos & (sizeof (struct xenix_dir_entry) - 1)) + return(-EBADF); + while (filp->f_pos < inode->i_size) { + offset = filp->f_pos & 1023; + block = xenix_bmap(inode, (filp->f_pos) >> BLOCK_SIZE_BITS); + if (!block || !(bh = bread(inode->i_dev, block, BLOCK_SIZE))) { + filp->f_pos += 1024 - offset; + continue; + } + de = (struct xenix_dir_entry *) (offset + bh->b_data); + while (offset < 1024 && filp->f_pos < inode->i_size) { + offset += sizeof (struct xenix_dir_entry); + filp->f_pos += sizeof (struct xenix_dir_entry); + if (de->inode) { + for (i = 0; i < XENIX_NAME_LEN; i++) + if (c = de->name[i]) + put_fs_byte(c, i + dirent->d_name); + else + break; + if (i) { + put_fs_long(de->inode, &dirent->d_ino); + put_fs_byte(0, i + dirent->d_name); + put_fs_word(i, &dirent->d_reclen); + brelse(bh); + return(i); + } + } + de++; + } + brelse(bh); + } + return(0); + } *** linux.pl1/fs/xenix/fifo.c Wed Aug 12 15:09:56 1992 --- linux/fs/xenix/fifo.c Tue Jul 28 23:56:25 1992 *************** *** 0 **** --- 1,28 ---- + /* + * linux/fs/fifo.c + * + * written by Paul H. Hargrove + */ + + #include + #include + #include + + extern struct file_operations def_fifo_fops; + + struct inode_operations xenix_fifo_inode_operations = { + &def_fifo_fops, /* default file operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* bmap */ + NULL /* truncate */ + }; *** linux.pl1/fs/xenix/file.c Wed Aug 12 15:09:56 1992 --- linux/fs/xenix/file.c Fri Aug 7 15:19:24 1992 *************** *** 0 **** --- 1,224 ---- + /* + * linux/fs/xenix/file.c + * + * (C) 1991 Linus Torvalds + * + * Taken from minix/file.c, modified by Doug Evans, dje@sspiff.UUCP, 92Jun15. + * + * This file contains xenix regular file handling primitives. + */ + + #include + #include + + #include + #include + #include + #include + #include + #include + #include + + #define NBUF 16 + + #define MIN(a,b) (((a)<(b))?(a):(b)) + #define MAX(a,b) (((a)>(b))?(a):(b)) + + int xenix_file_read(struct inode *, struct file *, char *, int); + static int xenix_file_write(struct inode *, struct file *, char *, int); + + /* + * We have mostly NULL's here: the current defaults are ok for + * the xenix filesystem. + */ + + static struct file_operations xenix_file_operations = { + NULL, /* lseek - default */ + xenix_file_read, /* read */ + xenix_file_write, /* write */ + NULL, /* readdir - bad */ + NULL, /* select - default */ + NULL, /* ioctl - default */ + NULL, /* no special open is needed */ + NULL /* release */ + }; + + struct inode_operations xenix_file_inode_operations = { + &xenix_file_operations, /* default file operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + xenix_bmap, /* bmap */ + xenix_truncate /* truncate */ + }; + + static inline void + wait_on_buffer(struct buffer_head * bh) + { + cli(); + while (bh->b_lock) + sleep_on(&bh->b_wait); + sti(); + } + + /* + * xenix_file_read() is also needed by the directory read-routine, + * so it's not static. NOTE! reading directories directly is a bad idea, + * but has to be supported for now for compatability reasons with older + * versions. + */ + + int + xenix_file_read(struct inode * inode, struct file * filp, char * buf, int count) + { + int read,left,chars,nr; + int block, blocks, offset; + struct buffer_head ** bhb, ** bhe; + struct buffer_head * buflist[NBUF]; + + if (!inode) { + printk("xenix_file_read: inode = NULL\n"); + return(-EINVAL); + } + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) { + printk("xenix_file_read: mode = %07o\n", inode->i_mode); + return(-EINVAL); + } + if (filp->f_pos > inode->i_size) + left = 0; + else + left = inode->i_size - filp->f_pos; + if (left > count) + left = count; + if (left <= 0) + return(0); + read = 0; + block = filp->f_pos >> BLOCK_SIZE_BITS; + offset = filp->f_pos & (BLOCK_SIZE - 1); + blocks = (left + offset + BLOCK_SIZE - 1) / BLOCK_SIZE; + bhb = bhe = buflist; + do { + if (blocks) { + --blocks; + if (nr = xenix_bmap(inode, block++)) { + *bhb = getblk(inode->i_dev, nr, BLOCK_SIZE); + if (!(*bhb)->b_uptodate) + ll_rw_block(READ, *bhb); + } else + *bhb = NULL; + + if (++bhb == &buflist[NBUF]) + bhb = buflist; + + if (bhb != bhe) + continue; + } + if (*bhe) { + wait_on_buffer(*bhe); + if (!(*bhe)->b_uptodate) { + do { + brelse(*bhe); + if (++bhe == &buflist[NBUF]) + bhe = buflist; + } while (bhe != bhb); + break; + } + } + + if (left < BLOCK_SIZE - offset) + chars = left; + else + chars = BLOCK_SIZE - offset; + filp->f_pos += chars; + left -= chars; + read += chars; + if (*bhe) { + memcpy_tofs(buf, offset + (*bhe)->b_data, chars); + brelse(*bhe); + buf += chars; + } else { + while (chars-- > 0) + put_fs_byte(0, buf++); + } + offset = 0; + if (++bhe == &buflist[NBUF]) + bhe = buflist; + } while (left > 0); + if (!read) + return(-EIO); + if (!IS_RDONLY(inode)) { + inode->i_atime = CURRENT_TIME; + inode->i_dirt = 1; + } + return(read); + } + + static int + xenix_file_write(struct inode * inode, struct file * filp, char * buf, int count) + { + off_t pos; + int written,block,c; + struct buffer_head * bh; + char * p; + + if (!inode) { + printk("xenix_file_write: inode = NULL\n"); + return(-EINVAL); + } + if (!S_ISREG(inode->i_mode)) { + printk("xenix_file_write: mode = %07o\n", inode->i_mode); + return(-EINVAL); + } + /* + * ok, append may not work when many processes are writing at the same time + * but so what. That way leads to madness anyway. + */ + if (filp->f_flags & O_APPEND) + pos = inode->i_size; + else + pos = filp->f_pos; + written = 0; + while (written < count) { + if (!(block = xenix_create_block(inode, pos / BLOCK_SIZE))) { + if (!written) + written = -ENOSPC; + break; + } + c = BLOCK_SIZE - (pos % BLOCK_SIZE); + if (c > count - written) + c = count - written; + if (c == BLOCK_SIZE) + bh = getblk(inode->i_dev, block, BLOCK_SIZE); + else + bh = bread(inode->i_dev, block, BLOCK_SIZE); + if (!bh) { + if (!written) + written = -EIO; + break; + } + p = (pos % BLOCK_SIZE) + bh->b_data; + pos += c; + if (pos > inode->i_size) { + inode->i_size = pos; + inode->i_dirt = 1; + } + written += c; + memcpy_fromfs(p, buf, c); + buf += c; + bh->b_uptodate = 1; + bh->b_dirt = 1; + brelse(bh); + } + inode->i_ctime = inode->i_mtime = CURRENT_TIME; + filp->f_pos = pos; + inode->i_dirt = 1; + return(written); + } *** linux.pl1/fs/xenix/inode.c Wed Aug 12 15:09:57 1992 --- linux/fs/xenix/inode.c Wed Aug 12 03:33:42 1992 *************** *** 0 **** --- 1,317 ---- + /* + * linux/fs/xenix/inode.c + * + * (C) 1991 Linus Torvalds + * + * Taken from minix/inode.c, modified by Doug Evans, dje@sspiff.UUCP, 92Jun04. + * + * This file contains code for allocating/freeing inodes and for read/writing + * the superblock. + */ + + #include + #include + #include + #include + #include + #include + #include + + #include + #include + + char xenix_inodes = 0; /* for debugging */ + char xenix_blocks = 0; + + static int inline + read3byte(unsigned char *p, int index) + { + return(p[index * 3] + (p[index * 3 + 1] << 8) + (p[index * 3 + 2] << 16)); + } + + static void inline + write3byte(unsigned char *p, int index, int val) + { + p[index * 3] = (unsigned char) val; + p[index * 3 + 1] = (unsigned char) (val >> 8); + p[index * 3 + 2] = (unsigned char) (val >> 16); + } + + static struct super_operations xenix_sops = { + xenix_read_inode, + xenix_write_inode, + xenix_put_inode, + xenix_put_super, + NULL, + xenix_statfs + }; + + void + xenix_put_inode(struct inode *inode) + { + inode->i_size = 0; + xenix_truncate(inode); + xenix_free_inode(inode); + } + + void + xenix_put_super(struct super_block *sb) + { + struct buffer_head * bh; + struct xenix_super_block * xsb; + + lock_super(sb); + bh = sb->s_xenix_bh; + xsb = sb->s_xenix_xsb; + #ifdef XENIX_GOT_PACK_2 + xsb->xs_time = CURRENT_TIME; + #else + *(time_t *) xsb->xs_time = CURRENT_TIME; + #endif + xsb->xs_clean = XENIX_SB_CLEAN; + bh->b_dirt = 1; + brelse(bh); + sb->s_dev = 0; + free_super(sb); + } + + struct super_block * + xenix_read_super(struct super_block * sb, void * data) + { + struct buffer_head * bh; + struct xenix_super_block * xsb; + int dev = sb->s_dev; + + lock_super(sb); + if (!(bh = bread(dev, 1, BLOCK_SIZE))) { + sb->s_dev = 0; + free_super(sb); + printk("xenix_read_super: bread failed\n"); + return(NULL); + } + sb->s_blocksize = 1024; + sb->s_xenix_bh = bh; + sb->s_xenix_xsb = xsb = (struct xenix_super_block *) bh->b_data; + #if 0 + hex_dump(xsb, 1024); + printk("xsb: 0x%x, &xs_magic: 0x%x\n", xsb, &xsb->xs_magic); + #endif + if (xsb->xs_magic != XENIX_SB_MAGIC) { + sb->s_dev = 0; + brelse(bh); + free_super(sb); + printk("xenix_read_super: magic match failed\n"); + return(NULL); + } + sb->s_magic = xsb->xs_magic; + /* + * are kept in the main super_block + * struct because they are constant, and suffers from + * being wrongly aligned. + */ + sb->s_xenix_isize = xsb->xs_isize; + #ifdef XENIX_GOT_PACK_2 + sb->s_xenix_fsize = xsb->xs_fsize; + #else + sb->s_xenix_fsize = *(daddr_t *) xsb->xs_fsize; + #endif + /* set up enough so that it can read an inode */ + sb->s_dev = dev; + sb->s_op = &xenix_sops; + free_super(sb); + if (!(sb->s_mounted = iget(dev, XENIX_ROOT_INO))) { + sb->s_dev = 0; + brelse(bh); + printk("xenix_read_super: get root inode failed\n"); + return(NULL); + } + /* is freed when the disk is unmounted */ + return(sb); + } + + void + xenix_statfs(struct super_block * sb, struct statfs * buf) + { + long tmp; + + put_fs_long(XENIX_SB_MAGIC, &buf->f_type); + put_fs_long(1024, &buf->f_bsize); + put_fs_long(sb->s_xenix_fsize - sb->s_xenix_isize - 2, &buf->f_blocks); + tmp = xenix_count_free_blocks(sb); + put_fs_long(tmp, &buf->f_bfree); + put_fs_long(tmp, &buf->f_bavail); + put_fs_long(sb->s_xenix_isize * XENIX_INODES_PER_BLOCK, &buf->f_files); + put_fs_long(xenix_count_free_inodes(sb), &buf->f_ffree); + /* Don't know what value to put in buf->f_fsid */ + } + + static int + _xenix_bmap(struct inode * inode, int block, int create) + { + struct buffer_head * bh; + int i; + + /* sizeof() cast to int: see truncate.c */ + #define BLOCKS_PER_BLOCK (BLOCK_SIZE / (int) sizeof(daddr_t)) + + if (block < 0) { + printk("_xenix_bmap: block<0\n"); + return(0); + } + if (block >= 10 + BLOCKS_PER_BLOCK + BLOCKS_PER_BLOCK * BLOCKS_PER_BLOCK) { + printk("_xenix_bmap: block>big\n"); + return(0); + } + if (block < 10) { + if (create && !inode->i_data[block]) + if (inode->i_data[block] = xenix_new_block(inode->i_dev)) { + inode->i_ctime = CURRENT_TIME; + inode->i_dirt = 1; + } + return(inode->i_data[block]); + } + + block -= 10; + if (block < BLOCKS_PER_BLOCK) { + if (create && !inode->i_data[10]) + if (inode->i_data[10] = xenix_new_block(inode->i_dev)) { + inode->i_dirt = 1; + inode->i_ctime = CURRENT_TIME; + } + if (!inode->i_data[10]) + return(0); + if (!(bh = bread(inode->i_dev, inode->i_data[10], BLOCK_SIZE))) + return(0); + i = ((daddr_t *) (bh->b_data))[block]; + if (create && !i) + if (i = xenix_new_block(inode->i_dev)) { + ((daddr_t *) (bh->b_data))[block] = i; + bh->b_dirt = 1; + } + brelse(bh); + return(i); + } + block -= BLOCKS_PER_BLOCK; + if (create && !inode->i_data[11]) + if (inode->i_data[11] = xenix_new_block(inode->i_dev)) { + inode->i_dirt = 1; + inode->i_ctime = CURRENT_TIME; + } + if (!inode->i_data[11]) + return(0); + if (!(bh = bread(inode->i_dev, inode->i_data[11], BLOCK_SIZE))) + return(0); + i = ((daddr_t *) bh->b_data)[block >> 8]; /* 8: log2(BLOCKS_PER_BLOCK) */ + if (create && !i) + if (i = xenix_new_block(inode->i_dev)) { + ((daddr_t *) (bh->b_data))[block >> 8] = i; + bh->b_dirt = 1; + } + brelse(bh); + if (!i) + return(0); + if (!(bh = bread(inode->i_dev, i, BLOCK_SIZE))) + return(0); + i = ((daddr_t *) bh->b_data)[block & 255]; + if (create && !i) + if (i = xenix_new_block(inode->i_dev)) { + ((daddr_t *) (bh->b_data))[block & 255] = i; + bh->b_dirt = 1; + } + brelse(bh); + return(i); + } + + #undef BLOCKS_PER_BLOCK + + int + xenix_bmap(struct inode * inode, int block) + { + return(_xenix_bmap(inode, block, 0)); + } + + int + xenix_create_block(struct inode * inode, int block) + { + return(_xenix_bmap(inode, block, 1)); + } + + void + xenix_read_inode(struct inode * inode) + { + struct buffer_head * bh; + struct xenix_inode * raw_inode; + int block; + + DEBUGPK(xenix_inodes, ("xenix_read_inode: dev 0x%x, inode %d\n", + inode->i_dev, inode->i_ino)); + + block = 2 + (inode->i_ino - 1) / XENIX_INODES_PER_BLOCK; + if (!(bh = bread(inode->i_dev, block, BLOCK_SIZE))) + panic("xenix_read_inode: unable to read i-node block"); + raw_inode = ((struct xenix_inode *) bh->b_data) + + (inode->i_ino - 1) % XENIX_INODES_PER_BLOCK; + inode->i_mode = raw_inode->i_mode; + inode->i_uid = raw_inode->i_uid; + inode->i_gid = raw_inode->i_gid; + inode->i_nlink = raw_inode->i_nlink; + inode->i_size = raw_inode->i_size; + inode->i_ctime = raw_inode->i_ctime; + inode->i_mtime = raw_inode->i_mtime; + inode->i_atime = raw_inode->i_atime; + if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) + inode->i_rdev = read3byte(raw_inode->i_addr, 0); + else for (block = 0; block < 13; block++) + inode->i_data[block] = read3byte(raw_inode->i_addr, block); + brelse(bh); + inode->i_op = NULL; + if (S_ISREG(inode->i_mode)) + inode->i_op = &xenix_file_inode_operations; + else if (S_ISDIR(inode->i_mode)) + inode->i_op = &xenix_dir_inode_operations; + else if (S_ISLNK(inode->i_mode)) + inode->i_op = &xenix_symlink_inode_operations; + else if (S_ISCHR(inode->i_mode)) + inode->i_op = &xenix_chrdev_inode_operations; + else if (S_ISBLK(inode->i_mode)) + inode->i_op = &xenix_blkdev_inode_operations; + else if (S_ISFIFO(inode->i_mode)) { + inode->i_op = &xenix_fifo_inode_operations; + inode->i_size = 0; + inode->i_pipe = 1; + PIPE_HEAD(*inode) = PIPE_TAIL(*inode) = 0; + PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 0; + } + } + + void + xenix_write_inode(struct inode * inode) + { + struct buffer_head * bh; + struct xenix_inode * raw_inode; + int block; + + DEBUGPK(xenix_inodes, ("xenix_write_inode: dev 0x%x, inode %d\n", + inode->i_dev, inode->i_ino)); + + block = 2 + (inode->i_ino - 1) / XENIX_INODES_PER_BLOCK; + if (!(bh = bread(inode->i_dev, block, BLOCK_SIZE))) + panic("xenix_write_inode: unable to read i-node block"); + raw_inode = ((struct xenix_inode *) bh->b_data) + + (inode->i_ino - 1) % XENIX_INODES_PER_BLOCK; + raw_inode->i_mode = inode->i_mode; + raw_inode->i_uid = inode->i_uid; + raw_inode->i_gid = inode->i_gid; + raw_inode->i_nlink = inode->i_nlink; + raw_inode->i_size = inode->i_size; + raw_inode->i_ctime = inode->i_ctime; + raw_inode->i_mtime = inode->i_mtime; + raw_inode->i_atime = inode->i_atime; + if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) + write3byte(raw_inode->i_addr, 0, inode->i_rdev); + else for (block = 0; block < 13; block++) + write3byte(raw_inode->i_addr, block, inode->i_data[block]); + bh->b_dirt = 1; + inode->i_dirt = 0; + brelse(bh); + } *** linux.pl1/fs/xenix/namei.c Wed Aug 12 15:09:57 1992 --- linux/fs/xenix/namei.c Fri Aug 7 15:26:17 1992 *************** *** 0 **** --- 1,798 ---- + /* + * linux/fs/xenix/namei.c + * + * (C) 1991 Linus Torvalds + * + * Taken from minix/namei.c, modified by Doug Evans, dje@sspiff.UUCP, 92Jun04. + * + * This file contains code for looking up entries in directories. + */ + + #include + #include + #include + #include + #include + #include + #include + #include + + #include + + #include + + /* + * comment out this line if you want names > XENIX_NAME_LEN chars to be + * truncated. Else they will be disallowed. + */ + /* #define NO_TRUNCATE */ + + /* + * ok, we cannot use strncmp, as the name is not in our data space. + * Thus we'll have to use xenix_match. No big problem. Match also makes + * some sanity tests. + * + * NOTE! unlike strncmp, xenix_match returns 1 for success, 0 for failure. + */ + + static int + xenix_match(int len, const char * name, struct xenix_dir_entry * de) + { + register int same __asm__("ax"); + + if (!de || !de->inode || len > XENIX_NAME_LEN) + return 0; + /* "" means "." ---> so paths like "/usr/lib//libc.a" work */ + /* FIXME: Do I want them to work? */ + if (!len && de->name[0] == '.' && de->name[1] == '\0') + return 1; + if (len < XENIX_NAME_LEN && de->name[len]) + return 0; + __asm__("cld\n\t" + "fs ; repe ; cmpsb\n\t" + "setz %%al" + :"=a" (same) + :"0" (0),"S" ((long) name),"D" ((long) de->name),"c" (len) + :"cx","di","si"); + return same; + } + + /* + * xenix_find_entry() + * + * finds an entry in the specified directory with the wanted name. It + * returns the cache buffer in which the entry was found, and the entry + * itself (as a parameter - res_dir). It does NOT read the inode of the + * entry - you'll have to do that yourself if you want to. + */ + + static struct buffer_head * + xenix_find_entry(struct inode * dir, const char * name, int namelen, + struct xenix_dir_entry ** res_dir) + { + int entries; + int block,i; + struct buffer_head * bh; + struct xenix_dir_entry * de; + + *res_dir = NULL; + if (!dir) + return(NULL); + #ifdef NO_TRUNCATE + if (namelen > XENIX_NAME_LEN) + return(NULL); + #else + if (namelen > XENIX_NAME_LEN) + namelen = XENIX_NAME_LEN; + #endif + entries = dir->i_size / (sizeof (struct xenix_dir_entry)); + if (!(block = dir->i_data[0])) + return(NULL); + if (!(bh = bread(dir->i_dev, block, BLOCK_SIZE))) + return(NULL); + i = 0; + de = (struct xenix_dir_entry *) bh->b_data; + while (i < entries) { + if ((char *) de >= BLOCK_SIZE + bh->b_data) { + brelse(bh); + bh = NULL; + if (!(block = xenix_bmap(dir, i / XENIX_DIR_ENTRIES_PER_BLOCK)) || + !(bh = bread(dir->i_dev, block, BLOCK_SIZE))) { + i += XENIX_DIR_ENTRIES_PER_BLOCK; + continue; /* FIXME: printk error msg? */ + } + de = (struct xenix_dir_entry *) bh->b_data; + } + if (xenix_match(namelen, name, de)) { + *res_dir = de; + return(bh); + } + de++; + i++; + } + brelse(bh); + return(NULL); + } + + int + xenix_lookup(struct inode * dir, const char * name, int len, + struct inode ** result) + { + int ino; + struct xenix_dir_entry * de; + struct buffer_head * bh; + + *result = NULL; + if (!dir) + return(-ENOENT); + if (!S_ISDIR(dir->i_mode)) { + iput(dir); + return(-ENOENT); + } + if (!(bh = xenix_find_entry(dir, name, len, &de))) { + iput(dir); + return(-ENOENT); + } + ino = de->inode; + brelse(bh); + if (!(*result = iget(dir->i_dev, ino))) { + iput(dir); + return(-EACCES); + } + iput(dir); + return(0); + } + + /* + * xenix_add_entry() + * + * adds a file entry to the specified directory, using the same + * semantics as xenix_find_entry(). It returns NULL if it failed. + * + * NOTE!! The inode part of 'de' is left at 0 - which means you + * may not sleep between calling this and putting something into + * the entry, as someone else might have used it while you slept. + */ + + static struct buffer_head * + xenix_add_entry(struct inode * dir, const char * name, int namelen, + struct xenix_dir_entry ** res_dir) + { + int block,i; + struct buffer_head * bh; + struct xenix_dir_entry * de; + + *res_dir = NULL; + if (!dir) + return(NULL); + #ifdef NO_TRUNCATE + if (namelen > XENIX_NAME_LEN) + return(NULL); + #else + if (namelen > XENIX_NAME_LEN) + namelen = XENIX_NAME_LEN; + #endif + if (!namelen) + return(NULL); + if (!(block = dir->i_data[0])) + return(NULL); + if (!(bh = bread(dir->i_dev, block, BLOCK_SIZE))) + return(NULL); + i = 0; + de = (struct xenix_dir_entry *) bh->b_data; + while (1) { + if ((char *) de >= BLOCK_SIZE + bh->b_data) { + brelse(bh); + bh = NULL; + block = xenix_create_block(dir, i / XENIX_DIR_ENTRIES_PER_BLOCK); + if (!block) + return(NULL); + if (!(bh = bread(dir->i_dev, block, BLOCK_SIZE))) { + i += XENIX_DIR_ENTRIES_PER_BLOCK; + continue; + /* FIXME: That's it? What about ? */ + } + de = (struct xenix_dir_entry *) bh->b_data; + } + if (i * sizeof(struct xenix_dir_entry) >= dir->i_size) { + de->inode = 0; + dir->i_size = (i + 1) * sizeof(struct xenix_dir_entry); + dir->i_dirt = 1; + dir->i_ctime = CURRENT_TIME; + } + if (!de->inode) { + dir->i_mtime = CURRENT_TIME; + for (i = 0; i < XENIX_NAME_LEN ; i++) + de->name[i] = (i < namelen) ? + get_fs_byte(name + i) : 0; + bh->b_dirt = 1; + *res_dir = de; + return(bh); + } + de++; + i++; + } + brelse(bh); + return(NULL); + } + + int + xenix_create(struct inode * dir, const char * name, int len, int mode, + struct inode ** result) + { + struct inode * inode; + struct buffer_head * bh; + struct xenix_dir_entry * de; + + *result = NULL; + if (!dir) + return(-ENOENT); + inode = xenix_new_inode(dir->i_dev); + if (!inode) { + iput(dir); + return(-ENOSPC); + } + inode->i_op = &xenix_file_inode_operations; + inode->i_mode = mode; + inode->i_dirt = 1; + bh = xenix_add_entry(dir, name, len, &de); + if (!bh) { + inode->i_nlink--; + inode->i_dirt = 1; + iput(inode); + iput(dir); + return(-ENOSPC); + } + de->inode = inode->i_ino; + bh->b_dirt = 1; + brelse(bh); + iput(dir); + *result = inode; + return(0); + } + + int + xenix_mknod(struct inode * dir, const char * name, int len, int mode, int rdev) + { + struct inode * inode; + struct buffer_head * bh; + struct xenix_dir_entry * de; + + if (!dir) + return(-ENOENT); + bh = xenix_find_entry(dir, name, len, &de); + if (bh) { + brelse(bh); + iput(dir); + return(-EEXIST); + } + inode = xenix_new_inode(dir->i_dev); + if (!inode) { + iput(dir); + return(-ENOSPC); + } + inode->i_uid = current->euid; + inode->i_mode = mode; + inode->i_op = NULL; + if (S_ISREG(inode->i_mode)) + inode->i_op = &xenix_file_inode_operations; + else if (S_ISDIR(inode->i_mode)) + inode->i_op = &xenix_dir_inode_operations; + else if (S_ISLNK(inode->i_mode)) + inode->i_op = &xenix_symlink_inode_operations; + else if (S_ISCHR(inode->i_mode)) + inode->i_op = &xenix_chrdev_inode_operations; + else if (S_ISBLK(inode->i_mode)) + inode->i_op = &xenix_blkdev_inode_operations; + else if (S_ISFIFO(inode->i_mode)) { + inode->i_op = &xenix_fifo_inode_operations; + inode->i_size = 0; + inode->i_pipe = 1; + PIPE_HEAD(*inode) = PIPE_TAIL(*inode) = 0; + PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 0; + } + if (S_ISBLK(mode) || S_ISCHR(mode)) + inode->i_rdev = rdev; + inode->i_mtime = inode->i_atime = CURRENT_TIME; + inode->i_dirt = 1; + bh = xenix_add_entry(dir, name, len, &de); + if (!bh) { + inode->i_nlink--; + inode->i_dirt = 1; + iput(inode); + iput(dir); + return(-ENOSPC); + } + de->inode = inode->i_ino; + bh->b_dirt = 1; + brelse(bh); + iput(dir); + iput(inode); + return(0); + } + + int + xenix_mkdir(struct inode * dir, const char * name, int len, int mode) + { + struct inode * inode; + struct buffer_head * bh, * dir_block; + struct xenix_dir_entry * de; + + bh = xenix_find_entry(dir, name, len, &de); + if (bh) { + brelse(bh); + iput(dir); + return(-EEXIST); + } + inode = xenix_new_inode(dir->i_dev); + if (!inode) { + iput(dir); + return(-ENOSPC); + } + inode->i_op = &xenix_dir_inode_operations; + inode->i_size = 2 * sizeof (struct xenix_dir_entry); + if (!(inode->i_data[0] = xenix_new_block(inode->i_dev))) { + iput(dir); + inode->i_nlink--; + inode->i_dirt = 1; + iput(inode); + return(-ENOSPC); + } + inode->i_dirt = 1; + if (!(dir_block = bread(inode->i_dev, inode->i_data[0], BLOCK_SIZE))) { + iput(dir); + inode->i_nlink--; + inode->i_dirt = 1; + iput(inode); + return(-EIO); + } + de = (struct xenix_dir_entry *) dir_block->b_data; + de->inode = inode->i_ino; + strcpy(de->name, "."); + de++; + de->inode = dir->i_ino; + strcpy(de->name, ".."); + inode->i_nlink = 2; + dir_block->b_dirt = 1; + brelse(dir_block); + inode->i_mode = I_DIRECTORY | (mode & 0777 & ~current->umask); + inode->i_dirt = 1; + bh = xenix_add_entry(dir, name, len, &de); + if (!bh) { + iput(dir); + inode->i_nlink = 0; + iput(inode); + return(-ENOSPC); + } + de->inode = inode->i_ino; + bh->b_dirt = 1; + dir->i_nlink++; + dir->i_dirt = 1; + iput(dir); + iput(inode); + brelse(bh); + return(0); + } + + /* + * routine to check that the specified directory is empty (for rmdir) + */ + + static int + empty_dir(struct inode * inode) + { + int nr,block,len; + struct buffer_head * bh; + struct xenix_dir_entry * de; + + len = inode->i_size / sizeof (struct xenix_dir_entry); + if (len < 2 || !inode->i_data[0] || + !(bh = bread(inode->i_dev,inode->i_data[0], BLOCK_SIZE))) { + printk("xenix.empty_dir: warning - bad directory on dev %04x\n", inode->i_dev); + return 0; + } + de = (struct xenix_dir_entry *) bh->b_data; + if (de[0].inode != inode->i_ino || !de[1].inode || + strcmp(".", de[0].name) || strcmp("..", de[1].name)) { + printk("xenix.empty_dir: warning - bad directory on dev %04x\n", inode->i_dev); + return 0; + } + nr = 2; + de += 2; + while (nr < len) { + if ((void *) de >= (void *) (bh->b_data + BLOCK_SIZE)) { + brelse(bh); + block = xenix_bmap(inode, nr / XENIX_DIR_ENTRIES_PER_BLOCK); + if (!block) { + nr += XENIX_DIR_ENTRIES_PER_BLOCK; + continue; + } + if (!(bh = bread(inode->i_dev, block, BLOCK_SIZE))) + return(0); + de = (struct xenix_dir_entry *) bh->b_data; + } + if (de->inode) { + brelse(bh); + return(0); + } + de++; + nr++; + } + brelse(bh); + return(1); + } + + int + xenix_rmdir(struct inode * dir, const char * name, int len) + { + int retval; + struct inode * inode; + struct buffer_head * bh; + struct xenix_dir_entry * de; + + inode = NULL; + bh = xenix_find_entry(dir, name, len, &de); + retval = -ENOENT; + if (!bh) + goto end_rmdir; + retval = -EPERM; + if (!(inode = iget(dir->i_dev, de->inode))) + goto end_rmdir; + if ((dir->i_mode & S_ISVTX) && current->euid && + inode->i_uid != current->euid) + goto end_rmdir; + if (inode->i_dev != dir->i_dev) + goto end_rmdir; + if (inode == dir) /* we may not delete ".", but "../dir" is ok */ + goto end_rmdir; + if (!S_ISDIR(inode->i_mode)) { + retval = -ENOTDIR; + goto end_rmdir; + } + if (!empty_dir(inode)) { + retval = -ENOTEMPTY; + goto end_rmdir; + } + if (inode->i_count > 1) { + retval = -EBUSY; + goto end_rmdir; + } + if (inode->i_nlink != 2) + printk("xenix_rmdir: empty directory has nlink!=2 (%d)\n", inode->i_nlink); + de->inode = 0; + bh->b_dirt = 1; + inode->i_nlink = 0; + inode->i_dirt = 1; + dir->i_nlink--; + dir->i_ctime = dir->i_mtime = CURRENT_TIME; + dir->i_dirt = 1; + retval = 0; + end_rmdir: + iput(dir); + iput(inode); + brelse(bh); + return(retval); + } + + int + xenix_unlink(struct inode * dir, const char * name, int len) + { + int retval; + struct inode * inode; + struct buffer_head * bh; + struct xenix_dir_entry * de; + + retval = -ENOENT; + inode = NULL; + bh = xenix_find_entry(dir, name, len, &de); + if (!bh) + goto end_unlink; + if (!(inode = iget(dir->i_dev, de->inode))) + goto end_unlink; + retval = -EPERM; + if ((dir->i_mode & S_ISVTX) && !suser() && + current->euid != inode->i_uid && + current->euid != dir->i_uid) + goto end_unlink; + if (S_ISDIR(inode->i_mode)) + goto end_unlink; + if (!inode->i_nlink) { + printk("xenix_unlink: deleting nonexistent file (%04x:%d), %d\n", + inode->i_dev, inode->i_ino, inode->i_nlink); + inode->i_nlink = 1; + } + de->inode = 0; + bh->b_dirt = 1; + inode->i_nlink--; + inode->i_dirt = 1; + inode->i_ctime = CURRENT_TIME; + retval = 0; + end_unlink: + brelse(bh); + iput(inode); + iput(dir); + return(retval); + } + + int + xenix_symlink(struct inode * dir, const char * name, int len, const char * symname) + { + #if 1 + return(-ENOSYS); /* FIXME: for now */ + #else + struct xenix_dir_entry * de; + struct inode * inode = NULL; + struct buffer_head * bh = NULL, * name_block = NULL; + int i; + char c; + + if (!(inode = xenix_new_inode(dir->i_dev))) { + iput(dir); + return(-ENOSPC); + } + inode->i_mode = S_IFLNK | 0777; + inode->i_op = &xenix_symlink_inode_operations; + if (!(inode->i_data[0] = xenix_new_block(inode->i_dev))) { + iput(dir); + inode->i_nlink--; + inode->i_dirt = 1; + iput(inode); + return(-ENOSPC); + } + inode->i_dirt = 1; + if (!(name_block = bread(inode->i_dev, inode->i_data[0], BLOCK_SIZE))) { + iput(dir); + inode->i_nlink--; + inode->i_dirt = 1; + iput(inode); + return(-EIO); + } + i = 0; + while (i < 1023 && (c = get_fs_byte(symname++))) + name_block->b_data[i++] = c; + name_block->b_data[i] = 0; + name_block->b_dirt = 1; + brelse(name_block); + inode->i_size = i; + inode->i_dirt = 1; + bh = xenix_find_entry(dir, name, len, &de); + if (bh) { + inode->i_nlink--; + inode->i_dirt = 1; + iput(inode); + brelse(bh); + iput(dir); + return(-EEXIST); + } + bh = xenix_add_entry(dir, name, len, &de); + if (!bh) { + inode->i_nlink--; + inode->i_dirt = 1; + iput(inode); + iput(dir); + return(-ENOSPC); + } + de->inode = inode->i_ino; + bh->b_dirt = 1; + brelse(bh); + iput(dir); + iput(inode); + return(0); + #endif + } + + int + xenix_link(struct inode * oldinode, struct inode * dir, const char * name, int len) + { + struct xenix_dir_entry * de; + struct buffer_head * bh; + + if (S_ISDIR(oldinode->i_mode)) { + iput(oldinode); + iput(dir); + return(-EPERM); + } + bh = xenix_find_entry(dir,name,len,&de); + if (bh) { + brelse(bh); + iput(dir); + iput(oldinode); + return(-EEXIST); + } + bh = xenix_add_entry(dir,name,len,&de); + if (!bh) { + iput(dir); + iput(oldinode); + return(-ENOSPC); + } + de->inode = oldinode->i_ino; + bh->b_dirt = 1; + brelse(bh); + iput(dir); + oldinode->i_nlink++; + oldinode->i_ctime = CURRENT_TIME; + oldinode->i_dirt = 1; + iput(oldinode); + return(0); + } + + static int + subdir(struct inode * new, struct inode * old) + { + unsigned short fs; + int ino; + int result; + + __asm__("mov %%fs,%0":"=r" (fs)); + __asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10)); + new->i_count++; + result = 0; + for (;;) { + if (new == old) { + result = 1; + break; + } + if (new->i_dev != old->i_dev) + break; + ino = new->i_ino; + if (xenix_lookup(new, "..", 2, &new)) + break; + if (new->i_ino == ino) + break; + } + iput(new); + __asm__("mov %0,%%fs"::"r" (fs)); + return(result); + } + + #define PARENT_INO(buffer) \ + (((struct xenix_dir_entry *) (buffer))[1].inode) + + #define PARENT_NAME(buffer) \ + (((struct xenix_dir_entry *) (buffer))[1].name) + + /* + * rename uses retrying to avoid race-conditions: at least they should be minimal. + * it tries to allocate all the blocks, then sanity-checks, and if the sanity- + * checks fail, it tries to restart itself again. Very practical - no changes + * are done until we know everything works ok.. and then all the changes can be + * done in one fell swoop when we have claimed all the buffers needed. + * + * Anybody can rename anything with this: the permission checks are left to the + * higher-level routines. + */ + + static int + do_xenix_rename(struct inode * old_dir, const char * old_name, int old_len, + struct inode * new_dir, const char * new_name, int new_len) + { + struct inode * old_inode, * new_inode; + struct buffer_head * old_bh, * new_bh, * dir_bh; + struct xenix_dir_entry * old_de, * new_de; + int retval; + + goto start_up; + try_again: + brelse(old_bh); + brelse(new_bh); + brelse(dir_bh); + iput(old_inode); + iput(new_inode); + current->counter = 0; + schedule(); + start_up: + old_inode = new_inode = NULL; + old_bh = new_bh = dir_bh = NULL; + old_bh = xenix_find_entry(old_dir, old_name, old_len, &old_de); + retval = -ENOENT; + if (!old_bh) + goto end_rename; + old_inode = iget(old_dir->i_dev, old_de->inode); + if (!old_inode) + goto end_rename; + if ((old_dir->i_mode & S_ISVTX) && + current->euid != old_inode->i_uid && + current->euid != old_dir->i_uid && !suser()) + goto end_rename; + new_bh = xenix_find_entry(new_dir, new_name, new_len, &new_de); + if (new_bh) { + new_inode = iget(new_dir->i_dev, new_de->inode); + if (!new_inode) { + brelse(new_bh); + new_bh = NULL; + } + } + if (new_inode == old_inode) { + retval = 0; + goto end_rename; + } + if (S_ISDIR(new_inode->i_mode)) { + retval = -EEXIST; + goto end_rename; + } + if (S_ISDIR(old_inode->i_mode)) { + retval = -EEXIST; + if (new_bh) + goto end_rename; + retval = -EACCES; + if (!permission(old_inode, MAY_WRITE)) + goto end_rename; + retval = -EINVAL; + if (subdir(new_dir, old_inode)) + goto end_rename; + retval = -EIO; + if (!old_inode->i_data[0]) + goto end_rename; + if (!(dir_bh = bread(old_inode->i_dev, old_inode->i_data[0], BLOCK_SIZE))) + goto end_rename; + if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino) + goto end_rename; + } + if (!new_bh) + new_bh = xenix_add_entry(new_dir, new_name, new_len, &new_de); + retval = -ENOSPC; + if (!new_bh) + goto end_rename; + /* sanity checking before doing the rename - avoid races */ + if (new_inode && (new_de->inode != new_inode->i_ino)) + goto try_again; + if (new_de->inode && !new_inode) + goto try_again; + if (old_de->inode != old_inode->i_ino) + goto try_again; + /* ok, that's it */ + old_de->inode = 0; + new_de->inode = old_inode->i_ino; + if (new_inode) { + new_inode->i_nlink--; + new_inode->i_dirt = 1; + } + old_bh->b_dirt = 1; + new_bh->b_dirt = 1; + if (dir_bh) { + PARENT_INO(dir_bh->b_data) = new_dir->i_ino; + dir_bh->b_dirt = 1; + old_dir->i_nlink--; + new_dir->i_nlink++; + old_dir->i_dirt = 1; + new_dir->i_dirt = 1; + } + retval = 0; + end_rename: + brelse(dir_bh); + brelse(old_bh); + brelse(new_bh); + iput(old_inode); + iput(new_inode); + iput(old_dir); + iput(new_dir); + return(retval); + } + + /* + * Ok, rename also locks out other renames, as they can change the parent of + * a directory, and we don't want any races. Other races are checked for by + * "do_rename()", which restarts if there are inconsistencies. + * + * Note that there is no race between different filesystems: it's only within + * the same device that races occur: many renames can happen at once, as long + * as they are on different partitions. + */ + + int + xenix_rename(struct inode * old_dir, const char * old_name, int old_len, + struct inode * new_dir, const char * new_name, int new_len) + { + static struct wait_queue * wait = NULL; + static int lock = 0; + int result; + + while (lock) + sleep_on(&wait); + lock = 1; + result = do_xenix_rename(old_dir, old_name, old_len, + new_dir, new_name, new_len); + lock = 0; + wake_up(&wait); + return(result); + } *** linux.pl1/fs/xenix/symlink.c Wed Aug 12 15:09:57 1992 --- linux/fs/xenix/symlink.c Fri Aug 7 15:27:23 1992 *************** *** 0 **** --- 1,107 ---- + /* + * linux/fs/xenix/symlink.c + * + * (C) 1991 Linus Torvalds + * + * Taken from minix/symlink.c, modified by Doug Evans, dje@sspiff.UUCP, 92Jun04. + * + * This file contains xenix symlink handling code. While xenix filesystems + * don't support symbolic links, one can make a non-upward compatible extension + * and add them if one wants to. + */ + + #include + + #include + #include + #include + #include + #include + + static int xenix_readlink(struct inode *, char *, int); + static struct inode * xenix_follow_link(struct inode *, struct inode *); + + /* + * symlinks can't do much... + */ + + struct inode_operations xenix_symlink_inode_operations = { + NULL, /* no file-operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + xenix_readlink, /* readlink */ + xenix_follow_link, /* follow_link */ + NULL, /* bmap */ + NULL /* truncate */ + }; + + static struct inode * + xenix_follow_link(struct inode * dir, struct inode * inode) + { + unsigned short fs; + struct buffer_head * bh; + + if (!dir) { + dir = current->root; + dir->i_count++; + } + if (!inode) { + iput(dir); + return(NULL); + } + if (!S_ISLNK(inode->i_mode)) { + iput(dir); + return(inode); + } + __asm__("mov %%fs,%0":"=r" (fs)); + if ((current->link_count > 5) || !inode->i_data[0] || + !(bh = bread(inode->i_dev, inode->i_data[0], BLOCK_SIZE))) { + iput(dir); + iput(inode); + return(NULL); + } + iput(inode); + __asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10)); + current->link_count++; + inode = _namei(bh->b_data, dir, 1); + current->link_count--; + __asm__("mov %0,%%fs"::"r" (fs)); + brelse(bh); + return(inode); + } + + static int + xenix_readlink(struct inode * inode, char * buffer, int buflen) + { + struct buffer_head * bh; + int i; + char c; + + if (!S_ISLNK(inode->i_mode)) { + iput(inode); + return(-EINVAL); + } + if (buflen > 1023) + buflen = 1023; + if (inode->i_data[0]) + bh = bread(inode->i_dev, inode->i_data[0], BLOCK_SIZE); + else + bh = NULL; + iput(inode); + if (!bh) + return(0); + i = 0; + while (i < buflen && (c = bh->b_data[i])) { + i++; + put_fs_byte(c, buffer++); + } + brelse(bh); + return(i); + } *** linux.pl1/fs/xenix/truncate.c Wed Aug 12 15:09:57 1992 --- linux/fs/xenix/truncate.c Fri Aug 7 15:28:06 1992 *************** *** 0 **** --- 1,171 ---- + /* + * linux/fs/truncate.c + * + * (C) 1991 Linus Torvalds + * + * Taken from minix/truncate.c, modified by Doug Evans, dje@sspiff.UUCP, 92Jun04. + * + * This file contains code for truncating files. + */ + + #include + #include + #include + #include + #include + #include + #include + + /* + * The code in trunc_indirect() fails if BLOCKS_PER_BLOCK is unsigned!. + * The test in the for() loop fails when (i < 0). + */ + + #define BLOCKS_PER_BLOCK (BLOCK_SIZE / (int) sizeof(daddr_t)) + + /* + * Truncate has the most races in the whole filesystem: coding it is + * a pain in the a**. Especially as I don't do any locking... + * + * The code may look a bit weird, but that's just because I've tried to + * handle things like file-size changes in a somewhat graceful manner. + * Anyway, truncating a file at the same time somebody else writes to it + * is likely to result in pretty weird behaviour... + * + * The new code handles normal truncates (size = 0) as well as the more + * general case (size = XXX). I hope. + */ + + static int + trunc_direct(struct inode * inode) + { + int i; + int result = 0; + + #define DIRECT_BLOCK ((inode->i_size + BLOCK_SIZE - 1) >> 10) + /* FIXME: #define 10 */ + + repeat: + for (i = DIRECT_BLOCK ; i < 10 ; i++) { + if (i < DIRECT_BLOCK) + goto repeat; + if (!inode->i_data[i]) + continue; + result = 1; + if (xenix_free_block(inode->i_dev, inode->i_data[i])) + inode->i_data[i] = 0; + } + return(result); + } + + static int + trunc_indirect(struct inode * inode, int offset, daddr_t * p) + { + int i; + struct buffer_head * bh = NULL; + daddr_t * ind; + int result = 0; + + #define INDIRECT_BLOCK (DIRECT_BLOCK - offset) + + if (*p) + bh = bread(inode->i_dev, *p, BLOCK_SIZE); + if (!bh) + return(0); + repeat: + for (i = INDIRECT_BLOCK ; i < BLOCKS_PER_BLOCK ; i++) { + if (i < 0) + i = 0; + if (i < INDIRECT_BLOCK) + goto repeat; + ind = i + (daddr_t *) bh->b_data; + if (!*ind) + continue; + result = 1; + if (xenix_free_block(inode->i_dev, *ind)) + *ind = 0; + } + ind = (daddr_t *) bh->b_data; + for (i = 0; i < BLOCKS_PER_BLOCK; i++) + if (*(ind++)) + break; + brelse(bh); + if (i >= BLOCKS_PER_BLOCK) { + result = 1; + if (xenix_free_block(inode->i_dev, *p)) + *p = 0; + } + return(result); + } + + static int + trunc_dindirect(struct inode * inode) + { + int i; + struct buffer_head * bh = NULL; + daddr_t * dind; + int result = 0; + + #define DINDIRECT_BLOCK ((DIRECT_BLOCK - (BLOCKS_PER_BLOCK + 10)) >> 8) + /* 8 = log2(BLOCKS_PER_BLOCK) */ + + if (inode->i_data[11]) + bh = bread(inode->i_dev, inode->i_data[11], BLOCK_SIZE); + if (!bh) + return(0); + repeat: + for (i = DINDIRECT_BLOCK ; i < BLOCKS_PER_BLOCK ; i ++) { + if (i < 0) + i = 0; + if (i < DINDIRECT_BLOCK) + goto repeat; + dind = i + (daddr_t *) bh->b_data; + if (!*dind) + continue; + result |= trunc_indirect(inode, 10 + BLOCKS_PER_BLOCK + (i << 8), dind); + } + dind = (daddr_t *) bh->b_data; + for (i = 0; i < BLOCKS_PER_BLOCK; i++) + if (*(dind++)) + break; + brelse(bh); + if (i >= BLOCKS_PER_BLOCK) { + result = 1; + if (xenix_free_block(inode->i_dev, inode->i_data[11])) + inode->i_data[11] = 0; + } + return(result); + } + + void + xenix_truncate(struct inode * inode) + { + int flag; + + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || + S_ISLNK(inode->i_mode))) + return; + while (1) { + flag = trunc_direct(inode); + flag |= trunc_indirect(inode, 10, (daddr_t *) &inode->i_data[10]); + flag |= trunc_dindirect(inode); + if (!flag) + break; + current->counter = 0; + schedule(); + } + inode->i_mtime = inode->i_ctime = CURRENT_TIME; + inode->i_dirt = 1; + } + + /* + * Called when a inode is released. Note that this is different + * from xenix_open: open gets called at every open, but release + * gets called only when /all/ the files are closed. + */ + + void + xenix_release(struct inode * inode, struct file * filp) + { + printk("xenix_release: not implemented\n"); + } *** linux.pl1/fs/xenix/Makefile Wed Aug 12 15:09:42 1992 --- linux/fs/xenix/Makefile Fri Aug 7 19:23:43 1992 *************** *** 0 **** --- 1,32 ---- + # + # Makefile for the linux Xenix-filesystem routines. + # + # Note! Dependencies are done automagically by 'make dep', which also + # removes any old dependencies. DON'T put your own dependencies here + # unless it's something special (ie not a .c file). + # + # Note 2! The CFLAGS definitions are now in the main makefile... + + .c.s: + $(CC) $(CFLAGS) -S $< + .c.o: + $(CC) $(CFLAGS) -c $< + .s.o: + $(AS) -o $*.o $< + + OBJS= alloc.o truncate.o namei.o inode.o fifo.o \ + file.o dir.o symlink.o blkdev.o chrdev.o hexdump.o + + xenix.o: $(OBJS) + $(LD) -r -o xenix.o $(OBJS) + + clean: + rm -f core *.o *.a tmp_make + for i in *.c;do rm -f `basename $$i .c`.s;done + + dep: + sed '/\#\#\# Dependencies/q' < Makefile > tmp_make + for i in *.c;do $(CPP) -M $$i;done >> tmp_make + cp tmp_make Makefile + + ### Dependencies: *** linux.pl1/include/linux/fs.h Tue Aug 18 12:52:34 1992 --- linux/include/linux/fs.h Mon Aug 17 13:25:10 1992 *************** *** 149,157 **** --- 150,169 ---- off_t f_pos; }; + struct file_lock { + struct file_lock *fl_next; /* singly linked list */ + struct task_struct *fl_owner; /* NULL if on free list, for sanity checks */ + struct wait_queue *fl_wait; + char fl_type; + char fl_whence; + off_t fl_start; + off_t fl_end; + }; + #include #include #include + #include struct super_block { unsigned short s_dev; *************** *** 170,175 **** --- 182,188 ---- struct minix_sb_info minix_sb; struct ext_sb_info ext_sb; struct msdos_sb_info msdos_sb; + struct xenix_sb_info xenix_sb; } u; }; *** linux.pl1/include/linux/xenix_fs.h Tue Aug 18 13:03:21 1992 --- linux/include/linux/xenix_fs.h Mon Aug 17 13:40:36 1992 *************** *** 0 **** --- 1,171 ---- + /* + * The Xenix filesystem constants/structures + */ + + #ifndef _LINUX_XENIX_FS_H + #define _LINUX_XENIX_FS_H + + #include + typedef unsigned short short_ino_t; + + #define XENIX_NAME_LEN 14 + #define XENIX_ROOT_INO 2 + + #define XENIX_SB_NICINOD 100 /* number of superblock inodes */ + #define XENIX_SB_NICFREE 100 /* number of superblock free blocks */ + #define XENIX_SB_FILL 371 /* aligns s_magic at end of super block */ + #define XENIX_SB_CLEAN 0106 /* s_clean, arbitrary magic value */ + #define XENIX_SB_MAGIC 0x2b5544 /* s_magic, system 3 arbitrary magic value */ + #define XENIX_SB_B512 1 /* s_type, 512 byte block */ + #define XENIX_SB_B1024 2 /* s_type, 1024 byte block */ + + #define XENIX_INODES_PER_BLOCK ((BLOCK_SIZE) / (sizeof (struct xenix_inode))) + #define XENIX_DIR_ENTRIES_PER_BLOCK ((BLOCK_SIZE) / (sizeof (struct xenix_dir_entry))) + + struct xenix_inode { + umode_t i_mode; /* mode and type of file */ + nlink_t i_nlink; /* number of links to file */ + uid_t i_uid; /* owner's user id */ + gid_t i_gid; /* owner's group id */ + off_t i_size; /* number of bytes in file */ + char i_addr[40]; /* disk block addresses */ + time_t i_atime; /* time last accessed */ + time_t i_mtime; /* time last modified */ + time_t i_ctime; /* time created */ + }; + + /* + * the 40 address bytes: 39 used; 13 addresses of 3 bytes each. + */ + + #pragma pack(2) /* FIXME: what is gcc's version of this? */ + + struct xenix_super_block { + unsigned short xs_isize;/* size in blocks of i-list */ + #ifdef XENIX_GOT_PACK_2 + daddr_t xs_fsize; /* size in blocks of entire volume */ + #else + char xs_fsize[sizeof(daddr_t)]; + #endif + unsigned short xs_nfree; /* number of addresses in xs_free */ + #ifdef XENIX_GOT_PACK_2 + daddr_t xs_free[XENIX_SB_NICFREE]; /* free block list */ + #else + char xs_free[XENIX_SB_NICFREE * sizeof(daddr_t)]; + #endif + unsigned short xs_ninode; /* number of i-nodes in xs_inode */ + short_ino_t xs_inode[XENIX_SB_NICINOD]; /* free i-node list */ + char xs_flock; /* lock during free list manipulation */ + char xs_ilock; /* lock during i-list manipulation */ + char xs_fmod; /* super block modified flag */ + char xs_ronly; /* mounted read-only flag */ + #ifdef XENIX_GOT_PACK_2 + time_t xs_time; /* last super block update */ + daddr_t xs_tfree; /* total free blocks */ + #else + char xs_time[sizeof(time_t)]; + char xs_tfree[sizeof(daddr_t)]; + #endif + short_ino_t xs_tinode; /* total free inodes */ + short xs_dinfo[4]; /* device information */ + char xs_fname[6]; /* file system name */ + char xs_fpack[6]; /* file system pack name */ + /* remainder is maintained for xenix */ + char xs_clean; /* S_CLEAN if structure is properly closed */ + char xs_fill[XENIX_SB_FILL];/* space to make sizeof filsys be BSIZE */ + long xs_magic; /* indicates version of filsys */ + long xs_type; /* type of new file system */ + }; + + #pragma pack() + + struct xenix_dir_entry { + short_ino_t inode; + char name[XENIX_NAME_LEN]; + }; + + struct xenix_free_block { + unsigned short xfb_nfree; + #ifdef XENIX_GOT_PACK_2 + daddr_t xfb_free[XENIX_SB_NICFREE]; + #else + char xfb_free[XENIX_SB_NICFREE * sizeof(daddr_t)]; + #endif + }; + + /* + * Simplifies porting ... + * See . + */ + + #define s_xenix_bh u.xenix_sb.s_bh + #define s_xenix_xsb u.xenix_sb.s_xsb + #define s_xenix_isize u.xenix_sb.s_isize + #define s_xenix_fsize u.xenix_sb.s_fsize + #define s_xenix_nfree u.xenix_sb.s_xsb->xs_nfree + #define s_xenix_free u.xenix_sb.s_xsb->xs_free /* MISALIGNED! */ + #define s_xenix_ninode u.xenix_sb.s_xsb->xs_ninode + #define s_xenix_inode u.xenix_sb.s_xsb->xs_inode + #define s_xenix_tfree u.xenix_sb.s_xsb->xs_tfree /* MISALIGNED! */ + #define s_xenix_tinode u.xenix_sb.s_xsb->xs_tinode + + /* + * Debugging stuff ... + */ + + extern char xenix_inodes; + extern char xenix_blocks; + + /* + * Function prototypes ... + */ + + extern int xenix_open(struct inode * inode, struct file * filp); + extern void xenix_release(struct inode * inode, struct file * filp); + extern int xenix_lookup(struct inode * dir,const char * name, int len, + struct inode ** result); + extern int xenix_create(struct inode * dir,const char * name, int len, int mode, + struct inode ** result); + extern int xenix_mkdir(struct inode * dir, const char * name, int len, int mode); + extern int xenix_rmdir(struct inode * dir, const char * name, int len); + extern int xenix_unlink(struct inode * dir, const char * name, int len); + extern int xenix_symlink(struct inode * inode, const char * name, int len, + const char * symname); + extern int xenix_link(struct inode * oldinode, struct inode * dir, const char * name, int len); + extern int xenix_mknod(struct inode * dir, const char * name, int len, int mode, int rdev); + extern int xenix_rename(struct inode * old_dir, const char * old_name, int old_len, + struct inode * new_dir, const char * new_name, int new_len); + extern struct inode * xenix_new_inode(int dev); + extern void xenix_free_inode(struct inode * inode); + extern unsigned long xenix_count_free_inodes(struct super_block * sb); + extern int xenix_new_block(int dev); + extern int xenix_free_block(int dev, int block); + extern unsigned long xenix_count_free_blocks(struct super_block * sb); + + extern int xenix_create_block(struct inode *, int); + extern int xenix_bmap(struct inode *,int); + + extern void xenix_truncate(struct inode *); + extern void xenix_put_super(struct super_block *); + extern struct super_block *xenix_read_super(struct super_block *,void *); + extern void xenix_read_inode(struct inode *); + extern void xenix_write_inode(struct inode *); + extern void xenix_put_inode(struct inode *); + extern void xenix_statfs(struct super_block *, struct statfs *); + + extern int xenix_lseek(struct inode *, struct file *, off_t, int); + extern int xenix_read(struct inode *, struct file *, char *, int); + extern int xenix_write(struct inode *, struct file *, char *, int); + extern int xenix_file_read(struct inode *, struct file *, char *, int); + + extern struct inode_operations xenix_file_inode_operations; + extern struct inode_operations xenix_dir_inode_operations; + extern struct inode_operations xenix_symlink_inode_operations; + extern struct inode_operations xenix_chrdev_inode_operations; + extern struct inode_operations xenix_blkdev_inode_operations; + extern struct inode_operations xenix_fifo_inode_operations; + + extern struct file_operations xenix_file_operations; + extern struct file_operations xenix_dir_operations; + + #endif *** linux.pl1/include/linux/xenix_fs_sb.h Tue Aug 18 13:03:24 1992 --- linux/include/linux/xenix_fs_sb.h Fri Aug 7 10:13:03 1992 *************** *** 0 **** --- 1,25 ---- + #ifndef _XENIX_FS_SB + #define _XENIX_FS_SB + + /* + * Xenix super-block data in memory + * + * The Xenix superblock contains dynamic data (it gets modified while the + * system is running). This is in contrast to the Minix and Berkeley + * filesystems (where the superblock is never modified). This affects the + * sync() operation: we must keep the superblock in a disk buffer and use this + * one as our "working copy". + * + * FIXME: The structure is such that it's a pain in the ass to work with + * without #pragma pack(2), so we keep here (they + * don't change). + */ + + struct xenix_sb_info { + struct buffer_head *s_bh; /* actually, it's in a disk buffer */ + struct xenix_super_block *s_xsb; + unsigned short s_isize; + daddr_t s_fsize; + }; + + #endif SHAR_EOF # End of shell archive exit 0