echo x - Makefile.ansi
sed '/^X/s///' > Makefile.ansi << '/'
X# Set O=o for ANSI compiler and 68000 K&R compiler, or O=s for PC K&R compiler.
XO=o
X#O=s
X
X#Set b=/usr for /usr/include or b=<null string> for /include.
X#b=/usr
Xb=
X
X# Directories
Xi=$b/include
Xs=$i/sys
Xh=$i/minix
Xl=$b/lib
X
X# Programs, flags, and libraries
XCC=exec cc
XLD=$l/ld
XCV=$l/cv
X
X# Set compiler flags.
XCFLAGS = -I$i
X
X# Set LDFLAGS to -i for PC or <null string> for 68000.
XLDFLAGS =  -i
X#LDFLAGS = 
X
XHEAD=$l/nhead.$O
XLIB=$l/libc.A $l/libe.A $l/end.A
X
Xa=fs.h $h/config.h $s/types.h $h/const.h $h/type.h \
X  $i/limits.h $i/errno.h \
X  $i/ansi.h $h/syslib.h \
X  const.h type.h proto.h glo.h $s/dir.h
X
XOBJ =	main.$O open.$O read.$O write.$O pipe.$O \
X	device.$O path.$O mount.$O link.$O super.$O inode.$O cache.$O \
X	filedes.$O stadir.$O protect.$O time.$O misc.$O utility.$O table.$O \
X	putk.$O
X
Xfs:	Makefile $(HEAD) $(OBJ) $(LIB)
X	$(LD) -o tmp $(LDFLAGS) $(HEAD) $(OBJ) $(LIB)
X	$(CV) tmp $@
X	@rm -f tmp
X
Xclean:
X	@rm -f *.s *.o *.bak fs
X
Xcache.$O:	$a
Xcache.$O:	$h/com.h
Xcache.$O:	$h/boot.h
Xcache.$O:	buf.h
Xcache.$O:	file.h
Xcache.$O:	fproc.h
Xcache.$O:	super.h
X
Xdevice.$O:	$a
Xdevice.$O:	$h/callnr.h
Xdevice.$O:	$h/com.h
Xdevice.$O:	dev.h
Xdevice.$O:	file.h
Xdevice.$O:	fproc.h
Xdevice.$O:	inode.h
Xdevice.$O:	param.h
X
Xfiledes.$O:	$a
Xfiledes.$O:	file.h
Xfiledes.$O:	fproc.h
Xfiledes.$O:	inode.h
X
Xinode.$O:	$a
Xinode.$O:	$h/boot.h
Xinode.$O:	buf.h
Xinode.$O:	file.h
Xinode.$O:	fproc.h
Xinode.$O:	inode.h
Xinode.$O:	super.h
X
Xlink.$O:	$a
Xlink.$O:	$s/stat.h
Xlink.$O:	$i/string.h
Xlink.$O:	$h/callnr.h
Xlink.$O:	buf.h
Xlink.$O:	file.h
Xlink.$O:	fproc.h
Xlink.$O:	inode.h
Xlink.$O:	param.h
Xlink.$O:	super.h
X
Xmain.$O:	$a
Xmain.$O:	$i/fcntl.h
Xmain.$O:	$i/string.h
Xmain.$O:	$h/callnr.h
Xmain.$O:	$h/com.h
Xmain.$O:	$h/boot.h
Xmain.$O:	buf.h
Xmain.$O:	dev.h
Xmain.$O:	file.h
Xmain.$O:	fproc.h
Xmain.$O:	inode.h
Xmain.$O:	param.h
Xmain.$O:	super.h
X
Xmisc.$O:	$a
Xmisc.$O:	$i/fcntl.h
Xmisc.$O:	$i/tiny-unistd.h
Xmisc.$O:	$h/callnr.h
Xmisc.$O:	$h/com.h
Xmisc.$O:	$h/boot.h
Xmisc.$O:	buf.h
Xmisc.$O:	file.h
Xmisc.$O:	fproc.h
Xmisc.$O:	inode.h
Xmisc.$O:	param.h
X
Xmount.$O:	$a
Xmount.$O:	$h/com.h
Xmount.$O:	buf.h
Xmount.$O:	dev.h
Xmount.$O:	file.h
Xmount.$O:	fproc.h
Xmount.$O:	inode.h
Xmount.$O:	param.h
Xmount.$O:	super.h
X
Xopen.$O:	$a
Xopen.$O:	$s/stat.h
Xopen.$O:	$i/fcntl.h
Xopen.$O:	$h/callnr.h
Xopen.$O:	$h/com.h
Xopen.$O:	buf.h
Xopen.$O:	dev.h
Xopen.$O:	file.h
Xopen.$O:	fproc.h
Xopen.$O:	inode.h
Xopen.$O:	param.h
X
Xpath.$O:	$a
Xpath.$O:	$i/string.h
Xpath.$O:	$h/callnr.h
Xpath.$O:	buf.h
Xpath.$O:	file.h
Xpath.$O:	fproc.h
Xpath.$O:	inode.h
Xpath.$O:	super.h
X
Xpipe.$O:	$a
Xpipe.$O:	$i/fcntl.h
Xpipe.$O:	$i/signal.h
Xpipe.$O:	$h/boot.h
Xpipe.$O:	$h/callnr.h
Xpipe.$O:	$h/com.h
Xpipe.$O:	dev.h
Xpipe.$O:	file.h
Xpipe.$O:	fproc.h
Xpipe.$O:	inode.h
Xpipe.$O:	param.h
X
Xprotect.$O:	$a
Xprotect.$O:	buf.h
Xprotect.$O:	file.h
Xprotect.$O:	fproc.h
Xprotect.$O:	inode.h
Xprotect.$O:	param.h
Xprotect.$O:	super.h
X
Xputk.$O:	$a
Xputk.$O:	$h/com.h
X
Xread.$O:	$a
Xread.$O:	$i/fcntl.h
Xread.$O:	$h/com.h
Xread.$O:	buf.h
Xread.$O:	file.h
Xread.$O:	fproc.h
Xread.$O:	inode.h
Xread.$O:	param.h
Xread.$O:	super.h
X
Xstadir.$O:	$a
Xstadir.$O:	$s/stat.h
Xstadir.$O:	file.h
Xstadir.$O:	fproc.h
Xstadir.$O:	inode.h
Xstadir.$O:	param.h
X
Xsuper.$O:	$a
Xsuper.$O:	$i/string.h
Xsuper.$O:	$h/boot.h
Xsuper.$O:	buf.h
Xsuper.$O:	inode.h
Xsuper.$O:	super.h
X
Xtable.$O:	$a
Xtable.$O:	$h/callnr.h
Xtable.$O:	$h/com.h
Xtable.$O:	buf.h
Xtable.$O:	dev.h
Xtable.$O:	file.h
Xtable.$O:	fproc.h
Xtable.$O:	inode.h
Xtable.$O:	super.h
X
Xtime.$O:	$a
Xtime.$O:	$h/callnr.h
Xtime.$O:	$h/com.h
Xtime.$O:	file.h
Xtime.$O:	fproc.h
Xtime.$O:	inode.h
Xtime.$O:	param.h
X
Xutility.$O:	$a
Xutility.$O:	$h/com.h
Xutility.$O:	$h/boot.h
Xutility.$O:	buf.h
Xutility.$O:	file.h
Xutility.$O:	fproc.h
Xutility.$O:	inode.h
Xutility.$O:	param.h
X
Xwrite.$O:	$a
Xwrite.$O:	$i/string.h
Xwrite.$O:	buf.h
Xwrite.$O:	file.h
Xwrite.$O:	fproc.h
Xwrite.$O:	inode.h
Xwrite.$O:	super.h
/
echo x - Makefile.kr
sed '/^X/s///' > Makefile.kr << '/'
X# Set O=o for ANSI compiler and 68000 K&R compiler, or O=s for PC K&R compiler.
X#O=o
XO=s
X
X#Set b=/usr for /usr/include or b=<null string> for /include.
Xb=/usr
X#b=
X
X# Directories
Xi=$b/include
Xs=$i/sys
Xh=$i/minix
Xl=$b/lib
X
X# Programs, flags, and libraries
XCC=exec cc
XLD=asld
XCV=$l/cv
X
X# Set compiler flags.
XCFLAGS = -I$i
X
X# Set LDFLAGS to -i for PC or <null string> for 68000.
XLDFLAGS =  -i
X#LDFLAGS = 
X
XHEAD=$l/head.$O
XLIB=$l/libc.a $l/end.s
X
Xa=fs.h $h/config.h $s/types.h $h/const.h $h/type.h \
X  $i/limits.h $i/errno.h \
X  $i/ansi.h $h/syslib.h \
X  const.h type.h proto.h glo.h $s/dir.h
X
XOBJ =	main.$O open.$O read.$O write.$O pipe.$O \
X	device.$O path.$O mount.$O link.$O super.$O inode.$O cache.$O \
X	filedes.$O stadir.$O protect.$O time.$O misc.$O utility.$O table.$O \
X	putk.$O
X
Xfs:	Makefile $(HEAD) $(OBJ) $(LIB)
X	$(LD) -i -s -o fs $(HEAD) $(OBJ)  $(LIB) >symbol.out
X	ast -X fs
X	@rm symbol.out
X
Xclean:
X	@rm -f *.s *.o *.bak fs
X
Xcache.$O:	$a
Xcache.$O:	$h/com.h
Xcache.$O:	$h/boot.h
Xcache.$O:	buf.h
Xcache.$O:	file.h
Xcache.$O:	fproc.h
Xcache.$O:	super.h
X
Xdevice.$O:	$a
Xdevice.$O:	$h/callnr.h
Xdevice.$O:	$h/com.h
Xdevice.$O:	dev.h
Xdevice.$O:	file.h
Xdevice.$O:	fproc.h
Xdevice.$O:	inode.h
Xdevice.$O:	param.h
X
Xfiledes.$O:	$a
Xfiledes.$O:	file.h
Xfiledes.$O:	fproc.h
Xfiledes.$O:	inode.h
X
Xinode.$O:	$a
Xinode.$O:	$h/boot.h
Xinode.$O:	buf.h
Xinode.$O:	file.h
Xinode.$O:	fproc.h
Xinode.$O:	inode.h
Xinode.$O:	super.h
X
Xlink.$O:	$a
Xlink.$O:	$s/stat.h
Xlink.$O:	$i/string.h
Xlink.$O:	$h/callnr.h
Xlink.$O:	buf.h
Xlink.$O:	file.h
Xlink.$O:	fproc.h
Xlink.$O:	inode.h
Xlink.$O:	param.h
Xlink.$O:	super.h
X
Xmain.$O:	$a
Xmain.$O:	$i/fcntl.h
Xmain.$O:	$i/string.h
Xmain.$O:	$h/callnr.h
Xmain.$O:	$h/com.h
Xmain.$O:	$h/boot.h
Xmain.$O:	buf.h
Xmain.$O:	dev.h
Xmain.$O:	file.h
Xmain.$O:	fproc.h
Xmain.$O:	inode.h
Xmain.$O:	param.h
Xmain.$O:	super.h
X
Xmisc.$O:	$a
Xmisc.$O:	$i/fcntl.h
Xmisc.$O:	$i/tiny-unistd.h
Xmisc.$O:	$h/callnr.h
Xmisc.$O:	$h/com.h
Xmisc.$O:	$h/boot.h
Xmisc.$O:	buf.h
Xmisc.$O:	file.h
Xmisc.$O:	fproc.h
Xmisc.$O:	inode.h
Xmisc.$O:	param.h
X
Xmount.$O:	$a
Xmount.$O:	$h/com.h
Xmount.$O:	buf.h
Xmount.$O:	dev.h
Xmount.$O:	file.h
Xmount.$O:	fproc.h
Xmount.$O:	inode.h
Xmount.$O:	param.h
Xmount.$O:	super.h
X
Xopen.$O:	$a
Xopen.$O:	$s/stat.h
Xopen.$O:	$i/fcntl.h
Xopen.$O:	$h/callnr.h
Xopen.$O:	$h/com.h
Xopen.$O:	buf.h
Xopen.$O:	dev.h
Xopen.$O:	file.h
Xopen.$O:	fproc.h
Xopen.$O:	inode.h
Xopen.$O:	param.h
X
Xpath.$O:	$a
Xpath.$O:	$i/string.h
Xpath.$O:	$h/callnr.h
Xpath.$O:	buf.h
Xpath.$O:	file.h
Xpath.$O:	fproc.h
Xpath.$O:	inode.h
Xpath.$O:	super.h
X
Xpipe.$O:	$a
Xpipe.$O:	$i/fcntl.h
Xpipe.$O:	$i/signal.h
Xpipe.$O:	$h/boot.h
Xpipe.$O:	$h/callnr.h
Xpipe.$O:	$h/com.h
Xpipe.$O:	dev.h
Xpipe.$O:	file.h
Xpipe.$O:	fproc.h
Xpipe.$O:	inode.h
Xpipe.$O:	param.h
X
Xprotect.$O:	$a
Xprotect.$O:	buf.h
Xprotect.$O:	file.h
Xprotect.$O:	fproc.h
Xprotect.$O:	inode.h
Xprotect.$O:	param.h
Xprotect.$O:	super.h
X
Xputk.$O:	$a
Xputk.$O:	$h/com.h
X
Xread.$O:	$a
Xread.$O:	$i/fcntl.h
Xread.$O:	$h/com.h
Xread.$O:	buf.h
Xread.$O:	file.h
Xread.$O:	fproc.h
Xread.$O:	inode.h
Xread.$O:	param.h
Xread.$O:	super.h
X
Xstadir.$O:	$a
Xstadir.$O:	$s/stat.h
Xstadir.$O:	file.h
Xstadir.$O:	fproc.h
Xstadir.$O:	inode.h
Xstadir.$O:	param.h
X
Xsuper.$O:	$a
Xsuper.$O:	$i/string.h
Xsuper.$O:	$h/boot.h
Xsuper.$O:	buf.h
Xsuper.$O:	inode.h
Xsuper.$O:	super.h
X
Xtable.$O:	$a
Xtable.$O:	$h/callnr.h
Xtable.$O:	$h/com.h
Xtable.$O:	buf.h
Xtable.$O:	dev.h
Xtable.$O:	file.h
Xtable.$O:	fproc.h
Xtable.$O:	inode.h
Xtable.$O:	super.h
X
Xtime.$O:	$a
Xtime.$O:	$h/callnr.h
Xtime.$O:	$h/com.h
Xtime.$O:	file.h
Xtime.$O:	fproc.h
Xtime.$O:	inode.h
Xtime.$O:	param.h
X
Xutility.$O:	$a
Xutility.$O:	$h/com.h
Xutility.$O:	$h/boot.h
Xutility.$O:	buf.h
Xutility.$O:	file.h
Xutility.$O:	fproc.h
Xutility.$O:	inode.h
Xutility.$O:	param.h
X
Xwrite.$O:	$a
Xwrite.$O:	$i/string.h
Xwrite.$O:	buf.h
Xwrite.$O:	file.h
Xwrite.$O:	fproc.h
Xwrite.$O:	inode.h
Xwrite.$O:	super.h
/
echo x - putk.c
sed '/^X/s///' > putk.c << '/'
X/* FS must occasionally print some message.  It uses the standard library
X * routine prink().  (The name "printf" is really a macro defined as "printk").
X * Printing is done by calling the TTY task directly, not going through FS.
X */
X
X#include "fs.h"
X#include <minix/com.h>
X
X#define BUF_SIZE          100	/* print buffer size */
X
XPRIVATE int buf_count;		/* # characters in the buffer */
XPRIVATE char print_buf[BUF_SIZE];	/* output is buffered here */
XPRIVATE message putch_msg;	/* used for message to TTY task */
X
XFORWARD _PROTOTYPE( void flush, (void)					);
X
X/*===========================================================================*
X *				putk					     *
X *===========================================================================*/
XPUBLIC void putk(c)
Xint c;
X{
X/* Accumulate another character.  If '\n' or buffer full, print it. */
X
X  if (c == 0) {
X	flush();
X	return;
X  }
X  print_buf[buf_count++] = (char) c;
X  if (c == '\n' || buf_count == BUF_SIZE) flush();
X}
X
X
X/*===========================================================================*
X *				flush					     *
X *===========================================================================*/
XPRIVATE void flush()
X{
X/* Flush the print buffer by calling TTY task. */
X
X
X  if (buf_count == 0) return;
X  putch_msg.m_type = DEV_WRITE;
X  putch_msg.PROC_NR  = 1;
X  putch_msg.TTY_LINE = 0;
X  putch_msg.ADDRESS  = print_buf;
X  putch_msg.COUNT = buf_count;
X  call_task(TTY, &putch_msg);
X  buf_count = 0;
X}
/
echo x - fs.cd
sed '/^X/s///' > fs.cd << '/'
Xecho x - buf.h.d
Xsed '/^X/s///' > buf.h.d << '/'
XX*** /home/top/ast/minix/1.5/fs/buf.h  crc=46997   3007	Sat Apr 21 22:26:19 1990
XX--- /home/top/ast/minix/1.6.25/fs/buf.h  crc=15963   3387	Tue Nov  3 21:19:11 1992
XX***************
XX*** 1,7 ****
XX  /* Buffer (block) cache.  To acquire a block, a routine calls get_block(),
XX   * telling which block it wants.  The block is then regarded as "in use"
XX!  * and has its 'b_count' field incremented.  All the blocks, whether in use
XX!  * or not, are chained together in an LRU list, with 'front' pointing
XX   * to the least recently used block, and 'rear' to the most recently used
XX   * block.  A reverse chain, using the field b_prev is also maintained.
XX   * Usage for LRU is measured by the time the put_block() is done.  The second
XX--- 1,7 ----
XX  /* Buffer (block) cache.  To acquire a block, a routine calls get_block(),
XX   * telling which block it wants.  The block is then regarded as "in use"
XX!  * and has its 'b_count' field incremented.  All the blocks that are not
XX!  * in use are chained together in an LRU list, with 'front' pointing
XX   * to the least recently used block, and 'rear' to the most recently used
XX   * block.  A reverse chain, using the field b_prev is also maintained.
XX   * Usage for LRU is measured by the time the put_block() is done.  The second
XX***************
XX*** 11,31 ****
XX   * will eventually be rewritten to the disk.
XX   */
XX  
XX  EXTERN struct buf {
XX    /* Data portion of the buffer. */
XX    union {
XX!     char b__data[BLOCK_SIZE];		/* ordinary user data */
XX!     dir_struct b__dir[NR_DIR_ENTRIES];	/* directory block */
XX!     zone_nr b__ind[NR_INDIRECTS];	/* indirect block */
XX!     d_inode b__inode[INODES_PER_BLOCK];	/* inode block */
XX!     int b__int[INTS_PER_BLOCK];		/* block full of integers */
XX    } b;
XX  
XX    /* Header portion of the buffer. */
XX!   struct buf *b_next;		/* used to link bufs in a chain */
XX!   struct buf *b_prev;		/* used to link bufs the other way */
XX    struct buf *b_hash;		/* used to link bufs on hash chains */
XX!   block_nr b_blocknr;		/* block number of its (minor) device */
XX    dev_t b_dev;			/* major | minor device where block resides */
XX    char b_dirt;			/* CLEAN or DIRTY */
XX    char b_count;			/* number of users of this buffer */
XX--- 11,35 ----
XX   * will eventually be rewritten to the disk.
XX   */
XX  
XX+ #include <sys/dir.h>			/* need struct direct */
XX+ 
XX  EXTERN struct buf {
XX    /* Data portion of the buffer. */
XX    union {
XX!     char b__data[BLOCK_SIZE];		     /* ordinary user data */
XX!     struct direct b__dir[NR_DIR_ENTRIES];    /* directory block */
XX!     zone1_t b__v1_ind[V1_INDIRECTS];	     /* V1 indirect block */
XX!     zone_t  b__v2_ind[V2_INDIRECTS];	     /* V2 indirect block */
XX!     d1_inode b__v1_ino[V1_INODES_PER_BLOCK]; /* V1 inode block */
XX!     d2_inode b__v2_ino[V2_INODES_PER_BLOCK]; /* V2 inode block */
XX!     bitchunk_t b__bitmap[BITMAP_CHUNKS];     /* bit map block */
XX    } b;
XX  
XX    /* Header portion of the buffer. */
XX!   struct buf *b_next;		/* used to link all free bufs in a chain */
XX!   struct buf *b_prev;		/* used to link all free bufs the other way */
XX    struct buf *b_hash;		/* used to link bufs on hash chains */
XX!   block_t b_blocknr;		/* block number of its (minor) device */
XX    dev_t b_dev;			/* major | minor device where block resides */
XX    char b_dirt;			/* CLEAN or DIRTY */
XX    char b_count;			/* number of users of this buffer */
XX***************
XX*** 33,46 ****
XX  
XX  /* A block is free if b_dev == NO_DEV. */
XX  
XX! #define NIL_BUF (struct buf *) 0	/* indicates absence of a buffer */
XX  
XX  /* These defs make it possible to use to bp->b_data instead of bp->b.b__data */
XX! #define b_data	b.b__data
XX! #define b_dir	b.b__dir
XX! #define b_ind	b.b__ind
XX! #define b_inode	b.b__inode
XX! #define b_int	b.b__int
XX  
XX  EXTERN struct buf *buf_hash[NR_BUF_HASH];	/* the buffer hash table */
XX  
XX--- 37,52 ----
XX  
XX  /* A block is free if b_dev == NO_DEV. */
XX  
XX! #define NIL_BUF ((struct buf *) 0)	/* indicates absence of a buffer */
XX  
XX  /* These defs make it possible to use to bp->b_data instead of bp->b.b__data */
XX! #define b_data   b.b__data
XX! #define b_dir    b.b__dir
XX! #define b_v1_ind b.b__v1_ind
XX! #define b_v2_ind b.b__v2_ind
XX! #define b_v1_ino b.b__v1_ino
XX! #define b_v2_ino b.b__v2_ino
XX! #define b_bitmap b.b__bitmap
XX  
XX  EXTERN struct buf *buf_hash[NR_BUF_HASH];	/* the buffer hash table */
XX  
XX***************
XX*** 60,62 ****
XX--- 66,70 ----
XX  #define ZUPER_BLOCK       (5 + WRITE_IMMED + ONE_SHOT)	 /* super block */
XX  #define FULL_DATA_BLOCK    6		 	 	 /* data, fully used */
XX  #define PARTIAL_DATA_BLOCK 7 				 /* data, partly used*/
XX+ 
XX+ #define HASH_MASK (NR_BUF_HASH - 1)	/* mask for hashing block numbers */
X/
Xecho x - cache.c.d
Xsed '/^X/s///' > cache.c.d << '/'
XX*** /home/top/ast/minix/1.5/fs/cache.c  crc=22996  13852	Sat May  5 13:14:25 1990
XX--- /home/top/ast/minix/1.6.25/fs/cache.c  crc=61972  14452	Tue Nov  3 21:19:11 1992
XX***************
XX*** 10,15 ****
XX--- 10,16 ----
XX   *   free_zone:	  release a zone (when a file is removed)
XX   *   rw_block:	  read or write a block from the disk itself
XX   *   invalidate:  remove all the cache blocks on some device
XX+  *   rm_lru:	  remove a block from its LRU chain
XX   */
XX  
XX  #include "fs.h"
XX***************
XX*** 18,24 ****
XX  #include "buf.h"
XX  #include "file.h"
XX  #include "fproc.h"
XX- #include "inode.h"
XX  #include "super.h"
XX  
XX  /*===========================================================================*
XX--- 19,24 ----
XX***************
XX*** 26,37 ****
XX   *===========================================================================*/
XX  PUBLIC struct buf *get_block(dev, block, only_search)
XX  register dev_t dev;		/* on which device is the block? */
XX! register block_nr block;	/* which block is wanted? */
XX  int only_search;		/* if NO_READ, don't read, else act normal */
XX  {
XX  /* Check to see if the requested block is in the block cache.  If so, return
XX   * a pointer to it.  If not, evict some other block and fetch it (unless
XX!  * 'only_search' is 1).  All blocks in the cache, whether in use or not,
XX   * are linked together in a chain, with 'front' pointing to the least recently
XX   * used block and 'rear' to the most recently used block.  If 'only_search' is
XX   * 1, the block being requested will be overwritten in its entirety, so it is
XX--- 26,37 ----
XX   *===========================================================================*/
XX  PUBLIC struct buf *get_block(dev, block, only_search)
XX  register dev_t dev;		/* on which device is the block? */
XX! register block_t block;		/* which block is wanted? */
XX  int only_search;		/* if NO_READ, don't read, else act normal */
XX  {
XX  /* Check to see if the requested block is in the block cache.  If so, return
XX   * a pointer to it.  If not, evict some other block and fetch it (unless
XX!  * 'only_search' is 1).  All the blocks in the cache that are not in use
XX   * are linked together in a chain, with 'front' pointing to the least recently
XX   * used block and 'rear' to the most recently used block.  If 'only_search' is
XX   * 1, the block being requested will be overwritten in its entirety, so it is
XX***************
XX*** 44,59 ****
XX   * blocks whose block numbers end with the same bit strings, for fast lookup.
XX   */
XX  
XX    register struct buf *bp, *prev_ptr;
XX  
XX    /* Search the hash chain for (dev, block). */
XX    if (dev != NO_DEV) {
XX  	/* ??? DEBUG What if dev == NO_DEV ??? */
XX! 	bp = buf_hash[block & (NR_BUF_HASH - 1)];
XX  	while (bp != NIL_BUF) {
XX  		if (bp->b_blocknr == block && bp->b_dev == dev) {
XX  			/* Block needed has been found. */
XX! 			if (bp->b_count == 0) bufs_in_use++;
XX  			bp->b_count++;	/* record that block is in use */
XX  			return(bp);
XX  		} else {
XX--- 44,61 ----
XX   * blocks whose block numbers end with the same bit strings, for fast lookup.
XX   */
XX  
XX+   int b;
XX    register struct buf *bp, *prev_ptr;
XX  
XX    /* Search the hash chain for (dev, block). */
XX    if (dev != NO_DEV) {
XX  	/* ??? DEBUG What if dev == NO_DEV ??? */
XX! 	b = (int) block & HASH_MASK;
XX! 	bp = buf_hash[b];
XX  	while (bp != NIL_BUF) {
XX  		if (bp->b_blocknr == block && bp->b_dev == dev) {
XX  			/* Block needed has been found. */
XX! 			if (bp->b_count == 0) rm_lru(bp);
XX  			bp->b_count++;	/* record that block is in use */
XX  			return(bp);
XX  		} else {
XX***************
XX*** 63,83 ****
XX  	}
XX    }
XX  
XX!   /* Desired block is not on available chain.  Take oldest block ('front').
XX!    * However, a block that is already in use (b_count != 0) may not be taken.
XX!    */
XX!   if (bufs_in_use == NR_BUFS) panic("All buffers in use", NR_BUFS);
XX!   bp = front;
XX!   while (bp->b_count != 0) {
XX! 	bp = bp->b_next;
XX! 	if (bp == NIL_BUF) panic("No free buffer", NO_NUM);
XX!   }
XX!   bufs_in_use++;		/* one more buffer in use now */
XX  
XX    /* Remove the block that was just taken from its hash chain. */
XX!   prev_ptr = buf_hash[bp->b_blocknr & (NR_BUF_HASH - 1)];
XX    if (prev_ptr == bp) {
XX! 	buf_hash[bp->b_blocknr & (NR_BUF_HASH - 1)] = bp->b_hash;
XX    } else {
XX  	/* The block just taken is not on the front of its hash chain. */
XX  	while (prev_ptr->b_hash != NIL_BUF)
XX--- 65,79 ----
XX  	}
XX    }
XX  
XX!   /* Desired block is not on available chain.  Take oldest block ('front'). */
XX!   if ((bp = front) == NIL_BUF) panic("all buffers in use", NR_BUFS);
XX!   rm_lru(bp);
XX  
XX    /* Remove the block that was just taken from its hash chain. */
XX!   b = (int) bp->b_blocknr & HASH_MASK;
XX!   prev_ptr = buf_hash[b];
XX    if (prev_ptr == bp) {
XX! 	buf_hash[b] = bp->b_hash;
XX    } else {
XX  	/* The block just taken is not on the front of its hash chain. */
XX  	while (prev_ptr->b_hash != NIL_BUF)
XX***************
XX*** 99,106 ****
XX    if (only_search == PREFETCH) bp->b_dev = NO_DEV;
XX    bp->b_blocknr = block;	/* fill in block number */
XX    bp->b_count++;		/* record that block is being used */
XX!   bp->b_hash = buf_hash[bp->b_blocknr & (NR_BUF_HASH - 1)];
XX!   buf_hash[bp->b_blocknr & (NR_BUF_HASH - 1)] = bp;	/* add to hash list */
XX  
XX    /* Go get the requested block unless searching or prefetching. */
XX    if (dev != NO_DEV && only_search == NORMAL) rw_block(bp, READING);
XX--- 95,103 ----
XX    if (only_search == PREFETCH) bp->b_dev = NO_DEV;
XX    bp->b_blocknr = block;	/* fill in block number */
XX    bp->b_count++;		/* record that block is being used */
XX!   b = (int) bp->b_blocknr & HASH_MASK;
XX!   bp->b_hash = buf_hash[b];
XX!   buf_hash[b] = bp;		/* add to hash list */
XX  
XX    /* Go get the requested block unless searching or prefetching. */
XX    if (dev != NO_DEV && only_search == NORMAL) rw_block(bp, READING);
XX***************
XX*** 121,150 ****
XX   * go on the rear; blocks that are unlikely to be needed again shortly
XX   * (e.g., full data blocks) go on the front.  Blocks whose loss can hurt
XX   * the integrity of the file system (e.g., inode blocks) are written to
XX!  * disk immediately if they are dirty.  
XX   */
XX  
XX-   register struct buf *next_ptr, *prev_ptr;
XX- 
XX    if (bp == NIL_BUF) return;	/* it is easier to check here than in caller */
XX  
XX-   /* If block is no longer in use, first remove it from LRU chain. */
XX    bp->b_count--;		/* there is one use fewer now */
XX    if (bp->b_count != 0) return;	/* block is still in use */
XX  
XX    bufs_in_use--;		/* one fewer block buffers in use */
XX-   next_ptr = bp->b_next;	/* successor on LRU chain */
XX-   prev_ptr = bp->b_prev;	/* predecessor on LRU chain */
XX-   if (prev_ptr != NIL_BUF)
XX- 	prev_ptr->b_next = next_ptr;
XX-   else
XX- 	front = next_ptr;	/* this block was at front of chain */
XX  
XX-   if (next_ptr != NIL_BUF)
XX- 	next_ptr->b_prev = prev_ptr;
XX-   else
XX- 	rear = prev_ptr;	/* this block was at rear of chain */
XX- 
XX    /* Put this block back on the LRU chain.  If the ONE_SHOT bit is set in
XX     * 'block_type', the block is not likely to be needed again shortly, so put
XX     * it on the front of the LRU chain where it will be the first one to be
XX--- 118,133 ----
XX   * go on the rear; blocks that are unlikely to be needed again shortly
XX   * (e.g., full data blocks) go on the front.  Blocks whose loss can hurt
XX   * the integrity of the file system (e.g., inode blocks) are written to
XX!  * disk immediately if they are dirty.
XX   */
XX  
XX    if (bp == NIL_BUF) return;	/* it is easier to check here than in caller */
XX  
XX    bp->b_count--;		/* there is one use fewer now */
XX    if (bp->b_count != 0) return;	/* block is still in use */
XX  
XX    bufs_in_use--;		/* one fewer block buffers in use */
XX  
XX    /* Put this block back on the LRU chain.  If the ONE_SHOT bit is set in
XX     * 'block_type', the block is not likely to be needed again shortly, so put
XX     * it on the front of the LRU chain where it will be the first one to be
XX***************
XX*** 189,203 ****
XX  /*===========================================================================*
XX   *				alloc_zone				     *
XX   *===========================================================================*/
XX! PUBLIC zone_nr alloc_zone(dev, z)
XX  dev_t dev;			/* device where zone wanted */
XX! zone_nr z;			/* try to allocate new zone near this one */
XX  {
XX  /* Allocate a new zone on the indicated device and return its number. */
XX  
XX!   bit_nr b, bit;
XX    struct super_block *sp;
XX-   int major, minor;
XX  
XX    /* Note that the routine alloc_bit() returns 1 for the lowest possible
XX     * zone, which corresponds to sp->s_firstdatazone.  To convert a value
XX--- 172,186 ----
XX  /*===========================================================================*
XX   *				alloc_zone				     *
XX   *===========================================================================*/
XX! PUBLIC zone_t alloc_zone(dev, z)
XX  dev_t dev;			/* device where zone wanted */
XX! zone_t z;			/* try to allocate new zone near this one */
XX  {
XX  /* Allocate a new zone on the indicated device and return its number. */
XX  
XX!   int major, minor, bit_blocks;
XX!   bit_t b, bit, mapbits;
XX    struct super_block *sp;
XX  
XX    /* Note that the routine alloc_bit() returns 1 for the lowest possible
XX     * zone, which corresponds to sp->s_firstdatazone.  To convert a value
XX***************
XX*** 207,215 ****
XX     * Alloc_bit() never returns 0, since this is used for NO_BIT (failure).
XX     */
XX    sp = get_super(dev);		/* find the super_block for this device */
XX!   bit = (bit_nr) z - (sp->s_firstdatazone - 1);
XX!   b = alloc_bit(sp->s_zmap, (bit_nr) sp->s_nzones - sp->s_firstdatazone + 1,
XX! 						sp->s_zmap_blocks, bit);
XX    if (b == NO_BIT) {
XX  	err_code = ENOSPC;
XX  	major = (int) (sp->s_dev >> MAJOR) & BYTE;
XX--- 190,205 ----
XX     * Alloc_bit() never returns 0, since this is used for NO_BIT (failure).
XX     */
XX    sp = get_super(dev);		/* find the super_block for this device */
XX!   mapbits =  (bit_t) (sp->s_zones - (sp->s_firstdatazone - 1) );
XX!   bit_blocks = (int) sp->s_zmap_blocks;	/* # blocks in the bit map */
XX! 
XX!   /* If z is 0, skip initial part of the map known to be fully in use. */
XX!   if (z == sp->s_firstdatazone) {
XX! 	bit = sp->s_zsearch;
XX!   }  else
XX! 	bit = (bit_t) z - (sp->s_firstdatazone - 1);
XX! 
XX!   b = alloc_bit(sp->s_zmap, mapbits, bit_blocks, bit);
XX    if (b == NO_BIT) {
XX  	err_code = ENOSPC;
XX  	major = (int) (sp->s_dev >> MAJOR) & BYTE;
XX***************
XX*** 218,224 ****
XX  		sp->s_dev == ROOT_DEV ? "root " : "", major, minor);
XX  	return(NO_ZONE);
XX    }
XX!   return(sp->s_firstdatazone - 1 + (zone_nr) b);
XX  }
XX  
XX  
XX--- 208,215 ----
XX  		sp->s_dev == ROOT_DEV ? "root " : "", major, minor);
XX  	return(NO_ZONE);
XX    }
XX!   if (z == sp->s_firstdatazone) sp->s_zsearch = b;	/* for next time */
XX!   return(sp->s_firstdatazone - 1 + (zone_t) b);
XX  }
XX  
XX  
XX***************
XX*** 227,243 ****
XX   *===========================================================================*/
XX  PUBLIC void free_zone(dev, numb)
XX  dev_t dev;				/* device where zone located */
XX! zone_nr numb;				/* zone to be returned */
XX  {
XX  /* Return a zone. */
XX  
XX    register struct super_block *sp;
XX  
XX-   if (numb == NO_ZONE) return;	/* checking here easier than in caller */
XX- 
XX    /* Locate the appropriate super_block and return bit. */
XX    sp = get_super(dev);
XX!   free_bit(sp->s_zmap, (bit_nr) numb - (sp->s_firstdatazone - 1) );
XX  }
XX  
XX  
XX--- 218,236 ----
XX   *===========================================================================*/
XX  PUBLIC void free_zone(dev, numb)
XX  dev_t dev;				/* device where zone located */
XX! zone_t numb;				/* zone to be returned */
XX  {
XX  /* Return a zone. */
XX  
XX    register struct super_block *sp;
XX+   bit_t bit;
XX  
XX    /* Locate the appropriate super_block and return bit. */
XX    sp = get_super(dev);
XX!   bit = (bit_t) (numb - (sp->s_firstdatazone - 1));
XX!   if (bit <= 0 || numb >= sp->s_zones) return;	/* zone out of range */
XX!   free_bit(sp->s_zmap, bit);
XX!   if (bit < sp->s_zsearch) sp->s_zsearch = bit;
XX  }
XX  
XX  
XX***************
XX*** 254,271 ****
XX   * from the cache, it is not clear what the caller could do about it anyway.
XX   */
XX  
XX!   int r;
XX    off_t pos;
XX    dev_t dev;
XX  
XX    if ( (dev = bp->b_dev) != NO_DEV) {
XX  	pos = (off_t) bp->b_blocknr * BLOCK_SIZE;
XX! 	r = dev_io(rw_flag, FALSE, dev, pos, BLOCK_SIZE, FS_PROC_NR,
XX! 		   bp->b_data);
XX  	if (r != BLOCK_SIZE) {
XX! 		if (r >= 0) r = END_OF_FILE;
XX! 		if (r != END_OF_FILE)
XX! 		 printf("Unrecoverable disk error on device %d/%d, block %u\n",
XX  			(dev>>MAJOR)&BYTE, (dev>>MINOR)&BYTE, bp->b_blocknr);
XX  		bp->b_dev = NO_DEV;	/* invalidate block */
XX  
XX--- 247,264 ----
XX   * from the cache, it is not clear what the caller could do about it anyway.
XX   */
XX  
XX!   int r, op;
XX    off_t pos;
XX    dev_t dev;
XX  
XX    if ( (dev = bp->b_dev) != NO_DEV) {
XX  	pos = (off_t) bp->b_blocknr * BLOCK_SIZE;
XX! 	op = (rw_flag == READING ? DEV_READ : DEV_WRITE);
XX! 	r = dev_io(op, FALSE, dev, pos, BLOCK_SIZE, FS_PROC_NR, bp->b_data);
XX  	if (r != BLOCK_SIZE) {
XX! 	    if (r >= 0) r = END_OF_FILE;
XX! 	    if (r != END_OF_FILE)
XX! 	      printf("Unrecoverable disk error on device %d/%d, block %ld\n",
XX  			(dev>>MAJOR)&BYTE, (dev>>MINOR)&BYTE, bp->b_blocknr);
XX  		bp->b_dev = NO_DEV;	/* invalidate block */
XX  
XX***************
XX*** 312,317 ****
XX--- 305,335 ----
XX  
XX  
XX  /*===========================================================================*
XX+  *				rm_lru					     *
XX+  *===========================================================================*/
XX+ PUBLIC void rm_lru(bp)
XX+ struct buf *bp;
XX+ {
XX+ /* Remove a block from its LRU chain. */
XX+ 
XX+   struct buf *next_ptr, *prev_ptr;
XX+ 
XX+   bufs_in_use++;
XX+   next_ptr = bp->b_next;	/* successor on LRU chain */
XX+   prev_ptr = bp->b_prev;	/* predecessor on LRU chain */
XX+   if (prev_ptr != NIL_BUF)
XX+ 	prev_ptr->b_next = next_ptr;
XX+   else
XX+ 	front = next_ptr;	/* this block was at front of chain */
XX+ 
XX+   if (next_ptr != NIL_BUF)
XX+ 	next_ptr->b_prev = prev_ptr;
XX+   else
XX+ 	rear = prev_ptr;	/* this block was at rear of chain */
XX+ }
XX+ 
XX+ 
XX+ /*===========================================================================*
XX   *				rw_scattered				     *
XX   *===========================================================================*/
XX  PUBLIC void rw_scattered(dev, bufq, bufqsize, rw_flag)
XX***************
XX*** 336,342 ****
XX    if (bufqsize <= 0) return;
XX    if (bufqsize > NR_BUFS) panic("Too much scattered i/o", NO_NUM);
XX  
XX!   /* (Shell) sort buffers on block_nr. */
XX    gap = 1;
XX    do
XX  	gap = 3 * gap + 1;
XX--- 354,360 ----
XX    if (bufqsize <= 0) return;
XX    if (bufqsize > NR_BUFS) panic("Too much scattered i/o", NO_NUM);
XX  
XX!   /* (Shell) sort buffers on b_blocknr. */
XX    gap = 1;
XX    do
XX  	gap = 3 * gap + 1;
XX***************
XX*** 355,370 ****
XX    }
XX  
XX  #if HAVE_SCATTERED_IO
XX!   /* Set up i/o vector and do i/o. */
XX    for (i = 0, iop = iovec; i < bufqsize; i++, iop++) {
XX  	bp = bufq[i];
XX  	iop->io_position = (off_t) bp->b_blocknr * BLOCK_SIZE;
XX  	iop->io_buf = bp->b_data;
XX  	iop->io_nbytes = BLOCK_SIZE;
XX  	iop->io_request = rw_flag == WRITING ?
XX! 			  DISK_WRITE : DISK_READ | OPTIONAL_IO;
XX    }
XX!   dev_io(SCATTERED_IO, 0, dev, (off_t) 0, bufqsize, FS_PROC_NR, (char *)iovec);
XX  
XX    /* Harvest the results.  Leave read errors for rw_block() to complain. */
XX    for (i = 0, iop = iovec; i < bufqsize; i++, iop++) {
XX--- 373,392 ----
XX    }
XX  
XX  #if HAVE_SCATTERED_IO
XX!   /* Set up i/o vector and do i/o.  The result of dev_io is discarded because
XX!    * all results are returned in the vector.  If dev_io fails completely, the
XX!    * vector is unchanged and all results are taken as errors.
XX!    */  
XX    for (i = 0, iop = iovec; i < bufqsize; i++, iop++) {
XX  	bp = bufq[i];
XX  	iop->io_position = (off_t) bp->b_blocknr * BLOCK_SIZE;
XX  	iop->io_buf = bp->b_data;
XX  	iop->io_nbytes = BLOCK_SIZE;
XX  	iop->io_request = rw_flag == WRITING ?
XX! 			  DEV_WRITE : DEV_READ | OPTIONAL_IO;
XX    }
XX!   (void) dev_io(SCATTERED_IO, 0, dev, (off_t) 0, bufqsize, FS_PROC_NR,
XX! 		(char *)iovec);
XX  
XX    /* Harvest the results.  Leave read errors for rw_block() to complain. */
XX    for (i = 0, iop = iovec; i < bufqsize; i++, iop++) {
XX***************
XX*** 375,383 ****
XX  	    put_block(bp, PARTIAL_DATA_BLOCK);
XX    	} else {
XX  	    if (iop->io_nbytes != 0) {
XX! 		printf("Unrecoverable write error on device %d/%d, block %d\n",
XX  			(dev>>MAJOR)&BYTE, (dev>>MINOR)&BYTE, bp->b_blocknr);
XX! 	 		bp->b_dev = NO_DEV;	/* invalidate block */
XX  	    }
XX  	    bp->b_dirt = CLEAN;
XX  	}
XX--- 397,405 ----
XX  	    put_block(bp, PARTIAL_DATA_BLOCK);
XX    	} else {
XX  	    if (iop->io_nbytes != 0) {
XX! 	     printf("Unrecoverable write error on device %d/%d, block %ld\n",
XX  			(dev>>MAJOR)&BYTE, (dev>>MINOR)&BYTE, bp->b_blocknr);
XX! 	 	bp->b_dev = NO_DEV;	/* invalidate block */
XX  	    }
XX  	    bp->b_dirt = CLEAN;
XX  	}
X/
Xecho x - const.h.d
Xsed '/^X/s///' > const.h.d << '/'
XX*** /home/top/ast/minix/1.5/fs/const.h  crc=64487   3096	Sat Apr 21 22:26:19 1990
XX--- /home/top/ast/minix/1.6.25/fs/const.h  crc=42467   4474	Tue Nov  3 21:19:12 1992
XX***************
XX*** 1,32 ****
XX  /* Tables sizes */
XX! #define NR_ZONE_NUMS       9	/* # zone numbers in an inode */
XX  
XX  #define NR_FILPS          64	/* # slots in filp table */
XX! #define I_MAP_SLOTS        8	/* max # of blocks in the inode bit map */
XX! #define ZMAP_SLOTS         8	/* max # of blocks in the zone bit map */
XX! #define NR_INODES         32	/* # slots in "in core" inode table */
XX! #define NR_SUPERS          5	/* # slots in super block table */
XX  
XX! #define FS_STACK_BYTES  (272 * sizeof (char *)) /* size of file system stack */
XX  
XX! /* Miscellaneous constants */
XX  #define SUPER_MAGIC   0x137F	/* magic number contained in super-block */
XX! #define SU_UID 	   (uid_t) 0	/* super_user's uid_t */
XX! #define SYS_UID    (uid_t) 0	/* uid_t for processes MM and INIT */
XX! #define SYS_GID    (gid_t) 0	/* gid_t for processes MM and INIT */
XX  #define NORMAL	           0	/* forces get_block to do disk read */
XX  #define NO_READ            1	/* prevents get_block from doing disk read */
XX  #define PREFETCH           2	/* tells get_block not to read or mark dev */
XX  
XX! #define XPIPE  -(NR_TASKS+1)	/* used in fp_task when suspended on pipe */
XX! #define XOPEN  -(NR_TASKS+2)	/* used in fp_task when suspended in open */
XX  
XX! #define NO_BIT    (bit_nr) 0	/* returned by alloc_bit() to signal failure */
XX  #define DUP_MASK        0100	/* mask to distinguish dup2 from dup */
XX  
XX  #define LOOK_UP            0	/* tells search_dir to lookup string */
XX  #define ENTER              1	/* tells search_dir to make dir entry */
XX  #define DELETE             2	/* tells search_dir to delete entry */
XX  
XX  #define CLEAN              0	/* disk and memory copies identical */
XX  #define DIRTY              1	/* disk and memory copies differ */
XX--- 1,51 ----
XX  /* Tables sizes */
XX! #define V1_NR_DZONES       7	/* # direct zone numbers in a V1 inode */
XX! #define V1_NR_TZONES       9	/* total # zone numbers in a V1 inode */
XX! #define V2_NR_DZONES       7	/* # direct zone numbers in a V2 inode */
XX! #define V2_NR_TZONES      10	/* total # zone numbers in a V2 inode */
XX  
XX  #define NR_FILPS          64	/* # slots in filp table */
XX! #define NR_INODES         64	/* # slots in "in core" inode table */
XX! #define NR_SUPERS          6	/* # slots in super block table */
XX! #define NR_LOCKS           8	/* # slots in the file locking table */
XX  
XX! /* The type of sizeof may be (unsigned) long.  Use the following macro for
XX!  * taking the sizes of small objects so that there are no surprises like
XX!  * (small) long constants being passed to routines expecting an int.
XX!  */
XX! #define usizeof(t) ((unsigned) sizeof(t))
XX  
XX! #define FS_STACK_BYTES (512 * usizeof (char *)) /* size of file system stack */
XX! 
XX! /* File system types. */
XX  #define SUPER_MAGIC   0x137F	/* magic number contained in super-block */
XX! #define SUPER_REV     0x7F13	/* magic # when 68000 disk read on PC or vv */
XX! #define SUPER_V2      0x2468	/* magic # for V2 file systems */
XX! #define SUPER_V2_REV  0x6824	/* V2 magic written on PC, read on 68K or vv */
XX! 
XX! #define V1		   1	/* version number of V1 file systems */ 
XX! #define V2		   2	/* version number of V2 file systems */ 
XX! 
XX! /* Miscellaneous constants */
XX! #define SU_UID 	 ((uid_t) 0)	/* super_user's uid_t */
XX! #define SYS_UID  ((uid_t) 0)	/* uid_t for processes MM and INIT */
XX! #define SYS_GID  ((gid_t) 0)	/* gid_t for processes MM and INIT */
XX  #define NORMAL	           0	/* forces get_block to do disk read */
XX  #define NO_READ            1	/* prevents get_block from doing disk read */
XX  #define PREFETCH           2	/* tells get_block not to read or mark dev */
XX  
XX! #define XPIPE  (-NR_TASKS-1)	/* used in fp_task when susp'd on pipe */
XX! #define XOPEN  (-NR_TASKS-2)	/* used in fp_task when susp'd on open */
XX! #define XLOCK  (-NR_TASKS-3)	/* used in fp_task when susp'd on lock */
XX! #define XPOPEN (-NR_TASKS-4)	/* used in fp_task when susp'd on pipe open */
XX  
XX! #define NO_BIT   ((bit_t) 0)	/* returned by alloc_bit() to signal failure */
XX  #define DUP_MASK        0100	/* mask to distinguish dup2 from dup */
XX  
XX  #define LOOK_UP            0	/* tells search_dir to lookup string */
XX  #define ENTER              1	/* tells search_dir to make dir entry */
XX  #define DELETE             2	/* tells search_dir to delete entry */
XX+ #define IS_EMPTY           3	/* tells search_dir to ret. OK or ENOTEMPTY */  
XX  
XX  #define CLEAN              0	/* disk and memory copies identical */
XX  #define DIRTY              1	/* disk and memory copies differ */
XX***************
XX*** 34,57 ****
XX  #define CTIME            004	/* set if ctime field needs updating */
XX  #define MTIME            010	/* set if mtime field needs updating */
XX  
XX! #define BOOT_BLOCK  (block_nr)0	/* block number of boot block */
XX! #define SUPER_BLOCK (block_nr)1	/* block number of super block */
XX! #define ROOT_INODE  (ino_t)1	/* inode number for root directory */
XX  
XX  #define INFO               2	/* where in data_org is info from build */
XX! #define END_OF_FILE     -104	/* eof detected */
XX  
XX! /* Derived sizes */
XX! #define ZONE_NUM_SIZE    sizeof(zone_nr)	     /* # bytes in zone nr  */
XX! #define NR_DZONE_NUM     (NR_ZONE_NUMS-2)	     /* # zones in inode    */
XX! #define DIR_ENTRY_SIZE   sizeof(dir_struct)	     /* # bytes/dir entry   */
XX! #define INODES_PER_BLOCK (BLOCK_SIZE/INODE_SIZE)     /* # inodes/disk blk   */
XX! #define INODE_SIZE       (sizeof (d_inode))	     /* bytes in disk inode */
XX! #define NR_DIR_ENTRIES   (BLOCK_SIZE/DIR_ENTRY_SIZE) /* # dir entries/block */
XX! #define NR_INDIRECTS     (BLOCK_SIZE/ZONE_NUM_SIZE)  /* # zones/indir block */
XX! #define INTS_PER_BLOCK   (BLOCK_SIZE/sizeof(int))    /* # integers/block    */
XX! #define SUPER_SIZE       sizeof(struct super_block)  /* super_block size    */
XX! #define PIPE_SIZE        (NR_DZONE_NUM*BLOCK_SIZE)   /* pipe size in bytes  */
XX! #define MAX_ZONES (NR_DZONE_NUM+NR_INDIRECTS+(long)NR_INDIRECTS*NR_INDIRECTS)
XX! 						     /* max zones in a file */
XX  #define printf printk
XX--- 53,84 ----
XX  #define CTIME            004	/* set if ctime field needs updating */
XX  #define MTIME            010	/* set if mtime field needs updating */
XX  
XX! #define BYTE_SWAP          0	/* tells conv2/conv4 to swap bytes */
XX! #define DONT_SWAP          1	/* tells conv2/conv4 not to swap bytes */
XX  
XX  #define INFO               2	/* where in data_org is info from build */
XX! #define END_OF_FILE   (-104)	/* eof detected */
XX  
XX! #define ROOT_INODE         1	/* inode number for root directory */
XX! #define BOOT_BLOCK  ((block_t) 0)	/* block number of boot block */
XX! #define SUPER_BLOCK ((block_t) 1)	/* block number of super block */
XX! 
XX! #define DIR_ENTRY_SIZE       usizeof (struct direct)  /* # bytes/dir entry   */
XX! #define NR_DIR_ENTRIES   (BLOCK_SIZE/DIR_ENTRY_SIZE)  /* # dir entries/blk   */
XX! #define SUPER_SIZE      usizeof (struct super_block)  /* super_block size    */
XX! #define PIPE_SIZE          (V1_NR_DZONES*BLOCK_SIZE)  /* pipe size in bytes  */
XX! #define BITMAP_CHUNKS (BLOCK_SIZE/usizeof (bitchunk_t))/* # map chunks/blk   */
XX! 
XX! /* Derived sizes pertaining to the V1 file system. */
XX! #define V1_ZONE_NUM_SIZE           usizeof (zone1_t)  /* # bytes in V1 zone  */
XX! #define V1_INODE_SIZE             usizeof (d1_inode)  /* bytes in V1 dsk ino */
XX! #define V1_INDIRECTS   (BLOCK_SIZE/V1_ZONE_NUM_SIZE)  /* # zones/indir block */
XX! #define V1_INODES_PER_BLOCK (BLOCK_SIZE/V1_INODE_SIZE)/* # V1 dsk inodes/blk */
XX! 
XX! /* Derived sizes pertaining to the V2 file system. */
XX! #define V2_ZONE_NUM_SIZE            usizeof (zone_t)  /* # bytes in V2 zone  */
XX! #define V2_INODE_SIZE             usizeof (d2_inode)  /* bytes in V2 dsk ino */
XX! #define V2_INDIRECTS   (BLOCK_SIZE/V2_ZONE_NUM_SIZE)  /* # zones/indir block */
XX! #define V2_INODES_PER_BLOCK (BLOCK_SIZE/V2_INODE_SIZE)/* # V2 dsk inodes/blk */
XX! 
XX  #define printf printk
X/
Xecho x - dev.h.d
Xsed '/^X/s///' > dev.h.d << '/'
XX*** /home/top/ast/minix/1.5/fs/dev.h  crc=46357    276	Sat Apr 21 22:26:20 1990
XX--- /home/top/ast/minix/1.6.25/fs/dev.h  crc=15147    334	Tue Nov  3 21:19:12 1992
XX***************
XX*** 2,11 ****
XX   * the link between major device numbers and the routines that process them.
XX   */
XX  
XX  extern struct dmap {
XX!   void (*dmap_open)();
XX!   void (*dmap_rw)();
XX!   void (*dmap_close)();
XX    int dmap_task;
XX  } dmap[];
XX  
XX--- 2,13 ----
XX   * the link between major device numbers and the routines that process them.
XX   */
XX  
XX+ typedef _PROTOTYPE (void (*dmap_t), (int task, message *m_ptr) );
XX+ 
XX  extern struct dmap {
XX!   dmap_t dmap_open;
XX!   dmap_t dmap_rw;
XX!   dmap_t dmap_close;
XX    int dmap_task;
XX  } dmap[];
XX  
X/
Xecho x - device.c.d
Xsed '/^X/s///' > device.c.d << '/'
XX*** /home/top/ast/minix/1.5/fs/device.c  crc=21550   9093	Sat Apr 21 22:26:20 1990
XX--- /home/top/ast/minix/1.6.25/fs/device.c  crc=58390  14187	Sat Apr 10 19:45:43 1993
XX***************
XX*** 2,19 ****
XX   * Special character files also require I/O.  The routines for these are here.
XX   *
XX   * The entry points in this file are:
XX-  *   dev_open:	 called when a special file is opened
XX-  *   dev_close:  called when a special file is closed
XX   *   dev_io:	 perform a read or write on a block or character device
XX   *   do_ioctl:	 perform the IOCTL system call
XX!  *   rw_dev:	 procedure that actually calls the kernel tasks
XX   *   rw_dev2:	 procedure that actually calls task for /dev/tty
XX   *   no_call:	 dummy procedure (e.g., used when device need not be opened)
XX-  *   tty_open:   a tty has been opened
XX-  *   tty_exit:   a process with pid=pgrp has exited.
XX   */
XX  
XX  #include "fs.h"
XX  #include <minix/com.h>
XX  #include "dev.h"
XX  #include "file.h"
XX--- 2,21 ----
XX   * Special character files also require I/O.  The routines for these are here.
XX   *
XX   * The entry points in this file are:
XX   *   dev_io:	 perform a read or write on a block or character device
XX+  *   dev_opcl:   perform generic device-specific processing for open & close
XX+  *   tty_open:   perform tty-specific processing for open
XX+  *   tty_close:  perform tty-specific processing for close
XX+  *   ctty_open:  perform controlling-tty-specific processing for open
XX+  *   ctty_close: perform controlling-tty-specific processing for close
XX   *   do_ioctl:	 perform the IOCTL system call
XX!  *   call_task:	 procedure that actually calls the kernel tasks
XX   *   rw_dev2:	 procedure that actually calls task for /dev/tty
XX   *   no_call:	 dummy procedure (e.g., used when device need not be opened)
XX   */
XX  
XX  #include "fs.h"
XX+ #include <minix/callnr.h>
XX  #include <minix/com.h>
XX  #include "dev.h"
XX  #include "file.h"
XX***************
XX*** 24,74 ****
XX  PRIVATE message dev_mess;
XX  PRIVATE major, minor, task;
XX  
XX! FORWARD void find_dev();
XX  
XX  /*===========================================================================*
XX-  *				dev_open				     *
XX-  *===========================================================================*/
XX- PUBLIC int dev_open(rip, mod, nonblock)
XX- struct inode *rip;		/* pointer to the inode */
XX- int mod;			/* how to open it */
XX- int nonblock;			/* TRUE if nonblocking open */
XX- {
XX- /* Special files may need special processing upon open. */
XX- 
XX-   dev_t dev;
XX- 
XX-   if (rip->i_count > 1) return(OK);
XX-   dev = (dev_t) rip->i_zone[0];	/* device type */
XX-   find_dev(dev);
XX-   dev_mess.DEVICE = dev;
XX-   (*dmap[major].dmap_open)(task, &dev_mess);
XX-   return(dev_mess.REP_STATUS);
XX- }
XX- 
XX- 
XX- /*===========================================================================*
XX-  *				dev_close				     *
XX-  *===========================================================================*/
XX- PUBLIC void dev_close(rip)
XX- struct inode *rip;		/* ptr to the inode */
XX- {
XX- /* This procedure can be used when a special file needs to be closed. */
XX- 
XX-   dev_t dev;			/* which device to close */
XX- 
XX-   if (rip->i_count > 1) return;
XX-   dev = (dev_t) rip->i_zone[0];
XX-   find_dev(dev);
XX-   (*dmap[major].dmap_close)(task, &dev_mess);
XX- }
XX- 
XX- 
XX- /*===========================================================================*
XX   *				dev_io					     *
XX   *===========================================================================*/
XX! PUBLIC int dev_io(rw_flag, nonblock, dev, pos, bytes, proc, buff)
XX! int rw_flag;			/* READING or WRITING */
XX  int nonblock;			/* TRUE if nonblocking op */
XX  dev_t dev;			/* major-minor device number */
XX  off_t pos;			/* byte position */
XX--- 26,38 ----
XX  PRIVATE message dev_mess;
XX  PRIVATE major, minor, task;
XX  
XX! FORWARD _PROTOTYPE( void find_dev, (Dev_t dev)				);
XX  
XX  /*===========================================================================*
XX   *				dev_io					     *
XX   *===========================================================================*/
XX! PUBLIC int dev_io(op, nonblock, dev, pos, bytes, proc, buff)
XX! int op;				/* DEV_READ, DEV_WRITE, DEV_IOCTL, etc. */
XX  int nonblock;			/* TRUE if nonblocking op */
XX  dev_t dev;			/* major-minor device number */
XX  off_t pos;			/* byte position */
XX***************
XX*** 78,88 ****
XX  {
XX  /* Read or write from a device.  The parameter 'dev' tells which one. */
XX  
XX!   find_dev(dev);
XX  
XX    /* Set up the message passed to task. */
XX!   dev_mess.m_type   = (rw_flag == READING ? DISK_READ :
XX! 		       rw_flag == WRITING ? DISK_WRITE : rw_flag);
XX    dev_mess.DEVICE   = (dev >> MINOR) & BYTE;
XX    dev_mess.POSITION = pos;
XX    dev_mess.PROC_NR  = proc;
XX--- 42,51 ----
XX  {
XX  /* Read or write from a device.  The parameter 'dev' tells which one. */
XX  
XX!   find_dev(dev);		/* load the variables major, minor, and task */
XX  
XX    /* Set up the message passed to task. */
XX!   dev_mess.m_type   = op;
XX    dev_mess.DEVICE   = (dev >> MINOR) & BYTE;
XX    dev_mess.POSITION = pos;
XX    dev_mess.PROC_NR  = proc;
XX***************
XX*** 94,106 ****
XX    (*dmap[major].dmap_rw)(task, &dev_mess);
XX  
XX    /* Task has completed.  See if call completed. */
XX!   if (dev_mess.REP_STATUS == SUSPEND) suspend(task);	/* suspend user */
XX  
XX    return(dev_mess.REP_STATUS);
XX  }
XX  
XX  
XX  /*===========================================================================*
XX   *				do_ioctl				     *
XX   *===========================================================================*/
XX  PUBLIC int do_ioctl()
XX--- 57,214 ----
XX    (*dmap[major].dmap_rw)(task, &dev_mess);
XX  
XX    /* Task has completed.  See if call completed. */
XX!   if (dev_mess.REP_STATUS == SUSPEND) {
XX! 	if (op == DEV_OPEN) task = XPOPEN;
XX! 	suspend(task);		/* suspend user */
XX!   }
XX  
XX    return(dev_mess.REP_STATUS);
XX  }
XX  
XX  
XX  /*===========================================================================*
XX+  *				dev_opcl				     *
XX+  *===========================================================================*/
XX+ PUBLIC void dev_opcl(task_nr, mess_ptr)
XX+ int task_nr;			/* which task */
XX+ message *mess_ptr;		/* message pointer */
XX+ {
XX+ /* Called from the dmap struct in table.c on opens & closes of special files.*/
XX+ 
XX+   int op;
XX+ 
XX+   op = mess_ptr->m_type;	/* save DEV_OPEN or DEV_CLOSE for later */
XX+   mess_ptr->DEVICE = (mess_ptr->DEVICE >> MINOR) & BYTE;
XX+   mess_ptr->PROC_NR = fp - fproc;
XX+ 
XX+   /* The interface could be greatly improved by using 2 functions,
XX+    * dev_open(Dev_t dev, Mode_t mode) and dev_close(Dev_t dev) instead of
XX+    * pseudo-message passing.  The conversion of the dev to major+minor+
XX+    * task+function would be done here (and there would be another level
XX+    * of function calls).  Checking the dev here (in find_dev) would stop
XX+    * main.c crashing badly from bad boot/root dev numbers.
XX+    *
XX+    * Other problems: the printer driver is not called for open/close
XX+    * processing.  It should be.
XX+    *
XX+    * find_dev should return ENODEV for bad devices and that result
XX+    * should be tested for and passed back in the message (or in the
XX+    * new function interface).  do_mount should respect this code, or
XX+    * whatever is returned by the driver, and not convert it to EINVAL.
XX+    *
XX+    * This reminds me that EINVAL is a funny code for umount to return
XX+    * when the dev is not mounted.
XX+    */
XX+   call_task(task_nr, mess_ptr);
XX+ 
XX+   /* Task has completed.  See if call completed. */
XX+   if (mess_ptr->REP_STATUS == SUSPEND) {
XX+ 	if (op == DEV_OPEN) task_nr = XPOPEN;
XX+ 	suspend(task_nr);	/* suspend user */
XX+   }
XX+ }
XX+ 
XX+ /*===========================================================================*
XX+  *				tty_open				     *
XX+  *===========================================================================*/
XX+ PUBLIC void tty_open(task_nr, mess_ptr)
XX+ int task_nr;
XX+ message *mess_ptr;
XX+ {
XX+ /* This procedure is called from the dmap struct in table.c on tty opens. */
XX+   
XX+   int r, ldr, ctl;
XX+   dev_t dev;
XX+   int ncount, proc;
XX+ 
XX+   ldr = fp && (fp->fp_pid == fp->fp_pgrp);   /* is this a process grp leader?*/
XX+   dev = (dev_t) mess_ptr->DEVICE;
XX+   ncount = mess_ptr->COUNT;
XX+   proc = fp - fproc;
XX+   r = dev_io(DEV_OPEN, mode, dev, (off_t) ldr, ncount, proc, NIL_PTR);
XX+ 
XX+   find_dev(dev);
XX+   ctl = (major << MAJOR) | (r << MINOR);
XX+   if ((! fp->fs_tty) && (r != NO_CTL_TTY)) fp->fs_tty = ctl;
XX+ }
XX+ 
XX+ 
XX+ /*===========================================================================*
XX+  *				tty_close				     *
XX+  *===========================================================================*/
XX+ PUBLIC void tty_close(task_nr, mess_ptr)
XX+ int task_nr;
XX+ message *mess_ptr;
XX+ {
XX+ /* This procedure is called from the dmap struct in table.c on tty closes.
XX+  * When a process exits, MM calls FS to close all files, including stdin,
XX+  * stdout, and stderr.  For these calls, who = MM, so we use fp-fproc in 
XX+  * dev_io.
XX+  */
XX+ 
XX+   int r, ldr;
XX+   dev_t dev;
XX+   struct fproc *rfp;
XX+   int ncount, proc;
XX+   struct inode *ino;
XX+ 
XX+   ncount=0;
XX+   for (r=0; r<OPEN_MAX; r++) {
XX+ 	if (r == fd) continue;
XX+ 	if (fproc[fp-fproc].fp_filp[r] == NIL_FILP) continue;
XX+ 	ino=fproc[fp-fproc].fp_filp[r]->filp_ino;
XX+ 	if (ino == fproc[fp-fproc].fp_filp[fd]->filp_ino) ncount++;
XX+   }
XX+   ldr = (ncount == 0);   /* Is this the last ctty file to close? */
XX+   dev = (dev_t) mess_ptr->DEVICE;
XX+   ncount= mess_ptr->COUNT;
XX+   proc = fp -fproc;
XX+   r = dev_io(DEV_CLOSE, mode, dev, (off_t) ldr, ncount, proc, NIL_PTR);
XX+   if ((r == NO_CTL_TTY) && (ldr)) {
XX+ 	for (rfp = &fproc[INIT_PROC_NR + 1]; rfp < &fproc[NR_PROCS]; rfp++) {
XX+ 		if (rfp->fs_tty == dev) rfp->fs_tty = 0;
XX+ 	}
XX+   }
XX+ }
XX+ 
XX+ 
XX+ /*===========================================================================*
XX+  *				ctty_open				     *
XX+  *===========================================================================*/
XX+ PUBLIC void ctty_open(task_nr, mess_ptr)
XX+ int task_nr;
XX+ message *mess_ptr;
XX+ {
XX+ /* This procedure is called from the dmap struct in table.c on controlling
XX+  * tty opens.
XX+  */
XX+   
XX+   if (fp->fs_tty == 0) { /* no controlling tty present; deny open */
XX+ 	mess_ptr->REP_STATUS = ENXIO;
XX+ 	return;
XX+   }
XX+ }
XX+ 
XX+ 
XX+ /*===========================================================================*
XX+  *				ctty_close				     *
XX+  *===========================================================================*/
XX+ PUBLIC void ctty_close(task_nr, mess_ptr)
XX+ int task_nr;
XX+ message *mess_ptr;
XX+ {
XX+ /* This procedure is called from the dmap struct in table.c on controlling
XX+  * tty closes.
XX+  * When a process exits, MM calls FS to close all files, including stdin,
XX+  * stdout, and stderr.  For these calls, who = MM, so we use fp-fproc in 
XX+  * dev_io.
XX+  */
XX+ 
XX+   mess_ptr->REP_STATUS = OK;
XX+ }
XX+ 
XX+ 
XX+ /*===========================================================================*
XX   *				do_ioctl				     *
XX   *===========================================================================*/
XX  PUBLIC int do_ioctl()
XX***************
XX*** 109,131 ****
XX  
XX    struct filp *f;
XX    register struct inode *rip;
XX  
XX    if ( (f = get_filp(ls_fd)) == NIL_FILP) return(err_code);
XX    rip = f->filp_ino;		/* get inode pointer */
XX    if ( (rip->i_mode & I_TYPE) != I_CHAR_SPECIAL) return(ENOTTY);
XX!   find_dev(rip->i_zone[0]);
XX  
XX!   dev_mess.m_type  = TTY_IOCTL;
XX    dev_mess.PROC_NR = who;
XX    dev_mess.TTY_LINE = minor;	
XX!   dev_mess.TTY_REQUEST = m.TTY_REQUEST;
XX!   dev_mess.TTY_SPEK = m.TTY_SPEK;
XX!   dev_mess.TTY_FLAGS = m.TTY_FLAGS;
XX    /* Call the task. */
XX    (*dmap[major].dmap_rw)(task, &dev_mess);
XX  
XX    /* Task has completed.  See if call completed. */
XX!   if (dev_mess.m_type == SUSPEND) suspend(task);  /* User must be suspended. */
XX    m1.TTY_SPEK = dev_mess.TTY_SPEK;	/* erase and kill */
XX    m1.TTY_FLAGS = dev_mess.TTY_FLAGS;	/* flags */
XX    return(dev_mess.REP_STATUS);
XX--- 217,242 ----
XX  
XX    struct filp *f;
XX    register struct inode *rip;
XX+   dev_t dev;
XX  
XX    if ( (f = get_filp(ls_fd)) == NIL_FILP) return(err_code);
XX    rip = f->filp_ino;		/* get inode pointer */
XX    if ( (rip->i_mode & I_TYPE) != I_CHAR_SPECIAL) return(ENOTTY);
XX!   dev = (dev_t) rip->i_zone[0];
XX!   find_dev(dev);
XX  
XX!   dev_mess= m;
XX! 
XX!   dev_mess.m_type  = DEV_IOCTL;
XX    dev_mess.PROC_NR = who;
XX    dev_mess.TTY_LINE = minor;	
XX! 
XX    /* Call the task. */
XX    (*dmap[major].dmap_rw)(task, &dev_mess);
XX  
XX    /* Task has completed.  See if call completed. */
XX!   if (dev_mess.REP_STATUS == SUSPEND) suspend(task);
XX! 					/* User must be suspended. */
XX    m1.TTY_SPEK = dev_mess.TTY_SPEK;	/* erase and kill */
XX    m1.TTY_FLAGS = dev_mess.TTY_FLAGS;	/* flags */
XX    return(dev_mess.REP_STATUS);
XX***************
XX*** 142,156 ****
XX  
XX    major = (dev >> MAJOR) & BYTE;	/* major device number */
XX    minor = (dev >> MINOR) & BYTE;	/* minor device number */
XX!   if (major == 0 || major >= max_major) panic("bad major dev", major);
XX    task = dmap[major].dmap_task;	/* which task services the device */
XX  }
XX  
XX  
XX  /*===========================================================================*
XX!  *				rw_dev					     *
XX   *===========================================================================*/
XX! PUBLIC void rw_dev(task_nr, mess_ptr)
XX  int task_nr;			/* which task to call */
XX  message *mess_ptr;		/* pointer to message for task */
XX  {
XX--- 253,270 ----
XX  
XX    major = (dev >> MAJOR) & BYTE;	/* major device number */
XX    minor = (dev >> MINOR) & BYTE;	/* minor device number */
XX!   if (major == 0 || major >= max_major) {
XX! 	major = NULL_MAJOR;
XX! 	minor = NULL_DEV;
XX!   }
XX    task = dmap[major].dmap_task;	/* which task services the device */
XX  }
XX  
XX  
XX  /*===========================================================================*
XX!  *				call_task				     *
XX   *===========================================================================*/
XX! PUBLIC void call_task(task_nr, mess_ptr)
XX  int task_nr;			/* which task to call */
XX  message *mess_ptr;		/* pointer to message for task */
XX  {
XX***************
XX*** 159,190 ****
XX   */
XX  
XX    int r;
XX!   message m;
XX  
XX    while ((r = sendrec(task_nr, mess_ptr)) == ELOCKED) {
XX  	/* sendrec() failed to avoid deadlock. The task 'task_nr' is
XX  	 * trying to send a REVIVE message for an earlier request.
XX  	 * Handle it and go try again.
XX  	 */
XX! 	if (receive(task_nr, &m) != OK) panic("rw_dev: can't receive", NO_NUM);
XX  
XX  	/* If we're trying to send a cancel message to a task which has just
XX  	 * sent a completion reply, ignore the reply and abort the cancel
XX  	 * request. The caller will do the revive for the process. 
XX  	 */
XX! 	if (mess_ptr->m_type == CANCEL && m.REP_PROC_NR == mess_ptr->PROC_NR)
XX  		return;
XX! 	revive(m.REP_PROC_NR, m.REP_STATUS);
XX    }
XX!   if (r != OK) panic("rw_dev: can't send", NO_NUM);
XX  }
XX  
XX  
XX  /*===========================================================================*
XX   *				rw_dev2					     *
XX   *===========================================================================*/
XX! PUBLIC void rw_dev2(dummy, mess_ptr)
XX! int dummy;			/* not used - for compatibility with rw_dev() */
XX  message *mess_ptr;		/* pointer to message for task */
XX  {
XX  /* This routine is only called for one device, namely /dev/tty.  Its job
XX--- 273,306 ----
XX   */
XX  
XX    int r;
XX!   message local_m;
XX  
XX    while ((r = sendrec(task_nr, mess_ptr)) == ELOCKED) {
XX  	/* sendrec() failed to avoid deadlock. The task 'task_nr' is
XX  	 * trying to send a REVIVE message for an earlier request.
XX  	 * Handle it and go try again.
XX  	 */
XX! 	if (receive(task_nr, &local_m) != OK)
XX! 		panic("call_task: can't receive", NO_NUM);
XX  
XX  	/* If we're trying to send a cancel message to a task which has just
XX  	 * sent a completion reply, ignore the reply and abort the cancel
XX  	 * request. The caller will do the revive for the process. 
XX  	 */
XX! 	if (mess_ptr->m_type == CANCEL
XX! 	    && local_m.REP_PROC_NR == mess_ptr->PROC_NR)
XX  		return;
XX! 	revive(local_m.REP_PROC_NR, local_m.REP_STATUS);
XX    }
XX!   if (r != OK) panic("call_task: can't send", NO_NUM);
XX  }
XX  
XX  
XX  /*===========================================================================*
XX   *				rw_dev2					     *
XX   *===========================================================================*/
XX! PUBLIC void rw_dev2(task_nr, mess_ptr)
XX! int task_nr;			/* not used - for compatibility with dmap_t */
XX  message *mess_ptr;		/* pointer to message for task */
XX  {
XX  /* This routine is only called for one device, namely /dev/tty.  Its job
XX***************
XX*** 192,208 ****
XX   * major/minor pair for /dev/tty itself.
XX   */
XX  
XX!   int task_nr, major_device;
XX! 
XX!   if (fp->fs_tty == 0) {
XX! 	mess_ptr->DEVICE = NULL_DEV;
XX! 	rw_dev(MEM, mess_ptr);
XX  	return;
XX    }
XX    major_device = (fp->fs_tty >> MAJOR) & BYTE;
XX    task_nr = dmap[major_device].dmap_task;	/* task for controlling tty */
XX    mess_ptr->DEVICE = (fp->fs_tty >> MINOR) & BYTE;
XX!   rw_dev(task_nr, mess_ptr);
XX  }
XX  
XX  
XX--- 308,327 ----
XX   * major/minor pair for /dev/tty itself.
XX   */
XX  
XX!   int major_device;
XX!  
XX!   if (fp->fs_tty == 0) { /* no controlling tty present; deny open */
XX! 	if (mess_ptr->m_type == DEV_READ) {
XX! 	    mess_ptr->REP_STATUS = 0; 	/* 0 bytes read; EOF */
XX! 	} else {
XX! 	    mess_ptr->REP_STATUS = EIO;
XX! 	}
XX  	return;
XX    }
XX    major_device = (fp->fs_tty >> MAJOR) & BYTE;
XX    task_nr = dmap[major_device].dmap_task;	/* task for controlling tty */
XX    mess_ptr->DEVICE = (fp->fs_tty >> MINOR) & BYTE;
XX!   call_task(task_nr, mess_ptr);
XX  }
XX  
XX  
XX***************
XX*** 210,216 ****
XX   *				no_call					     *
XX   *===========================================================================*/
XX  PUBLIC void no_call(task_nr, m_ptr)
XX! int task_nr;			/* which task */
XX  message *m_ptr;			/* message pointer */
XX  {
XX  /* Null operation always succeeds. */
XX--- 329,335 ----
XX   *				no_call					     *
XX   *===========================================================================*/
XX  PUBLIC void no_call(task_nr, m_ptr)
XX! int task_nr;			/* not used - for compatibility with dmap_t */
XX  message *m_ptr;			/* message pointer */
XX  {
XX  /* Null operation always succeeds. */
XX***************
XX*** 218,277 ****
XX    m_ptr->REP_STATUS = OK;
XX  }
XX  
XX  /*===========================================================================*
XX!  *				tty_open				     *
XX   *===========================================================================*/
XX! PUBLIC void tty_open(task_nr, mess_ptr)
XX! int task_nr;
XX! message *mess_ptr;
XX  {
XX!   register struct fproc *rfp;
XX!   int maj;
XX  
XX!   mess_ptr->REP_STATUS = OK;
XX  
XX!   /* Is this a process group leader? */
XX!   if (fp->fp_pid != fp->fp_pgrp) return;
XX  
XX!   /* Is there a current control terminal? */
XX!   if (fp->fs_tty != 0) return;
XX  
XX!   /* Is this one already allocated to another process? */
XX!   for (rfp = &fproc[INIT_PROC_NR + 1]; rfp < &fproc[NR_PROCS]; rfp++)
XX! 	if (rfp->fs_tty == mess_ptr->DEVICE) return;
XX  
XX!   /* All conditions satisfied.  Make this a control terminal. */
XX!   fp->fs_tty = mess_ptr->DEVICE;
XX!   maj = (mess_ptr->DEVICE >> MAJOR) & BYTE;
XX!   mess_ptr->DEVICE = (mess_ptr->DEVICE >> MINOR) & BYTE;
XX!   mess_ptr->m_type = TTY_SETPGRP;
XX!   mess_ptr->PROC_NR = who;
XX!   mess_ptr->TTY_PGRP = who;
XX!   (*dmap[maj].dmap_rw)(task_nr, mess_ptr);
XX  }
XX  
XX  /*===========================================================================*
XX!  *				tty_exit				     *
XX   *===========================================================================*/
XX! PUBLIC int tty_exit()
XX  {
XX! /* Process group leader exits. Remove its control terminal
XX!  * from any processes currently running.
XX   */
XX  
XX!   register struct fproc *rfp;
XX!   register dev_t ttydev;
XX  
XX!   ttydev = fp->fs_tty;
XX!   for (rfp = &fproc[INIT_PROC_NR + 1]; rfp < &fproc[NR_PROCS]; rfp++)
XX! 	if (rfp->fs_tty == ttydev)
XX! 		rfp->fs_tty = 0;
XX!   /* Inform the terminal driver. */
XX!   find_dev(ttydev);
XX!   dev_mess.m_type = TTY_SETPGRP;
XX!   dev_mess.DEVICE = (ttydev >> MINOR) & BYTE;
XX!   dev_mess.PROC_NR = who;
XX!   dev_mess.TTY_PGRP = 0;
XX!   (*dmap[major].dmap_rw)(task, &dev_mess);
XX!   return(OK);
XX  }
XX--- 337,457 ----
XX    m_ptr->REP_STATUS = OK;
XX  }
XX  
XX+ 
XX+ #if NETWORKING_ENABLED
XX  /*===========================================================================*
XX!  *				net_open				     *
XX   *===========================================================================*/
XX! PUBLIC void net_open(task_nr, mess_ptr)
XX! int task_nr;			/* task to send message to */
XX! message *mess_ptr;		/* pointer to message to send */
XX  {
XX! /* network files may need special processing upon open. */
XX  
XX!   dev_t dev;
XX!   struct inode *rip, *nrip;
XX!   int result;
XX!   int ncount, proc;
XX  
XX!   rip= fp->fp_filp[fd]->filp_ino; 
XX  
XX!   nrip= alloc_inode(rip->i_dev, ALL_MODES | I_CHAR_SPECIAL);
XX!   if (nrip == NIL_INODE) {
XX! 	mess_ptr->REP_STATUS= err_code;
XX! 	return;
XX!   }
XX  
XX!   dev = (dev_t) mess_ptr->DEVICE;
XX!   ncount= mess_ptr->COUNT;
XX!   proc = fp - fproc;
XX!   result= dev_io(DEV_OPEN, mode, dev, (off_t) 0, ncount, proc, NIL_PTR);
XX  
XX!   if (result < 0)
XX!   {
XX! 	put_inode(nrip);
XX! 	return;
XX!   }
XX! 
XX!   dev= rip->i_zone[0]; 
XX!   dev= (dev & ~(BYTE << MINOR)) | ((result & BYTE) << MINOR); 
XX! 
XX!   nrip->i_zone[0]= dev;
XX!   put_inode (rip);
XX!   fp->fp_filp[fd]->filp_ino= nrip;
XX!   mess_ptr->REP_STATUS= OK;
XX  }
XX  
XX  /*===========================================================================*
XX!  *				net_rw					     *
XX   *===========================================================================*/
XX! PUBLIC void net_rw(task_nr, mess_ptr)
XX! int task_nr;			/* which task to call */
XX! message *mess_ptr;		/* pointer to message for task */
XX  {
XX! /* All file system I/O ultimately comes down to I/O on major/minor device
XX!  * pairs.  These lead to calls on the following routines via the dmap table.
XX   */
XX  
XX!   int r, proc_nr;
XX!   message m;
XX  
XX!   do {
XX! 	r = send (task_nr, mess_ptr);
XX! 	if (r != ELOCKED) break;
XX! 
XX! 	if (receive(task_nr, &m) != OK) panic("net_rw: can't receive", NO_NUM);
XX! 	if (mess_ptr->m_type == CANCEL && m.REP_PROC_NR == mess_ptr->PROC_NR)
XX! 		return;
XX! 
XX! 	if (m.m_type != REVIVE)	{
XX! 		printf("%s, %d: got a strange message (m_type == %d)\n",
XX! 			__FILE__, __LINE__, m.m_type);
XX! 		continue;
XX! 	}
XX! 	revive(m.REP_PROC_NR, m.REP_STATUS);
XX!   } while (TRUE);
XX! 
XX!   if (r != OK) {
XX! 	printf("send(%d, ...)= %d\r\n", task_nr, r);
XX! 	panic("net_rw: can't send", NO_NUM);
XX!   }
XX! 
XX!   proc_nr= mess_ptr->PROC_NR;
XX!   while (TRUE) {
XX! 	r = receive (task_nr, mess_ptr);
XX! 	
XX! 	if (r != OK) panic("net_rw: can't receive", NO_NUM);
XX! 
XX!   	if (mess_ptr->REP_PROC_NR == proc_nr)
XX! 		return;
XX! 
XX! 	if (mess_ptr->m_type != REVIVE) {
XX! 		printf("%s, %d: got a strange message for %d (m_type == %d)\n",
XX! 		  __FILE__, __LINE__, mess_ptr->REP_PROC_NR, mess_ptr->m_type);
XX! 		printf("REP_PROC_NR= %d, expecting %d\n",mess_ptr->REP_PROC_NR,
XX! 			proc_nr);
XX! 		continue;
XX! 	}
XX! 	revive(mess_ptr->REP_PROC_NR, mess_ptr->REP_STATUS);
XX!   }
XX  }
XX+ 
XX+ PUBLIC void net_close (task_nr, mess_ptr)
XX+ int task_nr;
XX+ message *mess_ptr;
XX+ {
XX+   dev_t dev;
XX+   int ncount, proc;
XX+ 
XX+   dev = (dev_t) mess_ptr->DEVICE;
XX+   ncount= mess_ptr->COUNT;
XX+   proc = fp - fproc;
XX+   if (ncount) {
XX+ 	/* more users present */
XX+ 	mess_ptr->REP_STATUS= OK;
XX+ 	return;
XX+   }
XX+   (void) dev_io(DEV_CLOSE, mode, dev, (off_t) 0, ncount, proc, NIL_PTR);
XX+ }
XX+ #endif
XX+ 
X/
Xecho x - file.h.d
Xsed '/^X/s///' > file.h.d << '/'
XX*** /home/top/ast/minix/1.5/fs/file.h  crc=09749    518	Sat Apr 21 22:26:20 1990
XX--- /home/top/ast/minix/1.6.25/fs/file.h  crc=50469   1014	Tue Nov  3 21:19:12 1992
XX***************
XX*** 11,13 ****
XX--- 11,26 ----
XX  } filp[NR_FILPS];
XX  
XX  #define NIL_FILP (struct filp *) 0	/* indicates absence of a filp slot */
XX+ 
XX+ 
XX+ 
XX+ /* This is the file locking table.  Like the filp table, it points to the
XX+  * inode table, however, in this case to achieve advisory locking.
XX+  */
XX+ EXTERN struct file_lock {
XX+   short lock_type;		/* F_RDLOCK or F_WRLOCK; 0 means unused slot */
XX+   pid_t lock_pid;		/* pid of the process holding the lock */
XX+   struct inode *lock_inode;	/* pointer to the inode locked */
XX+   off_t lock_first;		/* offset of first byte locked */
XX+   off_t lock_last;		/* offset of last byte locked */
XX+ } file_lock[NR_LOCKS];
X/
Xecho x - filedes.c.d
Xsed '/^X/s///' > filedes.c.d << '/'
XX*** /home/top/ast/minix/1.5/fs/filedes.c  crc=22121   3203	Sat Apr 21 22:26:20 1990
XX--- /home/top/ast/minix/1.6.25/fs/filedes.c  crc=23652   3279	Tue Nov  3 21:19:12 1992
XX***************
XX*** 77,87 ****
XX   *===========================================================================*/
XX  PUBLIC struct filp *find_filp(rip, bits)
XX  register struct inode *rip;	/* inode referred to by the filp to be found */
XX! int bits;			/* mode of the filp to be found (RWX bits) */
XX  {
XX  /* Find a filp slot that refers to the inode 'rip' in a way as described
XX   * by the mode bit 'bits'. Used for determining whether somebody is still
XX!  * interested in either end of a pipe; other applications are conceivable.
XX   * Like 'get_fd' it performs its job by linear search through the filp table.
XX   */
XX  
XX--- 77,88 ----
XX   *===========================================================================*/
XX  PUBLIC struct filp *find_filp(rip, bits)
XX  register struct inode *rip;	/* inode referred to by the filp to be found */
XX! Mode_t bits;			/* mode of the filp to be found (RWX bits) */
XX  {
XX  /* Find a filp slot that refers to the inode 'rip' in a way as described
XX   * by the mode bit 'bits'. Used for determining whether somebody is still
XX!  * interested in either end of a pipe.  Also used when opening a FIFO to
XX!  * find partners to share a filp field with (to shared the file position).
XX   * Like 'get_fd' it performs its job by linear search through the filp table.
XX   */
XX  
X/
Xecho x - fproc.h.d
Xsed '/^X/s///' > fproc.h.d << '/'
XX*** /home/top/ast/minix/1.5/fs/fproc.h  crc=33856   1507	Sat Apr 21 22:26:20 1990
XX--- /home/top/ast/minix/1.6.25/fs/fproc.h  crc=38491   1648	Tue Nov  3 21:19:12 1992
XX***************
XX*** 17,27 ****
XX    int fp_fd;			/* place to save fd if rd/wr can't finish */
XX    char *fp_buffer;		/* place to save buffer if rd/wr can't finish*/
XX    int  fp_nbytes;		/* place to save bytes if rd/wr can't finish */
XX    char fp_suspended;		/* set to indicate process hanging */
XX    char fp_revived;		/* set to indicate process being revived */
XX    char fp_task;			/* which task is proc suspended on */
XX!   int fp_pid;			/* process id */
XX!   int fp_pgrp;			/* process group */
XX  } fproc[NR_PROCS];
XX  
XX  /* Field values. */
XX--- 17,29 ----
XX    int fp_fd;			/* place to save fd if rd/wr can't finish */
XX    char *fp_buffer;		/* place to save buffer if rd/wr can't finish*/
XX    int  fp_nbytes;		/* place to save bytes if rd/wr can't finish */
XX+   int  fp_cum_io_partial;	/* partial byte count if rd/wr can't finish */
XX    char fp_suspended;		/* set to indicate process hanging */
XX    char fp_revived;		/* set to indicate process being revived */
XX    char fp_task;			/* which task is proc suspended on */
XX!   pid_t fp_pid;			/* process id */
XX!   pid_t fp_pgrp;		/* process group */
XX!   long fp_cloexec;		/* bit map for POSIX Table 6-2 FD_CLOEXEC */
XX  } fproc[NR_PROCS];
XX  
XX  /* Field values. */
X/
Xecho x - fs.h.d
Xsed '/^X/s///' > fs.h.d << '/'
XX*** /home/top/ast/minix/1.5/fs/fs.h  crc=25637    635	Sat Apr 21 22:26:20 1990
XX--- /home/top/ast/minix/1.6.25/fs/fs.h  crc=40605    845	Tue Nov  3 21:19:13 1992
XX***************
XX*** 5,21 ****
XX  #define _MINIX             1	/* tell headers to include MINIX stuff */
XX  #define _SYSTEM            1	/* tell headers that this is the kernel */
XX  
XX  /* The following are so basic, all the *.c files get them automatically. */
XX  #include <minix/config.h>	/* MUST be first */
XX  #include <minix/const.h>
XX  #include <minix/type.h>
XX  
XX- #include <sys/types.h>
XX  #include <limits.h>
XX  #include <errno.h>
XX  
XX  #include "const.h"
XX  #include "type.h"
XX  #include "proto.h"
XX  #include "glo.h"
XX- 
XX--- 5,28 ----
XX  #define _MINIX             1	/* tell headers to include MINIX stuff */
XX  #define _SYSTEM            1	/* tell headers that this is the kernel */
XX  
XX+ /* The ANSI C namespace pollution rules forbid the use of sendrec etc. */
XX+ #define send _send
XX+ #define receive _receive
XX+ #define sendrec _sendrec
XX+ 
XX  /* The following are so basic, all the *.c files get them automatically. */
XX  #include <minix/config.h>	/* MUST be first */
XX+ #include <ansi.h>		/* MUST be second */
XX+ #include <sys/types.h>
XX  #include <minix/const.h>
XX  #include <minix/type.h>
XX  
XX  #include <limits.h>
XX  #include <errno.h>
XX  
XX+ #include <minix/syslib.h>
XX+ 
XX  #include "const.h"
XX  #include "type.h"
XX  #include "proto.h"
XX  #include "glo.h"
X/
Xecho x - glo.h.d
Xsed '/^X/s///' > glo.h.d << '/'
XX*** /home/top/ast/minix/1.5/fs/glo.h  crc=64334   1492	Sat Apr 21 22:26:20 1990
XX--- /home/top/ast/minix/1.6.25/fs/glo.h  crc=00225   1698	Tue Nov  3 21:19:13 1992
XX***************
XX*** 9,14 ****
XX--- 9,15 ----
XX  EXTERN int super_user;		/* 1 if caller is super_user, else 0 */
XX  EXTERN int dont_reply;		/* normally 0; set to 1 to inhibit reply */
XX  EXTERN int susp_count;		/* number of procs suspended on pipe */
XX+ EXTERN int nr_locks;		/* number of locks currently in place */
XX  EXTERN int reviving;		/* number of pipe processes to be revived */
XX  EXTERN off_t rdahedpos;		/* position to read ahead */
XX  EXTERN struct inode *rdahed_inode;	/* pointer to inode to read ahead */
XX***************
XX*** 26,33 ****
XX  EXTERN int rdwt_err;		/* status of last disk i/o request */
XX  
XX  /* Data which needs initialization. */
XX! typedef unsigned short u16_t;	/* belongs in h/type.h */
XX! extern u16_t data_org[INFO + 2];/* origin and sizes of init */
XX  				/* belongs in h/build.h */
XX! extern int (*call_vector[])();	/* table of system calls handled by FS */
XX! extern max_major;		/* maximum major device (+ 1) */
XX--- 27,37 ----
XX  EXTERN int rdwt_err;		/* status of last disk i/o request */
XX  
XX  /* Data which needs initialization. */
XX! extern unsigned short data_org[INFO + 2]; /* origin and sizes of init */
XX  				/* belongs in h/build.h */
XX! extern _PROTOTYPE (int (*call_vector[]), (void) );
XX! 				/* table of system calls handled by FS */
XX! extern int max_major;		/* maximum major device (+ 1) */
XX! 
XX! extern char dot1[2];   /* dot1 (&dot1[0]) and dot2 (&dot2[0]) have a special */
XX! extern char dot2[3];   /* meaning to search_dir: no access permission check. */
X/
Xecho x - inode.c.d
Xsed '/^X/s///' > inode.c.d << '/'
XX*** /home/top/ast/minix/1.5/fs/inode.c  crc=64755   8695	Sat Apr 21 22:26:20 1990
XX--- /home/top/ast/minix/1.6.25/fs/inode.c  crc=50878  14063	Sun Nov 15 23:16:57 1992
XX***************
XX*** 10,20 ****
XX   *   free_inode:   mark an inode as available for a new file
XX   *   update_times: update atime, ctime, and mtime
XX   *   rw_inode:	   read a disk block and extract an inode, or corresp. write
XX   *   dup_inode:	   indicate that someone else is using an inode table entry
XX   */
XX  
XX  #include "fs.h"
XX- #include <sys/stat.h>
XX  #include <minix/boot.h>
XX  #include "buf.h"
XX  #include "file.h"
XX--- 10,21 ----
XX   *   free_inode:   mark an inode as available for a new file
XX   *   update_times: update atime, ctime, and mtime
XX   *   rw_inode:	   read a disk block and extract an inode, or corresp. write
XX+  *   old_icopy:	   copy to/from in-core inode struct and disk inode (V1.x)
XX+  *   new_icopy:	   copy to/from in-core inode struct and disk inode (V2.x)
XX   *   dup_inode:	   indicate that someone else is using an inode table entry
XX   */
XX  
XX  #include "fs.h"
XX  #include <minix/boot.h>
XX  #include "buf.h"
XX  #include "file.h"
XX***************
XX*** 22,33 ****
XX  #include "inode.h"
XX  #include "super.h"
XX  
XX  /*===========================================================================*
XX   *				get_inode				     *
XX   *===========================================================================*/
XX  PUBLIC struct inode *get_inode(dev, numb)
XX  dev_t dev;			/* device on which inode resides */
XX! ino_t numb;			/* inode number */
XX  {
XX  /* Find a slot in the inode table, load the specified inode into it, and
XX   * return a pointer to the slot.  If 'dev' == NO_DEV, just return a free slot.
XX--- 23,40 ----
XX  #include "inode.h"
XX  #include "super.h"
XX  
XX+ FORWARD _PROTOTYPE( void old_icopy, (struct inode *rip, d1_inode *dip,
XX+ 						int direction, int norm));
XX+ FORWARD _PROTOTYPE( void new_icopy, (struct inode *rip, d2_inode *dip,
XX+ 						int direction, int norm));
XX+ 
XX+ 
XX  /*===========================================================================*
XX   *				get_inode				     *
XX   *===========================================================================*/
XX  PUBLIC struct inode *get_inode(dev, numb)
XX  dev_t dev;			/* device on which inode resides */
XX! int numb;			/* inode number (ANSI: may not be unshort) */
XX  {
XX  /* Find a slot in the inode table, load the specified inode into it, and
XX   * return a pointer to the slot.  If 'dev' == NO_DEV, just return a free slot.
XX***************
XX*** 44,51 ****
XX  			rip->i_count++;
XX  			return(rip);	/* (dev, numb) found */
XX  		}
XX! 	} else
XX  		xp = rip;	/* remember this free slot for later */
XX    }
XX  
XX    /* Inode we want is not currently in use.  Did we find a free slot? */
XX--- 51,59 ----
XX  			rip->i_count++;
XX  			return(rip);	/* (dev, numb) found */
XX  		}
XX! 	} else {
XX  		xp = rip;	/* remember this free slot for later */
XX+ 	}
XX    }
XX  
XX    /* Inode we want is not currently in use.  Did we find a free slot? */
XX***************
XX*** 76,92 ****
XX   * return it to the pool of available inodes.
XX   */
XX  
XX    if (rip == NIL_INODE) return;	/* checking here is easier than in caller */
XX    if (--rip->i_count == 0) {	/* i_count == 0 means no one is using it now */
XX  	if ((rip->i_nlinks & BYTE) == 0) {
XX  		/* i_nlinks == 0 means free the inode. */
XX  		truncate(rip);	/* return all the disk blocks */
XX  		rip->i_mode = I_NOT_ALLOC;	/* clear I_TYPE field */
XX! 		free_inode(rip->i_dev, rip->i_num);
XX  	}
XX- 	else if (rip->i_pipe == I_PIPE) truncate(rip);
XX  	rip->i_pipe = NO_PIPE;  /* should always be cleared */
XX- 
XX  	if (rip->i_dirt == DIRTY) rw_inode(rip, WRITING);
XX    }
XX  }
XX--- 84,103 ----
XX   * return it to the pool of available inodes.
XX   */
XX  
XX+   int inum;
XX+ 
XX    if (rip == NIL_INODE) return;	/* checking here is easier than in caller */
XX    if (--rip->i_count == 0) {	/* i_count == 0 means no one is using it now */
XX  	if ((rip->i_nlinks & BYTE) == 0) {
XX  		/* i_nlinks == 0 means free the inode. */
XX  		truncate(rip);	/* return all the disk blocks */
XX  		rip->i_mode = I_NOT_ALLOC;	/* clear I_TYPE field */
XX! 		inum = (int) rip->i_num;	/* do not pass an unshort */
XX! 		free_inode(rip->i_dev, inum);
XX! 	} else {
XX! 		if (rip->i_pipe == I_PIPE) truncate(rip);
XX  	}
XX  	rip->i_pipe = NO_PIPE;  /* should always be cleared */
XX  	if (rip->i_dirt == DIRTY) rw_inode(rip, WRITING);
XX    }
XX  }
XX***************
XX*** 102,114 ****
XX  
XX    register struct inode *rip;
XX    register struct super_block *sp;
XX!   int major, minor;
XX!   ino_t numb;
XX!   bit_nr b;
XX  
XX    /* Acquire an inode from the bit map. */
XX!   sp = get_super(dev);		/* get pointer to super_block */
XX!   b=alloc_bit(sp->s_imap,(bit_nr)sp->s_ninodes+1, sp->s_imap_blocks,(bit_nr)0);
XX    if (b == NO_BIT) {
XX  	err_code = ENFILE;
XX  	major = (int) (sp->s_dev >> MAJOR) & BYTE;
XX--- 113,130 ----
XX  
XX    register struct inode *rip;
XX    register struct super_block *sp;
XX!   int major, minor, inumb;
XX!   bit_t b, bit;
XX  
XX+   sp = get_super(dev);	/* get pointer to super_block */
XX+   if (sp->s_rd_only) {	/* can't allocate an inode on a read only device. */
XX+ 	err_code = EROFS;
XX+ 	return(NIL_INODE);
XX+   }
XX+ 
XX    /* Acquire an inode from the bit map. */
XX!   bit = sp->s_isearch;		/* start at first unused inode */
XX!   b = alloc_bit(sp->s_imap, (bit_t)sp->s_ninodes+1, sp->s_imap_blocks, bit);
XX    if (b == NO_BIT) {
XX  	err_code = ENFILE;
XX  	major = (int) (sp->s_dev >> MAJOR) & BYTE;
XX***************
XX*** 117,135 ****
XX  		sp->s_dev == ROOT_DEV ? "root " : "", major, minor);
XX  	return(NIL_INODE);
XX    }
XX!   numb = (ino_t) b;
XX  
XX    /* Try to acquire a slot in the inode table. */
XX!   if ( (rip = get_inode(NO_DEV, numb)) == NIL_INODE) {
XX  	/* No inode table slots available.  Free the inode just allocated. */
XX  	free_bit(sp->s_imap, b);
XX    } else {
XX  	/* An inode slot is available. Put the inode just allocated into it. */
XX! 	rip->i_mode = bits;
XX! 	rip->i_nlinks = (nlink_t) 0;
XX! 	rip->i_uid = fp->fp_effuid;
XX! 	rip->i_gid = fp->fp_effgid;
XX! 	rip->i_dev = dev;	/* was provisionally set to NO_DEV */
XX  
XX  	/* Fields not cleared already are cleared in wipe_inode().  They have
XX  	 * been put there because truncate() needs to clear the same fields if
XX--- 133,155 ----
XX  		sp->s_dev == ROOT_DEV ? "root " : "", major, minor);
XX  	return(NIL_INODE);
XX    }
XX!   sp->s_isearch = b;		/* next time start here */
XX!   inumb = (int) b;		/* be careful not to pass unshort as param */
XX  
XX    /* Try to acquire a slot in the inode table. */
XX!   if ( (rip = get_inode(NO_DEV, inumb)) == NIL_INODE) {
XX  	/* No inode table slots available.  Free the inode just allocated. */
XX  	free_bit(sp->s_imap, b);
XX    } else {
XX  	/* An inode slot is available. Put the inode just allocated into it. */
XX! 	rip->i_mode = bits;		/* set up RWX bits */
XX! 	rip->i_nlinks = (nlink_t) 0;	/* initial no links */
XX! 	rip->i_uid = fp->fp_effuid;	/* file's uid is owner's */
XX! 	rip->i_gid = fp->fp_effgid;	/* ditto group id */
XX! 	rip->i_dev = dev;		/* mark which device it is on */
XX! 	rip->i_ndzones = sp->s_ndzones;	/* number of direct zones */
XX! 	rip->i_nindirs = sp->s_nindirs;	/* number of indirect zones per blk*/
XX! 	rip->i_sp = sp;			/* pointer to super block */
XX  
XX  	/* Fields not cleared already are cleared in wipe_inode().  They have
XX  	 * been put there because truncate() needs to clear the same fields if
XX***************
XX*** 146,152 ****
XX   *				wipe_inode				     *
XX   *===========================================================================*/
XX  PUBLIC void wipe_inode(rip)
XX! register struct inode *rip;	/* The inode to be erased. */
XX  {
XX  /* Erase some fields in the inode.  This function is called from alloc_inode()
XX   * when a new inode is to be allocated, and from truncate(), when an existing
XX--- 166,172 ----
XX   *				wipe_inode				     *
XX   *===========================================================================*/
XX  PUBLIC void wipe_inode(rip)
XX! register struct inode *rip;	/* the inode to be erased */
XX  {
XX  /* Erase some fields in the inode.  This function is called from alloc_inode()
XX   * when a new inode is to be allocated, and from truncate(), when an existing
XX***************
XX*** 156,182 ****
XX    register int i;
XX  
XX    rip->i_size = 0;
XX!   rip->i_update = MTIME;	/* mark mtime for update later */
XX    rip->i_dirt = DIRTY;
XX!   for (i = 0; i < NR_ZONE_NUMS; i++)
XX! 	rip->i_zone[i] = NO_ZONE;
XX  }
XX  
XX  
XX  /*===========================================================================*
XX   *				free_inode				     *
XX   *===========================================================================*/
XX! PUBLIC void free_inode(dev, numb)
XX  dev_t dev;			/* on which device is the inode */
XX! ino_t numb;			/* number of inode to be freed */
XX  {
XX  /* Return an inode to the pool of unallocated inodes. */
XX  
XX    register struct super_block *sp;
XX  
XX    /* Locate the appropriate super_block. */
XX    sp = get_super(dev);
XX!   free_bit(sp->s_imap, (bit_nr) numb);
XX  }
XX  
XX  /*===========================================================================*
XX--- 176,205 ----
XX    register int i;
XX  
XX    rip->i_size = 0;
XX!   rip->i_update = ATIME | CTIME | MTIME;	/* update all times later */
XX    rip->i_dirt = DIRTY;
XX!   for (i = 0; i < V2_NR_TZONES; i++) rip->i_zone[i] = NO_ZONE;
XX  }
XX  
XX  
XX  /*===========================================================================*
XX   *				free_inode				     *
XX   *===========================================================================*/
XX! PUBLIC void free_inode(dev, inumb)
XX  dev_t dev;			/* on which device is the inode */
XX! int inumb;			/* number of inode to be freed */
XX  {
XX  /* Return an inode to the pool of unallocated inodes. */
XX  
XX    register struct super_block *sp;
XX+   bit_t b;
XX  
XX    /* Locate the appropriate super_block. */
XX    sp = get_super(dev);
XX!   b = (bit_t) ((ino_t) inumb);	/* needed to avoid sign extension */
XX!   if (b <= 0 || b > sp->s_ninodes) return;
XX!   free_bit(sp->s_imap, b);
XX!   if (inumb < sp->s_isearch) sp->s_isearch = (bit_t) ((ino_t) inumb);
XX  }
XX  
XX  /*===========================================================================*
XX***************
XX*** 189,199 ****
XX   * or mtime.  Since updating a time requires sending a message to the clock
XX   * task--an expensive business--the times are marked for update by setting
XX   * bits in i_update.  When a stat, fstat, or sync is done, or an inode is 
XX!  * released, update_times() may be called to actually fill in the times
XX   */
XX  
XX    time_t cur_time;
XX  
XX    cur_time = clock_time();
XX    if (rip->i_update & ATIME) rip->i_atime = cur_time;
XX    if (rip->i_update & CTIME) rip->i_ctime = cur_time;
XX--- 212,226 ----
XX   * or mtime.  Since updating a time requires sending a message to the clock
XX   * task--an expensive business--the times are marked for update by setting
XX   * bits in i_update.  When a stat, fstat, or sync is done, or an inode is 
XX!  * released, update_times() may be called to actually fill in the times.
XX   */
XX  
XX    time_t cur_time;
XX+   struct super_block *sp;
XX  
XX+   sp = rip->i_sp;		/* get pointer to super block. */
XX+   if (sp->s_rd_only) return;	/* no updates for read-only file systems */
XX+ 
XX    cur_time = clock_time();
XX    if (rip->i_update & ATIME) rip->i_atime = cur_time;
XX    if (rip->i_update & CTIME) rip->i_ctime = cur_time;
XX***************
XX*** 212,243 ****
XX  /* An entry in the inode table is to be copied to or from the disk. */
XX  
XX    register struct buf *bp;
XX-   register d_inode *dip;
XX    register struct super_block *sp;
XX!   block_nr b;
XX  
XX    /* Get the block where the inode resides. */
XX!   sp = get_super(rip->i_dev);
XX!   b = (block_nr) (rip->i_num - 1)/INODES_PER_BLOCK +
XX! 				sp->s_imap_blocks + sp->s_zmap_blocks + 2;
XX    bp = get_block(rip->i_dev, b, NORMAL);
XX!   dip = bp->b_inode + (rip->i_num - 1) % INODES_PER_BLOCK;
XX  
XX    /* Do the read or write. */
XX!   if (rw_flag == READING) {
XX! 	copy((char *)rip, (char *)dip, INODE_SIZE); /* copy to inode*/
XX!   } else {
XX  	if (rip->i_update) update_times(rip);	/* times need updating */
XX! 	copy((char *)dip, (char *)rip, INODE_SIZE); /* copy from inode */
XX! 	bp->b_dirt = DIRTY;
XX    }
XX  
XX    put_block(bp, INODE_BLOCK);
XX    rip->i_dirt = CLEAN;
XX  }
XX  
XX  
XX  /*===========================================================================*
XX   *				dup_inode				     *
XX   *===========================================================================*/
XX  PUBLIC void dup_inode(ip)
XX--- 239,369 ----
XX  /* An entry in the inode table is to be copied to or from the disk. */
XX  
XX    register struct buf *bp;
XX    register struct super_block *sp;
XX!   d1_inode *dip;
XX!   d2_inode *dip2;
XX!   block_t b, offset;
XX  
XX    /* Get the block where the inode resides. */
XX!   sp = get_super(rip->i_dev);	/* get pointer to super block */
XX!   rip->i_sp = sp;		/* inode must contain super block pointer */
XX!   offset = sp->s_imap_blocks + sp->s_zmap_blocks + 2;
XX!   b = (block_t) (rip->i_num - 1)/sp->s_inodes_per_block + offset;
XX    bp = get_block(rip->i_dev, b, NORMAL);
XX!   dip  = bp->b_v1_ino + (rip->i_num - 1) % V1_INODES_PER_BLOCK;
XX!   dip2 = bp->b_v2_ino + (rip->i_num - 1) % V2_INODES_PER_BLOCK;
XX  
XX    /* Do the read or write. */
XX!   if (rw_flag == WRITING) {
XX  	if (rip->i_update) update_times(rip);	/* times need updating */
XX! 	if (sp->s_rd_only == FALSE) bp->b_dirt = DIRTY;
XX    }
XX  
XX+   /* Copy the inode from the disk block to the in-core table or vice versa.
XX+    * If the fourth parameter below is FALSE, the bytes are swapped.
XX+    */
XX+   if (sp->s_version == V1)
XX+ 	old_icopy(rip, dip,  rw_flag, sp->s_native);
XX+   else
XX+ 	new_icopy(rip, dip2, rw_flag, sp->s_native);
XX+   
XX    put_block(bp, INODE_BLOCK);
XX    rip->i_dirt = CLEAN;
XX  }
XX  
XX  
XX  /*===========================================================================*
XX+  *				old_icopy				     *
XX+  *===========================================================================*/
XX+ PRIVATE void old_icopy(rip, dip, direction, norm)
XX+ register struct inode *rip;	/* pointer to the in-core inode struct */
XX+ register d1_inode *dip;		/* pointer to the d1_inode inode struct */
XX+ int direction;			/* READING (from disk) or WRITING (to disk) */
XX+ int norm;			/* TRUE = do not swap bytes; FALSE = swap */
XX+ 
XX+ {
XX+ /* The V1.x IBM disk, the V1.x 68000 disk, and the V2 disk (same for IBM and
XX+  * 68000) all have different inode layouts.  When an inode is read or written
XX+  * this routine handles the conversions so that the information in the inode
XX+  * table is independent of the disk structure from which the inode came.
XX+  * The old_icopy routine copies to and from V1 disks.
XX+  */
XX+ 
XX+   int i;
XX+ 
XX+   if (direction == READING) {
XX+ 	/* Copy V1.x inode to the in-core table, swapping bytes if need be. */
XX+ 	rip->i_mode    = conv2(norm, (int) dip->d1_mode);
XX+ 	rip->i_uid     = conv2(norm, (int) dip->d1_uid );
XX+ 	rip->i_size    = conv4(norm,       dip->d1_size);
XX+ 	rip->i_mtime   = conv4(norm,       dip->d1_mtime);
XX+ 	rip->i_atime   = rip->i_mtime;
XX+ 	rip->i_ctime   = rip->i_mtime;
XX+ 	rip->i_nlinks  = (nlink_t) dip->d1_nlinks;	/* 1 char */
XX+ 	rip->i_gid     = (gid_t) dip->d1_gid;		/* 1 char */
XX+ 	rip->i_ndzones = V1_NR_DZONES;
XX+ 	rip->i_nindirs = V1_INDIRECTS;
XX+ 	for (i = 0; i < V1_NR_TZONES; i++)
XX+ 		rip->i_zone[i] = conv2(norm, (int) dip->d1_zone[i]);
XX+   } else {
XX+ 	/* Copying V1.x inode to disk from the in-core table. */
XX+ 	dip->d1_mode   = conv2(norm, (int) rip->i_mode);
XX+ 	dip->d1_uid    = conv2(norm, (int) rip->i_uid );
XX+ 	dip->d1_size   = conv4(norm,       rip->i_size);
XX+ 	dip->d1_mtime  = conv4(norm,       rip->i_mtime);
XX+ 	dip->d1_nlinks = (nlink_t) rip->i_nlinks;	/* 1 char */
XX+ 	dip->d1_gid    = (gid_t) rip->i_gid;		/* 1 char */
XX+ 	for (i = 0; i < V1_NR_TZONES; i++)
XX+ 		dip->d1_zone[i] = conv2(norm, (int) rip->i_zone[i]);
XX+   }
XX+ }
XX+ 
XX+ 
XX+ /*===========================================================================*
XX+  *				new_icopy				     *
XX+  *===========================================================================*/
XX+ PRIVATE void new_icopy(rip, dip, direction, norm)
XX+ register struct inode *rip;	/* pointer to the in-core inode struct */
XX+ register d2_inode *dip;	/* pointer to the d2_inode struct */
XX+ int direction;			/* READING (from disk) or WRITING (to disk) */
XX+ int norm;			/* TRUE = do not swap bytes; FALSE = swap */
XX+ 
XX+ {
XX+ /* Same as old_icopy, but to/from V2 disk layout. */
XX+ 
XX+   int i;
XX+ 
XX+   if (direction == READING) {
XX+ 	/* Copy V2.x inode to the in-core table, swapping bytes if need be. */
XX+ 	rip->i_mode    = conv2(norm,dip->d2_mode);
XX+ 	rip->i_uid     = conv2(norm,dip->d2_uid );
XX+ 	rip->i_nlinks  = conv2(norm,(int) dip->d2_nlinks);
XX+ 	rip->i_gid     = conv2(norm,(int) dip->d2_gid );
XX+ 	rip->i_size    = conv4(norm,dip->d2_size);
XX+ 	rip->i_atime   = conv4(norm,dip->d2_atime);
XX+ 	rip->i_ctime   = conv4(norm,dip->d2_ctime);
XX+ 	rip->i_mtime   = conv4(norm,dip->d2_mtime);
XX+ 	rip->i_ndzones = V2_NR_DZONES;
XX+ 	rip->i_nindirs = V2_INDIRECTS;
XX+ 	for (i = 0; i < V2_NR_TZONES; i++)
XX+ 		rip->i_zone[i] = conv4(norm, (long) dip->d2_zone[i]);
XX+   } else {
XX+ 	/* Copying V2.x inode to disk from the in-core table. */
XX+ 	dip->d2_mode   = conv2(norm,rip->i_mode);
XX+ 	dip->d2_uid    = conv2(norm,rip->i_uid );
XX+ 	dip->d2_nlinks = conv2(norm,rip->i_nlinks);
XX+ 	dip->d2_gid    = conv2(norm,rip->i_gid );
XX+ 	dip->d2_size   = conv4(norm,rip->i_size);
XX+ 	dip->d2_atime  = conv4(norm,rip->i_atime);
XX+ 	dip->d2_ctime  = conv4(norm,rip->i_ctime);
XX+ 	dip->d2_mtime  = conv4(norm,rip->i_mtime);
XX+ 	for (i = 0; i < V2_NR_TZONES; i++)
XX+ 		dip->d2_zone[i] = conv4(norm, (long) rip->i_zone[i]);
XX+   }
XX+ }
XX+ 
XX+ 
XX+ /*===========================================================================*
XX   *				dup_inode				     *
XX   *===========================================================================*/
XX  PUBLIC void dup_inode(ip)
XX***************
XX*** 249,252 ****
XX  
XX    ip->i_count++;
XX  }
XX- 
XX--- 375,377 ----
X/
Xecho x - inode.h.d
Xsed '/^X/s///' > inode.h.d << '/'
XX*** /home/top/ast/minix/1.5/fs/inode.h  crc=65256   2117	Sat Apr 21 22:26:20 1990
XX--- /home/top/ast/minix/1.6.25/fs/inode.h  crc=31419   2367	Tue Nov  3 21:19:13 1992
XX***************
XX*** 4,27 ****
XX   * such as to search a directory for a path name.
XX   * The first part of the struct holds fields that are present on the
XX   * disk; the second part holds fields not present on the disk.
XX!  * The disk inode part is also declared in "type.h" as 'd_inode'.
XX   */
XX  
XX  EXTERN struct inode {
XX!   unshort i_mode;		/* file type, protection, etc. */
XX    uid_t i_uid;			/* user id of the file's owner */
XX    off_t i_size;			/* current file size in bytes */
XX    time_t i_mtime;		/* when was file data last changed */
XX!   gid_t i_gid;			/* group number */
XX!   nlink_t i_nlinks;		/* how many links to this file */
XX!   zone_nr i_zone[NR_ZONE_NUMS];	/* zone numbers for direct, ind, and dbl ind */
XX! 
XX    /* The following items are not present on the disk. */
XX-   time_t i_atime;		/* time of last access */
XX-   time_t i_ctime;		/* time of last change to the inode's status */
XX    dev_t i_dev;			/* which device is the inode on */
XX    ino_t i_num;			/* inode number on its (minor) device */
XX!   short int i_count;		/* # times inode used; 0 means slot is free */
XX    char i_dirt;			/* CLEAN or DIRTY */
XX    char i_pipe;			/* set to I_PIPE if pipe */
XX    char i_mount;			/* this bit is set if file mounted on */
XX--- 4,31 ----
XX   * such as to search a directory for a path name.
XX   * The first part of the struct holds fields that are present on the
XX   * disk; the second part holds fields not present on the disk.
XX!  * The disk inode part is also declared in "type.h" as 'd1_inode' for V1
XX!  * file systems and 'd2_inode' for V2 file systems.
XX   */
XX  
XX  EXTERN struct inode {
XX!   mode_t i_mode;		/* file type, protection, etc. */
XX!   nlink_t i_nlinks;		/* how many links to this file */
XX    uid_t i_uid;			/* user id of the file's owner */
XX+   gid_t i_gid;			/* group number */
XX    off_t i_size;			/* current file size in bytes */
XX+   time_t i_atime;		/* time of last access (V2 only) */
XX    time_t i_mtime;		/* when was file data last changed */
XX!   time_t i_ctime;		/* when was inode itself changed (V2 only)*/
XX!   zone_t i_zone[V2_NR_TZONES];	/* zone numbers for direct, ind, and dbl ind */
XX!   
XX    /* The following items are not present on the disk. */
XX    dev_t i_dev;			/* which device is the inode on */
XX    ino_t i_num;			/* inode number on its (minor) device */
XX!   int i_count;			/* # times inode used; 0 means slot is free */
XX!   int i_ndzones;		/* # direct zones (Vx_NR_DZONES) */
XX!   int i_nindirs;		/* # indirect zones per indirect block */
XX!   struct super_block *i_sp;	/* pointer to super block for inode's device */
XX    char i_dirt;			/* CLEAN or DIRTY */
XX    char i_pipe;			/* set to I_PIPE if pipe */
XX    char i_mount;			/* this bit is set if file mounted on */
XX***************
XX*** 35,41 ****
XX  /* Field values.  Note that CLEAN and DIRTY are defined in "const.h" */
XX  #define NO_PIPE            0	/* i_pipe is NO_PIPE if inode is not a pipe */
XX  #define I_PIPE             1	/* i_pipe is I_PIPE if inode is a pipe */
XX! #define NO_MOUNT           0	/* i_mount is NO_MOUNT if file not mounted on */
XX  #define I_MOUNT            1	/* i_mount is I_MOUNT if file mounted on */
XX  #define NO_SEEK            0	/* i_seek = NO_SEEK if last op was not SEEK */
XX  #define ISEEK              1	/* i_seek = ISEEK if last op was SEEK */
XX--- 39,45 ----
XX  /* Field values.  Note that CLEAN and DIRTY are defined in "const.h" */
XX  #define NO_PIPE            0	/* i_pipe is NO_PIPE if inode is not a pipe */
XX  #define I_PIPE             1	/* i_pipe is I_PIPE if inode is a pipe */
XX! #define NO_MOUNT           0	/* i_mount is NO_MOUNT if file not mounted on*/
XX  #define I_MOUNT            1	/* i_mount is I_MOUNT if file mounted on */
XX  #define NO_SEEK            0	/* i_seek = NO_SEEK if last op was not SEEK */
XX  #define ISEEK              1	/* i_seek = ISEEK if last op was SEEK */
X/
Xecho x - link.c.d
Xsed '/^X/s///' > link.c.d << '/'
XX*** /home/top/ast/minix/1.5/fs/link.c  crc=55912  12019	Sat Apr 21 22:26:20 1990
XX--- /home/top/ast/minix/1.6.25/fs/link.c  crc=14913  14797	Sun Dec 20 17:24:30 1992
XX***************
XX*** 18,27 ****
XX  #include "fproc.h"
XX  #include "inode.h"
XX  #include "param.h"
XX  
XX  #define SAME 1000
XX- PRIVATE char dot2[NAME_MAX] =  "..\0\0\0\0\0\0\0\0\0\0\0";
XX  
XX  /*===========================================================================*
XX   *				do_link					     *
XX   *===========================================================================*/
XX--- 18,34 ----
XX  #include "fproc.h"
XX  #include "inode.h"
XX  #include "param.h"
XX+ #include "super.h"
XX  
XX  #define SAME 1000
XX  
XX+ FORWARD _PROTOTYPE( int remove_dir, (struct inode *rldirp, struct inode *rip,
XX+ 			char dir_name[NAME_MAX])			);
XX+ 
XX+ FORWARD _PROTOTYPE( int unlink_file, (struct inode *dirp, struct inode *rip,
XX+ 			char file_name[NAME_MAX])			);
XX+ 
XX+ 
XX  /*===========================================================================*
XX   *				do_link					     *
XX   *===========================================================================*/
XX***************
XX*** 40,46 ****
XX  
XX    /* Check to see if the file has maximum number of links already. */
XX    r = OK;
XX!   if ( (rip->i_nlinks & BYTE) == LINK_MAX) r = EMLINK;
XX  
XX    /* Only super_user may link to directories. */
XX    if (r == OK)
XX--- 47,53 ----
XX  
XX    /* Check to see if the file has maximum number of links already. */
XX    r = OK;
XX!   if ( (rip->i_nlinks & BYTE) >= LINK_MAX) r = EMLINK;
XX  
XX    /* Only super_user may link to directories. */
XX    if (r == OK)
XX***************
XX*** 81,86 ****
XX--- 88,94 ----
XX    /* If success, register the linking. */
XX    if (r == OK) {
XX  	rip->i_nlinks++;
XX+ 	rip->i_update |= CTIME;
XX  	rip->i_dirt = DIRTY;
XX    }
XX  
XX***************
XX*** 103,113 ****
XX  
XX    register struct inode *rip;
XX    struct inode *rldirp;
XX!   register struct fproc *rfp;
XX!   int r, r1;
XX!   ino_t numb;
XX!   mode_t old_mode;
XX!   uid_t old_uid;
XX    char string[NAME_MAX];
XX  
XX    /* Get the last directory in the path. */
XX--- 111,117 ----
XX  
XX    register struct inode *rip;
XX    struct inode *rldirp;
XX!   int r;
XX    char string[NAME_MAX];
XX  
XX    /* Get the last directory in the path. */
XX***************
XX*** 124,187 ****
XX  	put_inode(rldirp);
XX  	return(r);
XX    }
XX-   old_mode = rip->i_mode;	/* save mode; it must be fudged for . and .. */
XX-   old_uid =  rip->i_uid;	/* save uid;  it must be fudged for . and .. */
XX  
XX    /* Now test if the call is allowed, separately for unlink() and rmdir(). */
XX    if (fs_call == UNLINK) {
XX  	/* Only the su may unlink directories, but the su can unlink any dir.*/
XX  	if ( (rip->i_mode & I_TYPE) == I_DIRECTORY && !super_user) r = EPERM;
XX  
XX! 	/* Actually try to unlink the file; fails if parent is mode 0 etc. */
XX! 	if (r == OK) r = search_dir(rldirp, string, (ino_t *) 0, DELETE);
XX!   } else {
XX! 	/* The call is rmdir().  Five conditions have to met for this call:
XX! 	 * 	- The file must be a directory
XX! 	 *	- The directory must be empty (except for . and ..)
XX! 	 *	- It must not be /
XX!  	 *	- The path must not end in . or ..
XX! 	 *	- The directory must not be anybody's working directory
XX! 	 */
XX! 	if ( (rip->i_mode & I_TYPE) != I_DIRECTORY) r = ENOTDIR;
XX! 	if (search_dir(rip, "", &numb, LOOK_UP) == OK) r = ENOTEMPTY;
XX! 	if (strcmp(user_path, "/") == 0) r = EPERM;	/* can't remove root */
XX! 	if (strcmp(string, ".") == 0 || strcmp(string, "..") == 0) r = EPERM;
XX! 	for (rfp = &fproc[INIT_PROC_NR + 1]; rfp < &fproc[NR_PROCS]; rfp++) {
XX! 		if (rfp->fp_workdir == rip || rfp->fp_rootdir == rip) {
XX! 			r = EBUSY;	/* can't remove anybody's working dir*/
XX! 			break;
XX! 		}
XX! 	}
XX  
XX  	/* Actually try to unlink the file; fails if parent is mode 0 etc. */
XX! 	if (r == OK) r = search_dir(rldirp, string, (ino_t *) 0, DELETE);
XX  
XX! 	/* If all the conditions have been met, remove . and .. from the dir.
XX! 	 * If the directory is not searchable, it will not be possible to
XX!  	 * unlink . and .. even though this is legal, so change the mode.
XX! 	 */
XX! 	if (r == OK) {
XX! 		rip->i_mode |= S_IRWXU;	/* turn on all the owner bits */
XX! 		rip->i_uid = fp->fp_effuid;	/* may not fail due to uid */
XX! 		if ( (r = search_dir(rip, ".",  (ino_t *) 0, DELETE)) == OK)
XX! 			rip->i_nlinks --;	/* . pts to dir being removed*/
XX! 		if ( (r1 = search_dir(rip, "..", (ino_t *) 0, DELETE)) == OK)
XX! 			rldirp->i_nlinks--;	/* .. points to parent dir */
XX! 		rip->i_dirt = DIRTY;
XX! 		rldirp->i_dirt = DIRTY;
XX! 		if (r1 != OK) r = r1;
XX! 		rip->i_mode = old_mode;	/* restore the old mode */
XX! 		rip->i_uid = old_uid;
XX! 	}
XX    }
XX  
XX-   if (r == OK) {
XX- 	rip->i_nlinks--;
XX- 	rip->i_dirt = DIRTY;
XX-   }
XX- 
XX    /* If unlink was possible, it has been done, otherwise it has not. */
XX-   rip->i_mode = old_mode;	/* restore mode in case it has been changed */
XX    put_inode(rip);
XX    put_inode(rldirp);
XX    return(r);
XX--- 128,157 ----
XX  	put_inode(rldirp);
XX  	return(r);
XX    }
XX  
XX+   /* Do not remove a mount point. */
XX+   if (rip->i_num == ROOT_INODE) {
XX+ 	put_inode(rldirp);
XX+ 	put_inode(rip);
XX+ 	return(EBUSY);
XX+   }
XX+ 
XX    /* Now test if the call is allowed, separately for unlink() and rmdir(). */
XX    if (fs_call == UNLINK) {
XX  	/* Only the su may unlink directories, but the su can unlink any dir.*/
XX  	if ( (rip->i_mode & I_TYPE) == I_DIRECTORY && !super_user) r = EPERM;
XX  
XX! 	/* Don't unlink a file if it is the root of a mounted file system. */
XX! 	if (rip->i_num == ROOT_INODE) r = EBUSY;
XX  
XX  	/* Actually try to unlink the file; fails if parent is mode 0 etc. */
XX! 	if (r == OK) r = unlink_file(rldirp, rip, string);
XX  
XX!   } else {
XX! 	r = remove_dir(rldirp, rip, string); /* call is RMDIR */
XX    }
XX  
XX    /* If unlink was possible, it has been done, otherwise it has not. */
XX    put_inode(rip);
XX    put_inode(rldirp);
XX    return(r);
XX***************
XX*** 197,294 ****
XX  
XX    struct inode *old_dirp, *old_ip;	/* ptrs to old dir, file inodes */
XX    struct inode *new_dirp, *new_ip;	/* ptrs to new dir, file inodes */
XX    int r = OK;				/* error flag; initially no error */
XX    int odir, ndir;			/* TRUE iff {old|new} file is dir */
XX!   char string[NAME_MAX+1], old_string[NAME_MAX+1];
XX!   char old_name[PATH_MAX+1];
XX    ino_t numb;
XX    
XX    /* See if 'name1' (existing file) exists.  Get dir and file inodes. */
XX    if (fetch_name(name1, name1_length, M1) != OK) return(err_code);
XX!   if ( (old_dirp = last_dir(user_path, string)) == NIL_INODE) return(err_code);
XX  
XX!   if ( (old_ip = advance(old_dirp, string)) == NIL_INODE) r = err_code;
XX!   strcpy(old_name, user_path);	/* save the old name here */
XX!   strcpy(old_string, string);	/* save last component of the name here */
XX  
XX    /* See if 'name2' (new name) exists.  Get dir and file inodes. */
XX    if (fetch_name(name2, name2_length, M1) != OK) r = err_code;
XX!   if ( (new_dirp = last_dir(user_path, string)) == NIL_INODE) r = err_code;
XX!   new_ip = advance(new_dirp, string);	/* not required to exist */
XX  
XX    /* If it is ok, check for a variety of possible errors. */
XX    if (r == OK) {
XX! 	/* The old path must not be a prefix of the new one. */
XX! 	if (strncmp(old_name, user_path, strlen(old_name)) == 0) r = EINVAL;
XX  
XX! 	/* The old path must not be . or .. */
XX! 	if (strcmp(old_name, ".")==0 || strcmp(old_name, "..")==0) r = EINVAL;
XX  
XX! 	/* Both directories must be on the same device. */
XX  	if (old_dirp->i_dev != new_dirp->i_dev) r = EXDEV;
XX  
XX! 	/* Both directories must be writable and searchable. */
XX! 	if (forbidden(old_dirp, W_BIT | X_BIT, 0)) r = EACCES;
XX! 	if (forbidden(new_dirp, W_BIT | X_BIT, 0)) r = EACCES;
XX  
XX  	/* Some tests apply only if the new path exists. */
XX! 	odir = S_ISDIR(old_ip->i_mode);	/* TRUE iff old file is dir */
XX! 	if (new_ip != NIL_INODE) {
XX! 		ndir = S_ISDIR(new_ip->i_mode);	/* TRUE iff new file is dir */
XX  		if (odir == TRUE && ndir == FALSE) r = ENOTDIR;
XX  		if (odir == FALSE && ndir == TRUE) r = EISDIR;
XX- 		if (old_ip->i_num == new_ip->i_num) r = SAME; /* old=new */
XX- 		if (ndir == TRUE) {
XX- 			if (search_dir(new_ip, "", &numb, LOOK_UP) == OK)
XX- 				r = ENOTEMPTY;
XX- 		}
XX  	}
XX    }
XX  
XX!   /* The rename will probably work.  The only thing that could still go wrong
XX!    * is being unable to make the new directory entry (directory has to grow by
XX!    * one block and cannot because the disk is completely full).  Two cases can
XX!    * be distinguished now, depending on whether the 'new' entry exists or not.
XX!    *   Case 1 ('new' entry does not exist): create a dir entry for it.
XX!    *   Case 2 ('new' entry exists): update inum in existing dir entry.
XX     */
XX    if (r == OK) {
XX! 	/* For both cases we need the number of the old inode entry. */
XX  	numb = old_ip->i_num;		/* inode number of old file */
XX  
XX! 	/* For case 1, make new entry; for case 2, delete then enter. */
XX! 	if (new_ip == NIL_INODE) {
XX! 		/* There is no entry for 'new'.  Make one.*/
XX! 		r = search_dir(new_dirp, string, &numb, ENTER);	/* can fail */
XX! 		if (r == OK && odir) {
XX! 			new_dirp->i_nlinks++;  /* new entry created */
XX! 			new_dirp->i_dirt = DIRTY;
XX! 		}
XX  	} else {
XX! 		/* There is already an entry for 'new'.  Slot can be reused. */
XX! 		(void) search_dir(new_dirp, string, (ino_t *) 0, DELETE);
XX! 		(void) search_dir(new_dirp, string, &numb, ENTER); 
XX! 		new_ip->i_nlinks--;	/* entry deleted from parent's dir */
XX! 		new_ip->i_dirt = DIRTY;
XX! 		if (odir) new_ip->i_nlinks--;	/* new_ip's .  is going away */
XX  	}
XX  
XX! 	/* Delete the directory entry for 'old', but do not change link ct. */
XX! 	if (r == OK) {
XX! 		if (odir) {
XX! 			old_dirp->i_nlinks--;	/* old_ip's .. is going away */
XX! 			old_dirp->i_dirt = DIRTY;
XX! 			numb = new_dirp->i_num;
XX! 			(void) search_dir(old_ip, "..", (ino_t *) 0, DELETE);
XX! 			(void) search_dir(old_ip, dot2, &numb ,ENTER);
XX! 		}
XX! 		(void) search_dir(old_dirp, old_string, (ino_t *)0, DELETE);
XX! 
XX! 		/* Mark times for updating later. */
XX! 		old_dirp->i_update = CTIME | MTIME;
XX! 		new_dirp->i_update = CTIME | MTIME;
XX! 	}
XX!   }	
XX  	
XX    /* Release the inodes. */
XX    put_inode(old_dirp);
XX--- 167,304 ----
XX  
XX    struct inode *old_dirp, *old_ip;	/* ptrs to old dir, file inodes */
XX    struct inode *new_dirp, *new_ip;	/* ptrs to new dir, file inodes */
XX+   struct inode *new_superdirp, *next_new_superdirp;
XX    int r = OK;				/* error flag; initially no error */
XX    int odir, ndir;			/* TRUE iff {old|new} file is dir */
XX!   int same_pdir;			/* TRUE iff parent dirs are the same */
XX!   char old_name[NAME_MAX], new_name[NAME_MAX];
XX    ino_t numb;
XX+   int r1;
XX    
XX    /* See if 'name1' (existing file) exists.  Get dir and file inodes. */
XX    if (fetch_name(name1, name1_length, M1) != OK) return(err_code);
XX!   if ( (old_dirp = last_dir(user_path, old_name))==NIL_INODE) return(err_code);
XX  
XX!   if ( (old_ip = advance(old_dirp, old_name)) == NIL_INODE) r = err_code;
XX  
XX    /* See if 'name2' (new name) exists.  Get dir and file inodes. */
XX    if (fetch_name(name2, name2_length, M1) != OK) r = err_code;
XX!   if ( (new_dirp = last_dir(user_path, new_name)) == NIL_INODE) r = err_code;
XX!   new_ip = advance(new_dirp, new_name);	/* not required to exist */
XX  
XX+   if (old_ip != NIL_INODE)
XX+ 	odir = ((old_ip->i_mode & I_TYPE) == I_DIRECTORY);  /* TRUE iff dir */
XX+ 
XX    /* If it is ok, check for a variety of possible errors. */
XX    if (r == OK) {
XX! 	same_pdir = (old_dirp == new_dirp);
XX  
XX! 	/* The old inode must not be a superdirectory of the new last dir. */
XX! 	if (odir && !same_pdir) {
XX! 		dup_inode(new_superdirp = new_dirp);
XX! 		while (TRUE) {		/* may hang in a file system loop */
XX! 			if (new_superdirp == old_ip) {
XX! 				r = EINVAL;
XX! 				break;
XX! 			}
XX! 			next_new_superdirp = advance(new_superdirp, dot2);
XX! 			put_inode(new_superdirp);
XX! 			if (next_new_superdirp == new_superdirp)
XX! 				break;	/* back at system root directory */
XX! 			new_superdirp = next_new_superdirp;
XX! 			if (new_superdirp == NIL_INODE) {
XX! 				/* Missing ".." entry.  Assume the worst. */
XX! 				r = EINVAL;
XX! 				break;
XX! 			}
XX! 		} 	
XX! 		put_inode(new_superdirp);
XX! 	}	
XX  
XX! 	/* The old or new name must not be . or .. */
XX! 	if (strcmp(old_name, ".")==0 || strcmp(old_name, "..")==0 ||
XX! 	    strcmp(new_name, ".")==0 || strcmp(new_name, "..")==0) r = EINVAL;
XX! 
XX! 	/* Both parent directories must be on the same device. */
XX  	if (old_dirp->i_dev != new_dirp->i_dev) r = EXDEV;
XX  
XX! 	/* Parent dirs must be writable, searchable and on a writable device */
XX! 	if ((r1 = forbidden(old_dirp, W_BIT | X_BIT, 0)) != OK ||
XX! 	    (r1 = forbidden(new_dirp, W_BIT | X_BIT, 0)) != OK) r = r1;
XX  
XX  	/* Some tests apply only if the new path exists. */
XX! 	if (new_ip == NIL_INODE) {
XX! 		/* don't rename a file with a file system mounted on it. */
XX! 		if (old_ip->i_dev != old_dirp->i_dev) r = EXDEV;
XX! 		if (odir && (new_dirp->i_nlinks & BYTE) >= LINK_MAX &&
XX! 		    !same_pdir && r == OK) r = EMLINK;
XX! 	} else {
XX! 		if (old_ip == new_ip) r = SAME; /* old=new */
XX! 
XX! 		/* has the old file or new file a file system mounted on it? */
XX! 		if (old_ip->i_dev != new_ip->i_dev) r = EXDEV;
XX! 
XX! 		ndir = ((new_ip->i_mode & I_TYPE) == I_DIRECTORY); /* dir ? */
XX  		if (odir == TRUE && ndir == FALSE) r = ENOTDIR;
XX  		if (odir == FALSE && ndir == TRUE) r = EISDIR;
XX  	}
XX    }
XX  
XX!   /* If a process has another root directory than the system root, we might
XX!    * "accidently" be moving it's working directory to a place where it's
XX!    * root directory isn't a super directory of it anymore. This can make
XX!    * the function chroot useless. If chroot will be used often we should
XX!    * probably check for it here.
XX     */
XX+ 
XX+   /* The rename will probably work. Only two things can go wrong now:
XX+    * 1. being unable to remove the new file. (when new file already exists)
XX+    * 2. being unable to make the new directory entry. (new file doesn't exists)
XX+    *     [directory has to grow by one block and cannot because the disk
XX+    *      is completely full].
XX+    */
XX    if (r == OK) {
XX! 	if (new_ip != NIL_INODE) {
XX! 		  /* There is already an entry for 'new'. Try to remove it. */
XX! 		if (odir) 
XX! 			r = remove_dir(new_dirp, new_ip, new_name);
XX! 		else 
XX! 			r = unlink_file(new_dirp, new_ip, new_name);
XX! 	}
XX! 	/* if r is OK, the rename will succeed, while there is now an
XX! 	 * unused entry in the new parent directory.
XX! 	 */
XX!   }
XX! 
XX!   if (r == OK) {
XX! 	/* If the new name will be in the same parent directory as the old one,
XX! 	 * first remove the old name to free an entry for the new name,
XX! 	 * otherwise first try to create the new name entry to make sure
XX! 	 * the rename will succeed.
XX! 	 */
XX  	numb = old_ip->i_num;		/* inode number of old file */
XX  
XX!   	if (same_pdir) {
XX! 		r = search_dir(old_dirp, old_name, (ino_t *) 0, DELETE);
XX! 						/* shouldn't go wrong. */
XX! 		if (r==OK) (void) search_dir(old_dirp, new_name, &numb, ENTER);
XX  	} else {
XX! 		r = search_dir(new_dirp, new_name, &numb, ENTER);
XX! 		if (r == OK)
XX! 		    (void) search_dir(old_dirp, old_name, (ino_t *) 0, DELETE);
XX  	}
XX+   }
XX+   /* If r is OK, the ctime and mtime of old_dirp and new_dirp have been marked
XX+    * for update in search_dir.
XX+    */
XX  
XX!   if (r == OK && odir && !same_pdir) {
XX! 	/* Update the .. entry in the directory (still points to old_dirp). */
XX! 	numb = new_dirp->i_num;
XX! 	(void) unlink_file(old_ip, NIL_INODE, dot2);
XX! 	if (search_dir(old_ip, dot2, &numb, ENTER) == OK) new_dirp->i_nlinks++;
XX! 							 /* new link created */
XX!   }
XX  	
XX    /* Release the inodes. */
XX    put_inode(old_dirp);
XX***************
XX*** 298,303 ****
XX--- 308,314 ----
XX    return(r == SAME ? OK : r);
XX  }
XX  
XX+ 
XX  /*===========================================================================*
XX   *				truncate				     *
XX   *===========================================================================*/
XX***************
XX*** 306,342 ****
XX  {
XX  /* Remove all the zones from the inode 'rip' and mark it dirty. */
XX  
XX!   register block_nr b;
XX!   register zone_nr z, *iz;
XX    off_t position;
XX!   zone_type zone_size;
XX!   int scale, file_type, waspipe;
XX    struct buf *bp;
XX    dev_t dev;
XX  
XX!   file_type = rip->i_mode & S_IFMT;	/* check to see if file is special */
XX!   if (file_type == S_IFCHR || file_type == S_IFBLK) return;
XX    dev = rip->i_dev;		/* device on which inode resides */
XX!   scale = scale_factor(rip);
XX!   zone_size = (zone_type) BLOCK_SIZE << scale;
XX!   if (waspipe = (rip->i_pipe == I_PIPE))
XX! 	rip->i_size = PIPE_SIZE;	/* pipes can shrink */
XX  
XX    /* Step through the file a zone at a time, finding and freeing the zones. */
XX    for (position = 0; position < rip->i_size; position += zone_size) {
XX  	if ( (b = read_map(rip, position)) != NO_BLOCK) {
XX! 		z = (zone_nr) b >> scale;
XX  		free_zone(dev, z);
XX  	}
XX    }
XX  
XX    /* All the data zones have been freed.  Now free the indirect zones. */
XX!   free_zone(dev, rip->i_zone[NR_DZONE_NUM]);	/* single indirect zone */
XX!   if ( (z = rip->i_zone[NR_DZONE_NUM+1]) != NO_ZONE) {
XX! 	b = (block_nr) z << scale;
XX  	bp = get_block(dev, b, NORMAL);	/* get double indirect zone */
XX! 	for (iz = &bp->b_ind[0]; iz < &bp->b_ind[NR_INDIRECTS]; iz++) {
XX! 		free_zone(dev, *iz);
XX  	}
XX  
XX  	/* Now free the double indirect zone itself. */
XX--- 317,363 ----
XX  {
XX  /* Remove all the zones from the inode 'rip' and mark it dirty. */
XX  
XX!   register block_t b;
XX!   zone_t z, zone_size, z1;
XX    off_t position;
XX!   int i, scale, file_type, waspipe, single, nr_indirects;
XX    struct buf *bp;
XX    dev_t dev;
XX  
XX!   file_type = rip->i_mode & I_TYPE;	/* check to see if file is special */
XX!   if (file_type == I_CHAR_SPECIAL || file_type == I_BLOCK_SPECIAL) return;
XX    dev = rip->i_dev;		/* device on which inode resides */
XX!   scale = rip->i_sp->s_log_zone_size;
XX!   zone_size = (zone_t) BLOCK_SIZE << scale;
XX!   nr_indirects = rip->i_nindirs;
XX  
XX+   /* Pipes can shrink, so adjust size to make sure all zones are removed. */
XX+   waspipe = rip->i_pipe == I_PIPE;	/* TRUE is this was a pipe */
XX+   if (waspipe) rip->i_size = PIPE_SIZE;
XX+ 
XX    /* Step through the file a zone at a time, finding and freeing the zones. */
XX    for (position = 0; position < rip->i_size; position += zone_size) {
XX  	if ( (b = read_map(rip, position)) != NO_BLOCK) {
XX! 		z = (zone_t) b >> scale;
XX  		free_zone(dev, z);
XX  	}
XX    }
XX  
XX    /* All the data zones have been freed.  Now free the indirect zones. */
XX!   rip->i_dirt = DIRTY;
XX!   if (waspipe) {
XX! 	wipe_inode(rip);	/* clear out inode for pipes */
XX! 	return;			/* indirect slots contain file positions */
XX!   }
XX!   single = rip->i_ndzones;
XX!   free_zone(dev, rip->i_zone[single]);	/* single indirect zone */
XX!   if ( (z = rip->i_zone[single+1]) != NO_ZONE) {
XX! 	/* Free all the single indirect zones pointed to by the double. */
XX! 	b = (block_t) z << scale;
XX  	bp = get_block(dev, b, NORMAL);	/* get double indirect zone */
XX! 	for (i = 0; i < nr_indirects; i++) {
XX! 		z1 = rd_indir(bp, i);
XX! 		free_zone(dev, z1);
XX  	}
XX  
XX  	/* Now free the double indirect zone itself. */
XX***************
XX*** 345,351 ****
XX    }
XX  
XX    /* Leave zone numbers for de(1) to recover file after an unlink(2).  */
XX!   if (waspipe)
XX! 	wipe_inode(rip);	/* clear out inode for pipes */
XX!   rip->i_dirt = DIRTY;
XX  }
XX--- 366,446 ----
XX    }
XX  
XX    /* Leave zone numbers for de(1) to recover file after an unlink(2).  */
XX! }
XX! 
XX! 
XX! /*===========================================================================*
XX!  *				remove_dir				     *
XX!  *===========================================================================*/
XX! PRIVATE int remove_dir(rldirp, rip, dir_name)
XX! struct inode *rldirp;		 	/* parent directory */
XX! struct inode *rip;			/* directory to be removed */
XX! char dir_name[NAME_MAX];		/* name of directory to be removed */
XX! {
XX!   /* A directory file has to be removed. Five conditions have to met:
XX!    * 	- The file must be a directory
XX!    *	- The directory must be empty (except for . and ..)
XX!    *	- The final component of the path must not be . or ..
XX!    *	- The directory must not be the root of a mounted file system
XX!    *	- The directory must not be anybody's root/working directory
XX!    */
XX! 
XX!   int r;
XX!   register struct fproc *rfp;
XX! 
XX!   /* search_dir checks that rip is a directory too. */
XX!   if ((r = search_dir(rip, "", (ino_t *) 0, IS_EMPTY)) != OK) return r;
XX! 
XX!   if (strcmp(dir_name, ".") == 0 || strcmp(dir_name, "..") == 0)return(EINVAL);
XX!   if (rip->i_num == ROOT_INODE) return(EBUSY); /* can't remove `root' */
XX!   
XX!   for (rfp = &fproc[INIT_PROC_NR + 1]; rfp < &fproc[NR_PROCS]; rfp++)
XX! 	if (rfp->fp_workdir == rip || rfp->fp_rootdir == rip) return(EBUSY);
XX! 				/* can't remove anybody's working dir */
XX! 
XX!   /* Actually try to unlink the file; fails if parent is mode 0 etc. */
XX!   if ((r = unlink_file(rldirp, rip, dir_name)) != OK) return r;
XX! 
XX!   /* Unlink . and .. from the dir. The super user can link and unlink any dir,
XX!    * so don't make too many assumptions about them.
XX!    */
XX!   (void) unlink_file(rip, NIL_INODE, dot1);
XX!   (void) unlink_file(rip, NIL_INODE, dot2);
XX!   return(OK);
XX! }
XX! 
XX! 
XX! /*===========================================================================*
XX!  *				unlink_file				     *
XX!  *===========================================================================*/
XX! PRIVATE int unlink_file(dirp, rip, file_name)
XX! struct inode *dirp;		/* parent directory of file */
XX! struct inode *rip;		/* inode of file, may be NIL_INODE too. */
XX! char file_name[NAME_MAX];	/* name of file to be removed */
XX! {
XX! /* Unlink 'file_name'; rip must be the inode of 'file_name' or NIL_INODE. */
XX! 
XX!   ino_t numb;			/* inode number */
XX!   int	r;
XX! 
XX!   /* If rip is not NIL_INODE, it is used to get faster access to the inode. */
XX!   if (rip == NIL_INODE) {
XX!   	/* Search for file in directory and try to get its inode. */
XX! 	err_code = search_dir(dirp, file_name, &numb, LOOK_UP);
XX! 	if (err_code == OK) rip = get_inode(dirp->i_dev, (int) numb);
XX! 	if (err_code != OK || rip == NIL_INODE) return(err_code);
XX!   } else {
XX! 	dup_inode(rip);		/* inode will be returned with put_inode */
XX!   }
XX! 
XX!   r = search_dir(dirp, file_name, (ino_t *) 0, DELETE);
XX! 
XX!   if (r == OK) {
XX! 	rip->i_nlinks--;	/* entry deleted from parent's dir */
XX! 	rip->i_update |= CTIME;
XX! 	rip->i_dirt = DIRTY;
XX!   }
XX! 
XX!   put_inode(rip);
XX!   return(r);
XX  }
X/
Xecho x - main.c.d
Xsed '/^X/s///' > main.c.d << '/'
XX*** /home/top/ast/minix/1.5/fs/main.c  crc=23426  16999	Sat Apr 21 22:26:20 1990
XX--- /home/top/ast/minix/1.6.25/fs/main.c  crc=18966  18663	Wed Mar 17 21:33:02 1993
XX***************
XX*** 1,3 ****
XX--- 1,4 ----
XX+ 
XX  /* This file contains the main program of the File System.  It consists of
XX   * a loop that gets messages requesting work, carries out the work, and sends
XX   * replies.
XX***************
XX*** 7,50 ****
XX   *   reply:	send a reply to a process after the requested work is done
XX   */
XX  
XX  #include "fs.h"
XX  #include <minix/callnr.h>
XX  #include <minix/com.h>
XX  #include <minix/boot.h>
XX  #include "buf.h"
XX  #include "file.h"
XX  #include "fproc.h"
XX  #include "inode.h"
XX  #include "param.h"
XX  #include "super.h"
XX  
XX- #if FASTLOAD
XX- #include "dev.h"
XX- #endif
XX- 
XX  #define M64K     0xFFFF0000L	/* 16 bit mask for DMA check */
XX  #define MAX_RAM        16384	/* maximum RAM disk size in blocks */
XX  #define RAM_IMAGE (dev_t)0x303	/* major-minor dev where root image is kept */
XX- #define DEMO_RAM_OFFSET  200	/* location of RAM image on demo diskette */
XX  
XX! FORWARD void buf_pool();
XX! FORWARD void fs_init();
XX! FORWARD void get_boot_parameters();
XX! FORWARD void get_work();
XX! FORWARD dev_t load_ram();
XX! FORWARD void load_super();
XX  
XX  #if ASKDEV
XX! FORWARD int askdev();
XX  #endif
XX  
XX  #if FASTLOAD
XX! FORWARD void fastload();
XX! FORWARD int lastused();
XX  #endif
XX  
XX  #if (CHIP == INTEL)
XX! FORWARD phys_bytes get_physbase();
XX  #endif
XX  
XX  /*===========================================================================*
XX--- 8,51 ----
XX   *   reply:	send a reply to a process after the requested work is done
XX   */
XX  
XX+ struct super_block;		/* proto.h needs to know this */
XX+ 
XX  #include "fs.h"
XX+ #include <fcntl.h>
XX+ #include <string.h>
XX  #include <minix/callnr.h>
XX  #include <minix/com.h>
XX  #include <minix/boot.h>
XX  #include "buf.h"
XX+ #include "dev.h"
XX  #include "file.h"
XX  #include "fproc.h"
XX  #include "inode.h"
XX  #include "param.h"
XX  #include "super.h"
XX  
XX  #define M64K     0xFFFF0000L	/* 16 bit mask for DMA check */
XX  #define MAX_RAM        16384	/* maximum RAM disk size in blocks */
XX  #define RAM_IMAGE (dev_t)0x303	/* major-minor dev where root image is kept */
XX  
XX! FORWARD _PROTOTYPE( void buf_pool, (void)				);
XX! FORWARD _PROTOTYPE( void fs_init, (void)				);
XX! FORWARD _PROTOTYPE( void get_boot_parameters, (void)			);
XX! FORWARD _PROTOTYPE( void get_work, (void)				);
XX! FORWARD _PROTOTYPE( dev_t load_ram, (void)				);
XX! FORWARD _PROTOTYPE( void load_super, (Dev_t super_dev, block_t origin)	);
XX  
XX  #if ASKDEV
XX! FORWARD _PROTOTYPE( int askdev, (void)					);
XX  #endif
XX  
XX  #if FASTLOAD
XX! FORWARD _PROTOTYPE( void fastload, (Dev_t boot_dev, char *address)	);
XX! FORWARD _PROTOTYPE( int lastused, (Dev_t boot_dev)			);
XX  #endif
XX  
XX  #if (CHIP == INTEL)
XX! FORWARD _PROTOTYPE( phys_bytes get_physbase, (void)			);
XX  #endif
XX  
XX  /*===========================================================================*
XX***************
XX*** 144,157 ****
XX    register struct inode *rip;
XX    int i;
XX    dev_t d;			/* device to fetch the superblock from */
XX  
XX    buf_pool();			/* initialize buffer pool */
XX!   get_boot_parameters();
XX    d = load_ram();		/* init RAM disk, load if it is root */
XX!   load_super(d);		/* Load super block for root device */
XX  
XX!   /* Initialize the 'fproc' fields for process 0 and process 2. */
XX!   for (i = 0; i < 3; i+= 2) {
XX  	fp = &fproc[i];
XX  	rip = get_inode(ROOT_DEV, ROOT_INODE);
XX  	fp->fp_rootdir = rip;
XX--- 145,163 ----
XX    register struct inode *rip;
XX    int i;
XX    dev_t d;			/* device to fetch the superblock from */
XX+   
XX+   /* The following 3 initializations are needed to let dev_open succeed .*/
XX+   fp = (struct fproc *) NULL;
XX+   who = FS_PROC_NR;
XX  
XX    buf_pool();			/* initialize buffer pool */
XX!   get_boot_parameters();	/* get the parameters from the menu */
XX    d = load_ram();		/* init RAM disk, load if it is root */
XX!   load_super(d, (block_t) 0);	/* load super block for root device */
XX  
XX!   /* Initialize the 'fproc' fields for process 0 .. INIT. */
XX!   for (i = 0; i <= LOW_USER; i+= 1) {
XX! 	if (i == FS_PROC_NR) continue;	/* do not initialize FS */
XX  	fp = &fproc[i];
XX  	rip = get_inode(ROOT_DEV, ROOT_INODE);
XX  	fp->fp_rootdir = rip;
XX***************
XX*** 165,176 ****
XX    }
XX  
XX    /* Certain relations must hold for the file system to work at all. */
XX-   if (ZONE_NUM_SIZE != 2) panic("ZONE_NUM_SIZE != 2", NO_NUM);
XX    if (SUPER_SIZE > BLOCK_SIZE) panic("SUPER_SIZE > BLOCK_SIZE", NO_NUM);
XX!   if(BLOCK_SIZE % INODE_SIZE != 0)panic("BLOCK_SIZE % INODE_SIZE != 0",NO_NUM);
XX    if (OPEN_MAX > 127) panic("OPEN_MAX > 127", NO_NUM);
XX    if (NR_BUFS < 6) panic("NR_BUFS < 6", NO_NUM);
XX!   if (sizeof(d_inode) != 32) panic("inode size != 32", NO_NUM);
XX  }
XX  
XX  /*===========================================================================*
XX--- 171,184 ----
XX    }
XX  
XX    /* Certain relations must hold for the file system to work at all. */
XX    if (SUPER_SIZE > BLOCK_SIZE) panic("SUPER_SIZE > BLOCK_SIZE", NO_NUM);
XX!   if (BLOCK_SIZE % V2_INODE_SIZE != 0)	/* this checks V1_INODE_SIZE too */
XX! 	panic("BLOCK_SIZE % V2_INODE_SIZE != 0", NO_NUM);
XX    if (OPEN_MAX > 127) panic("OPEN_MAX > 127", NO_NUM);
XX    if (NR_BUFS < 6) panic("NR_BUFS < 6", NO_NUM);
XX!   if (V1_INODE_SIZE != 32) panic("V1 inode size != 32", NO_NUM);
XX!   if (V2_INODE_SIZE != 64) panic("V2 inode size != 64", NO_NUM);
XX!   if (OPEN_MAX > 8 * sizeof(long)) panic("Too few bits in fp_cloexec", NO_NUM);
XX  }
XX  
XX  /*===========================================================================*
XX***************
XX*** 210,222 ****
XX  	high_off = low_off + BLOCK_SIZE - 1;
XX  	if (((org + low_off) & M64K) != ((org + high_off) & M64K)) {
XX  		++bp->b_count;	/* it was 0, by static initialization */
XX! 		++bufs_in_use;
XX  	}
XX    }
XX  #endif
XX  
XX    for (bp = &buf[0]; bp < &buf[NR_BUFS]; bp++) bp->b_hash = bp->b_next;
XX!   buf_hash[NO_BLOCK & (NR_BUF_HASH - 1)] = front;
XX  }
XX  
XX  
XX--- 218,230 ----
XX  	high_off = low_off + BLOCK_SIZE - 1;
XX  	if (((org + low_off) & M64K) != ((org + high_off) & M64K)) {
XX  		++bp->b_count;	/* it was 0, by static initialization */
XX! 		rm_lru(bp);
XX  	}
XX    }
XX  #endif
XX  
XX    for (bp = &buf[0]; bp < &buf[NR_BUFS]; bp++) bp->b_hash = bp->b_next;
XX!   buf_hash[0] = front;
XX  }
XX  
XX  
XX***************
XX*** 232,244 ****
XX  
XX    register struct buf *bp, *bp1;
XX    int count;
XX!   long k_loaded;
XX    struct super_block *sp;
XX!   block_nr ram_offset = 0;	/* block offset of RAM image on demo diskette*/
XX!   block_nr i, b;
XX    dev_t root_device;		/* really the root image device */
XX    dev_t super_dev;		/* device to get superblock from */
XX    phys_clicks ram_clicks, init_org, init_text_clicks, init_data_clicks;
XX  
XX    /* Get size of INIT by reading block on diskette where 'build' put it. */
XX    init_org = data_org[INFO];
XX--- 240,254 ----
XX  
XX    register struct buf *bp, *bp1;
XX    int count;
XX!   long k_loaded, lcount;
XX    struct super_block *sp;
XX!   block_t ram_offset = 0;	/* block offset of RAM image on demo diskette*/
XX!   block_t i, b;
XX    dev_t root_device;		/* really the root image device */
XX    dev_t super_dev;		/* device to get superblock from */
XX    phys_clicks ram_clicks, init_org, init_text_clicks, init_data_clicks;
XX+   int major, task;
XX+   message dev_mess;
XX  
XX    /* Get size of INIT by reading block on diskette where 'build' put it. */
XX    init_org = data_org[INFO];
XX***************
XX*** 247,297 ****
XX  
XX    /* Print ATARI copyright message. */
XX  #if (MACHINE == ATARI)
XX!   printf("Booting MINIX 1.5.  Copyright 1990 Prentice-Hall, Inc.\n");
XX  #endif
XX  
XX    /* If the root device is specified in the boot parameters, use it. */
XX    if (ROOT_DEV != DEV_RAM) {
XX! 	count = boot_parameters.bp_ramsize;
XX  	super_dev = ROOT_DEV;	/* get superblock directly from root device */
XX  	goto got_root_dev;	/* kludge to avoid excessive indent/diffs */
XX    } else {
XX  	super_dev = DEV_RAM;	/* get superblock from RAM disk */
XX    }
XX  
XX    /* Get size of RAM disk by reading root file system's super block.
XX     * First read block 0 from the floppy.  If this is a valid file system, use
XX     * it as the root image, otherwise try the hard disk (RAM_IMAGE).  
XX     */
XX  #if ASKDEV
XX!   root_device = (dev_t)askdev();
XX!   if (root_device == 0)
XX  #endif
XX  
XX! #if DEMO
XX!   /* If this file is compiled with -DDEMO=1, RAM image is at DEMO_RAM_OFFSET */
XX!   ram_offset = DEMO_RAM_OFFSET;
XX! #endif
XX  
XX!   root_device = BOOT_DEV;	/* get super block; try floppy disk first */
XX!   bp = get_block(root_device, SUPER_BLOCK + ram_offset, NORMAL);
XX!   copy(super_block, bp->b_data, SUPER_SIZE);
XX!   sp = &super_block[0];
XX!   if (sp->s_magic != SUPER_MAGIC) {
XX! 	put_block(bp, FULL_DATA_BLOCK);
XX! 	root_device = RAM_IMAGE;
XX! 	bp = get_block(root_device, SUPER_BLOCK, NORMAL);  /* get super block*/
XX! 	copy(super_block, bp->b_data, SUPER_SIZE);
XX! 	sp = &super_block[0];
XX! 	if (sp->s_magic != SUPER_MAGIC)
XX! 		panic("Invalid root file system", NO_NUM);
XX    }
XX-   count = sp->s_nzones << sp->s_log_zone_size;	/* # blocks on root dev */
XX-   put_block(bp, FULL_DATA_BLOCK);
XX  
XX  got_root_dev:
XX!   if (count > MAX_RAM) panic("RAM disk is too big. # blocks = ", count);
XX!   ram_clicks = count * (BLOCK_SIZE/CLICK_SIZE);
XX  
XX    /* Tell MM the origin and size of INIT, and the amount of memory used for the
XX     * system plus RAM disk combined, so it can remove all of it from the map.
XX--- 257,323 ----
XX  
XX    /* Print ATARI copyright message. */
XX  #if (MACHINE == ATARI)
XX!   printf("Booting MINIX 1.6.25.  Copyright 1993 Prentice-Hall, Inc.\n");
XX  #endif
XX  
XX    /* If the root device is specified in the boot parameters, use it. */
XX    if (ROOT_DEV != DEV_RAM) {
XX! 	lcount = boot_parameters.bp_ramsize;
XX  	super_dev = ROOT_DEV;	/* get superblock directly from root device */
XX+ 	major = (super_dev >> MAJOR) & BYTE;	/* major device nr */
XX+ 	task = dmap[major].dmap_task;		/* device task nr */
XX+ 	dev_mess.m_type = DEV_OPEN;		/* distinguish from close */
XX+ 	dev_mess.DEVICE = super_dev;
XX+ 	dev_mess.TTY_FLAGS = O_RDWR;
XX+ 	(*dmap[major].dmap_open)(task, &dev_mess);
XX+ 	if (dev_mess.REP_STATUS != OK) panic("Cannot open root device",NO_NUM);
XX  	goto got_root_dev;	/* kludge to avoid excessive indent/diffs */
XX    } else {
XX  	super_dev = DEV_RAM;	/* get superblock from RAM disk */
XX    }
XX  
XX+   sp = &super_block[0];
XX    /* Get size of RAM disk by reading root file system's super block.
XX     * First read block 0 from the floppy.  If this is a valid file system, use
XX     * it as the root image, otherwise try the hard disk (RAM_IMAGE).  
XX     */
XX  #if ASKDEV
XX!   sp->s_dev = (dev_t) askdev();
XX!   if (sp->s_dev == 0)
XX  #endif
XX+   sp->s_dev = BOOT_DEV;	/* this is the 'then' clause if ASKDEV is defined */
XX  
XX!   major = (sp->s_dev >> MAJOR) & BYTE;	/* major device nr */
XX!   task = dmap[major].dmap_task;		/* device task nr */
XX!   dev_mess.m_type = DEV_OPEN;		/* distinguish from close */
XX!   dev_mess.DEVICE = sp->s_dev;
XX!   dev_mess.TTY_FLAGS = O_RDWR;
XX!   (*dmap[major].dmap_open)(task, &dev_mess);
XX!   if (dev_mess.REP_STATUS != OK) panic("Cannot open root device", NO_NUM);
XX  
XX!   read_super(sp, ram_offset);	/* read in default (root or image) super blk*/
XX!   if (sp->s_version == 0) {
XX! 	dev_mess.m_type = DEV_CLOSE;		/* distinguish from open */
XX! 	(*dmap[major].dmap_close)(task, &dev_mess);
XX! 	sp->s_dev = RAM_IMAGE;
XX! 	major = (sp->s_dev >> MAJOR) & BYTE;	/* major device nr */
XX! 	task = dmap[major].dmap_task;		/* device task nr */
XX! 	dev_mess.m_type = DEV_OPEN;		/* distinguish from close */
XX! 	dev_mess.DEVICE = sp->s_dev;
XX! 	dev_mess.TTY_FLAGS = O_RDWR;
XX! 	(*dmap[major].dmap_open)(task, &dev_mess);
XX! 	if (dev_mess.REP_STATUS != OK) panic("Cannot open RAM image",NO_NUM);
XX! 	read_super(sp, ram_offset);	/* read in HD RAM image super block */
XX! 	if (sp->s_version == 0) panic("Bad root file system", NO_NUM);
XX    }
XX  
XX+   root_device = sp->s_dev;
XX+   lcount = sp->s_zones << sp->s_log_zone_size;	/* # blks on root dev*/
XX+ 
XX  got_root_dev:
XX!   if (lcount > MAX_RAM) panic("RAM disk is too big. # blocks > ", MAX_RAM);
XX!   count = (int) lcount;		/* lcount is now known to be <= MAX_RAM */
XX!   ram_clicks = (lcount * BLOCK_SIZE)/CLICK_SIZE;
XX  
XX    /* Tell MM the origin and size of INIT, and the amount of memory used for the
XX     * system plus RAM disk combined, so it can remove all of it from the map.
XX***************
XX*** 300,318 ****
XX    m1.m1_i1 = init_text_clicks;
XX    m1.m1_i2 = init_data_clicks;
XX    m1.m1_i3 = init_org + init_text_clicks + init_data_clicks + ram_clicks;
XX! 
XX! #if (MACHINE == ATARI)
XX!   m1.m1_p1 = (char *) (int) init_org;	/* bug in Alcyon 4.14 C */
XX! #else
XX!   m1.m1_p1 = (char *) init_org;		/* other compilers */
XX! #endif
XX! 
XX    if (sendrec(MM_PROC_NR, &m1) != OK) panic("FS Can't report to MM", NO_NUM);
XX  
XX    /* Tell RAM driver where RAM disk is and how big it is. The BRK2 call has
XX     * filled in the m1.POSITION field.
XX     */
XX!   m1.m_type = DISK_IOCTL;
XX    m1.DEVICE = RAM_DEV;
XX    m1.COUNT = count;
XX    if (sendrec(MEM, &m1) != OK) panic("Can't report size to MEM", NO_NUM);
XX--- 326,338 ----
XX    m1.m1_i1 = init_text_clicks;
XX    m1.m1_i2 = init_data_clicks;
XX    m1.m1_i3 = init_org + init_text_clicks + init_data_clicks + ram_clicks;
XX!   m1.m1_p1 = (char *) (int) init_org;	/* bug in Alcyon 4.14 C needs 2 casts*/
XX    if (sendrec(MM_PROC_NR, &m1) != OK) panic("FS Can't report to MM", NO_NUM);
XX  
XX    /* Tell RAM driver where RAM disk is and how big it is. The BRK2 call has
XX     * filled in the m1.POSITION field.
XX     */
XX!   m1.m_type = DEV_IOCTL;
XX    m1.DEVICE = RAM_DEV;
XX    m1.COUNT = count;
XX    if (sendrec(MEM, &m1) != OK) panic("Can't report size to MEM", NO_NUM);
XX***************
XX*** 328,349 ****
XX    /* If the root device is not the RAM disk, it doesn't need loading. */
XX    if (ROOT_DEV != DEV_RAM) return(super_dev);	/* ROOT_DEV is a macro */
XX  
XX-   /* Copy the blocks one at a time from the root diskette to the RAM */
XX- 
XX  #if FASTLOAD
XX    fastload(root_device, (char *) m1.POSITION);	/* assumes 32 bit pointers */
XX  #else
XX-   printf("Loading RAM disk.                            Loaded:   0K ");
XX  
XX    inode[0].i_mode = I_BLOCK_SPECIAL;	/* temp inode for rahead */
XX!   inode[0].i_size = MAX_P_LONG;
XX!   inode[0].i_dev = inode[0].i_zone[0] = root_device;
XX  
XX    for (i = 0; i < count; i++) {
XX  	b = i + ram_offset;		/* true block number */
XX! 	bp = rahead(&inode[0], (block_nr) b, (off_t)BLOCK_SIZE*b, BLOCK_SIZE);
XX  	bp1 = get_block(ROOT_DEV, i, NO_READ);
XX! 	copy(bp1->b_data, bp->b_data, BLOCK_SIZE);
XX  	bp1->b_dirt = DIRTY;
XX  	put_block(bp, I_MAP_BLOCK);
XX  	put_block(bp1, I_MAP_BLOCK);
XX--- 348,370 ----
XX    /* If the root device is not the RAM disk, it doesn't need loading. */
XX    if (ROOT_DEV != DEV_RAM) return(super_dev);	/* ROOT_DEV is a macro */
XX  
XX  #if FASTLOAD
XX+   /* Copy the blocks one at a time from the root diskette to the RAM */
XX    fastload(root_device, (char *) m1.POSITION);	/* assumes 32 bit pointers */
XX  #else
XX  
XX+   printf("Loading RAM disk.                       Loaded:    0K ");
XX+ 
XX    inode[0].i_mode = I_BLOCK_SPECIAL;	/* temp inode for rahead */
XX!   inode[0].i_size = LONG_MAX;
XX!   inode[0].i_dev = root_device;
XX!   inode[0].i_zone[0] = root_device;
XX  
XX    for (i = 0; i < count; i++) {
XX  	b = i + ram_offset;		/* true block number */
XX! 	bp = rahead(&inode[0], (block_t) b, (off_t)BLOCK_SIZE*b, BLOCK_SIZE);
XX  	bp1 = get_block(ROOT_DEV, i, NO_READ);
XX! 	memcpy(bp1->b_data, bp->b_data, (size_t) BLOCK_SIZE);
XX  	bp1->b_dirt = DIRTY;
XX  	put_block(bp, I_MAP_BLOCK);
XX  	put_block(bp1, I_MAP_BLOCK);
XX***************
XX*** 363,371 ****
XX  /*===========================================================================*
XX   *				load_super				     *
XX   *===========================================================================*/
XX! PRIVATE void load_super(super_dev)
XX  dev_t super_dev;			/* place to get superblock from */
XX  {
XX    register struct super_block *sp;
XX    register struct inode *rip;
XX  
XX--- 384,394 ----
XX  /*===========================================================================*
XX   *				load_super				     *
XX   *===========================================================================*/
XX! PRIVATE void load_super(super_dev, origin)
XX  dev_t super_dev;			/* place to get superblock from */
XX+ block_t origin;				/* offset to give to read_super() */
XX  {
XX+   int bad;
XX    register struct super_block *sp;
XX    register struct inode *rip;
XX  
XX***************
XX*** 376,388 ****
XX    /* Read in super_block for the root file system. */
XX    sp = &super_block[0];
XX    sp->s_dev = super_dev;
XX!   rw_super(sp,READING);
XX!   rip = get_inode(super_dev, ROOT_INODE);	/* inode for root dir */
XX  
XX    /* Check super_block for consistency (is it the right diskette?). */
XX!   if ( (rip->i_mode & I_TYPE) != I_DIRECTORY || rip->i_nlinks < 3 ||
XX! 						sp->s_magic != SUPER_MAGIC)
XX! 	panic("Root file system corrupted.  Possibly wrong diskette.", NO_NUM);
XX  
XX    sp->s_imount = rip;
XX    dup_inode(rip);
XX--- 399,413 ----
XX    /* Read in super_block for the root file system. */
XX    sp = &super_block[0];
XX    sp->s_dev = super_dev;
XX!   read_super(sp, origin);
XX  
XX    /* Check super_block for consistency (is it the right diskette?). */
XX!   bad = (sp->s_version == 0); /* version is zero if bad magic in super block.*/
XX!   if (!bad) {
XX! 	rip = get_inode(super_dev, ROOT_INODE);	/* inode for root dir */
XX! 	if ( (rip->i_mode & I_TYPE) != I_DIRECTORY || rip->i_nlinks < 3) bad++;
XX!   }
XX!   if (bad)panic("Invalid root file system.  Possibly wrong diskette.",NO_NUM);
XX  
XX    sp->s_imount = rip;
XX    dup_inode(rip);
XX***************
XX*** 397,448 ****
XX  /*===========================================================================*
XX   *				askdev					     *
XX   *===========================================================================*/
XX! PRIVATE askdev()
XX  {
XX    char line[80];
XX    register char *p;
XX    register min, maj, c, n;
XX  
XX    printf("Insert ROOT diskette and hit RETURN (or specify bootdev) %c", 0);
XX!   m.m_type = TTY_READ;
XX    m.TTY_LINE = 0;
XX    m.PROC_NR = FS_PROC_NR;
XX    m.ADDRESS = line;
XX    m.COUNT = sizeof(line);
XX!   if (sendrec(TTY, &m) != OK)
XX! 	return(0);
XX    for (;;) {
XX! 	if (m.REP_PROC_NR != FS_PROC_NR)
XX! 		return(-1);
XX! 	if (m.REP_STATUS != SUSPEND)
XX! 		break;
XX  	receive(TTY, &m);
XX    }
XX!   if ((n = m.REP_STATUS) <= 0)
XX! 	return(0);
XX    p = line;
XX    for (maj = 0;;) {
XX! 	if (--n < 0)
XX! 		return(0);
XX  	c = *p++;
XX! 	if (c == ',')
XX! 		break;
XX! 	if (c < '0' || c > '9')
XX! 		return(0);
XX  	maj = maj * 10 + c - '0';
XX    }
XX!   for (min = 0;;) {
XX! 	if (--n < 0)
XX! 		return(0);
XX  	c = *p++;
XX! 	if (c == '\n')
XX! 		break;
XX! 	if (c < '0' || c > '9')
XX! 		return(0);
XX  	min = min * 10 + c - '0';
XX    }
XX!   if (n != 0)
XX! 	return(0);
XX    return((maj << 8) | min);
XX  }
XX  #endif /* ASKDEV */
XX--- 422,462 ----
XX  /*===========================================================================*
XX   *				askdev					     *
XX   *===========================================================================*/
XX! PRIVATE int askdev()
XX  {
XX    char line[80];
XX    register char *p;
XX    register min, maj, c, n;
XX  
XX    printf("Insert ROOT diskette and hit RETURN (or specify bootdev) %c", 0);
XX!   m.m_type = DEV_READ;
XX    m.TTY_LINE = 0;
XX    m.PROC_NR = FS_PROC_NR;
XX    m.ADDRESS = line;
XX    m.COUNT = sizeof(line);
XX!   if (sendrec(TTY, &m) != OK) return(0);
XX    for (;;) {
XX! 	if (m.REP_PROC_NR != FS_PROC_NR) return(-1);
XX! 	if (m.REP_STATUS != SUSPEND) break;
XX  	receive(TTY, &m);
XX    }
XX!   if ((n = m.REP_STATUS) <= 0) return(0);
XX    p = line;
XX    for (maj = 0;;) {
XX! 	if (--n < 0) return(0);
XX  	c = *p++;
XX! 	if (c == ',') break;
XX! 	if (c < '0' || c > '9') return(0);
XX  	maj = maj * 10 + c - '0';
XX    }
XX!   for (min = 0; ;) {
XX! 	if (--n < 0) return(0);
XX  	c = *p++;
XX! 	if (c == '\n') break;
XX! 	if (c < '0' || c > '9') return(0);
XX  	min = min * 10 + c - '0';
XX    }
XX!   if (n != 0) return(0);
XX    return((maj << 8) | min);
XX  }
XX  #endif /* ASKDEV */
XX***************
XX*** 459,474 ****
XX    register long position;
XX  
XX    blocks = lastused(boot_dev);
XX!   printf("Loading RAM disk. To load: %4DK           Loaded:   0K %c",
XX  	((long)blocks * BLOCK_SIZE) / 1024, 0);
XX    position = 0;
XX    while (blocks) {
XX  	i = blocks;
XX! 	if (i > (18*1024)/BLOCK_SIZE)
XX! 		i = (18*1024)/BLOCK_SIZE;
XX  	blocks -= i;
XX  	i *= BLOCK_SIZE;
XX! 	m1.m_type = DISK_READ;
XX  	m1.DEVICE = (boot_dev >> MINOR) & BYTE;
XX  	m1.POSITION = position;
XX  	m1.PROC_NR = HARDWARE;
XX--- 473,487 ----
XX    register long position;
XX  
XX    blocks = lastused(boot_dev);
XX!   printf("Loading RAM disk. To load: %4DK        Loaded:   0K %c",
XX  	((long)blocks * BLOCK_SIZE) / 1024, 0);
XX    position = 0;
XX    while (blocks) {
XX  	i = blocks;
XX! 	if (i > (18*1024)/BLOCK_SIZE) i = (18*1024)/BLOCK_SIZE;
XX  	blocks -= i;
XX  	i *= BLOCK_SIZE;
XX! 	m1.m_type = DEV_READ;
XX  	m1.DEVICE = (boot_dev >> MINOR) & BYTE;
XX  	m1.POSITION = position;
XX  	m1.PROC_NR = HARDWARE;
XX***************
XX*** 495,518 ****
XX    register i, w, b, last, this, zbase;
XX    register struct super_block *sp = &super_block[0];
XX    register struct buf *bp;
XX!   register short *wptr, *wlim;
XX  
XX    zbase = SUPER_BLOCK + 1 + sp->s_imap_blocks;
XX    this = sp->s_firstdatazone;
XX    last = this - 1;
XX    for (i = 0; i < sp->s_zmap_blocks; i++) {
XX! 	bp = get_block(boot_dev, (block_nr) zbase + i, NORMAL);
XX! 	wptr = (short *)&bp->b_data[0];
XX! 	wlim = (short *)&bp->b_data[BLOCK_SIZE];
XX  	while (wptr != wlim) {
XX  		w = *wptr++;
XX  		for (b = 0; b < 8*sizeof(*wptr); b++) {
XX! 			if (this == sp->s_nzones) {
XX  				put_block(bp, ZMAP_BLOCK);
XX  				return(last << sp->s_log_zone_size);
XX  			}
XX! 			if ((w>>b) & 1)
XX! 				last = this;
XX  			this++;
XX  		}
XX  	}
XX--- 508,530 ----
XX    register i, w, b, last, this, zbase;
XX    register struct super_block *sp = &super_block[0];
XX    register struct buf *bp;
XX!   register bitchunk_t *wptr, *wlim;
XX  
XX    zbase = SUPER_BLOCK + 1 + sp->s_imap_blocks;
XX    this = sp->s_firstdatazone;
XX    last = this - 1;
XX    for (i = 0; i < sp->s_zmap_blocks; i++) {
XX! 	bp = get_block(boot_dev, (block_t) zbase + i, NORMAL);
XX! 	wptr = &bp->b_bitmap[0];
XX! 	wlim = &bp->b_bitmap[BITMAP_CHUNKS];
XX  	while (wptr != wlim) {
XX  		w = *wptr++;
XX  		for (b = 0; b < 8*sizeof(*wptr); b++) {
XX! 			if (this == sp->s_zones) {
XX  				put_block(bp, ZMAP_BLOCK);
XX  				return(last << sp->s_log_zone_size);
XX  			}
XX! 			if ((w>>b) & 1) last = this;
XX  			this++;
XX  		}
XX  	}
XX***************
XX*** 558,563 ****
XX    m1.COPY_BYTES = 1;
XX    if (sendrec(SYSTASK, &m1) != OK || m1.SRC_BUFFER == 0)
XX  	panic("Can't get fs base", NO_NUM);
XX!   return m1.SRC_BUFFER;
XX  }
XX  #endif /* INTEL */
XX--- 570,576 ----
XX    m1.COPY_BYTES = 1;
XX    if (sendrec(SYSTASK, &m1) != OK || m1.SRC_BUFFER == 0)
XX  	panic("Can't get fs base", NO_NUM);
XX!   return(m1.SRC_BUFFER);
XX  }
XX  #endif /* INTEL */
XX+ 
X/
Xecho x - misc.c.d
Xsed '/^X/s///' > misc.c.d << '/'
XX*** /home/top/ast/minix/1.5/fs/misc.c  crc=08671   8446	Sat Apr 21 22:26:20 1990
XX--- /home/top/ast/minix/1.6.25/fs/misc.c  crc=54700  15616	Wed Mar 17 21:33:10 1993
XX***************
XX*** 3,19 ****
XX   * that are mostly performed by the Memory Manager.
XX   *
XX   * The entry points into this file are
XX!  *   do_dup:	perform the DUP system call
XX!  *   do_fcntl:	perform the FCNTL system call
XX!  *   do_sync:	perform the SYNC system call
XX!  *   do_fork:	adjust the tables after MM has performed a FORK system call
XX!  *   do_exit:	a process has exited; note that in the tables
XX!  *   do_set:	set uid or gid for some process
XX!  *   do_revive:	revive a process that was waiting for something (e.g. TTY)
XX   */
XX  
XX  #include "fs.h"
XX  #include <fcntl.h>
XX  #include <minix/callnr.h>
XX  #include <minix/com.h>
XX  #include <minix/boot.h>
XX--- 3,23 ----
XX   * that are mostly performed by the Memory Manager.
XX   *
XX   * The entry points into this file are
XX!  *   do_dup:	  perform the DUP system call
XX!  *   do_fcntl:	  perform the FCNTL system call
XX!  *   lock_op:	  handle the setting of locks
XX!  *   lock_revive: revive processes when a lock is released
XX!  *   do_sync:	  perform the SYNC system call
XX!  *   do_fork:	  adjust the tables after MM has performed a FORK system call
XX!  *   do_exec:	  handle files with FD_CLOEXEC on after MM has done an EXEC
XX!  *   do_exit:	  a process has exited; note that in the tables
XX!  *   do_set:	  set uid or gid for some process
XX!  *   do_revive:	  revive a process that was waiting for something (e.g. TTY)
XX   */
XX  
XX  #include "fs.h"
XX  #include <fcntl.h>
XX+ #include <tiny-unistd.h>	/* cc runs out of memory with unistd.h :-( */
XX  #include <minix/callnr.h>
XX  #include <minix/com.h>
XX  #include <minix/boot.h>
XX***************
XX*** 22,35 ****
XX  #include "fproc.h"
XX  #include "inode.h"
XX  #include "param.h"
XX- #include "super.h"
XX  
XX  /*===========================================================================*
XX   *				do_dup					     *
XX   *===========================================================================*/
XX  PUBLIC int do_dup()
XX  {
XX! /* Perform the dup(fd) or dup(fd,fd2) system call. */
XX  
XX    register int rfd;
XX    register struct filp *f;
XX--- 26,45 ----
XX  #include "fproc.h"
XX  #include "inode.h"
XX  #include "param.h"
XX  
XX+ FORWARD _PROTOTYPE( int lock_op, (struct filp *f, int req)		);
XX+ 
XX+ 
XX  /*===========================================================================*
XX   *				do_dup					     *
XX   *===========================================================================*/
XX  PUBLIC int do_dup()
XX  {
XX! /* Perform the dup(fd) or dup(fd,fd2) system call. These system calls are
XX!  * obsolete.  In fact, it is not even possible to invoke them using the
XX!  * current library because the library routines call fcntl().  They are
XX!  * provided to permit old binary programs to continue to run.
XX!  */
XX  
XX    register int rfd;
XX    register struct filp *f;
XX***************
XX*** 67,72 ****
XX--- 77,84 ----
XX  
XX    register struct filp *f;
XX    int new_fd, r, fl;
XX+   long cloexec_mask;		/* bit map for the FD_CLOEXEC flag */
XX+   long clo_value;		/* FD_CLOEXEC flag in proper position */
XX    struct filp *dummy;
XX  
XX    /* Is the file descriptor valid? */
XX***************
XX*** 74,100 ****
XX  
XX    switch (request) {
XX       case F_DUPFD: 
XX! 	/* DUP */
XX! 	if (addr < 0 || addr >= OPEN_MAX) break;
XX  	if ((r = get_fd(addr, 0, &new_fd, &dummy)) != OK) return(r);
XX     	f->filp_count++;
XX    	fp->fp_filp[new_fd] = f;
XX    	return(new_fd);
XX  
XX       case F_GETFD: 
XX! 	/* Get close-on-exec flag. */
XX! 	break;	
XX  
XX       case F_SETFD: 
XX! 	/* Set close-on-exec flag. */
XX! 	break;	
XX  
XX       case F_GETFL: 
XX! 	/* Get file status flags. */
XX! 	return(f->filp_flags);	
XX  
XX       case F_SETFL: 
XX! 	/* Set file status flags. */
XX  	fl = O_NONBLOCK | O_APPEND;
XX  	f->filp_flags = (f->filp_flags & ~fl) | (addr & fl);
XX  	return(OK);
XX--- 86,116 ----
XX  
XX    switch (request) {
XX       case F_DUPFD: 
XX! 	/* This replaces the old dup() system call. */
XX! 	if (addr < 0 || addr >= OPEN_MAX) return(EINVAL);
XX  	if ((r = get_fd(addr, 0, &new_fd, &dummy)) != OK) return(r);
XX     	f->filp_count++;
XX    	fp->fp_filp[new_fd] = f;
XX    	return(new_fd);
XX  
XX       case F_GETFD: 
XX! 	/* Get close-on-exec flag (FD_CLOEXEC in POSIX Table 6-2). */
XX! 	return( ((fp->fp_cloexec >> fd) & 01) ? FD_CLOEXEC : 0);
XX  
XX       case F_SETFD: 
XX! 	/* Set close-on-exec flag (FD_CLOEXEC in POSIX Table 6-2). */
XX! 	cloexec_mask = 1L << fd;	/* singleton set position ok */
XX! 	clo_value = (addr & FD_CLOEXEC ? cloexec_mask : 0L);
XX! 	fp->fp_cloexec = (fp->fp_cloexec & ~cloexec_mask) | clo_value;
XX! 	return(OK);
XX  
XX       case F_GETFL: 
XX! 	/* Get file status flags (O_NONBLOCK and O_APPEND). */
XX! 	fl = f->filp_flags & (O_NONBLOCK | O_APPEND | O_ACCMODE);
XX! 	return(fl);	
XX  
XX       case F_SETFL: 
XX! 	/* Set file status flags (O_NONBLOCK and O_APPEND). */
XX  	fl = O_NONBLOCK | O_APPEND;
XX  	f->filp_flags = (f->filp_flags & ~fl) | (addr & fl);
XX  	return(OK);
XX***************
XX*** 102,114 ****
XX       case F_GETLK:
XX       case F_SETLK:
XX       case F_SETLKW:
XX! 	printf("do_fcntl: flag not yet implemented\n");
XX    }
XX-   return(EINVAL);
XX  }
XX  
XX  
XX  /*===========================================================================*
XX   *				do_sync					     *
XX   *===========================================================================*/
XX  PUBLIC int do_sync()
XX--- 118,307 ----
XX       case F_GETLK:
XX       case F_SETLK:
XX       case F_SETLKW:
XX! 	/* Set or clear a file lock. */
XX! 	r = lock_op(f, request);
XX! 	return(r);
XX! 
XX!      default:
XX! 	return(EINVAL);
XX    }
XX  }
XX  
XX  
XX  /*===========================================================================*
XX+  *				lock_op					     *
XX+  *===========================================================================*/
XX+ PRIVATE int lock_op(f, req)
XX+ struct filp *f;
XX+ int req;			/* either F_SETLK or F_SETLKW */
XX+ {
XX+ /* Perform the advisory locking required by POSIX. */
XX+ 
XX+   int r, ltype, mo, i, conflict = 0, unlocking = 0;
XX+   off_t first, last;
XX+   struct flock flock;
XX+ 
XX+   char *fs_addr;
XX+   vir_bytes user_flock, fs_flock, flock_size;
XX+   struct file_lock *flp, *flp2, *empty;
XX+ 
XX+   /* Fetch the flock structure from user space. */
XX+   fs_flock   = (vir_bytes) &flock;
XX+   flock_size = (vir_bytes) sizeof(struct flock);
XX+   user_flock = (vir_bytes) name1;
XX+   fs_addr = (char *) fs_flock;
XX+   r = rw_user(D, who, user_flock, flock_size, fs_addr, FROM_USER);
XX+   if (r != OK) return(EINVAL);
XX+ 
XX+   /* Make some error checks. */
XX+   ltype = flock.l_type;
XX+   mo = f->filp_mode;
XX+   if (ltype != F_UNLCK && ltype != F_RDLCK && ltype != F_WRLCK) return(EINVAL);
XX+   if (req == F_GETLK && ltype == F_UNLCK) return(EINVAL);
XX+   if ( (f->filp_ino->i_mode & I_TYPE) != I_REGULAR) return(EINVAL);
XX+   if (req != F_GETLK && ltype == F_RDLCK && (mo & R_BIT) == 0) return(EBADF);
XX+   if (req != F_GETLK && ltype == F_WRLCK && (mo & W_BIT) == 0) return(EBADF);
XX+ 
XX+   /* Compute the first and last bytes in the lock region. */
XX+   switch (flock.l_whence) {
XX+ 	case SEEK_SET:	first = 0; break;
XX+ 	case SEEK_CUR:	first = f->filp_pos; break;
XX+ 	case SEEK_END:	first = f->filp_ino->i_size; break;
XX+ 	default:	return(EINVAL);
XX+   }
XX+   /* check for overflow */
XX+   if (((long)flock.l_start > 0) && ((first + flock.l_start) < first))
XX+ 	return(EINVAL);
XX+   if (((long)flock.l_start < 0) && ((first + flock.l_start) > first))
XX+ 	return(EINVAL);
XX+   first = first + flock.l_start;
XX+   last = first + flock.l_len - 1;
XX+   if (flock.l_len == 0) last = MAX_FILE_POS;
XX+   if (last < first) return(EINVAL);
XX+ 
XX+   /* Check if this region conflicts with any existing lock. */
XX+   empty = (struct file_lock *) 0;
XX+   for (flp = &file_lock[0]; flp < & file_lock[NR_LOCKS]; flp++) {
XX+ 	if (flp->lock_type == 0) {
XX+ 		if (empty == (struct file_lock *) 0) empty = flp;
XX+ 		continue;	/* 0 means unused slot */
XX+ 	}
XX+ 	if (flp->lock_inode != f->filp_ino) continue;	/* different file */
XX+ 	if (last < flp->lock_first) continue;	/* new one is in front */
XX+ 	if (first > flp->lock_last) continue;	/* new one is afterwards */
XX+ 	if (ltype == F_RDLCK && flp->lock_type == F_RDLCK) continue;
XX+ 	if (req != F_GETLK && ltype != F_UNLCK && flp->lock_pid == fp->fp_pid) 
XX+ 		continue;
XX+   
XX+ 	/* There might be a conflict.  Process it. */
XX+ 	conflict = 1;
XX+ 	if (req == F_GETLK) break;
XX+ 
XX+ 	/* If we are trying to set a lock, it just failed. */
XX+ 	if (ltype == F_RDLCK || ltype == F_WRLCK) {
XX+ 		if (req == F_SETLK) {
XX+ 			/* For F_SETLK, just report back failure. */
XX+ 			return(EAGAIN);
XX+ 		} else {
XX+ 			/* For F_SETLKW, suspend the process. */
XX+ 			suspend(XLOCK);
XX+ 			return(0);
XX+ 		}
XX+ 	}
XX+ 
XX+ 	/* We are clearing a lock and we found something that overlaps. */
XX+ 	unlocking = 1;
XX+ 	if (first <= flp->lock_first && last >= flp->lock_last) {
XX+ 		flp->lock_type = 0;	/* mark slot as unused */
XX+ 		nr_locks--;		/* number of locks is now 1 less */
XX+ 		continue;
XX+ 	}
XX+ 
XX+ 	/* Part of a locked region has been unlocked. */
XX+ 	if (first <= flp->lock_first) {
XX+ 		flp->lock_first = last + 1;
XX+ 		continue;
XX+ 	}
XX+ 
XX+ 	if (last >= flp->lock_last) {
XX+ 		flp->lock_last = first - 1;
XX+ 		continue;
XX+ 	}
XX+ 	
XX+ 	/* Bad luck. A lock has been split in two by unlocking the middle. */
XX+ 	if (nr_locks == NR_LOCKS) return(ENOLCK);
XX+ 	for (i = 0; i < NR_LOCKS; i++)
XX+ 		if (file_lock[i].lock_type == 0) break;
XX+ 	flp2 = &file_lock[i];
XX+ 	flp2->lock_type = flp->lock_type;
XX+ 	flp2->lock_pid = flp->lock_pid;
XX+ 	flp2->lock_inode = flp->lock_inode;
XX+ 	flp2->lock_first = last + 1;
XX+ 	flp2->lock_last = flp->lock_last;
XX+ 	flp->lock_last = first - 1;
XX+ 	nr_locks++;
XX+   }
XX+   if (unlocking) lock_revive();
XX+ 
XX+   if (req == F_GETLK) {
XX+ 	if (conflict) {
XX+ 		/* GETLK and conflict. Report on the conflicting lock. */
XX+ 		flock.l_type = flp->lock_type;
XX+ 		flock.l_whence = SEEK_SET;
XX+ 		flock.l_start = flp->lock_first;
XX+ 		flock.l_len = flp->lock_last - flp->lock_first + 1;
XX+ 		flock.l_pid = flp->lock_pid;
XX+ 
XX+ 	} else {
XX+ 		/* It is GETLK and there is no conflict. */
XX+ 		flock.l_type = F_UNLCK;
XX+ 	}
XX+ 
XX+ 	/* Copy the flock structure back to the caller. */
XX+ 	fs_addr = (char *) fs_flock;
XX+ 	r = rw_user(D, who, user_flock, flock_size, fs_addr, TO_USER);
XX+ 	return(r);
XX+   }
XX+ 
XX+   if (ltype == F_UNLCK) return(OK);	/* unlocked a region with no locks */
XX+ 
XX+   /* There is no conflict.  If space exists, store new lock in the table. */
XX+   if (empty == (struct file_lock *) 0) return(ENOLCK);	/* table full */
XX+   empty->lock_type = ltype;
XX+   empty->lock_pid = fp->fp_pid;
XX+   empty->lock_inode = f->filp_ino;
XX+   empty->lock_first = first;
XX+   empty->lock_last = last;
XX+   nr_locks++;
XX+   return(OK);
XX+ }
XX+ 
XX+ /*===========================================================================*
XX+  *				lock_revive				     *
XX+  *===========================================================================*/
XX+ PUBLIC void lock_revive()
XX+ {
XX+ /* Go find all the processes that are waiting for any kind of lock and 
XX+  * revive them all.  The ones that are still blocked will block again when 
XX+  * they run.  The others will complete.  This strategy is a space-time 
XX+  * tradeoff.  Figuring out exactly which ones to unblock now would take 
XX+  * extra code, and the only thing it would win would be some performance in 
XX+  * extremely rare circumstances (namely, that somebody actually used 
XX+  * locking).
XX+  */
XX+ 
XX+   int task;
XX+   struct fproc *fptr;
XX+ 
XX+   for (fptr = &fproc[INIT_PROC_NR + 1]; fptr < &fproc[NR_PROCS]; fptr++){
XX+ 	task = -fptr->fp_task;
XX+ 	if (fptr->fp_suspended == SUSPENDED && task == XLOCK) {
XX+ 		revive((int)(fptr - fproc), 0);
XX+ 	}
XX+   }
XX+ }
XX+ 
XX+ /*===========================================================================*
XX   *				do_sync					     *
XX   *===========================================================================*/
XX  PUBLIC int do_sync()
XX***************
XX*** 117,144 ****
XX  
XX    register struct inode *rip;
XX    register struct buf *bp;
XX-   register struct super_block *sp;
XX  
XX    /* The order in which the various tables are flushed is critical.  The
XX!    * blocks must be flushed last, since rw_inode() and rw_super() leave their
XX!    * results in the block cache.
XX     */
XX  
XX-   /* Update the time in the root super_block. */
XX-   sp = get_super(ROOT_DEV);
XX-   if (sp != NIL_SUPER) {
XX- 	  sp->s_time = clock_time();
XX- 	  if (sp->s_rd_only == FALSE) sp->s_dirt = DIRTY;
XX-   }
XX- 
XX    /* Write all the dirty inodes to the disk. */
XX    for (rip = &inode[0]; rip < &inode[NR_INODES]; rip++)
XX  	if (rip->i_count > 0 && rip->i_dirt == DIRTY) rw_inode(rip, WRITING);
XX  
XX-   /* Write all the dirty super_blocks to the disk. */
XX-   for (sp = &super_block[0]; sp < &super_block[NR_SUPERS]; sp++)
XX- 	if (sp->s_dev != NO_DEV && sp->s_dirt == DIRTY) rw_super(sp, WRITING);
XX- 
XX    /* Write all the dirty blocks to the disk, one drive at a time. */
XX    for (bp = &buf[0]; bp < &buf[NR_BUFS]; bp++)
XX  	if (bp->b_dev != NO_DEV && bp->b_dirt == DIRTY) flushall(bp->b_dev);
XX--- 310,325 ----
XX  
XX    register struct inode *rip;
XX    register struct buf *bp;
XX  
XX    /* The order in which the various tables are flushed is critical.  The
XX!    * blocks must be flushed last, since rw_inode() leaves its results in
XX!    * the block cache.
XX     */
XX  
XX    /* Write all the dirty inodes to the disk. */
XX    for (rip = &inode[0]; rip < &inode[NR_INODES]; rip++)
XX  	if (rip->i_count > 0 && rip->i_dirt == DIRTY) rw_inode(rip, WRITING);
XX  
XX    /* Write all the dirty blocks to the disk, one drive at a time. */
XX    for (bp = &buf[0]; bp < &buf[NR_BUFS]; bp++)
XX  	if (bp->b_dev != NO_DEV && bp->b_dirt == DIRTY) flushall(bp->b_dev);
XX***************
XX*** 166,172 ****
XX    if (who != MM_PROC_NR) return(ERROR);
XX  
XX    /* Copy the parent's fproc struct to the child. */
XX!   sptr = (char *) &fproc[parent];	/* pointer to parent's 'fproc' struct */
XX    dptr = (char *) &fproc[child];	/* pointer to child's 'fproc' struct */
XX    i = sizeof(struct fproc);		/* how many bytes to copy */
XX    while (i--) *dptr++ = *sptr++;	/* fproc[child] = fproc[parent] */
XX--- 347,353 ----
XX    if (who != MM_PROC_NR) return(ERROR);
XX  
XX    /* Copy the parent's fproc struct to the child. */
XX!   sptr = (char *) &fproc[parent];	/* pointer to parent's 'fproc' struct*/
XX    dptr = (char *) &fproc[child];	/* pointer to child's 'fproc' struct */
XX    i = sizeof(struct fproc);		/* how many bytes to copy */
XX    while (i--) *dptr++ = *sptr++;	/* fproc[child] = fproc[parent] */
XX***************
XX*** 190,195 ****
XX--- 371,406 ----
XX  
XX  
XX  /*===========================================================================*
XX+  *				do_exec					     *
XX+  *===========================================================================*/
XX+ PUBLIC int do_exec()
XX+ {
XX+ /* Files can be marked with the FD_CLOEXEC bit (in fp->fp_cloexec).  When
XX+  * MM does an EXEC, it calls FS to allow FS to find these files and close them.
XX+  */
XX+ 
XX+   register int i;
XX+   long bitmap;
XX+ 
XX+   /* Only MM may make this call directly. */
XX+   if (who != MM_PROC_NR) return(ERROR);
XX+ 
XX+   /* The array of FD_CLOEXEC bits is in the fp_cloexec bit map. */
XX+   fp = &fproc[slot1];		/* get_filp() needs 'fp' */
XX+   bitmap = fp->fp_cloexec;
XX+   if (bitmap == 0) return(OK);	/* normal case, no FD_CLOEXECs */
XX+ 
XX+   /* Check the file desriptors one by one for presence of FD_CLOEXEC. */
XX+   for (i = 0; i < OPEN_MAX; i++) {
XX+ 	fd = i;
XX+ 	if ( (bitmap >> i) & 01) (void) do_close();
XX+   }
XX+ 
XX+   return(OK);
XX+ }
XX+ 
XX+ 
XX+ /*===========================================================================*
XX   *				do_exit					     *
XX   *===========================================================================*/
XX  PUBLIC int do_exit()
XX***************
XX*** 205,223 ****
XX    fp = &fproc[slot1];		/* get_filp() needs 'fp' */
XX    exitee = slot1;
XX  
XX-   /* Can this be a process group leader associated with a terminal? */
XX-   if (fp->fp_pid == fp->fp_pgrp && fp->fs_tty != 0) tty_exit();
XX- 
XX    if (fp->fp_suspended == SUSPENDED) {
XX  	task = -fp->fp_task;
XX! 	if (task == XPIPE || task == XOPEN) susp_count--;
XX  	pro = exitee;
XX! 	do_unpause();
XX  	fp->fp_suspended = NOT_SUSPENDED;
XX    }
XX  
XX    /* Loop on file descriptors, closing any that are open. */
XX!   for (i=0; i < OPEN_MAX; i++) {
XX  	fd = i;
XX  	(void) do_close();
XX    }
XX--- 416,431 ----
XX    fp = &fproc[slot1];		/* get_filp() needs 'fp' */
XX    exitee = slot1;
XX  
XX    if (fp->fp_suspended == SUSPENDED) {
XX  	task = -fp->fp_task;
XX! 	if (task == XPIPE || task == XPOPEN) susp_count--;
XX  	pro = exitee;
XX! 	(void) do_unpause();	/* this always succeeds for MM */
XX  	fp->fp_suspended = NOT_SUSPENDED;
XX    }
XX  
XX    /* Loop on file descriptors, closing any that are open. */
XX!   for (i = 0; i < OPEN_MAX; i++) {
XX  	fd = i;
XX  	(void) do_close();
XX    }
XX***************
XX*** 272,278 ****
XX--- 480,489 ----
XX   * in revive().
XX   */
XX  
XX+ #if !ALLOW_USER_SEND
XX    if (who > 0) return(EPERM);
XX+ #endif
XX+ 
XX    revive(m.REP_PROC_NR, m.REP_STATUS);
XX    dont_reply = TRUE;		/* don't reply to the TTY task */
XX    return(OK);
X/
Xecho x - mount.c.d
Xsed '/^X/s///' > mount.c.d << '/'
XX*** /home/top/ast/minix/1.5/fs/mount.c  crc=22925   6079	Sat Apr 21 22:26:20 1990
XX--- /home/top/ast/minix/1.6.25/fs/mount.c  crc=28296   7377	Mon Mar  8 22:11:40 1993
XX***************
XX*** 6,21 ****
XX   */
XX  
XX  #include "fs.h"
XX  #include <sys/stat.h>
XX  #include "buf.h"
XX  #include "file.h"
XX  #include "fproc.h"
XX  #include "inode.h"
XX  #include "param.h"
XX  #include "super.h"
XX  
XX! FORWARD dev_t name_to_dev();
XX  
XX  /*===========================================================================*
XX   *				do_mount				     *
XX   *===========================================================================*/
XX--- 6,27 ----
XX   */
XX  
XX  #include "fs.h"
XX+ #include <fcntl.h>
XX+ #include <minix/com.h>
XX  #include <sys/stat.h>
XX  #include "buf.h"
XX+ #include "dev.h"
XX+ #include "fcntl.h"
XX  #include "file.h"
XX  #include "fproc.h"
XX  #include "inode.h"
XX  #include "param.h"
XX  #include "super.h"
XX  
XX! PRIVATE message dev_mess;
XX  
XX+ FORWARD _PROTOTYPE( dev_t name_to_dev, (char *path)			);
XX+ 
XX  /*===========================================================================*
XX   *				do_mount				     *
XX   *===========================================================================*/
XX***************
XX*** 27,33 ****
XX    struct super_block *xp, *sp;
XX    dev_t dev;
XX    mode_t bits;
XX!   int r, found, loaded;
XX  
XX    /* Only the super-user may do MOUNT. */
XX    if (!super_user) return(EPERM);
XX--- 33,40 ----
XX    struct super_block *xp, *sp;
XX    dev_t dev;
XX    mode_t bits;
XX!   int rdir, mdir;		/* TRUE iff {root|mount} file is dir */
XX!   int r, found, loaded, major, task;
XX  
XX    /* Only the super-user may do MOUNT. */
XX    if (!super_user) return(EPERM);
XX***************
XX*** 46,70 ****
XX    if (found) return(EBUSY);	/* already mounted */
XX    if (sp == NIL_SUPER) return(ENFILE);	/* no super block available */
XX  
XX    /* Fill in the super block. */
XX!   sp->s_dev = dev;		/* rw_super() needs to know which dev */
XX!   rw_super(sp, READING);
XX!   sp->s_dev = dev;		/* however, rw_super() overwrites s_dev */
XX  
XX    /* Make a few basic checks to see if super block looks reasonable. */
XX!   if (sp->s_magic != SUPER_MAGIC || sp->s_ninodes < 1 || sp->s_nzones < 1 || 
XX! 			sp->s_imap_blocks < 1 || sp->s_zmap_blocks < 1) {
XX  	sp->s_dev = NO_DEV;
XX  	return(EINVAL);
XX    }
XX  
XX    /* Now get the inode of the file to be mounted on. */
XX    if (fetch_name(name2, name2_length, M1) != OK) {
XX  	sp->s_dev = NO_DEV;
XX  	return(err_code);
XX    }
XX    if ( (rip = eat_path(user_path)) == NIL_INODE) {
XX  	sp->s_dev = NO_DEV;
XX  	return(err_code);
XX    }
XX  
XX--- 53,96 ----
XX    if (found) return(EBUSY);	/* already mounted */
XX    if (sp == NIL_SUPER) return(ENFILE);	/* no super block available */
XX  
XX+   dev_mess.m_type = DEV_OPEN;		/* distinguish from close */
XX+   dev_mess.DEVICE = dev;		/* Touch the device. */  
XX+   if (rd_only) dev_mess.TTY_FLAGS = O_RDONLY;
XX+   else  dev_mess.TTY_FLAGS = O_RDWR;
XX+ 
XX+   major = (dev >> MAJOR) & BYTE;
XX+   if (major <= 0 || major >= max_major) return(ENODEV);
XX+   task = dmap[major].dmap_task;		/* device task nr */
XX+   (*dmap[major].dmap_open)(task, &dev_mess);
XX+   if (dev_mess.REP_STATUS != OK) return(EINVAL);
XX+ 
XX    /* Fill in the super block. */
XX!   sp->s_dev = dev;		/* read_super() needs to know which dev */
XX!   read_super(sp, (block_t) 0);
XX  
XX    /* Make a few basic checks to see if super block looks reasonable. */
XX!   if (sp->s_version == 0 || sp->s_imap_blocks < 1 || sp->s_zmap_blocks < 1 ||
XX! 				sp->s_ninodes < 1 || sp->s_zones < 1 ) {
XX  	sp->s_dev = NO_DEV;
XX+ 	dev_mess.m_type = DEV_CLOSE;
XX+ 	dev_mess.DEVICE = dev;
XX+ 	(*dmap[major].dmap_close)(task, &dev_mess);
XX  	return(EINVAL);
XX    }
XX  
XX    /* Now get the inode of the file to be mounted on. */
XX    if (fetch_name(name2, name2_length, M1) != OK) {
XX  	sp->s_dev = NO_DEV;
XX+ 	dev_mess.m_type = DEV_CLOSE;
XX+ 	dev_mess.DEVICE = dev;
XX+ 	(*dmap[major].dmap_close)(task, &dev_mess);
XX  	return(err_code);
XX    }
XX    if ( (rip = eat_path(user_path)) == NIL_INODE) {
XX  	sp->s_dev = NO_DEV;
XX+ 	dev_mess.m_type = DEV_CLOSE;
XX+ 	dev_mess.DEVICE = dev;
XX+ 	(*dmap[major].dmap_close)(task, &dev_mess);
XX  	return(err_code);
XX    }
XX  
XX***************
XX*** 87,98 ****
XX    loaded = FALSE;
XX    if (r == OK) {
XX  	if (load_bit_maps(dev) != OK) r = ENFILE;	/* load bit maps */
XX! 	loaded = TRUE;
XX    }
XX  
XX    /* File types of 'rip' and 'root_ip' may not conflict. */
XX!   if ( (r == OK) && ((rip->i_mode & I_TYPE) == I_DIRECTORY) &&
XX! 	((root_ip->i_mode & I_TYPE) != I_DIRECTORY)) r = ENOTDIR;
XX  
XX    /* If error, return the super block and both inodes; release the maps. */
XX    if (r != OK) {
XX--- 113,127 ----
XX    loaded = FALSE;
XX    if (r == OK) {
XX  	if (load_bit_maps(dev) != OK) r = ENFILE;	/* load bit maps */
XX! 	if (r == OK) loaded = TRUE;
XX    }
XX  
XX    /* File types of 'rip' and 'root_ip' may not conflict. */
XX!   if (r == OK) {
XX! 	mdir = ((rip->i_mode & I_TYPE) == I_DIRECTORY);  /* TRUE iff dir */
XX! 	rdir = ((root_ip->i_mode & I_TYPE) == I_DIRECTORY);
XX! 	if (!mdir && rdir) r = EISDIR;
XX!   }
XX  
XX    /* If error, return the super block and both inodes; release the maps. */
XX    if (r != OK) {
XX***************
XX*** 101,107 ****
XX--- 130,140 ----
XX  	if (loaded) (void) unload_bit_maps(dev);
XX  	(void) do_sync();
XX  	invalidate(dev);
XX+ 
XX  	sp->s_dev = NO_DEV;
XX+ 	dev_mess.m_type = DEV_CLOSE;
XX+ 	dev_mess.DEVICE = dev;
XX+ 	(*dmap[major].dmap_close)(task, &dev_mess);
XX  	return(r);
XX    }
XX  
XX***************
XX*** 125,130 ****
XX--- 158,164 ----
XX    struct super_block *sp, *sp1;
XX    dev_t dev;
XX    int count;
XX+   int major, task;
XX  
XX    /* Only the super-user may do UMOUNT. */
XX    if (!super_user) return(EPERM);
XX***************
XX*** 156,161 ****
XX--- 190,201 ----
XX    (void) do_sync();		/* force any cached blocks out of memory */
XX    invalidate(dev);		/* invalidate cache entries for this dev */
XX    if (sp == NIL_SUPER) return(EINVAL);
XX+ 
XX+   major = (dev >> MAJOR) & BYTE;	/* major device nr */
XX+   task = dmap[major].dmap_task;	/* device task nr */
XX+   dev_mess.m_type = DEV_CLOSE;		/* distinguish from open */
XX+   dev_mess.DEVICE = dev;
XX+   (*dmap[major].dmap_close)(task, &dev_mess);
XX  
XX    /* Finish off the unmount. */
XX    sp->s_imount->i_mount = NO_MOUNT;	/* inode returns to normal */
X/
Xecho x - open.c.d
Xsed '/^X/s///' > open.c.d << '/'
XX*** /home/top/ast/minix/1.5/fs/open.c  crc=08922  13329	Sat May  5 13:14:25 1990
XX--- /home/top/ast/minix/1.6.25/fs/open.c  crc=58508  16438	Mon Mar  8 22:11:40 1993
XX***************
XX*** 11,32 ****
XX   */
XX  
XX  #include "fs.h"
XX- #include <minix/callnr.h>
XX  #include <sys/stat.h>
XX  #include <fcntl.h>
XX  #include "buf.h"
XX  #include "file.h"
XX  #include "fproc.h"
XX  #include "inode.h"
XX  #include "param.h"
XX  
XX  PRIVATE char mode_map[] = {R_BIT, W_BIT, R_BIT|W_BIT, 0};
XX- PRIVATE char dot1[NAME_MAX] = ".\0\0\0\0\0\0\0\0\0\0\0\0";
XX- PRIVATE char dot2[NAME_MAX] =  "..\0\0\0\0\0\0\0\0\0\0\0";
XX  
XX! FORWARD int common_open();
XX! FORWARD struct inode *new_node();
XX! FORWARD int pipe_open();
XX  
XX  /*===========================================================================*
XX   *				do_creat				     *
XX--- 11,34 ----
XX   */
XX  
XX  #include "fs.h"
XX  #include <sys/stat.h>
XX  #include <fcntl.h>
XX+ #include <minix/callnr.h>
XX+ #include <minix/com.h>
XX  #include "buf.h"
XX+ #include "dev.h"
XX  #include "file.h"
XX  #include "fproc.h"
XX  #include "inode.h"
XX  #include "param.h"
XX  
XX+ PRIVATE message dev_mess;
XX  PRIVATE char mode_map[] = {R_BIT, W_BIT, R_BIT|W_BIT, 0};
XX  
XX! FORWARD _PROTOTYPE( int common_open, (int oflags, Mode_t omode)		);
XX! FORWARD _PROTOTYPE( int pipe_open, (struct inode *rip,Mode_t bits,int oflags));
XX! FORWARD _PROTOTYPE( struct inode *new_node, (char *path, Mode_t bits,
XX! 			zone_t z0, off_t lsize)			);
XX  
XX  /*===========================================================================*
XX   *				do_creat				     *
XX***************
XX*** 34,42 ****
XX  PUBLIC int do_creat()
XX  {
XX  /* Perform the creat(name, mode) system call. */
XX!   /* get name */
XX    if (fetch_name(name, name_length, M3) != OK) return(err_code);
XX!   return common_open(O_WRONLY | O_CREAT | O_TRUNC, (mode_t) mode);
XX  }
XX  
XX  
XX--- 36,46 ----
XX  PUBLIC int do_creat()
XX  {
XX  /* Perform the creat(name, mode) system call. */
XX!   int r;
XX! 
XX    if (fetch_name(name, name_length, M3) != OK) return(err_code);
XX!   r = common_open(O_WRONLY | O_CREAT | O_TRUNC, (mode_t) mode);
XX!   return(r);
XX  }
XX  
XX  
XX***************
XX*** 45,61 ****
XX   *===========================================================================*/
XX  PUBLIC int do_mknod()
XX  {
XX! /* Perform the mknod(name, mode, addr) system call. */
XX  
XX!   register mode_t bits;
XX!   unsigned int size;
XX  
XX    /* Only the super_user may make nodes other than fifos. */
XX!   if (!super_user && ((mode & I_TYPE) != I_NAMED_PIPE)) return(EPERM);
XX!   if (fetch_name(name1, name1_length, M1) != OK) return(err_code);
XX!   bits = (mode & I_TYPE) | (mode & ALL_MODES & fp->fp_umask);
XX!   size = (unsigned int) name2;
XX!   put_inode(new_node(user_path, bits, (zone_nr) addr), (off_t)size*BLOCK_SIZE);
XX    return(err_code);
XX  }
XX  
XX--- 49,69 ----
XX   *===========================================================================*/
XX  PUBLIC int do_mknod()
XX  {
XX! /* Perform the mknod(name, mode, addr, size) system call. */
XX  
XX!   register mode_t bits, mode_bits;
XX!   long size;
XX!   struct inode *ip;
XX  
XX    /* Only the super_user may make nodes other than fifos. */
XX!   mode_bits = (mode_t) m.m1_i2;	/* mode of the inode */
XX!   if (!super_user && ((mode_bits & I_TYPE) != I_NAMED_PIPE)) return(EPERM);
XX!   if (fetch_name(m.m1_p1, m.m1_i1, M1) != OK) return(err_code);
XX!   bits = (mode_bits & I_TYPE) | (mode_bits & ALL_MODES & fp->fp_umask);
XX!   size = (long) m.m1_p2;	/* number of blocks in the device */
XX!   if (size > MAX_FILE_POS/BLOCK_SIZE) return(EINVAL);
XX!   ip = new_node(user_path, bits, (zone_t) m.m1_i3, (off_t) size * BLOCK_SIZE);
XX!   put_inode(ip);
XX    return(err_code);
XX  }
XX  
XX***************
XX*** 66,72 ****
XX  PRIVATE struct inode *new_node(path, bits, z0, lsize)
XX  char *path;			/* pointer to path name */
XX  mode_t bits;			/* mode of the new inode */
XX! zone_nr z0;			/* zone number 0 for new inode */
XX  off_t lsize;			/* size of the special file */
XX  {
XX  /* New_node() is called by common_open(), do_mknod(), and do_mkdir().  
XX--- 74,80 ----
XX  PRIVATE struct inode *new_node(path, bits, z0, lsize)
XX  char *path;			/* pointer to path name */
XX  mode_t bits;			/* mode of the new inode */
XX! zone_t z0;			/* zone number 0 for new inode */
XX  off_t lsize;			/* size of the special file */
XX  {
XX  /* New_node() is called by common_open(), do_mknod(), and do_mkdir().  
XX***************
XX*** 134,140 ****
XX  {
XX  /* Perform the open(name, flags,...) system call. */
XX  
XX!   int create_mode = 0;
XX    int r;
XX  
XX    /* If O_CREAT is set, open has three parameters, otherwise two. */
XX--- 142,148 ----
XX  {
XX  /* Perform the open(name, flags,...) system call. */
XX  
XX!   int create_mode = 0;		/* is really mode_t but this gives problems */
XX    int r;
XX  
XX    /* If O_CREAT is set, open has three parameters, otherwise two. */
XX***************
XX*** 146,152 ****
XX    }
XX  
XX    if (r != OK) return(err_code); /* name was bad */
XX!   return common_open(mode, (mode_t) create_mode);
XX  }
XX  
XX  
XX--- 154,161 ----
XX    }
XX  
XX    if (r != OK) return(err_code); /* name was bad */
XX!   r = common_open(mode, create_mode);
XX!   return(r);
XX  }
XX  
XX  
XX***************
XX*** 160,170 ****
XX  /* Common code from do_creat and do_open. */
XX  
XX    register struct inode *rip;
XX!   register int r;
XX!   register mode_t bits;
XX!   struct filp *fil_ptr;
XX    dev_t dev;
XX!   int nonblocking, exist = TRUE;
XX  
XX    /* Remap the bottom two bits of oflags. */
XX    bits = (mode_t) mode_map[oflags & O_ACCMODE];
XX--- 169,179 ----
XX  /* Common code from do_creat and do_open. */
XX  
XX    register struct inode *rip;
XX!   int r, b, major, task, exist = TRUE;
XX    dev_t dev;
XX!   mode_t bits;
XX!   off_t pos;
XX!   struct filp *fil_ptr, *filp2;
XX  
XX    /* Remap the bottom two bits of oflags. */
XX    bits = (mode_t) mode_map[oflags & O_ACCMODE];
XX***************
XX*** 187,206 ****
XX      	if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code);
XX    }
XX  
XX  
XX    /* Only do the normal open code if we didn't just create the file. */
XX    if (exist) {
XX- 
XX- #if 0	/* I doubt this, but what does POSIX say?
XX- 	 * I fixed the test anyway, to go with fixing the O_TRUNC test.
XX- 	 * BDE
XX- 	 */
XX- 
XX-   	/* O_TRUNC and O_CREAT implies W_BIT */
XX- 	if ((oflags & (O_TRUNC | O_CREAT)) == (O_CREAT | O_TRUNC))
XX- 		bits |= W_BIT;
XX- #endif
XX- 
XX    	/* Check protections. */
XX    	if ((r = forbidden(rip, bits, 0)) == OK) {
XX    		/* Opening reg. files directories and special files differ. */
XX--- 196,209 ----
XX      	if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code);
XX    }
XX  
XX+   /* Claim the file descriptor and filp slot and fill them in. */
XX+   fp->fp_filp[fd] = fil_ptr;
XX+   fil_ptr->filp_count = 1;
XX+   fil_ptr->filp_ino = rip;
XX+   fil_ptr->filp_flags = oflags;
XX  
XX    /* Only do the normal open code if we didn't just create the file. */
XX    if (exist) {
XX    	/* Check protections. */
XX    	if ((r = forbidden(rip, bits, 0)) == OK) {
XX    		/* Opening reg. files directories and special files differ. */
XX***************
XX*** 208,213 ****
XX--- 211,217 ----
XX      		   case I_REGULAR: 
XX  			/* Truncate regular file if O_TRUNC. */
XX  			if (oflags & O_TRUNC) {
XX+ 				if ((r = forbidden(rip, W_BIT, 0)) !=OK) break;
XX  				truncate(rip);
XX  				wipe_inode(rip);
XX  			}
XX***************
XX*** 221,233 ****
XX  	     	   case I_CHAR_SPECIAL:
XX       		   case I_BLOCK_SPECIAL:
XX  			/* Invoke the driver for special processing. */
XX  			dev = (dev_t) rip->i_zone[0];
XX! 			nonblocking = oflags & O_NONBLOCK;
XX! 			r = dev_open(rip, (int) bits, nonblocking);
XX  			break;
XX  
XX  		   case I_NAMED_PIPE:
XX  			r = pipe_open(rip, bits, oflags);
XX  			break;
XX   		}
XX    	}
XX--- 225,278 ----
XX  	     	   case I_CHAR_SPECIAL:
XX       		   case I_BLOCK_SPECIAL:
XX  			/* Invoke the driver for special processing. */
XX+ 			dev_mess.m_type = DEV_OPEN;
XX  			dev = (dev_t) rip->i_zone[0];
XX! 			dev_mess.DEVICE = dev;
XX! 			dev_mess.TTY_FLAGS = mode;
XX! 			major = (dev >> MAJOR) & BYTE;	/* major device nr */
XX! 			if (major <= 0 || major >= max_major) {
XX! 				r = ENODEV;
XX! 				break;
XX! 			}
XX! 			task = dmap[major].dmap_task;	/* device task nr */
XX! 			(*dmap[major].dmap_open)(task, &dev_mess);
XX! 			r = dev_mess.REP_STATUS;
XX  			break;
XX  
XX  		   case I_NAMED_PIPE:
XX+ 			oflags |= O_APPEND;	/* force append mode */
XX+ 			fil_ptr->filp_flags = oflags;
XX  			r = pipe_open(rip, bits, oflags);
XX+ 			if (r == OK) {
XX+ 				/* See if someone else is doing a rd or wt on
XX+ 				 * the FIFO.  If so, use its filp entry so the
XX+ 				 * file position will be automatically shared.
XX+ 				 */
XX+ 				b = (bits & R_BIT ? R_BIT : W_BIT);
XX+ 				fil_ptr->filp_count = 0; /* don't find self */
XX+ 				if ((filp2 = find_filp(rip, b)) != NIL_FILP) {
XX+ 					/* Co-reader or writer found. Use it.*/
XX+ 					fp->fp_filp[fd] = filp2;
XX+ 					filp2->filp_count++;
XX+ 					filp2->filp_ino = rip;
XX+ 					filp2->filp_flags = oflags;
XX+ 
XX+ 					/* i_count was incremented incorrectly
XX+ 					 * by eatpath above, not knowing that
XX+ 					 * we were going to use an existing
XX+ 					 * filp entry.  Correct this error.
XX+ 					 */
XX+ 					rip->i_count--;
XX+ 				} else {
XX+ 					/* Nobody else found.  Restore filp. */
XX+ 					fil_ptr->filp_count = 1;
XX+ 					if (b == R_BIT)
XX+ 					     pos = rip->i_zone[V2_NR_DZONES+1];
XX+ 					else
XX+ 					     pos = rip->i_zone[V2_NR_DZONES+2];
XX+ 					fil_ptr->filp_pos = pos;
XX+ 				}
XX+ 			}
XX  			break;
XX   		}
XX    	}
XX***************
XX*** 235,249 ****
XX  
XX    /* If error, release inode. */
XX    if (r != OK) {
XX  	put_inode(rip);
XX  	return(r);
XX    }
XX    
XX-   /* Claim the file descriptor and filp slot and fill them in. */
XX-   fp->fp_filp[fd] = fil_ptr;
XX-   fil_ptr->filp_count = 1;
XX-   fil_ptr->filp_ino = rip;
XX-   fil_ptr->filp_flags = oflags;
XX    return(fd);
XX  }
XX  
XX--- 280,291 ----
XX  
XX    /* If error, release inode. */
XX    if (r != OK) {
XX+ 	fp->fp_filp[fd] = NIL_FILP;
XX+ 	fil_ptr->filp_count= 0;
XX  	put_inode(rip);
XX  	return(r);
XX    }
XX    
XX    return(fd);
XX  }
XX  
XX***************
XX*** 255,276 ****
XX  register mode_t bits;
XX  register int oflags;
XX  {
XX! /*  This function is called from do_creat and do_open, it checks if
XX   *  there is at least one reader/writer pair for the pipe, if not
XX   *  it suspends the caller, otherwise it revives all other blocked
XX   *  processes hanging on the pipe.
XX   */
XX  
XX    if (find_filp(rip, bits & W_BIT ? R_BIT : W_BIT) == NIL_FILP) { 
XX! 	if (oflags & O_NONBLOCK) return(bits & W_BIT ? ENXIO : OK);
XX! 	suspend(XOPEN); /* suspend caller */
XX    } else if (susp_count > 0) {/* revive blocked processes */
XX  	release(rip, OPEN, susp_count);
XX  	release(rip, CREAT, susp_count);
XX    }
XX    rip->i_pipe = I_PIPE; 
XX  
XX!   return OK ;
XX  }
XX  
XX  
XX--- 297,320 ----
XX  register mode_t bits;
XX  register int oflags;
XX  {
XX! /*  This function is called from common_open. It checks if
XX   *  there is at least one reader/writer pair for the pipe, if not
XX   *  it suspends the caller, otherwise it revives all other blocked
XX   *  processes hanging on the pipe.
XX   */
XX  
XX    if (find_filp(rip, bits & W_BIT ? R_BIT : W_BIT) == NIL_FILP) { 
XX! 	if (oflags & O_NONBLOCK) {
XX! 		if (bits & W_BIT) return(ENXIO);
XX! 	} else
XX! 		suspend(XPOPEN);	/* suspend caller */
XX    } else if (susp_count > 0) {/* revive blocked processes */
XX  	release(rip, OPEN, susp_count);
XX  	release(rip, CREAT, susp_count);
XX    }
XX    rip->i_pipe = I_PIPE; 
XX  
XX!   return(OK);
XX  }
XX  
XX  
XX***************
XX*** 283,290 ****
XX  
XX    register struct filp *rfilp;
XX    register struct inode *rip;
XX!   int rw;
XX!   int mode_word;
XX  
XX    /* First locate the inode that belongs to the file descriptor. */
XX    if ( (rfilp = get_filp(fd)) == NIL_FILP) return(err_code);
XX--- 327,335 ----
XX  
XX    register struct filp *rfilp;
XX    register struct inode *rip;
XX!   struct file_lock *flp;
XX!   int rw, mode_word, major, task, lock_count;
XX!   dev_t dev;
XX  
XX    /* First locate the inode that belongs to the file descriptor. */
XX    if ( (rfilp = get_filp(fd)) == NIL_FILP) return(err_code);
XX***************
XX*** 293,316 ****
XX    /* Check to see if the file is special. */
XX    mode_word = rip->i_mode & I_TYPE;
XX    if (mode_word == I_CHAR_SPECIAL || mode_word == I_BLOCK_SPECIAL) {
XX  	if (mode_word == I_BLOCK_SPECIAL)  {
XX  		/* Invalidate cache entries unless special is mounted or ROOT*/
XX! 		do_sync();	/* purge cache */
XX! 		if (mounted(rip) == FALSE) invalidate((dev_t) rip->i_zone[0]);
XX  	}
XX! 	if (rfilp->filp_count == 1) dev_close(rip);	/* about to become 0 */
XX    }
XX  
XX    /* If the inode being closed is a pipe, release everyone hanging on it. */
XX!   if (rip->i_pipe) {
XX  	rw = (rfilp->filp_mode & R_BIT ? WRITE : READ);
XX  	release(rip, rw, NR_PROCS);
XX    }
XX  
XX    /* If a write has been done, the inode is already marked as DIRTY. */
XX!   if (--rfilp->filp_count == 0) put_inode(rip);
XX  
XX    fp->fp_filp[fd] = NIL_FILP;
XX    return(OK);
XX  }
XX  
XX--- 338,396 ----
XX    /* Check to see if the file is special. */
XX    mode_word = rip->i_mode & I_TYPE;
XX    if (mode_word == I_CHAR_SPECIAL || mode_word == I_BLOCK_SPECIAL) {
XX+ 	dev = (dev_t) rip->i_zone[0];
XX  	if (mode_word == I_BLOCK_SPECIAL)  {
XX  		/* Invalidate cache entries unless special is mounted or ROOT*/
XX! 		(void) do_sync();	/* purge cache */
XX! 		if (mounted(rip) == FALSE) invalidate(dev);
XX  	}
XX! 	/* Use the dmap_close entry to do any special processing required. */
XX! 	dev_mess.m_type = DEV_CLOSE;
XX! 	dev_mess.DEVICE = dev;
XX! 	dev_mess.COUNT= rfilp->filp_count - 1;
XX! 		/* Device wants to know how many times this fd is open after
XX! 		 * the close. */
XX! 	major = (dev >> MAJOR) & BYTE;	/* major device nr */
XX! 	task = dmap[major].dmap_task;	/* device task nr */
XX! 	(*dmap[major].dmap_close)(task, &dev_mess);
XX    }
XX  
XX    /* If the inode being closed is a pipe, release everyone hanging on it. */
XX!   if (rip->i_pipe == I_PIPE) {
XX  	rw = (rfilp->filp_mode & R_BIT ? WRITE : READ);
XX  	release(rip, rw, NR_PROCS);
XX    }
XX  
XX    /* If a write has been done, the inode is already marked as DIRTY. */
XX!   if (--rfilp->filp_count == 0) {
XX! 	if (rip->i_pipe == I_PIPE && rip->i_count > 1) {
XX! 		/* Save the file position in the i-node in case needed later.
XX! 		 * The read and write positions are saved separately.  The
XX! 		 * last 3 zones in the i-node are not used for (named) pipes.
XX! 		 */
XX! 		if (rfilp->filp_mode == R_BIT)
XX! 			rip->i_zone[V2_NR_DZONES+1] = (zone_t) rfilp->filp_pos;
XX! 		else
XX! 			rip->i_zone[V2_NR_DZONES+2] = (zone_t) rfilp->filp_pos;
XX! 	}
XX! 	put_inode(rip);
XX!   }
XX  
XX+   fp->fp_cloexec &= ~(1L << fd);
XX+   fp->fp_cloexec &= ~(1L << fd);	/* turn off close-on-exec bit */
XX    fp->fp_filp[fd] = NIL_FILP;
XX+ 
XX+   /* Check to see if the file is locked.  If so, release all locks. */
XX+   if (nr_locks == 0) return(OK);
XX+   lock_count = nr_locks;	/* save count of locks */
XX+   for (flp = &file_lock[0]; flp < &file_lock[NR_LOCKS]; flp++) {
XX+ 	if (flp->lock_type == 0) continue;	/* slot not in use */
XX+ 	if (flp->lock_inode == rip && flp->lock_pid == fp->fp_pid) {
XX+ 		flp->lock_type = 0;
XX+ 		nr_locks--;
XX+ 	}
XX+   }
XX+   if (nr_locks < lock_count) lock_revive();	/* lock released */
XX    return(OK);
XX  }
XX  
XX***************
XX*** 331,351 ****
XX    /* No lseek on pipes. */
XX    if (rfilp->filp_ino->i_pipe == I_PIPE) return(ESPIPE);
XX  
XX!   /* The value of 'whence' determines the algorithm to use. */
XX    switch(whence) {
XX! 	case 0:	pos = offset;	break;
XX! 	case 1: pos = rfilp->filp_pos + offset;	break;
XX! 	case 2: pos = rfilp->filp_ino->i_size + offset;	break;
XX  	default: return(EINVAL);
XX    }
XX  
XX!   /* Check if pos is invalid. */
XX!   if (pos < 0 || pos > MAX_FILE_POS) return(EINVAL);
XX  
XX    if (pos != rfilp->filp_pos)
XX  	rfilp->filp_ino->i_seek = ISEEK;	/* inhibit read ahead */
XX    rfilp->filp_pos = pos;
XX- 
XX    reply_l1 = pos;		/* insert the long into the output message */
XX    return(OK);
XX  }
XX--- 411,432 ----
XX    /* No lseek on pipes. */
XX    if (rfilp->filp_ino->i_pipe == I_PIPE) return(ESPIPE);
XX  
XX!   /* The value of 'whence' determines the start position to use. */
XX    switch(whence) {
XX! 	case 0:	pos = 0;	break;
XX! 	case 1: pos = rfilp->filp_pos;	break;
XX! 	case 2: pos = rfilp->filp_ino->i_size;	break;
XX  	default: return(EINVAL);
XX    }
XX  
XX!   /* Check for overflow. */
XX!   if (((long)offset > 0) && ((long)(pos + offset) < (long)pos)) return(EINVAL);
XX!   if (((long)offset < 0) && ((long)(pos + offset) > (long)pos)) return(EINVAL);
XX!   pos = pos + offset;
XX  
XX    if (pos != rfilp->filp_pos)
XX  	rfilp->filp_ino->i_seek = ISEEK;	/* inhibit read ahead */
XX    rfilp->filp_pos = pos;
XX    reply_l1 = pos;		/* insert the long into the output message */
XX    return(OK);
XX  }
XX***************
XX*** 364,389 ****
XX    char string[NAME_MAX];	/* last component of the new dir's path name */
XX    register struct inode *rip, *ldirp;
XX  
XX!   /* First make the inode. If that fails, return error code. */
XX    if (fetch_name(name1, name1_length, M1) != OK) return(err_code);
XX!   bits = S_IFDIR | (mode & RWX_MODES & fp->fp_umask);
XX!   rip = new_node(user_path, bits, (zone_nr) 0, (off_t) 0);
XX!   if (rip == NIL_INODE) return(err_code);
XX!   if (err_code == EEXIST) {
XX  	put_inode(rip);		/* can't make dir: it already exists */
XX  	return(err_code);
XX    }
XX  
XX    /* Get the inode numbers for . and .. to enter in the directory. */
XX-   ldirp = last_dir(user_path, string);	/* pointer to new dir's parent */
XX    dotdot = ldirp->i_num;	/* parent's inode number */
XX    dot = rip->i_num;		/* inode number of the new dir itself */
XX  
XX    /* Now make dir entries for . and .. unless the disk is completely full. */
XX!   rip->i_mode |= S_IRWXU;	/* make sure . and .. can be entered */
XX    r1 = search_dir(rip, dot1, &dot, ENTER);	/* enter . in the new dir */
XX    r2 = search_dir(rip, dot2, &dotdot, ENTER);	/* enter .. in the new dir */
XX-   rip->i_mode = bits;		/* now set mode correctly */
XX  
XX    /* If both . and .. were successfully entered, increment the link counts. */
XX    if (r1 == OK && r2 == OK) {
XX--- 445,477 ----
XX    char string[NAME_MAX];	/* last component of the new dir's path name */
XX    register struct inode *rip, *ldirp;
XX  
XX!   /* Check to see if it is possible to make another link in the parent dir. */
XX    if (fetch_name(name1, name1_length, M1) != OK) return(err_code);
XX!   ldirp = last_dir(user_path, string);	/* pointer to new dir's parent */
XX!   if (ldirp == NIL_INODE) return(err_code);
XX!   if ( (ldirp->i_nlinks & BYTE) >= LINK_MAX) {
XX! 	put_inode(ldirp);	/* return parent */
XX! 	return(EMLINK);
XX!   }
XX! 
XX!   /* Next make the inode. If that fails, return error code. */
XX!   bits = I_DIRECTORY | (mode & RWX_MODES & fp->fp_umask);
XX!   rip = new_node(user_path, bits, (zone_t) 0, (off_t) 0);
XX!   if (rip == NIL_INODE || err_code == EEXIST) {
XX  	put_inode(rip);		/* can't make dir: it already exists */
XX+ 	put_inode(ldirp);	/* return parent too */
XX  	return(err_code);
XX    }
XX  
XX    /* Get the inode numbers for . and .. to enter in the directory. */
XX    dotdot = ldirp->i_num;	/* parent's inode number */
XX    dot = rip->i_num;		/* inode number of the new dir itself */
XX  
XX    /* Now make dir entries for . and .. unless the disk is completely full. */
XX!   /* Use dot1 and dot2, so the mode of the directory isn't important. */
XX!   rip->i_mode = bits;	/* set mode */
XX    r1 = search_dir(rip, dot1, &dot, ENTER);	/* enter . in the new dir */
XX    r2 = search_dir(rip, dot2, &dotdot, ENTER);	/* enter .. in the new dir */
XX  
XX    /* If both . and .. were successfully entered, increment the link counts. */
XX    if (r1 == OK && r2 == OK) {
XX***************
XX*** 393,400 ****
XX  	ldirp->i_dirt = DIRTY;	/* mark parent's inode as dirty */
XX    } else {
XX  	/* It was not possible to enter . or .. probably disk was full. */
XX- 	(void) search_dir(rip, ".",  (ino_t *) 0, DELETE);
XX- 	(void) search_dir(rip, "..", (ino_t *) 0, DELETE);
XX  	(void) search_dir(ldirp, string, (ino_t *) 0, DELETE);
XX  	rip->i_nlinks--;	/* undo the increment done in new_node() */
XX    }
XX--- 481,486 ----
X/
Xecho x - param.h.d
Xsed '/^X/s///' > param.h.d << '/'
XX*** /home/top/ast/minix/1.5/fs/param.h  crc=08767   1617	Sat Apr 21 22:26:20 1990
XX--- /home/top/ast/minix/1.6.25/fs/param.h  crc=24511   1648	Tue Nov  3 21:19:15 1992
XX***************
XX*** 2,8 ****
XX  #define acc_time      m.m2_l1
XX  #define addr	      m.m1_i3
XX  #define buffer	      m.m1_p1
XX- #define cd_flag	      m.m1_i2
XX  #define child	      m.m1_i2
XX  #define co_mode	      m.m1_i1
XX  #define eff_grp_id    m.m1_i3
XX--- 2,7 ----
XX***************
XX*** 37,43 ****
XX  #define sig	      m.m1_i2
XX  #define slot1	      m.m1_i1
XX  #define tp	      m.m2_l1
XX! #define updated_time  m.m2_l2
XX  #define utime_file    m.m2_p1
XX  #define utime_length  m.m2_i1
XX  #define whence	      m.m2_i2
XX--- 36,43 ----
XX  #define sig	      m.m1_i2
XX  #define slot1	      m.m1_i1
XX  #define tp	      m.m2_l1
XX! #define utime_actime  m.m2_l1
XX! #define utime_modtime m.m2_l2
XX  #define utime_file    m.m2_p1
XX  #define utime_length  m.m2_i1
XX  #define whence	      m.m2_i2
XX***************
XX*** 51,53 ****
XX--- 51,54 ----
XX  #define reply_t2      m1.m4_l2
XX  #define reply_t3      m1.m4_l3
XX  #define reply_t4      m1.m4_l4
XX+ #define reply_t5      m1.m4_l5
X/
Xecho x - path.c.d
Xsed '/^X/s///' > path.c.d << '/'
XX*** /home/top/ast/minix/1.5/fs/path.c  crc=09882  11597	Sat Apr 21 22:26:20 1990
XX--- /home/top/ast/minix/1.6.25/fs/path.c  crc=22611  12358	Sun Nov 15 23:17:00 1992
XX***************
XX*** 17,24 ****
XX  #include "inode.h"
XX  #include "super.h"
XX  
XX! FORWARD char *get_name();
XX  
XX  /*===========================================================================*
XX   *				eat_path				     *
XX   *===========================================================================*/
XX--- 17,27 ----
XX  #include "inode.h"
XX  #include "super.h"
XX  
XX! PUBLIC char dot1[2] = ".";	/* used for search_dir to bypass the access */
XX! PUBLIC char dot2[3] = "..";	/* permissions for . and ..		    */
XX  
XX+ FORWARD _PROTOTYPE( char *get_name, (char *old_name, char string [NAME_MAX]) );
XX+ 
XX  /*===========================================================================*
XX   *				eat_path				     *
XX   *===========================================================================*/
XX***************
XX*** 64,70 ****
XX    register struct inode *rip;
XX    register char *new_name;
XX    register struct inode *new_ip;
XX-   char *p;
XX  
XX    /* Is the path absolute or relative?  Initialize 'rip' accordingly. */
XX    rip = (*path == '/' ? fp->fp_rootdir : fp->fp_workdir);
XX--- 67,72 ----
XX***************
XX*** 77,93 ****
XX  
XX    dup_inode(rip);		/* inode will be returned with put_inode */
XX  
XX-   /* Remove trailing "/." from paths (e.g., "/usr/ast/." becomes "/usr/ast") */
XX-   if (fs_call == UNLINK || fs_call == RMDIR) {
XX- 	while (1) {
XX- 		p = path + strlen(path) - 2;	/* pts to next-to-last char */
XX- 		if (p > path && *p == '/' && *(p + 1) == '.') 
XX- 			*p = '\0';
XX- 		else
XX- 			break;
XX- 	}
XX-   }
XX- 
XX    /* Scan the path component by component. */
XX    while (TRUE) {
XX  	/* Extract one component. */
XX--- 79,84 ----
XX***************
XX*** 95,101 ****
XX  		put_inode(rip);	/* bad path in user space */
XX  		return(NIL_INODE);
XX  	}
XX! 	if (*new_name == '\0') return(rip);	/* normal exit */
XX  
XX  	/* There is more path.  Keep parsing. */
XX  	new_ip = advance(rip, string);
XX--- 86,100 ----
XX  		put_inode(rip);	/* bad path in user space */
XX  		return(NIL_INODE);
XX  	}
XX! 	if (*new_name == '\0')
XX! 		if ( (rip->i_mode & I_TYPE) == I_DIRECTORY)
XX! 			return(rip);	/* normal exit */
XX! 		else {
XX! 			/* last file of path prefix is not a directory */
XX! 			put_inode(rip);
XX! 			err_code = ENOTDIR;			
XX! 			return(NIL_INODE);
XX! 		}
XX  
XX  	/* There is more path.  Keep parsing. */
XX  	new_ip = advance(rip, string);
XX***************
XX*** 141,148 ****
XX    /* To make /usr/ast/ equivalent to /usr/ast, skip trailing slashes. */
XX    while (c == '/' && rnp < &old_name[PATH_MAX]) c = *++rnp;
XX  
XX!   /* Pad the component name out to NAME_MAX chars, using 0 as filler. */
XX!   while (np < &string[NAME_MAX]) *np++ = '\0';
XX  
XX    if (rnp >= &old_name[PATH_MAX]) {
XX  	err_code = ENAMETOOLONG;
XX--- 140,146 ----
XX    /* To make /usr/ast/ equivalent to /usr/ast, skip trailing slashes. */
XX    while (c == '/' && rnp < &old_name[PATH_MAX]) c = *++rnp;
XX  
XX!   if (np < &string[NAME_MAX]) *np = '\0';	/* Terminate string */
XX  
XX    if (rnp >= &old_name[PATH_MAX]) {
XX  	err_code = ENAMETOOLONG;
XX***************
XX*** 167,178 ****
XX    register struct inode *rip;
XX    struct inode *rip2;
XX    register struct super_block *sp;
XX!   int r;
XX    dev_t mnt_dev;
XX    ino_t numb;
XX  
XX    /* If 'string' is empty, yield same inode straight away. */
XX!   if (string[0] == '\0') return(get_inode(dirp->i_dev, dirp->i_num));
XX  
XX    /* Check for NIL_INODE. */
XX    if (dirp == NIL_INODE) return(NIL_INODE);
XX--- 165,176 ----
XX    register struct inode *rip;
XX    struct inode *rip2;
XX    register struct super_block *sp;
XX!   int r, inumb;
XX    dev_t mnt_dev;
XX    ino_t numb;
XX  
XX    /* If 'string' is empty, yield same inode straight away. */
XX!   if (string[0] == '\0') return(get_inode(dirp->i_dev, (int) dirp->i_num));
XX  
XX    /* Check for NIL_INODE. */
XX    if (dirp == NIL_INODE) return(NIL_INODE);
XX***************
XX*** 183,190 ****
XX  	return(NIL_INODE);
XX    }
XX  
XX    /* The component has been found in the directory.  Get inode. */
XX!   if ( (rip = get_inode(dirp->i_dev, numb)) == NIL_INODE) return(NIL_INODE);
XX  
XX    if (rip->i_num == ROOT_INODE)
XX  	if (dirp->i_num == ROOT_INODE) {
XX--- 181,193 ----
XX  	return(NIL_INODE);
XX    }
XX  
XX+   /* Don't go beyond the current root directory, unless the string is dot2. */
XX+   if (dirp == fp->fp_rootdir && strcmp(string, "..") == 0 && string != dot2)
XX+ 		return(get_inode(dirp->i_dev, (int) dirp->i_num));
XX+ 
XX    /* The component has been found in the directory.  Get inode. */
XX!   if ( (rip = get_inode(dirp->i_dev, (int) numb)) == NIL_INODE) 
XX! 	return(NIL_INODE);
XX  
XX    if (rip->i_num == ROOT_INODE)
XX  	if (dirp->i_num == ROOT_INODE) {
XX***************
XX*** 196,202 ****
XX  				 */
XX  				put_inode(rip);
XX  				mnt_dev = sp->s_imount->i_dev;
XX! 				rip2 = get_inode(mnt_dev, sp->s_imount->i_num);
XX  				rip = advance(rip2, string);
XX  				put_inode(rip2);
XX  				break;
XX--- 199,206 ----
XX  				 */
XX  				put_inode(rip);
XX  				mnt_dev = sp->s_imount->i_dev;
XX! 				inumb = (int) sp->s_imount->i_num;
XX! 				rip2 = get_inode(mnt_dev, inumb);
XX  				rip = advance(rip2, string);
XX  				put_inode(rip2);
XX  				break;
XX***************
XX*** 234,268 ****
XX  register struct inode *ldir_ptr;	/* ptr to inode for dir to search */
XX  char string[NAME_MAX];		/* component to search for */
XX  ino_t *numb;			/* pointer to inode number */
XX! int flag;			/* LOOK_UP, ENTER, or DELETE */
XX  {
XX  /* This function searches the directory whose inode is pointed to by 'ldip':
XX   * if (flag == ENTER)  enter 'string' in the directory with inode # '*numb';
XX   * if (flag == DELETE) delete 'string' from the directory;
XX   * if (flag == LOOK_UP) search for 'string' and return inode # in 'numb';
XX!  *  	If 'string' is "", return success on any entry except . and ..
XX   */
XX  
XX!   register dir_struct *dp;
XX    register struct buf *bp;
XX!   register struct inode *rip;
XX!   int r, e_hit, t, match, huntany;
XX    mode_t bits;
XX    off_t pos;
XX    unsigned new_slots, old_slots;
XX!   block_nr b;
XX  
XX!   /* If 'ldir_ptr' is not a pointer to a searchable dir inode, error. */
XX    if ( (ldir_ptr->i_mode & I_TYPE) != I_DIRECTORY) return(ENOTDIR);
XX-   bits = (flag == LOOK_UP ? X_BIT : W_BIT|X_BIT);
XX-   if ( (r = forbidden(ldir_ptr, bits, 0)) != OK) return(r);
XX  
XX    /* Step through the directory one block at a time. */
XX!   old_slots = ldir_ptr->i_size/DIR_ENTRY_SIZE;
XX    new_slots = 0;
XX    e_hit = FALSE;
XX    match = 0;			/* set when a string match occurs */
XX-   huntany = (*string == '\0' ? 1 : 0);	/* set iff looking up "" */
XX  
XX    for (pos = 0; pos < ldir_ptr->i_size; pos += BLOCK_SIZE) {
XX  	b = read_map(ldir_ptr, pos);	/* get block number */
XX--- 238,284 ----
XX  register struct inode *ldir_ptr;	/* ptr to inode for dir to search */
XX  char string[NAME_MAX];		/* component to search for */
XX  ino_t *numb;			/* pointer to inode number */
XX! int flag;			/* LOOK_UP, ENTER, DELETE or IS_EMPTY */
XX  {
XX  /* This function searches the directory whose inode is pointed to by 'ldip':
XX   * if (flag == ENTER)  enter 'string' in the directory with inode # '*numb';
XX   * if (flag == DELETE) delete 'string' from the directory;
XX   * if (flag == LOOK_UP) search for 'string' and return inode # in 'numb';
XX!  * if (flag == IS_EMPTY) return OK if only . and .. in dir else ENOTEMPTY;
XX!  *
XX!  *    if 'string' is dot1 or dot2, no access permissions are checked.
XX   */
XX  
XX!   register struct direct *dp;
XX    register struct buf *bp;
XX!   int i, r, e_hit, t, match;
XX    mode_t bits;
XX    off_t pos;
XX    unsigned new_slots, old_slots;
XX!   block_t b;
XX!   struct super_block *sp;
XX  
XX!   /* If 'ldir_ptr' is not a pointer to a dir inode, error. */
XX    if ( (ldir_ptr->i_mode & I_TYPE) != I_DIRECTORY) return(ENOTDIR);
XX  
XX+   r = OK;
XX+ 
XX+   if (flag != IS_EMPTY) {
XX+ 	bits = (flag == LOOK_UP ? X_BIT : W_BIT | X_BIT);
XX+ 
XX+ 	if (string == dot1 || string == dot2) {
XX+ 		if (flag != LOOK_UP) r = read_only(ldir_ptr);
XX+ 				     /* only a writable device is required. */
XX+         }
XX+ 	else r = forbidden(ldir_ptr, bits, 0); /* check access permissions */
XX+   }
XX+   if (r != OK) return(r);
XX+   
XX    /* Step through the directory one block at a time. */
XX!   old_slots = (unsigned) (ldir_ptr->i_size/DIR_ENTRY_SIZE);
XX    new_slots = 0;
XX    e_hit = FALSE;
XX    match = 0;			/* set when a string match occurs */
XX  
XX    for (pos = 0; pos < ldir_ptr->i_size; pos += BLOCK_SIZE) {
XX  	b = read_map(ldir_ptr, pos);	/* get block number */
XX***************
XX*** 277,285 ****
XX  			break;
XX  		}
XX  
XX! 		/* Match occurs if string found; "" matches all exc . and .. */
XX! 		if (flag != ENTER && dp->d_inum != 0) {
XX! 			if (huntany) {
XX  				/* If this test succeeds, dir is not empty. */
XX  				if (strcmp(dp->d_name, "." ) != 0 &&
XX  				    strcmp(dp->d_name, "..") != 0) match = 1;
XX--- 293,301 ----
XX  			break;
XX  		}
XX  
XX! 		/* Match occurs if string found. */
XX! 		if (flag != ENTER && dp->d_ino != 0) {
XX! 			if (flag == IS_EMPTY) {
XX  				/* If this test succeeds, dir is not empty. */
XX  				if (strcmp(dp->d_name, "." ) != 0 &&
XX  				    strcmp(dp->d_name, "..") != 0) match = 1;
XX***************
XX*** 292,315 ****
XX  		if (match) {
XX  			/* LOOK_UP or DELETE found what it wanted. */
XX  			r = OK;
XX! 			if (flag == DELETE) {
XX! 				/* Save d_inum for recovery. */
XX! 				rip = get_inode(ldir_ptr->i_dev, dp->d_inum);
XX  				t = NAME_MAX - sizeof(ino_t);
XX! 				*((ino_t *) &dp->d_name[t])=dp->d_inum;
XX! 				dp->d_inum = 0;	/* erase entry */
XX  				bp->b_dirt = DIRTY;
XX! 				ldir_ptr->i_update = MTIME;
XX! 				put_inode(rip);
XX! 			} else
XX! 				*numb = dp->d_inum;	/* 'flag' is LOOK_UP */
XX  			put_block(bp, DIRECTORY_BLOCK);
XX  			return(r);
XX  		}
XX  
XX  
XX  		/* Check for free slot for the benefit of ENTER. */
XX! 		if (flag == ENTER && dp->d_inum == 0) {
XX  			e_hit = TRUE;	/* we found a free slot */
XX  			break;
XX  		}
XX--- 308,333 ----
XX  		if (match) {
XX  			/* LOOK_UP or DELETE found what it wanted. */
XX  			r = OK;
XX! 			if (flag == IS_EMPTY) r = ENOTEMPTY;
XX! 			else if (flag == DELETE) {
XX! 				/* Save d_ino for recovery. */
XX  				t = NAME_MAX - sizeof(ino_t);
XX! 				*((ino_t *) &dp->d_name[t]) = dp->d_ino;
XX! 				dp->d_ino = 0;	/* erase entry */
XX  				bp->b_dirt = DIRTY;
XX! 				ldir_ptr->i_update |= CTIME | MTIME;
XX! 				ldir_ptr->i_dirt = DIRTY;
XX! 			} else {
XX! 				sp = ldir_ptr->i_sp;	/* 'flag' is LOOK_UP */
XX! 				*numb = conv2(sp->s_native, (int) dp->d_ino);
XX! 			}
XX  			put_block(bp, DIRECTORY_BLOCK);
XX  			return(r);
XX  		}
XX  
XX  
XX  		/* Check for free slot for the benefit of ENTER. */
XX! 		if (flag == ENTER && dp->d_ino == 0) {
XX  			e_hit = TRUE;	/* we found a free slot */
XX  			break;
XX  		}
XX***************
XX*** 321,327 ****
XX    }
XX  
XX    /* The whole directory has now been searched. */
XX!   if (flag != ENTER) return(ENOENT);
XX  
XX    /* This call is for ENTER.  If no free slot has been found so far, try to
XX     * extend directory.
XX--- 339,345 ----
XX    }
XX  
XX    /* The whole directory has now been searched. */
XX!   if (flag != ENTER) return(flag == IS_EMPTY ? OK : ENOENT);
XX  
XX    /* This call is for ENTER.  If no free slot has been found so far, try to
XX     * extend directory.
XX***************
XX*** 335,345 ****
XX    }
XX  
XX    /* 'bp' now points to a directory block with space. 'dp' points to slot. */
XX!   copy(dp->d_name, string, NAME_MAX);
XX!   dp->d_inum = *numb;
XX    bp->b_dirt = DIRTY;
XX    put_block(bp, DIRECTORY_BLOCK);
XX!   ldir_ptr->i_update = MTIME;	/* mark mtime for update later */
XX    ldir_ptr->i_dirt = DIRTY;
XX    if (new_slots > old_slots)
XX  	ldir_ptr->i_size = (off_t) new_slots * DIR_ENTRY_SIZE;
XX--- 353,365 ----
XX    }
XX  
XX    /* 'bp' now points to a directory block with space. 'dp' points to slot. */
XX!   (void) memset(dp->d_name, 0, (size_t) NAME_MAX); /* clear entry */
XX!   for (i = 0; string[i] && i < NAME_MAX; i++) dp->d_name[i] = string[i];
XX!   sp = ldir_ptr->i_sp; 
XX!   dp->d_ino = conv2(sp->s_native, (int) *numb);
XX    bp->b_dirt = DIRTY;
XX    put_block(bp, DIRECTORY_BLOCK);
XX!   ldir_ptr->i_update |= CTIME | MTIME;	/* mark mtime for update later */
XX    ldir_ptr->i_dirt = DIRTY;
XX    if (new_slots > old_slots)
XX  	ldir_ptr->i_size = (off_t) new_slots * DIR_ENTRY_SIZE;
X/
Xecho x - pipe.c.d
Xsed '/^X/s///' > pipe.c.d << '/'
XX*** /home/top/ast/minix/1.5/fs/pipe.c  crc=03416   8791	Sat Apr 21 22:26:20 1990
XX--- /home/top/ast/minix/1.6.25/fs/pipe.c  crc=19912  10199	Tue Nov  3 21:19:15 1992
XX***************
XX*** 16,21 ****
XX--- 16,22 ----
XX  #include "fs.h"
XX  #include <fcntl.h>
XX  #include <signal.h>
XX+ #include <minix/boot.h>
XX  #include <minix/callnr.h>
XX  #include <minix/com.h>
XX  #include "dev.h"
XX***************
XX*** 36,42 ****
XX    register struct fproc *rfp;
XX    register struct inode *rip;
XX    int r;
XX-   dev_t device;
XX    struct filp *fil_ptr0, *fil_ptr1;
XX    int fil_des[2];		/* reply goes here */
XX  
XX--- 37,42 ----
XX***************
XX*** 53,61 ****
XX    rfp->fp_filp[fil_des[1]] = fil_ptr1;
XX    fil_ptr1->filp_count = 1;
XX  
XX!   /* Make the inode in the current working directory. */
XX!   device = rfp->fp_workdir->i_dev;	/* inode dev is same as working dir */
XX!   if ( (rip = alloc_inode(device, I_REGULAR)) == NIL_INODE) {
XX  	rfp->fp_filp[fil_des[0]] = NIL_FILP;
XX  	fil_ptr0->filp_count = 0;
XX  	rfp->fp_filp[fil_des[1]] = NIL_FILP;
XX--- 53,60 ----
XX    rfp->fp_filp[fil_des[1]] = fil_ptr1;
XX    fil_ptr1->filp_count = 1;
XX  
XX!   /* Make the inode on the pipe device. */
XX!   if ( (rip = alloc_inode(PIPE_DEV, I_REGULAR) ) == NIL_INODE) {
XX  	rfp->fp_filp[fil_des[0]] = NIL_FILP;
XX  	fil_ptr0->filp_count = 0;
XX  	rfp->fp_filp[fil_des[1]] = NIL_FILP;
XX***************
XX*** 63,75 ****
XX--- 62,81 ----
XX  	return(err_code);
XX    }
XX  
XX+   if (read_only(rip) != OK) panic("pipe device is read only", NO_NUM);
XX+  
XX    rip->i_pipe = I_PIPE;
XX+   rip->i_mode &= ~I_REGULAR;
XX+   rip->i_mode |= I_NAMED_PIPE;	/* pipes and FIFOs have this bit set */
XX    fil_ptr0->filp_ino = rip;
XX+   fil_ptr0->filp_flags = O_RDONLY;
XX    dup_inode(rip);		/* for double usage */
XX    fil_ptr1->filp_ino = rip;
XX+   fil_ptr1->filp_flags = O_WRONLY;
XX    rw_inode(rip, WRITING);	/* mark inode as allocated */
XX    reply_i1 = fil_des[0];
XX    reply_i2 = fil_des[1];
XX+   rip->i_update = ATIME | CTIME | MTIME;
XX    return(OK);
XX  }
XX  
XX***************
XX*** 77,88 ****
XX  /*===========================================================================*
XX   *				pipe_check				     *
XX   *===========================================================================*/
XX! PUBLIC int pipe_check(rip, rw_flag, oflags, bytes, position)
XX  register struct inode *rip;	/* the inode of the pipe */
XX  int rw_flag;			/* READING or WRITING */
XX  int oflags;			/* flags set by open or fcntl */
XX  register int bytes;		/* bytes to be read or written (all chunks) */
XX  register off_t position;	/* current file position */
XX  {
XX  /* Pipes are a little different.  If a process reads from an empty pipe for
XX   * which a writer still exists, suspend the reader.  If the pipe is empty
XX--- 83,95 ----
XX  /*===========================================================================*
XX   *				pipe_check				     *
XX   *===========================================================================*/
XX! PUBLIC int pipe_check(rip, rw_flag, oflags, bytes, position, canwrite)
XX  register struct inode *rip;	/* the inode of the pipe */
XX  int rw_flag;			/* READING or WRITING */
XX  int oflags;			/* flags set by open or fcntl */
XX  register int bytes;		/* bytes to be read or written (all chunks) */
XX  register off_t position;	/* current file position */
XX+ int *canwrite;			/* return: number of bytes we can write */
XX  {
XX  /* Pipes are a little different.  If a process reads from an empty pipe for
XX   * which a writer still exists, suspend the reader.  If the pipe is empty
XX***************
XX*** 98,105 ****
XX  		/* Process is reading from an empty pipe. */
XX  		if (find_filp(rip, W_BIT) != NIL_FILP) {
XX  			/* Writer exists */
XX! 			if (oflags & O_NONBLOCK) r = EAGAIN;
XX! 			else suspend(XPIPE);	/* block reader */
XX  
XX  			/* If need be, activate sleeping writers. */
XX  			if (susp_count > 0) release(rip, WRITE, susp_count);
XX--- 105,114 ----
XX  		/* Process is reading from an empty pipe. */
XX  		if (find_filp(rip, W_BIT) != NIL_FILP) {
XX  			/* Writer exists */
XX! 			if (oflags & O_NONBLOCK) 
XX! 				r = EAGAIN;
XX! 			else 
XX! 				suspend(XPIPE);	/* block reader */
XX  
XX  			/* If need be, activate sleeping writers. */
XX  			if (susp_count > 0) release(rip, WRITE, susp_count);
XX***************
XX*** 108,114 ****
XX  	}
XX    } else {
XX  	/* Process is writing to a pipe. */
XX! 	if (bytes > PIPE_SIZE) return(EFBIG);
XX  	if (find_filp(rip, R_BIT) == NIL_FILP) {
XX  		/* Tell kernel to generate a SIGPIPE signal. */
XX  		sys_kill((int)(fp - fproc), SIGPIPE);
XX--- 117,123 ----
XX  	}
XX    } else {
XX  	/* Process is writing to a pipe. */
XX! /*	if (bytes > PIPE_SIZE) return(EFBIG); */
XX  	if (find_filp(rip, R_BIT) == NIL_FILP) {
XX  		/* Tell kernel to generate a SIGPIPE signal. */
XX  		sys_kill((int)(fp - fproc), SIGPIPE);
XX***************
XX*** 116,122 ****
XX  	}
XX  
XX  	if (position + bytes > PIPE_SIZE) {
XX! 		if (oflags & O_NONBLOCK) return(EAGAIN);
XX  		suspend(XPIPE);	/* stop writer -- pipe full */
XX  		return(0);
XX  	}
XX--- 125,150 ----
XX  	}
XX  
XX  	if (position + bytes > PIPE_SIZE) {
XX! 		if ((oflags & O_NONBLOCK) && bytes < PIPE_SIZE) 
XX! 			return(EAGAIN);
XX! 		else if ((oflags & O_NONBLOCK) && bytes > PIPE_SIZE) {
XX! 			if ( (*canwrite = (PIPE_SIZE - position)) > 0)  {
XX! 				/* Do a partial write. Need to wakeup reader */
XX! 				release(rip, READ, susp_count);
XX! 				return(1);
XX! 			} else {
XX! 				return(EAGAIN);
XX! 			}
XX! 		     }
XX! 		if (bytes > PIPE_SIZE) {
XX! 			if ((*canwrite = PIPE_SIZE - position) > 0) {
XX! 				/* Do a partial write. Need to wakeup reader
XX! 				 * since we'll suspend ourself in read_write()
XX! 				 */
XX! 				release(rip, READ, susp_count);
XX! 				return(1);
XX! 			}
XX! 		}
XX  		suspend(XPIPE);	/* stop writer -- pipe full */
XX  		return(0);
XX  	}
XX***************
XX*** 125,130 ****
XX--- 153,159 ----
XX  	if (position == 0) release(rip, READ, susp_count);
XX    }
XX  
XX+   *canwrite = 0;
XX    return(1);
XX  }
XX  
XX***************
XX*** 141,152 ****
XX   * but they are needed for pipes, and it is not worth making the distinction.)
XX   */
XX  
XX!   if (task == XPIPE || task == XOPEN) susp_count++;/* count procs suspended on pipe */
XX    fp->fp_suspended = SUSPENDED;
XX    fp->fp_fd = fd << 8 | fs_call;
XX-   fp->fp_buffer = buffer;
XX-   fp->fp_nbytes = nbytes;
XX    fp->fp_task = -task;
XX    dont_reply = TRUE;		/* do not send caller a reply message now */
XX  }
XX  
XX--- 170,186 ----
XX   * but they are needed for pipes, and it is not worth making the distinction.)
XX   */
XX  
XX!   if (task == XPIPE || task == XPOPEN) susp_count++;/* #procs susp'ed on pipe*/
XX    fp->fp_suspended = SUSPENDED;
XX    fp->fp_fd = fd << 8 | fs_call;
XX    fp->fp_task = -task;
XX+   if (task == XLOCK) {
XX+ 	fp->fp_buffer = (char *) name1;	/*  third arg to fcntl() */
XX+ 	fp->fp_nbytes =request;		/* second arg to fcntl() */
XX+   } else {
XX+ 	fp->fp_buffer = buffer;		/* for reads and writes */
XX+ 	fp->fp_nbytes = nbytes;
XX+   }
XX    dont_reply = TRUE;		/* do not send caller a reply message now */
XX  }
XX  
XX***************
XX*** 156,167 ****
XX   *===========================================================================*/
XX  PUBLIC void release(ip, call_nr, count)
XX  register struct inode *ip;	/* inode of pipe */
XX! int call_nr;			/* READ or WRITE */
XX  int count;			/* max number of processes to release */
XX  {
XX  /* Check to see if any process is hanging on the pipe whose inode is in 'ip'.
XX!  * If one is, and it was trying to perform the call indicated by 'call_nr'
XX!  * (READ or WRITE), release it.
XX   */
XX  
XX    register struct fproc *rp;
XX--- 190,201 ----
XX   *===========================================================================*/
XX  PUBLIC void release(ip, call_nr, count)
XX  register struct inode *ip;	/* inode of pipe */
XX! int call_nr;			/* READ, WRITE, OPEN or CREAT */
XX  int count;			/* max number of processes to release */
XX  {
XX  /* Check to see if any process is hanging on the pipe whose inode is in 'ip'.
XX!  * If one is, and it was trying to perform the call indicated by 'call_nr',
XX!  * release it.
XX   */
XX  
XX    register struct fproc *rp;
XX***************
XX*** 204,220 ****
XX     * must be restarted so it can try again.
XX     */
XX    task = -rfp->fp_task;
XX!   if (task == XPIPE) {
XX! 	/* Revive a process suspended on a pipe. */
XX  	rfp->fp_revived = REVIVING;
XX! 	reviving++;		/* process was waiting on pipe */
XX    } else {
XX  	rfp->fp_suspended = NOT_SUSPENDED;
XX! 	if (task == XOPEN) /* process blocked in open or create */
XX  		reply(proc_nr, rfp->fp_fd>>8);
XX  	else {
XX  		/* Revive a process suspended on TTY or other device. */
XX! 		rfp->fp_nbytes = bytes;	/* pretend it only wants what there is */
XX  		reply(proc_nr, bytes);	/* unblock the process */
XX  	}
XX    }
XX--- 238,254 ----
XX     * must be restarted so it can try again.
XX     */
XX    task = -rfp->fp_task;
XX!   if (task == XPIPE || task == XLOCK) {
XX! 	/* Revive a process suspended on a pipe or lock. */
XX  	rfp->fp_revived = REVIVING;
XX! 	reviving++;		/* process was waiting on pipe or lock */
XX    } else {
XX  	rfp->fp_suspended = NOT_SUSPENDED;
XX! 	if (task == XPOPEN) /* process blocked in open or create */
XX  		reply(proc_nr, rfp->fp_fd>>8);
XX  	else {
XX  		/* Revive a process suspended on TTY or other device. */
XX! 		rfp->fp_nbytes = bytes;	/*pretend it wants only what there is*/
XX  		reply(proc_nr, bytes);	/* unblock the process */
XX  	}
XX    }
XX***************
XX*** 242,263 ****
XX    if (rfp->fp_suspended == NOT_SUSPENDED) return(OK);
XX    task = -rfp->fp_task;
XX  
XX!   if (task != XPIPE) {
XX! 	if (task != XOPEN) {
XX  		fild = (rfp->fp_fd >> 8) & BYTE;/* extract file descriptor */
XX! 		if (fild < 0 || fild >= OPEN_MAX) panic("unpause err 2", NO_NUM);
XX  		f = rfp->fp_filp[fild];
XX! 		dev = f->filp_ino->i_zone[0];	/* device on which proc is hanging */
XX  		mess.TTY_LINE = (dev >> MINOR) & BYTE;
XX  		mess.PROC_NR = proc_nr;
XX! 	/* Tell kernel whether R or W. Mode is from current call, not open. */
XX  		mess.COUNT = (rfp->fp_fd & BYTE) == READ ? R_BIT : W_BIT;
XX  		mess.m_type = CANCEL;
XX  		(*dmap[(dev >> MAJOR) & BYTE].dmap_rw)(task, &mess);
XX- 	}
XX- 	rfp->fp_suspended = NOT_SUSPENDED;
XX- 	reply(proc_nr, EINTR);	/* signal interrupted call */
XX    }
XX  
XX    return(OK);
XX  }
XX--- 276,310 ----
XX    if (rfp->fp_suspended == NOT_SUSPENDED) return(OK);
XX    task = -rfp->fp_task;
XX  
XX!   switch(task) {
XX! 	case XPIPE:		/* process trying to read or write a pipe */
XX! 		break;
XX! 
XX! 	case XOPEN:		/* process trying to open a special file */
XX! 		panic ("fs/do_unpause called with XOPEN\n", NO_NUM);
XX! 
XX! 	case XLOCK:		/* process trying to set a lock with FCNTL */
XX! 		break;
XX! 
XX! 	case XPOPEN:		/* process trying to open a fifo */
XX! 		break;
XX! 
XX! 	default:		/* process trying to do device I/O (e.g. tty)*/
XX  		fild = (rfp->fp_fd >> 8) & BYTE;/* extract file descriptor */
XX! 		if (fild < 0 || fild >= OPEN_MAX)panic("unpause err 2",NO_NUM);
XX  		f = rfp->fp_filp[fild];
XX! 		dev = (dev_t) f->filp_ino->i_zone[0];	/* device hung on */
XX  		mess.TTY_LINE = (dev >> MINOR) & BYTE;
XX  		mess.PROC_NR = proc_nr;
XX! 
XX! 		/* Tell kernel R or W. Mode is from current call, not open. */
XX  		mess.COUNT = (rfp->fp_fd & BYTE) == READ ? R_BIT : W_BIT;
XX  		mess.m_type = CANCEL;
XX+ 		fp = rfp;	/* hack - rw_dev2 uses fp */
XX  		(*dmap[(dev >> MAJOR) & BYTE].dmap_rw)(task, &mess);
XX    }
XX  
XX+   rfp->fp_suspended = NOT_SUSPENDED;
XX+   reply(proc_nr, EINTR);	/* signal interrupted call */
XX    return(OK);
XX  }
X/
Xecho x - protect.c.d
Xsed '/^X/s///' > protect.c.d << '/'
XX*** /home/top/ast/minix/1.5/fs/protect.c  crc=27104   5592	Sat Apr 21 22:26:20 1990
XX--- /home/top/ast/minix/1.6.25/fs/protect.c  crc=16528   6780	Tue Nov  3 21:19:16 1992
XX***************
XX*** 10,15 ****
XX--- 10,16 ----
XX   */
XX  
XX  #include "fs.h"
XX+ #include <unistd.h>
XX  #include "buf.h"
XX  #include "file.h"
XX  #include "fproc.h"
XX***************
XX*** 45,52 ****
XX  	return(r);
XX    }
XX  
XX!   /* Now make the change. */
XX    rip->i_mode = (rip->i_mode & ~ALL_MODES) | (mode & ALL_MODES);
XX    rip->i_dirt = DIRTY;
XX  
XX    put_inode(rip);
XX--- 46,55 ----
XX  	return(r);
XX    }
XX  
XX!   /* Now make the change. Clear setgid bit if file is not in caller's grp */
XX    rip->i_mode = (rip->i_mode & ~ALL_MODES) | (mode & ALL_MODES);
XX+   if (!super_user && rip->i_gid != fp->fp_effgid)rip->i_mode &= ~I_SET_GID_BIT;
XX+   rip->i_update |= CTIME;
XX    rip->i_dirt = DIRTY;
XX  
XX    put_inode(rip);
XX***************
XX*** 64,72 ****
XX    register struct inode *rip;
XX    register int r;
XX  
XX-   /* Only the super_user may perform the chown() call. */
XX-   if (!super_user) return(EPERM);
XX- 
XX    /* Temporarily open the file. */
XX    if (fetch_name(name1, name1_length, M1) != OK) return(err_code);
XX    if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code);
XX--- 67,72 ----
XX***************
XX*** 74,81 ****
XX    /* Not permitted to change the owner of a file on a read-only file sys. */
XX    r = read_only(rip);
XX    if (r == OK) {
XX! 	rip->i_uid = owner;
XX  	rip->i_gid = group;
XX  	rip->i_dirt = DIRTY;
XX    }
XX  
XX--- 74,97 ----
XX    /* Not permitted to change the owner of a file on a read-only file sys. */
XX    r = read_only(rip);
XX    if (r == OK) {
XX! 	/* FS is R/W.  Whether call is allowed depends on ownership, etc. */
XX! 	if (super_user) {
XX! 		/* The super user can do anything. */
XX! 		rip->i_uid = owner;	
XX! 		rip->i_gid = group;
XX! 		rip->i_update |= CTIME;
XX! 		rip->i_dirt = DIRTY;
XX! 	} else {
XX! 		/* Regular users can only change groups of their own files. */
XX! 		if (rip->i_uid != fp->fp_effuid) r = EPERM;
XX! 		if (rip->i_uid != owner) r = EPERM;	/* no giving away */
XX! 		if (fp->fp_effgid != group) r = EPERM;
XX! 	}
XX!   }
XX!   if (r == OK) {
XX  	rip->i_gid = group;
XX+ 	rip->i_mode &= ~(I_SET_UID_BIT | I_SET_GID_BIT);
XX+ 	rip->i_update |= CTIME;
XX  	rip->i_dirt = DIRTY;
XX    }
XX  
XX***************
XX*** 108,113 ****
XX--- 124,133 ----
XX    struct inode *rip;
XX    register int r;
XX  
XX+   /* First check to see if the mode is correct. */
XX+   if ( (mode & ~(R_OK | W_OK | X_OK)) != 0 && mode != F_OK)
XX+ 	return(EINVAL);
XX+ 
XX    /* Temporarily open the file whose access is to be checked. */
XX    if (fetch_name(name, name_length, M3) != OK) return(err_code);
XX    if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code);
XX***************
XX*** 133,168 ****
XX   * if it is forbidden, EACCES is returned.
XX   */
XX  
XX!   register mode_t bits, perm_bits, xmask;
XX    int r, shift, test_uid, test_gid;
XX  
XX    /* Isolate the relevant rwx bits from the mode. */
XX    bits = rip->i_mode;
XX    test_uid = (real_uid ? fp->fp_realuid : fp->fp_effuid);
XX    test_gid = (real_uid ? fp->fp_realgid : fp->fp_effgid);
XX    if (test_uid == SU_UID) {
XX! 	perm_bits = 07;
XX    } else {
XX  	if (test_uid == rip->i_uid) shift = 6;		/* owner */
XX  	else if (test_gid == rip->i_gid ) shift = 3;	/* group */
XX  	else shift = 0;					/* other */
XX! 	perm_bits = (bits >> shift) & 07;
XX    }
XX  
XX    /* If access desired is not a subset of what is allowed, it is refused. */
XX    r = OK;
XX    if ((perm_bits | access_desired) != perm_bits) r = EACCES;
XX  
XX-   /* If none of the X bits are on, not even the super-user can execute it. */
XX-   xmask = (X_BIT << 6) | (X_BIT << 3) | X_BIT;	/* all 3 X bits */
XX-   if ( (access_desired & X_BIT) && (bits & xmask) == 0) r = EACCES;
XX- 
XX    /* Check to see if someone is trying to write on a file system that is
XX     * mounted read-only.
XX     */
XX    if (r == OK)
XX  	if (access_desired & W_BIT) r = read_only(rip);
XX  
XX    return(r);
XX  }
XX  
XX--- 153,203 ----
XX   * if it is forbidden, EACCES is returned.
XX   */
XX  
XX!   register struct inode *old_rip = rip;
XX!   register struct super_block *sp;
XX!   register mode_t bits, perm_bits;
XX    int r, shift, test_uid, test_gid;
XX  
XX+   if (rip->i_mount == I_MOUNT)	/* The inode is mounted on. */
XX+ 	for (sp = &super_block[1]; sp < &super_block[NR_SUPERS]; sp++)
XX+ 		if (sp->s_imount == rip) {
XX+ 			rip = get_inode(sp->s_dev, ROOT_INODE);
XX+ 			break;
XX+ 		} /* if */
XX+ 
XX    /* Isolate the relevant rwx bits from the mode. */
XX    bits = rip->i_mode;
XX    test_uid = (real_uid ? fp->fp_realuid : fp->fp_effuid);
XX    test_gid = (real_uid ? fp->fp_realgid : fp->fp_effgid);
XX    if (test_uid == SU_UID) {
XX! 	/* Grant read and write permission.  Grant search permission for
XX! 	 * directories.  Grant execute permission (for non-directories) if
XX! 	 * and only if one of the 'X' bits is set.
XX! 	 */
XX! 	if ( (bits & I_TYPE) == I_DIRECTORY ||
XX! 	     bits & ((X_BIT << 6) | (X_BIT << 3) | X_BIT))
XX! 		perm_bits = R_BIT | W_BIT | X_BIT;
XX! 	else	
XX! 		perm_bits = R_BIT | W_BIT;
XX    } else {
XX  	if (test_uid == rip->i_uid) shift = 6;		/* owner */
XX  	else if (test_gid == rip->i_gid ) shift = 3;	/* group */
XX  	else shift = 0;					/* other */
XX! 	perm_bits = (bits >> shift) & (R_BIT | W_BIT | X_BIT);
XX    }
XX  
XX    /* If access desired is not a subset of what is allowed, it is refused. */
XX    r = OK;
XX    if ((perm_bits | access_desired) != perm_bits) r = EACCES;
XX  
XX    /* Check to see if someone is trying to write on a file system that is
XX     * mounted read-only.
XX     */
XX    if (r == OK)
XX  	if (access_desired & W_BIT) r = read_only(rip);
XX  
XX+   if (rip != old_rip) put_inode(rip);
XX+ 
XX    return(r);
XX  }
XX  
XX***************
XX*** 179,184 ****
XX  
XX    register struct super_block *sp;
XX  
XX!   sp = get_super(ip->i_dev);
XX    return(sp->s_rd_only ? EROFS : OK);
XX  }
XX--- 214,219 ----
XX  
XX    register struct super_block *sp;
XX  
XX!   sp = ip->i_sp;
XX    return(sp->s_rd_only ? EROFS : OK);
XX  }
X/
Xecho x - proto.h.d
Xsed '/^X/s///' > proto.h.d << '/'
XX*** /home/top/ast/minix/1.5/fs/proto.h  crc=00607   2198	Sat Apr 21 22:26:20 1990
XX--- /home/top/ast/minix/1.6.25/fs/proto.h  crc=50750   6432	Sat Apr 10 19:45:43 1993
XX***************
XX*** 1,147 ****
XX  /* Function prototypes. */
XX  
XX  /* cache.c */
XX! zone_nr alloc_zone();
XX! void flushall();
XX! void free_zone();
XX! struct buf *get_block();
XX! void invalidate();
XX! void put_block();
XX! void rw_block();
XX! void rw_scattered();
XX  
XX  /* device.c */
XX! void dev_close();
XX! int dev_io();
XX! int do_ioctl();
XX! int dev_open();
XX! void no_call();
XX! void rw_dev();
XX! void rw_dev2();
XX! int tty_exit();
XX! void tty_open();
XX  
XX  /* filedes.c */
XX! struct filp *find_filp();
XX! int get_fd();
XX! struct filp *get_filp();
XX  
XX  /* inode.c */
XX! struct inode *alloc_inode();
XX! void dup_inode();
XX! void free_inode();
XX! struct inode *get_inode();
XX! void put_inode();
XX! void update_times();
XX! void rw_inode();
XX! void wipe_inode();
XX  
XX  /* link.c */
XX! int do_link();
XX! int do_unlink();
XX! int do_rename();
XX! void truncate();
XX  
XX  /* main.c */
XX! void main();
XX! void reply();
XX  
XX  /* misc.c */
XX! int do_dup();
XX! int do_exit();
XX! int do_fcntl();
XX! int do_fork();
XX! int do_revive();
XX! int do_set();
XX! int do_sync();
XX  
XX  /* mount.c */
XX! int do_mount();
XX! int do_umount();
XX  
XX  /* open.c */
XX! int do_close();
XX! int do_creat();
XX! int do_lseek();
XX! int do_mknod();
XX! int do_mkdir();
XX! int do_open();
XX  
XX  /* path.c */
XX! struct inode *advance();
XX! int search_dir();
XX! struct inode *eat_path();
XX! struct inode *last_dir();
XX  
XX  /* pipe.c */
XX! int do_pipe();
XX! int do_unpause();
XX! int pipe_check();
XX! void release();
XX! void revive();
XX! void suspend();
XX  
XX  /* protect.c */
XX! int do_access();
XX! int do_chmod();
XX! int do_chown();
XX! int do_umask();
XX! int forbidden();
XX! int read_only();
XX  
XX! /* putc.c */
XX! void putc();
XX  
XX  /* read.c */
XX! int do_read();
XX! struct buf *rahead();
XX! void read_ahead();
XX! block_nr read_map();
XX! int read_write();
XX! int rw_user();
XX  
XX  /* stadir.c */
XX! int do_chdir();
XX! int do_chroot();
XX! int do_fstat();
XX! int do_stat();
XX  
XX  /* super.c */
XX! bit_nr alloc_bit();
XX! void free_bit();
XX! struct super_block *get_super();
XX! int load_bit_maps();
XX! int mounted();
XX! void rw_super();
XX! int scale_factor();
XX! int unload_bit_maps();
XX  
XX  /* time.c */
XX! int do_stime();
XX! int do_time();
XX! int do_tims();
XX! int do_utime();
XX  
XX  /* utility.c */
XX! time_t clock_time();
XX! int cmp_string();
XX! void copy();
XX! int fetch_name();
XX! int no_sys();
XX! void panic();
XX  
XX  /* write.c */
XX! void clear_zone();
XX! int do_write();
XX! struct buf *new_block();
XX! void zero_block();
XX! 
XX! /* library */
XX! void printk();
XX! int receive();
XX! int send();
XX! int sendrec();
XX! void sys_abort();
XX! void sys_copy();
XX! void sys_kill();
XX! void sys_times();
XX--- 1,160 ----
XX  /* Function prototypes. */
XX  
XX+ /* Structs used in prototypes must be declared as such first. */
XX+ struct buf;
XX+ struct filp;		
XX+ struct inode;
XX+ struct super_block;
XX+ 
XX  /* cache.c */
XX! _PROTOTYPE( zone_t alloc_zone, (Dev_t dev, zone_t z)			);
XX! _PROTOTYPE( void flushall, (Dev_t dev)					);
XX! _PROTOTYPE( void free_zone, (Dev_t dev, zone_t numb)			);
XX! _PROTOTYPE( struct buf *get_block, (Dev_t dev, block_t block,int only_search));
XX! _PROTOTYPE( void invalidate, (Dev_t device)				);
XX! _PROTOTYPE( void put_block, (struct buf *bp, int block_type)		);
XX! _PROTOTYPE( void rm_lru, (struct buf *bp)				);
XX! _PROTOTYPE( void rw_block, (struct buf *bp, int rw_flag)		);
XX! _PROTOTYPE( void rw_scattered, (Dev_t dev,
XX! 			struct buf **bufq, int bufqsize, int rw_flag)	);
XX  
XX  /* device.c */
XX! _PROTOTYPE( void call_task, (int task_nr, message *mess_ptr)		);
XX! _PROTOTYPE( void dev_opcl, (int task_nr, message *mess_ptr)		);
XX! _PROTOTYPE( int dev_io, (int rw_flag, int nonblock, Dev_t dev,
XX! 			off_t pos, int bytes, int proc, char *buff)	);
XX! _PROTOTYPE( int do_ioctl, (void)					);
XX! _PROTOTYPE( void no_call, (int task_nr, message *m_ptr)			);
XX! _PROTOTYPE( void rw_dev2, (int task_nr, message *mess_ptr)		);
XX! _PROTOTYPE( void tty_close, (int task_nr, message *mess_ptr)		);
XX! _PROTOTYPE( void tty_open, (int task_nr, message *mess_ptr)		);
XX! _PROTOTYPE( void ctty_close, (int task_nr, message *mess_ptr)		);
XX! _PROTOTYPE( void ctty_open, (int task_nr, message *mess_ptr)		);
XX! _PROTOTYPE( void net_open, (int task_nr, message *mess_ptr)		);
XX! _PROTOTYPE( void net_rw, (int task_nr, message *mess_ptr)		);
XX! _PROTOTYPE( void net_close, (int task_nr, message *mess_ptr)		);
XX  
XX  /* filedes.c */
XX! _PROTOTYPE( struct filp *find_filp, (struct inode *rip, Mode_t bits)	);
XX! _PROTOTYPE( int get_fd, (int start, Mode_t bits, int *k, struct filp **fpt) );
XX! _PROTOTYPE( struct filp *get_filp, (int fild)				);
XX  
XX  /* inode.c */
XX! _PROTOTYPE( struct inode *alloc_inode, (Dev_t dev, Mode_t bits)		);
XX! _PROTOTYPE( void dup_inode, (struct inode *ip)				);
XX! _PROTOTYPE( void free_inode, (Dev_t dev, int numb)			);
XX! _PROTOTYPE( struct inode *get_inode, (Dev_t dev, int numb)		);
XX! _PROTOTYPE( void put_inode, (struct inode *rip)				);
XX! _PROTOTYPE( void update_times, (struct inode *rip)			);
XX! _PROTOTYPE( void rw_inode, (struct inode *rip, int rw_flag)		);
XX! _PROTOTYPE( void wipe_inode, (struct inode *rip)			);
XX  
XX  /* link.c */
XX! _PROTOTYPE( int do_link, (void)						);
XX! _PROTOTYPE( int do_unlink, (void)					);
XX! _PROTOTYPE( int do_rename, (void)					);
XX! _PROTOTYPE( void truncate, (struct inode *rip)				);
XX  
XX  /* main.c */
XX! _PROTOTYPE( void main, (void)						);
XX! _PROTOTYPE( void reply, (int whom, int result)				);
XX  
XX  /* misc.c */
XX! _PROTOTYPE( int do_dup, (void)						);
XX! _PROTOTYPE( int do_exit, (void)						);
XX! _PROTOTYPE( int do_fcntl, (void)					);
XX! _PROTOTYPE( int do_fork, (void)						);
XX! _PROTOTYPE( int do_exec, (void)						);
XX! _PROTOTYPE( int do_revive, (void)					);
XX! _PROTOTYPE( int do_set, (void)						);
XX! _PROTOTYPE( int do_sync, (void)						);
XX! _PROTOTYPE( void lock_revive, (void)					);
XX  
XX  /* mount.c */
XX! _PROTOTYPE( int do_mount, (void)					);
XX! _PROTOTYPE( int do_umount, (void)					);
XX  
XX  /* open.c */
XX! _PROTOTYPE( int do_close, (void)					);
XX! _PROTOTYPE( int do_creat, (void)					);
XX! _PROTOTYPE( int do_lseek, (void)					);
XX! _PROTOTYPE( int do_mknod, (void)					);
XX! _PROTOTYPE( int do_mkdir, (void)					);
XX! _PROTOTYPE( int do_open, (void)						);
XX  
XX  /* path.c */
XX! _PROTOTYPE( struct inode *advance,(struct inode *dirp, char string[NAME_MAX]));
XX! _PROTOTYPE( int search_dir, (struct inode *ldir_ptr,
XX! 			char string [NAME_MAX], ino_t *numb, int flag)	);
XX! _PROTOTYPE( struct inode *eat_path, (char *path)			);
XX! _PROTOTYPE( struct inode *last_dir, (char *path, char string [NAME_MAX]));
XX  
XX  /* pipe.c */
XX! _PROTOTYPE( int do_pipe, (void)						);
XX! _PROTOTYPE( int do_unpause, (void)					);
XX! _PROTOTYPE( int pipe_check, (struct inode *rip, int rw_flag,
XX! 			int oflags, int bytes, off_t position, int *canwrite));
XX! _PROTOTYPE( void release, (struct inode *ip, int call_nr, int count)	);
XX! _PROTOTYPE( void revive, (int proc_nr, int bytes)			);
XX! _PROTOTYPE( void suspend, (int task)					);
XX  
XX  /* protect.c */
XX! _PROTOTYPE( int do_access, (void)					);
XX! _PROTOTYPE( int do_chmod, (void)					);
XX! _PROTOTYPE( int do_chown, (void)					);
XX! _PROTOTYPE( int do_umask, (void)					);
XX! _PROTOTYPE( int forbidden, (struct inode *rip,
XX! 			Mode_t access_desired, int real_uid)		);
XX! _PROTOTYPE( int read_only, (struct inode *ip)				);
XX  
XX! /* putk.c */
XX! _PROTOTYPE( void putk, (int c)						);
XX  
XX  /* read.c */
XX! _PROTOTYPE( int do_read, (void)						);
XX! _PROTOTYPE( struct buf *rahead, (struct inode *rip, block_t baseblock,
XX! 			off_t position, unsigned bytes_ahead)		);
XX! _PROTOTYPE( void read_ahead, (void)					);
XX! _PROTOTYPE( block_t read_map, (struct inode *rip, off_t position)	);
XX! _PROTOTYPE( int read_write, (int rw_flag)				);
XX! _PROTOTYPE( zone_t rd_indir, (struct buf *bp, int index)		);
XX! _PROTOTYPE( int rw_user, (int s, int u, vir_bytes vir,
XX! 			vir_bytes bytes, char *buff, int direction)	);
XX  
XX  /* stadir.c */
XX! _PROTOTYPE( int do_chdir, (void)					);
XX! _PROTOTYPE( int do_chroot, (void)					);
XX! _PROTOTYPE( int do_fstat, (void)					);
XX! _PROTOTYPE( int do_stat, (void)						);
XX  
XX  /* super.c */
XX! _PROTOTYPE( bit_t alloc_bit, (struct buf *map_ptr [], bit_t map_bits,
XX! 				int bit_blocks, bit_t origin)		);
XX! _PROTOTYPE( void free_bit, (struct buf *map_ptr [], bit_t bit_returned));
XX! _PROTOTYPE( struct super_block *get_super, (Dev_t dev)			);
XX! _PROTOTYPE( int load_bit_maps, (Dev_t dev)				);
XX! _PROTOTYPE( int mounted, (struct inode *rip)				);
XX! _PROTOTYPE( void read_super, (struct super_block *sp, block_t offset)	);
XX! _PROTOTYPE( int unload_bit_maps, (Dev_t dev)				);
XX  
XX  /* time.c */
XX! _PROTOTYPE( int do_stime, (void)					);
XX! _PROTOTYPE( int do_time, (void)						);
XX! _PROTOTYPE( int do_tims, (void)						);
XX! _PROTOTYPE( int do_utime, (void)					);
XX  
XX  /* utility.c */
XX! _PROTOTYPE( time_t clock_time, (void)					);
XX! _PROTOTYPE( unsigned conv2, (int norm, int w)				);
XX! _PROTOTYPE( long conv4, (int norm, long x)				);
XX! _PROTOTYPE( int fetch_name, (char *path, int len, int flag)		);
XX! _PROTOTYPE( int no_sys, (void)						);
XX! _PROTOTYPE( void panic, (char *format, int num)				);
XX! _PROTOTYPE( void sys_kill, (int proc, int sig)				);
XX! _PROTOTYPE( void sys_times, (int proc, clock_t ptr[5])			);
XX  
XX  /* write.c */
XX! _PROTOTYPE( void clear_zone, (struct inode *rip, off_t pos, int flag)	);
XX! _PROTOTYPE( int do_write, (void)					);
XX! _PROTOTYPE( struct buf *new_block, (struct inode *rip, off_t position)	);
XX! _PROTOTYPE( void zero_block, (struct buf *bp)				);
X/
Xecho x - read.c.d
Xsed '/^X/s///' > read.c.d << '/'
XX*** /home/top/ast/minix/1.5/fs/read.c  crc=40616  16536	Sat May  5 13:14:25 1990
XX--- /home/top/ast/minix/1.6.25/fs/read.c  crc=64915  19604	Tue Nov  3 21:19:16 1992
XX***************
XX*** 7,12 ****
XX--- 7,13 ----
XX   *   do_read:	 perform the READ system call by calling read_write
XX   *   read_write: actually do the work of READ and WRITE
XX   *   read_map:	 given an inode and file position, look up its zone number
XX+  *   rd_indir:	 read an entry in an indirect block 
XX   *   rw_user:	 call the kernel to read and write user space
XX   *   read_ahead: manage the block read ahead business
XX   */
XX***************
XX*** 25,31 ****
XX  
XX  PRIVATE message umess;		/* message for asking SYSTASK for user copy */
XX  
XX! FORWARD int rw_chunk();
XX  
XX  /*===========================================================================*
XX   *				do_read					     *
XX--- 26,34 ----
XX  
XX  PRIVATE message umess;		/* message for asking SYSTASK for user copy */
XX  
XX! FORWARD _PROTOTYPE( int rw_chunk, (struct inode *rip, off_t position,
XX! 			unsigned off, int chunk, unsigned left, int rw_flag,
XX! 			char *buff, int seg, int usr)			);
XX  
XX  /*===========================================================================*
XX   *				do_read					     *
XX***************
XX*** 46,56 ****
XX  
XX    register struct inode *rip;
XX    register struct filp *f;
XX!   register off_t bytes_left, f_size;
XX!   register unsigned off, cum_io;
XX!   register int oflags;
XX!   off_t position;
XX!   int r, chunk, mode_word, usr, seg, block_spec, char_spec, regular;
XX    struct filp *wf;
XX  
XX    /* MM loads segments by putting funny things in upper 10 bits of 'fd'. */
XX--- 49,60 ----
XX  
XX    register struct inode *rip;
XX    register struct filp *f;
XX!   off_t bytes_left, f_size, position;
XX!   unsigned int off, cum_io;
XX!   int op, oflags, r, chunk, usr, seg, block_spec, char_spec;
XX!   int regular, partial_pipe = 0, partial_cnt = 0;
XX!   dev_t dev;
XX!   mode_t mode_word;
XX    struct filp *wf;
XX  
XX    /* MM loads segments by putting funny things in upper 10 bits of 'fd'. */
XX***************
XX*** 64,97 ****
XX    }
XX  
XX    /* If the file descriptor is valid, get the inode, size and mode. */
XX- #if (CHIP == INTEL)
XX-   if (who != MM_PROC_NR)	/* only MM > 32K */
XX- #endif
XX- 
XX    if (nbytes < 0) return(EINVAL);
XX    if ( (f = get_filp(fd)) == NIL_FILP) return(err_code);
XX    if ( ((f->filp_mode) & (rw_flag == READING ? R_BIT : W_BIT)) == 0)
XX  	return(EBADF);
XX    if (nbytes == 0) return(0);	/* so char special files need not check for 0*/
XX    position = f->filp_pos;
XX!   if (position < 0 || position > MAX_FILE_POS) return(EINVAL);
XX    oflags = f->filp_flags;
XX    rip = f->filp_ino;
XX    f_size = rip->i_size;
XX    r = OK;
XX!   cum_io = 0;
XX    mode_word = rip->i_mode & I_TYPE;
XX    regular = mode_word == I_REGULAR || mode_word == I_NAMED_PIPE;
XX  
XX    char_spec = (mode_word == I_CHAR_SPECIAL ? 1 : 0);
XX    block_spec = (mode_word == I_BLOCK_SPECIAL ? 1 : 0);
XX!   if (block_spec && f_size == 0) f_size = MAX_P_LONG;
XX    rdwt_err = OK;		/* set to EIO if disk error occurs */
XX  
XX    /* Check for character special files. */
XX    if (char_spec) {
XX! 	if ((r = dev_io(rw_flag, oflags & O_NONBLOCK, (dev_t) rip->i_zone[0],
XX! 				 position, nbytes, who, buffer)) >= 0) {
XX  		cum_io = r;
XX  		position += r;
XX  		r = OK;
XX--- 68,105 ----
XX    }
XX  
XX    /* If the file descriptor is valid, get the inode, size and mode. */
XX    if (nbytes < 0) return(EINVAL);
XX    if ( (f = get_filp(fd)) == NIL_FILP) return(err_code);
XX    if ( ((f->filp_mode) & (rw_flag == READING ? R_BIT : W_BIT)) == 0)
XX  	return(EBADF);
XX    if (nbytes == 0) return(0);	/* so char special files need not check for 0*/
XX    position = f->filp_pos;
XX!   if (position > MAX_FILE_POS) return(EINVAL);
XX!   if (position + nbytes < position) return(EINVAL); /* unsigned overflow */
XX    oflags = f->filp_flags;
XX    rip = f->filp_ino;
XX    f_size = rip->i_size;
XX    r = OK;
XX!   if (rip->i_pipe == I_PIPE) {
XX! 	/* fp->fp_cum_io_partial is only nonzero when doing partial writes */
XX! 	cum_io = fp->fp_cum_io_partial; 
XX!   } else {
XX! 	cum_io = 0;
XX!   }
XX!   op = (rw_flag == READING ? DEV_READ : DEV_WRITE);
XX    mode_word = rip->i_mode & I_TYPE;
XX    regular = mode_word == I_REGULAR || mode_word == I_NAMED_PIPE;
XX  
XX    char_spec = (mode_word == I_CHAR_SPECIAL ? 1 : 0);
XX    block_spec = (mode_word == I_BLOCK_SPECIAL ? 1 : 0);
XX!   if (block_spec && f_size == 0) f_size = LONG_MAX;
XX    rdwt_err = OK;		/* set to EIO if disk error occurs */
XX  
XX    /* Check for character special files. */
XX    if (char_spec) {
XX! 	dev = (dev_t) rip->i_zone[0];
XX! 	r = dev_io(op, oflags & O_NONBLOCK, dev, position, nbytes, who,buffer);
XX! 	if (r >= 0) {
XX  		cum_io = r;
XX  		position += r;
XX  		r = OK;
XX***************
XX*** 99,108 ****
XX    } else {
XX  	if (rw_flag == WRITING && block_spec == 0) {
XX  		/* Check in advance to see if file will grow too big. */
XX! 		if (position > get_super(rip->i_dev)->s_max_size - nbytes )
XX! 			return(EFBIG);
XX  
XX! 		/* check for O_APPEND flag */
XX  		if (oflags & O_APPEND) position = f_size;
XX  
XX  		/* Clear the zone containing present EOF if hole about
XX--- 107,115 ----
XX    } else {
XX  	if (rw_flag == WRITING && block_spec == 0) {
XX  		/* Check in advance to see if file will grow too big. */
XX! 		if (position > rip->i_sp->s_max_size - nbytes) return(EFBIG);
XX  
XX! 		/* Check for O_APPEND flag. */
XX  		if (oflags & O_APPEND) position = f_size;
XX  
XX  		/* Clear the zone containing present EOF if hole about
XX***************
XX*** 113,137 ****
XX  	}
XX  
XX  	/* Pipes are a little different.  Check. */
XX! 	if (rip->i_pipe &&
XX! 	    (r = pipe_check(rip, rw_flag, oflags, nbytes, position)) <= 0)
XX! 		return r;
XX  
XX  	/* Split the transfer into chunks that don't span two blocks. */
XX  	while (nbytes != 0) {
XX! 		off = position % BLOCK_SIZE;	/* offset within a block */
XX! 		chunk = MIN(nbytes, BLOCK_SIZE - off);
XX  		if (chunk < 0) chunk = BLOCK_SIZE - off;
XX  
XX  		if (rw_flag == READING || (block_spec && rw_flag == WRITING)) {
XX  			bytes_left = f_size - position;
XX  			if (position >= f_size) break;	/* we are beyond EOF */
XX! 			if (chunk > bytes_left) chunk = bytes_left;
XX  		}
XX  
XX  		/* Read or write 'chunk' bytes. */
XX! 		r = rw_chunk(rip, position, off, chunk, nbytes, rw_flag,
XX! 							     buffer, seg, usr);
XX  		if (r != OK) break;	/* EOF reached */
XX  		if (rdwt_err < 0) break;
XX  
XX--- 120,150 ----
XX  	}
XX  
XX  	/* Pipes are a little different.  Check. */
XX! 	if (rip->i_pipe == I_PIPE) {
XX! 	       r = pipe_check(rip,rw_flag,oflags,nbytes,position,&partial_cnt);
XX! 	       if (r <= 0) return(r);
XX! 	}
XX  
XX+ 	if (partial_cnt > 0) partial_pipe = 1;
XX+ 
XX  	/* Split the transfer into chunks that don't span two blocks. */
XX  	while (nbytes != 0) {
XX! 		off = (unsigned int) (position % BLOCK_SIZE);/* offset in blk*/
XX! 		if (partial_pipe) {  /* pipes only */
XX! 			chunk = MIN(partial_cnt, BLOCK_SIZE - off);
XX! 		} else
XX! 			chunk = MIN(nbytes, BLOCK_SIZE - off);
XX  		if (chunk < 0) chunk = BLOCK_SIZE - off;
XX  
XX  		if (rw_flag == READING || (block_spec && rw_flag == WRITING)) {
XX  			bytes_left = f_size - position;
XX  			if (position >= f_size) break;	/* we are beyond EOF */
XX! 			if (chunk > bytes_left) chunk = (int) bytes_left;
XX  		}
XX  
XX  		/* Read or write 'chunk' bytes. */
XX! 		r = rw_chunk(rip, position, off, chunk, (unsigned) nbytes,
XX! 			     rw_flag, buffer, seg, usr);
XX  		if (r != OK) break;	/* EOF reached */
XX  		if (rdwt_err < 0) break;
XX  
XX***************
XX*** 140,157 ****
XX  		nbytes -= chunk;	/* bytes yet to be read */
XX  		cum_io += chunk;	/* bytes read so far */
XX  		position += chunk;	/* position within the file */
XX  	}
XX    }
XX  
XX    /* On write, update file size and access time. */
XX    if (rw_flag == WRITING) {
XX  	if (regular || mode_word == I_DIRECTORY) {
XX  		if (position > f_size) rip->i_size = position;
XX- 		rip->i_update = MTIME; /* mark mtime for update later */
XX- 		rip->i_dirt = DIRTY;
XX  	}
XX    } else {
XX! 	if (rip->i_pipe && position >= rip->i_size) {
XX  		/* Reset pipe pointers. */
XX  		rip->i_size = 0;	/* no data left */
XX  		position = 0;		/* reset reader(s) */
XX--- 153,183 ----
XX  		nbytes -= chunk;	/* bytes yet to be read */
XX  		cum_io += chunk;	/* bytes read so far */
XX  		position += chunk;	/* position within the file */
XX+ 
XX+ 		if (partial_pipe) {
XX+ 			partial_cnt -= chunk;
XX+ 			if (partial_cnt <= 0)  break;
XX+ 		}
XX  	}
XX    }
XX  
XX    /* On write, update file size and access time. */
XX+   /* DEBUG FIXME.  Don't we have to set i_dirty after changing i_size?
XX+    * Probably write_map will already have changed it for the WRITING case
XX+    * and it doesn't matter for the case of reading from pipes.  However,
XX+    * it would be cleaner to set it for all cases at the start of this
XX+    * routine, and not in write_map, etc., now that the inode is almost
XX+    * always dirtied by changing some of its times.
XX+    *
XX+    * Does POSIX really say not to change i_ctime after an unsuccesful write?
XX+    * It is possible for part of a failed write to work and change i_size.
XX+    */
XX    if (rw_flag == WRITING) {
XX  	if (regular || mode_word == I_DIRECTORY) {
XX  		if (position > f_size) rip->i_size = position;
XX  	}
XX    } else {
XX! 	if (rip->i_pipe == I_PIPE && position >= rip->i_size) {
XX  		/* Reset pipe pointers. */
XX  		rip->i_size = 0;	/* no data left */
XX  		position = 0;		/* reset reader(s) */
XX***************
XX*** 169,176 ****
XX    rip->i_seek = NO_SEEK;
XX  
XX    if (rdwt_err != OK) r = rdwt_err;	/* check for disk error */
XX!   if (rdwt_err == END_OF_FILE) r = cum_io;
XX!   return(r == OK ? cum_io : r);
XX  }
XX  
XX  
XX--- 195,220 ----
XX    rip->i_seek = NO_SEEK;
XX  
XX    if (rdwt_err != OK) r = rdwt_err;	/* check for disk error */
XX!   if (rdwt_err == END_OF_FILE) r = OK;
XX!   if (r == OK) {
XX! 	if (rw_flag == READING) rip->i_update |= ATIME;
XX! 	if (rw_flag == WRITING) rip->i_update |= CTIME | MTIME;
XX! 	rip->i_dirt = DIRTY;		/* inode is thus now dirty */
XX! 	if (partial_pipe) {
XX! 		partial_pipe = 0;
XX! 			/* partial write on pipe with */
XX! 			/* O_NOBLOCK, return write count */
XX! 		if (!(oflags & O_NONBLOCK)) {
XX! 			fp->fp_cum_io_partial += cum_io;
XX! 			suspend(XPIPE); /* partial write on pipe with */
XX! 			return(0);	/* nbyte > PIPE_SIZE - non-atomic */
XX! 		}
XX! 	}
XX! 	fp->fp_cum_io_partial = 0;
XX! 	return(cum_io);
XX!   } else {
XX! 	return(r);
XX!   }
XX  }
XX  
XX  
XX***************
XX*** 193,199 ****
XX    register struct buf *bp;
XX    register int r;
XX    int dir, n, block_spec;
XX!   block_nr b;
XX    dev_t dev;
XX  
XX    block_spec = (rip->i_mode & I_TYPE) == I_BLOCK_SPECIAL;
XX--- 237,244 ----
XX    register struct buf *bp;
XX    register int r;
XX    int dir, n, block_spec;
XX!   vir_bytes vbuff, vchunk;
XX!   block_t b;
XX    dev_t dev;
XX  
XX    block_spec = (rip->i_mode & I_TYPE) == I_BLOCK_SPECIAL;
XX***************
XX*** 207,218 ****
XX  
XX    if (!block_spec && b == NO_BLOCK) {
XX  	if (rw_flag == READING) {
XX! 		/* Reading from a nonexistent block.  Must read as all zeros. */
XX! 		bp = get_block(NO_DEV, NO_BLOCK, NORMAL);     /* get a buffer */
XX  		zero_block(bp);
XX  	} else {
XX! 		/* Writing to a nonexistent block. Create and enter in inode. */
XX! 		if ((bp = new_block(rip, position)) == NIL_BUF)return(err_code);
XX  	}
XX    } else if (rw_flag == READING) {
XX  	/* Read and read ahead if convenient. */
XX--- 252,263 ----
XX  
XX    if (!block_spec && b == NO_BLOCK) {
XX  	if (rw_flag == READING) {
XX! 		/* Reading from a nonexistent block.  Must read as all zeros.*/
XX! 		bp = get_block(NO_DEV, NO_BLOCK, NORMAL);    /* get a buffer */
XX  		zero_block(bp);
XX  	} else {
XX! 		/* Writing to a nonexistent block. Create and enter in inode.*/
XX! 		if ((bp= new_block(rip, position)) == NIL_BUF)return(err_code);
XX  	}
XX    } else if (rw_flag == READING) {
XX  	/* Read and read ahead if convenient. */
XX***************
XX*** 232,238 ****
XX  					position >= rip->i_size && off == 0)
XX  	zero_block(bp);
XX    dir = (rw_flag == READING ? TO_USER : FROM_USER);
XX!   r = rw_user(seg, usr, (vir_bytes)buff, (vir_bytes)chunk, bp->b_data+off, dir);
XX    if (rw_flag == WRITING) bp->b_dirt = DIRTY;
XX    n = (off + chunk == BLOCK_SIZE ? FULL_DATA_BLOCK : PARTIAL_DATA_BLOCK);
XX    put_block(bp, n);
XX--- 277,285 ----
XX  					position >= rip->i_size && off == 0)
XX  	zero_block(bp);
XX    dir = (rw_flag == READING ? TO_USER : FROM_USER);
XX!   vbuff = (vir_bytes) buff;
XX!   vchunk = (vir_bytes) chunk;
XX!   r = rw_user(seg, usr, vbuff, vchunk, bp->b_data+off,dir);
XX    if (rw_flag == WRITING) bp->b_dirt = DIRTY;
XX    n = (off + chunk == BLOCK_SIZE ? FULL_DATA_BLOCK : PARTIAL_DATA_BLOCK);
XX    put_block(bp, n);
XX***************
XX*** 243,249 ****
XX  /*===========================================================================*
XX   *				read_map				     *
XX   *===========================================================================*/
XX! PUBLIC block_nr read_map(rip, position)
XX  register struct inode *rip;	/* ptr to inode to map from */
XX  off_t position;			/* position in file whose blk wanted */
XX  {
XX--- 290,296 ----
XX  /*===========================================================================*
XX   *				read_map				     *
XX   *===========================================================================*/
XX! PUBLIC block_t read_map(rip, position)
XX  register struct inode *rip;	/* ptr to inode to map from */
XX  off_t position;			/* position in file whose blk wanted */
XX  {
XX***************
XX*** 252,304 ****
XX   */
XX  
XX    register struct buf *bp;
XX!   register zone_nr z;
XX!   register block_nr b;
XX!   register long excess, zone, block_pos;
XX!   register int scale, boff;
XX! 
XX!   scale = scale_factor(rip);	/* for block-zone conversion */
XX    block_pos = position/BLOCK_SIZE;	/* relative blk # in file */
XX    zone = block_pos >> scale;	/* position's zone */
XX!   boff = block_pos - (zone << scale);	/* relative blk # within zone */
XX  
XX    /* Is 'position' to be found in the inode itself? */
XX!   if (zone < NR_DZONE_NUM) {
XX! 	if ( (z = rip->i_zone[(int) zone]) == NO_ZONE) return(NO_BLOCK);
XX! 	b = ((block_nr) z << scale) + boff;
XX  	return(b);
XX    }
XX  
XX    /* It is not in the inode, so it must be single or double indirect. */
XX!   excess = zone - NR_DZONE_NUM;	/* first NR_DZONE_NUM don't count */
XX  
XX!   if (excess < NR_INDIRECTS) {
XX  	/* 'position' can be located via the single indirect block. */
XX! 	z = rip->i_zone[NR_DZONE_NUM];
XX    } else {
XX  	/* 'position' can be located via the double indirect block. */
XX! 	if ( (z = rip->i_zone[NR_DZONE_NUM+1]) == NO_ZONE) return(NO_BLOCK);
XX! 	excess -= NR_INDIRECTS;			/* single indir doesn't count */
XX! 	b = (block_nr) z << scale;
XX  	bp = get_block(rip->i_dev, b, NORMAL);	/* get double indirect block */
XX! 	z = bp->b_ind[(int)(excess/NR_INDIRECTS)];/*z is zone # for single ind*/
XX  	put_block(bp, INDIRECT_BLOCK);		/* release double ind block */
XX! 	excess = excess % NR_INDIRECTS;		/* index into single ind blk */
XX    }
XX  
XX    /* 'z' is zone num for single indirect block; 'excess' is index into it. */
XX    if (z == NO_ZONE) return(NO_BLOCK);
XX!   b = (block_nr) z << scale;
XX    bp = get_block(rip->i_dev, b, NORMAL);	/* get single indirect block */
XX!   z = bp->b_ind[(int) excess];
XX    put_block(bp, INDIRECT_BLOCK);		/* release single indir blk */
XX    if (z == NO_ZONE) return(NO_BLOCK);
XX!   b = ((block_nr) z << scale) + boff;
XX    return(b);
XX  }
XX  
XX  
XX  /*===========================================================================*
XX   *				rw_user					     *
XX   *===========================================================================*/
XX  PUBLIC int rw_user(s, u, vir, bytes, buff, direction)
XX--- 299,390 ----
XX   */
XX  
XX    register struct buf *bp;
XX!   register zone_t z;
XX!   int scale, boff, dzones, nr_indirects, index, zind, ex;
XX!   block_t b;
XX!   long excess, zone, block_pos;
XX!   
XX!   scale = rip->i_sp->s_log_zone_size;	/* for block-zone conversion */
XX    block_pos = position/BLOCK_SIZE;	/* relative blk # in file */
XX    zone = block_pos >> scale;	/* position's zone */
XX!   boff = (int) (block_pos - (zone << scale) ); /* relative blk # within zone */
XX!   dzones = rip->i_ndzones;
XX!   nr_indirects = rip->i_nindirs;
XX  
XX    /* Is 'position' to be found in the inode itself? */
XX!   if (zone < dzones) {
XX! 	zind = (int) zone;	/* index should be an int */
XX! 	z = rip->i_zone[zind];
XX! 	if (z == NO_ZONE) return(NO_BLOCK);
XX! 	b = ((block_t) z << scale) + boff;
XX  	return(b);
XX    }
XX  
XX    /* It is not in the inode, so it must be single or double indirect. */
XX!   excess = zone - dzones;	/* first Vx_NR_DZONES don't count */
XX  
XX!   if (excess < nr_indirects) {
XX  	/* 'position' can be located via the single indirect block. */
XX! 	z = rip->i_zone[dzones];
XX    } else {
XX  	/* 'position' can be located via the double indirect block. */
XX! 	if ( (z = rip->i_zone[dzones+1]) == NO_ZONE) return(NO_BLOCK);
XX! 	excess -= nr_indirects;			/* single indir doesn't count*/
XX! 	b = (block_t) z << scale;
XX  	bp = get_block(rip->i_dev, b, NORMAL);	/* get double indirect block */
XX! 	index = (int) (excess/nr_indirects);
XX! 	z = rd_indir(bp, index);		/* z= zone for single*/
XX  	put_block(bp, INDIRECT_BLOCK);		/* release double ind block */
XX! 	excess = excess % nr_indirects;		/* index into single ind blk */
XX    }
XX  
XX    /* 'z' is zone num for single indirect block; 'excess' is index into it. */
XX    if (z == NO_ZONE) return(NO_BLOCK);
XX!   b = (block_t) z << scale;			/* b is blk # for single ind */
XX    bp = get_block(rip->i_dev, b, NORMAL);	/* get single indirect block */
XX!   ex = (int) excess;				/* need an integer */
XX!   z = rd_indir(bp, ex);				/* get block pointed to */
XX    put_block(bp, INDIRECT_BLOCK);		/* release single indir blk */
XX    if (z == NO_ZONE) return(NO_BLOCK);
XX!   b = ((block_t) z << scale) + boff;
XX    return(b);
XX  }
XX  
XX  
XX  /*===========================================================================*
XX+  *				rd_indir				     *
XX+  *===========================================================================*/
XX+ PUBLIC zone_t rd_indir(bp, index)
XX+ struct buf *bp;			/* pointer to indirect block */
XX+ int index;			/* index into *bp */
XX+ {
XX+ /* Given a pointer to an indirect block, read one entry.  The reason for
XX+  * making a separate routine out of this is that there are four cases:
XX+  * V1 (IBM and 68000), and V2 (IBM and 68000).
XX+  */
XX+ 
XX+   struct super_block *sp;
XX+   zone_t zone;			/* V2 zones are longs (shorts in V1) */
XX+ 
XX+   sp = get_super(bp->b_dev);	/* need super block to find file sys type */
XX+ 
XX+   /* read a zone from an indirect block */
XX+   if (sp->s_version == V1)
XX+ 	zone = (zone_t) conv2(sp->s_native, (int)  bp->b_v1_ind[index]);
XX+   else
XX+ 	zone = (zone_t) conv4(sp->s_native, (long) bp->b_v2_ind[index]);
XX+ 
XX+   if (zone != NO_ZONE &&
XX+ 		(zone < (zone_t) sp->s_firstdatazone || zone >= sp->s_zones)) {
XX+ 	printf("Illegal zone number %ld in indirect block, index %d\n",
XX+ 	       (long) zone, index);
XX+ 	panic("check file system", NO_NUM);
XX+   }
XX+   return(zone);
XX+ }
XX+ 
XX+ 
XX+ /*===========================================================================*
XX   *				rw_user					     *
XX   *===========================================================================*/
XX  PUBLIC int rw_user(s, u, vir, bytes, buff, direction)
XX***************
XX*** 318,324 ****
XX  	/* Write from FS space to user space. */
XX  	umess.SRC_SPACE  = D;
XX  	umess.SRC_PROC_NR = FS_PROC_NR;
XX! 	umess.SRC_BUFFER = (long) buff;
XX  	umess.DST_SPACE  = s;
XX  	umess.DST_PROC_NR = u;
XX  	umess.DST_BUFFER = (long) vir;
XX--- 404,410 ----
XX  	/* Write from FS space to user space. */
XX  	umess.SRC_SPACE  = D;
XX  	umess.SRC_PROC_NR = FS_PROC_NR;
XX! 	umess.SRC_BUFFER = (long) (vir_bytes) buff;
XX  	umess.DST_SPACE  = s;
XX  	umess.DST_PROC_NR = u;
XX  	umess.DST_BUFFER = (long) vir;
XX***************
XX*** 329,335 ****
XX  	umess.SRC_BUFFER = (long) vir;
XX  	umess.DST_SPACE  = D;
XX  	umess.DST_PROC_NR = FS_PROC_NR;
XX! 	umess.DST_BUFFER = (long) buff;
XX    }
XX  
XX    umess.COPY_BYTES = (long) bytes;
XX--- 415,421 ----
XX  	umess.SRC_BUFFER = (long) vir;
XX  	umess.DST_SPACE  = D;
XX  	umess.DST_PROC_NR = FS_PROC_NR;
XX! 	umess.DST_BUFFER = (long) (vir_bytes) buff;
XX    }
XX  
XX    umess.COPY_BYTES = (long) bytes;
XX***************
XX*** 347,353 ****
XX  
XX    register struct inode *rip;
XX    struct buf *bp;
XX!   block_nr b;
XX  
XX    rip = rdahed_inode;		/* pointer to inode to read ahead from */
XX    rdahed_inode = NIL_INODE;	/* turn off read ahead */
XX--- 433,439 ----
XX  
XX    register struct inode *rip;
XX    struct buf *bp;
XX!   block_t b;
XX  
XX    rip = rdahed_inode;		/* pointer to inode to read ahead from */
XX    rdahed_inode = NIL_INODE;	/* turn off read ahead */
XX***************
XX*** 362,368 ****
XX   *===========================================================================*/
XX  PUBLIC struct buf *rahead(rip, baseblock, position, bytes_ahead)
XX  register struct inode *rip;	/* pointer to inode for file to be read */
XX! block_nr baseblock;		/* block at current position */
XX  off_t position;			/* position within file */
XX  unsigned bytes_ahead;		/* bytes beyond position for immediate use */
XX  {
XX--- 448,454 ----
XX   *===========================================================================*/
XX  PUBLIC struct buf *rahead(rip, baseblock, position, bytes_ahead)
XX  register struct inode *rip;	/* pointer to inode for file to be read */
XX! block_t baseblock;		/* block at current position */
XX  off_t position;			/* position within file */
XX  unsigned bytes_ahead;		/* bytes beyond position for immediate use */
XX  {
XX***************
XX*** 374,394 ****
XX   * Rw_scattered() puts an optional flag on all reads to allow this.
XX   */
XX  
XX!   block_nr block;
XX!   unsigned blocks_ahead;
XX!   unsigned blocks_per_track;
XX!   register struct buf *bp;
XX!   int block_spec;
XX    dev_t dev;
XX!   off_t dev_size;
XX!   off_t file_size;
XX!   unsigned fragment;
XX!   unsigned limit_bufs_in_use;
XX!   unsigned max_track;
XX!   int reading_ahead;
XX    static struct buf *read_q[NR_BUFS];	/* static so it isn't on stack */
XX-   int read_q_size;
XX-   unsigned track;
XX  
XX    block_spec = (rip->i_mode & I_TYPE) == I_BLOCK_SPECIAL;
XX    if (block_spec)
XX--- 460,473 ----
XX   * Rw_scattered() puts an optional flag on all reads to allow this.
XX   */
XX  
XX!   int block_spec, reading_ahead, read_q_size;
XX!   unsigned int blocks_ahead, blocks_per_track;
XX!   unsigned int fragment, limit_bufs_in_use, track, max_track;
XX!   block_t block;
XX    dev_t dev;
XX!   off_t dev_size, file_size;
XX!   register struct buf *bp;
XX    static struct buf *read_q[NR_BUFS];	/* static so it isn't on stack */
XX  
XX    block_spec = (rip->i_mode & I_TYPE) == I_BLOCK_SPECIAL;
XX    if (block_spec)
XX***************
XX*** 419,425 ****
XX  	blocks_per_track = 18;	/* higher-density floppy */
XX  
XX    file_size = rip->i_size;
XX!   if (block_spec && file_size == 0) file_size = MAX_P_LONG;
XX    fragment = (unsigned) (position % BLOCK_SIZE);
XX    position = position - fragment + BLOCK_SIZE;
XX    blocks_ahead = (fragment + bytes_ahead + BLOCK_SIZE - 1) / BLOCK_SIZE - 1;
XX--- 498,504 ----
XX  	blocks_per_track = 18;	/* higher-density floppy */
XX  
XX    file_size = rip->i_size;
XX!   if (block_spec && file_size == 0) file_size = LONG_MAX;
XX    fragment = (unsigned) (position % BLOCK_SIZE);
XX    position = position - fragment + BLOCK_SIZE;
XX    blocks_ahead = (fragment + bytes_ahead + BLOCK_SIZE - 1) / BLOCK_SIZE - 1;
XX***************
XX*** 433,439 ****
XX     */
XX    limit_bufs_in_use = block_spec ? NR_BUFS : NR_BUFS - 2;
XX  
XX!   max_track = bp->b_blocknr / blocks_per_track;
XX    reading_ahead = FALSE;
XX    read_q[0] = bp;		/* first buffer must be read */
XX    read_q_size = 1;
XX--- 512,518 ----
XX     */
XX    limit_bufs_in_use = block_spec ? NR_BUFS : NR_BUFS - 2;
XX  
XX!   max_track = (unsigned) (bp->b_blocknr / blocks_per_track);
XX    reading_ahead = FALSE;
XX    read_q[0] = bp;		/* first buffer must be read */
XX    read_q_size = 1;
XX***************
XX*** 462,468 ****
XX  	else
XX  		block = read_map(rip, position);
XX  	position += BLOCK_SIZE;
XX! 	track = block / blocks_per_track;
XX  	if (reading_ahead) {
XX  		if (track != max_track) continue;
XX  	} else {
XX--- 541,547 ----
XX  	else
XX  		block = read_map(rip, position);
XX  	position += BLOCK_SIZE;
XX! 	track = (unsigned) (block / blocks_per_track);
XX  	if (reading_ahead) {
XX  		if (track != max_track) continue;
XX  	} else {
X/
Xecho x - stadir.c.d
Xsed '/^X/s///' > stadir.c.d << '/'
XX*** /home/top/ast/minix/1.5/fs/stadir.c  crc=14136   5343	Sat Apr 21 22:26:20 1990
XX--- /home/top/ast/minix/1.6.25/fs/stadir.c  crc=15890   6113	Sun Dec 20 17:24:32 1992
XX***************
XX*** 15,22 ****
XX  #include "inode.h"
XX  #include "param.h"
XX  
XX! FORWARD int change();
XX! FORWARD int stat_inode();
XX  
XX  /*===========================================================================*
XX   *				do_chdir				     *
XX--- 15,23 ----
XX  #include "inode.h"
XX  #include "param.h"
XX  
XX! FORWARD _PROTOTYPE( int change, (struct inode **iip, char *name_ptr, int len));
XX! FORWARD _PROTOTYPE( int stat_inode, (struct inode *rip, struct filp *fil_ptr,
XX! 			char *user_addr)				);
XX  
XX  /*===========================================================================*
XX   *				do_chdir				     *
XX***************
XX*** 24,45 ****
XX  PUBLIC int do_chdir()
XX  {
XX  /* Change directory.  This function is  also called by MM to simulate a chdir
XX!  * in order to do EXEC, etc.
XX   */
XX  
XX    register struct fproc *rfp;
XX  
XX    if (who == MM_PROC_NR) {
XX  	rfp = &fproc[slot1];
XX  	put_inode(fp->fp_workdir);
XX! 	fp->fp_workdir = (cd_flag ? fp->fp_rootdir : rfp->fp_workdir);
XX! 	dup_inode(fp->fp_workdir);
XX! 	fp->fp_effuid = (cd_flag ? SUPER_USER : rfp->fp_effuid);
XX  	return(OK);
XX    }
XX  
XX! /* Perform the chdir(name) system call. */
XX!   return change(&fp->fp_workdir, name, name_length);
XX  }
XX  
XX  
XX--- 25,61 ----
XX  PUBLIC int do_chdir()
XX  {
XX  /* Change directory.  This function is  also called by MM to simulate a chdir
XX!  * in order to do EXEC, etc.  It also changes the root directory, the uids and
XX!  * gids, and the umask.  The name of this function is now misleading and the
XX!  * cd_flag argument is no longer supported.
XX   */
XX  
XX+   int r;
XX    register struct fproc *rfp;
XX  
XX    if (who == MM_PROC_NR) {
XX  	rfp = &fproc[slot1];
XX+ 	put_inode(fp->fp_rootdir);
XX+ 	dup_inode(fp->fp_rootdir = rfp->fp_rootdir);
XX  	put_inode(fp->fp_workdir);
XX! 	dup_inode(fp->fp_workdir = rfp->fp_workdir);
XX! 
XX! 	/* MM uses access() to check permissions.  To make this work, pretend
XX! 	 * that the user's real ids are the same as the user's effective ids.
XX! 	 * FS calls other than access() do not use the real ids, so are not
XX! 	 * affected.
XX! 	 */
XX! 	fp->fp_realuid =
XX! 	fp->fp_effuid = rfp->fp_effuid;
XX! 	fp->fp_realgid =
XX! 	fp->fp_effgid = rfp->fp_effgid;
XX! 	fp->fp_umask = rfp->fp_umask;
XX  	return(OK);
XX    }
XX  
XX!   /* Perform the chdir(name) system call. */
XX!   r = change(&fp->fp_workdir, name, name_length);
XX!   return(r);
XX  }
XX  
XX  
XX***************
XX*** 137,168 ****
XX  PRIVATE int stat_inode(rip, fil_ptr, user_addr)
XX  register struct inode *rip;	/* pointer to inode to stat */
XX  struct filp *fil_ptr;		/* filp pointer, supplied by 'fstat' */
XX! char *user_addr;			/* user space address where stat buf goes */
XX  {
XX  /* Common code for stat and fstat system calls. */
XX  
XX    register struct stat *stp;
XX    struct stat statbuf;
XX!   int r;
XX    vir_bytes v;
XX  
XX    /* Update the atime, ctime, and mtime fields in the inode, if need be. */
XX    if (rip->i_update) update_times(rip);
XX  
XX    /* Fill in the statbuf struct. */
XX    stp = &statbuf;		/* set up pointer to the buffer */
XX!   stp->st_dev = (int) rip->i_dev;
XX    stp->st_ino = rip->i_num;
XX    stp->st_mode = rip->i_mode;
XX    stp->st_nlink = rip->i_nlinks & BYTE;
XX    stp->st_uid = rip->i_uid;
XX    stp->st_gid = rip->i_gid & BYTE;
XX!   stp->st_rdev = rip->i_zone[0];
XX    stp->st_size = rip->i_size;
XX!   if (	(rip->i_pipe == I_PIPE) &&	/* IF it is a pipe */
XX! 	(fil_ptr != NIL_FILP) &&	/* AND it was fstat */
XX! 	(fil_ptr->filp_mode == R_BIT))	/* on the reading end, */
XX! 	stp->st_size -= fil_ptr->filp_pos; /* adjust the visible size. */
XX    stp->st_atime = rip->i_atime;
XX    stp->st_mtime = rip->i_mtime;
XX    stp->st_ctime = rip->i_ctime;
XX--- 153,190 ----
XX  PRIVATE int stat_inode(rip, fil_ptr, user_addr)
XX  register struct inode *rip;	/* pointer to inode to stat */
XX  struct filp *fil_ptr;		/* filp pointer, supplied by 'fstat' */
XX! char *user_addr;		/* user space address where stat buf goes */
XX  {
XX  /* Common code for stat and fstat system calls. */
XX  
XX    register struct stat *stp;
XX    struct stat statbuf;
XX!   mode_t mo;
XX!   int r, s;
XX    vir_bytes v;
XX  
XX    /* Update the atime, ctime, and mtime fields in the inode, if need be. */
XX    if (rip->i_update) update_times(rip);
XX  
XX    /* Fill in the statbuf struct. */
XX+   mo = rip->i_mode & I_TYPE;
XX+   s = (mo == I_CHAR_SPECIAL || mo == I_BLOCK_SPECIAL);	/* true iff special */
XX    stp = &statbuf;		/* set up pointer to the buffer */
XX!   stp->st_dev = rip->i_dev;
XX    stp->st_ino = rip->i_num;
XX    stp->st_mode = rip->i_mode;
XX    stp->st_nlink = rip->i_nlinks & BYTE;
XX    stp->st_uid = rip->i_uid;
XX    stp->st_gid = rip->i_gid & BYTE;
XX!   stp->st_rdev = (dev_t) (s ? rip->i_zone[0] : NO_DEV);
XX    stp->st_size = rip->i_size;
XX! 
XX!   if (rip->i_pipe == I_PIPE) {
XX! 	stp->st_mode &= ~I_REGULAR;	/* wipe out I_REGULAR bit for pipes */
XX! 	if (fil_ptr != NIL_FILP && fil_ptr->filp_mode & R_BIT) 
XX! 		stp->st_size -= fil_ptr->filp_pos;
XX!   }
XX! 
XX    stp->st_atime = rip->i_atime;
XX    stp->st_mtime = rip->i_mtime;
XX    stp->st_ctime = rip->i_ctime;
X/
Xecho x - super.c.d
Xsed '/^X/s///' > super.c.d << '/'
XX*** /home/top/ast/minix/1.5/fs/super.c  crc=36226   8651	Sat Apr 21 22:26:20 1990
XX--- /home/top/ast/minix/1.6.25/fs/super.c  crc=09735  11337	Sun Nov 15 23:17:00 1992
XX***************
XX*** 10,27 ****
XX   *   free_bit:        indicate that a zone or inode is available for allocation
XX   *   get_super:       search the 'superblock' table for a device
XX   *   mounted:         tells if file inode is on mounted (or ROOT) file system
XX!  *   scale_factor:    get the zone-to-block conversion factor for a device
XX!  *   rw_super:        read or write a superblock
XX   */
XX  
XX  #include "fs.h"
XX  #include <minix/boot.h>
XX  #include "buf.h"
XX  #include "inode.h"
XX  #include "super.h"
XX  
XX! #define INT_BITS (sizeof(int)<<3)
XX! #define BIT_MAP_SHIFT     13	/* (log2 of BLOCK_SIZE) + 3; 13 for 1k blocks */
XX  
XX  /*===========================================================================*
XX   *				load_bit_maps				     *
XX--- 10,27 ----
XX   *   free_bit:        indicate that a zone or inode is available for allocation
XX   *   get_super:       search the 'superblock' table for a device
XX   *   mounted:         tells if file inode is on mounted (or ROOT) file system
XX!  *   read_super:      read a superblock
XX   */
XX  
XX  #include "fs.h"
XX+ #include <string.h>
XX  #include <minix/boot.h>
XX  #include "buf.h"
XX  #include "inode.h"
XX  #include "super.h"
XX  
XX! #define BITCHUNK_BITS (usizeof(bitchunk_t) * CHAR_BIT)
XX! #define BIT_MAP_SHIFT     13	/* (log2 of BLOCK_SIZE) + 3; 13 for 1k blocks*/
XX  
XX  /*===========================================================================*
XX   *				load_bit_maps				     *
XX***************
XX*** 33,45 ****
XX  
XX    register int i;
XX    register struct super_block *sp;
XX!   block_nr zbase;
XX  
XX    sp = get_super(dev);		/* get the superblock pointer */
XX    if (bufs_in_use + sp->s_imap_blocks + sp->s_zmap_blocks >= NR_BUFS - 3)
XX  	return(ERROR);		/* insufficient buffers left for bit maps */
XX!   if (sp->s_imap_blocks > I_MAP_SLOTS || sp->s_zmap_blocks > ZMAP_SLOTS)
XX! 	panic("too many map blocks", NO_NUM);
XX  
XX    /* Load the inode map from the disk. */
XX    for (i = 0; i < sp->s_imap_blocks; i++)
XX--- 33,45 ----
XX  
XX    register int i;
XX    register struct super_block *sp;
XX!   block_t zbase;
XX  
XX    sp = get_super(dev);		/* get the superblock pointer */
XX    if (bufs_in_use + sp->s_imap_blocks + sp->s_zmap_blocks >= NR_BUFS - 3)
XX  	return(ERROR);		/* insufficient buffers left for bit maps */
XX!   if (sp->s_imap_blocks > I_MAP_SLOTS || sp->s_zmap_blocks > Z_MAP_SLOTS)
XX! 	return(ERROR);
XX  
XX    /* Load the inode map from the disk. */
XX    for (i = 0; i < sp->s_imap_blocks; i++)
XX***************
XX*** 50,58 ****
XX    for (i = 0; i < sp->s_zmap_blocks; i++)
XX  	sp->s_zmap[i] = get_block(dev, zbase + i, NORMAL);
XX  
XX!   /* inodes 0 and 1, and zone 0 are never allocated.  Mark them as busy. */
XX!   sp->s_imap[0]->b_int[0] |= 3;	/* inodes 0, 1 busy */
XX!   sp->s_zmap[0]->b_int[0] |= 1;	/* zone 0 busy */
XX    return(OK);
XX  }
XX  
XX--- 50,58 ----
XX    for (i = 0; i < sp->s_zmap_blocks; i++)
XX  	sp->s_zmap[i] = get_block(dev, zbase + i, NORMAL);
XX  
XX!   /* Inodes 0 and 1, and zone 0 are never allocated.  Mark them as busy. */
XX!   sp->s_imap[0]->b_bitmap[0] |= conv2(sp->s_native, 3); /* inodes 0, 1 busy */
XX!   sp->s_zmap[0]->b_bitmap[0] |= conv2(sp->s_native, 1); /* zone 0 busy */
XX    return(OK);
XX  }
XX  
XX***************
XX*** 68,78 ****
XX  
XX    register int i;
XX    register struct super_block *sp;
XX-   struct super_block *get_super();
XX  
XX    sp = get_super(dev);		/* get the superblock pointer */
XX!   for (i = 0; i < sp->s_imap_blocks; i++) put_block(sp->s_imap[i], I_MAP_BLOCK);
XX!   for (i = 0; i < sp->s_zmap_blocks; i++) put_block(sp->s_zmap[i], ZMAP_BLOCK);
XX    return(OK);
XX  }
XX  
XX--- 68,82 ----
XX  
XX    register int i;
XX    register struct super_block *sp;
XX  
XX    sp = get_super(dev);		/* get the superblock pointer */
XX! 
XX!   for (i = 0; i < sp->s_imap_blocks; i++)
XX! 	put_block(sp->s_imap[i],I_MAP_BLOCK);
XX! 
XX!   for (i = 0; i < sp->s_zmap_blocks; i++)
XX! 	put_block(sp->s_zmap[i], ZMAP_BLOCK);
XX! 
XX    return(OK);
XX  }
XX  
XX***************
XX*** 80,103 ****
XX  /*===========================================================================*
XX   *				alloc_bit				     *
XX   *===========================================================================*/
XX! PUBLIC bit_nr alloc_bit(map_ptr, map_bits, bit_blocks, origin)
XX  struct buf *map_ptr[];		/* pointer to array of bit block pointers */
XX! bit_nr map_bits;		/* how many bits are there in the bit map? */
XX! unshort bit_blocks;		/* how many blocks are there in the bit map? */
XX! bit_nr origin;			/* number of bit to start searching at */
XX  {
XX  /* Allocate a bit from a bit map and return its bit number. */
XX  
XX!   register unsigned k;
XX!   register int *wptr, *wlim;
XX!   int i, a, b, w, o, block_count;
XX    struct buf *bp;
XX  
XX    /* Figure out where to start the bit search (depends on 'origin'). */
XX!   if (origin >= map_bits) origin = 0;	/* for robustness */
XX!   b = origin >> BIT_MAP_SHIFT;
XX!   o = origin - (b << BIT_MAP_SHIFT);
XX!   w = o/INT_BITS;
XX    block_count = (w == 0 ? bit_blocks : bit_blocks + 1);
XX  
XX    /* The outer while loop iterates on the blocks of the map.  The inner
XX--- 84,123 ----
XX  /*===========================================================================*
XX   *				alloc_bit				     *
XX   *===========================================================================*/
XX! PUBLIC bit_t alloc_bit(map_ptr, map_bits, bit_blocks, origin)
XX  struct buf *map_ptr[];		/* pointer to array of bit block pointers */
XX! bit_t map_bits;			/* how many bits are there in the bit map? */
XX! int bit_blocks;			/* how many blocks are there in the bit map? */
XX! bit_t origin;			/* number of bit to start searching at */
XX  {
XX  /* Allocate a bit from a bit map and return its bit number. */
XX  
XX!   int i, o, w, w_off, b, count;
XX!   bit_t a;
XX!   register bitchunk_t *wptr, *wlim;
XX!   bitchunk_t k;
XX!   short block_count;
XX    struct buf *bp;
XX+   struct super_block *sp;
XX  
XX+   sp = get_super(map_ptr[0]->b_dev);	/* get the superblock pointer */
XX+   if (sp->s_rd_only) panic("can't allocate bit on read-only filesys.", NO_NUM);
XX+   
XX    /* Figure out where to start the bit search (depends on 'origin'). */
XX!   if (origin < 0 || origin >= map_bits) origin = 0;	/* for robustness */
XX! 
XX!   /* Truncation of the next expression from a bit_t to an int is safe because
XX!    * it it is inconceivable that the number of blocks in the bit map > 32K.
XX!    */  
XX!   b = (int) (origin >> BIT_MAP_SHIFT);	/* relevant bit map block. */
XX! 
XX!   /* Truncation of the next expression from a bit_t to an int is safe because
XX!    * its value is smaller than BITS_PER_BLOCK and easily fits in an int.
XX!    * The expression is better written as (int) origin % BITS_PER_BLOCK or
XX!    * even (int) origin & ~(BITS_PER_BLOCK - 1).
XX!    */  
XX!   o = (int) (origin - ((bit_t) b << BIT_MAP_SHIFT) );
XX!   w = o/BITCHUNK_BITS;
XX    block_count = (w == 0 ? bit_blocks : bit_blocks + 1);
XX  
XX    /* The outer while loop iterates on the blocks of the map.  The inner
XX***************
XX*** 107,133 ****
XX    while (block_count--) {
XX  	/* If need be, loop on all the blocks in the bit map. */
XX  	bp = map_ptr[b];
XX! 	wptr = &bp->b_int[w];
XX! 	wlim = &bp->b_int[INTS_PER_BLOCK];
XX! 	while (wptr != wlim) {
XX  		/* Loop on all the words of one of the bit map blocks. */
XX! 		if ((k = (unsigned) *wptr) != (unsigned) ~0) {
XX  			/* This word contains a free bit.  Allocate it. */
XX! 			for (i = 0; i < INT_BITS; i++)
XX  				if (((k >> i) & 1) == 0) {
XX! 					a = i + (int)(wptr - &bp->b_int[0])*INT_BITS
XX! 							+ (b << BIT_MAP_SHIFT);
XX  					/* If 'a' beyond map check other blks*/
XX  					if (a >= map_bits) {
XX  						wptr = wlim - 1;
XX  						break;
XX  					}
XX! 					*wptr |= 1 << i;
XX  					bp->b_dirt = DIRTY;
XX! 					return( (bit_nr) a);
XX  				}
XX  		}
XX! 		wptr++;		/* examine next word in this bit map block */
XX  	}
XX  	if (++b == bit_blocks) b = 0;	/* we have wrapped around */
XX  	w = 0;
XX--- 127,159 ----
XX    while (block_count--) {
XX  	/* If need be, loop on all the blocks in the bit map. */
XX  	bp = map_ptr[b];
XX! 	wptr = &bp->b_bitmap[w];
XX! 	wlim = &bp->b_bitmap[BITMAP_CHUNKS];
XX! 	count = 0;
XX! 	while (count < BITMAP_CHUNKS) {
XX  		/* Loop on all the words of one of the bit map blocks. */
XX! 		if (*wptr != 0xFFFF) {
XX  			/* This word contains a free bit.  Allocate it. */
XX! 			k = conv2(sp->s_native, (int) *wptr);
XX! 			for (i = 0; i < BITCHUNK_BITS; i++)
XX  				if (((k >> i) & 1) == 0) {
XX! 					w_off = (int)(wptr - &bp->b_bitmap[0]);
XX! 					w_off = w_off * BITCHUNK_BITS;
XX! 					a = i + w_off
XX! 					    + ((bit_t) b << BIT_MAP_SHIFT);
XX  					/* If 'a' beyond map check other blks*/
XX  					if (a >= map_bits) {
XX  						wptr = wlim - 1;
XX  						break;
XX  					}
XX! 					k |= 1 << i;
XX! 					*wptr = conv2(sp->s_native, (int) k);
XX  					bp->b_dirt = DIRTY;
XX! 					return(a);
XX  				}
XX  		}
XX! 		if (++wptr == wlim) wptr = &bp->b_bitmap[0];	/* wrap */
XX! 		count++;
XX  	}
XX  	if (++b == bit_blocks) b = 0;	/* we have wrapped around */
XX  	w = 0;
XX***************
XX*** 141,164 ****
XX   *===========================================================================*/
XX  PUBLIC void free_bit(map_ptr, bit_returned)
XX  struct buf *map_ptr[];		/* pointer to array of bit block pointers */
XX! bit_nr bit_returned;		/* number of bit to insert into the map */
XX  {
XX  /* Return a zone or inode by turning off its bitmap bit. */
XX  
XX    int b, r, w, bit;
XX    struct buf *bp;
XX  
XX!   b = bit_returned >> BIT_MAP_SHIFT;	/* 'b' tells which block it is in */
XX!   r = bit_returned - (b << BIT_MAP_SHIFT);
XX!   w = r/INT_BITS;		/* 'w' tells which word it is in */
XX!   bit = r % INT_BITS;
XX    bp = map_ptr[b];
XX    if (bp == NIL_BUF) return;
XX!   if (((bp->b_int[w] >> bit)& 1)== 0) {
XX! printf("FS freeing unused block of inode.  bit = %d\n",bit_returned); /*DEBUG*/
XX! /*  panic("freeing unused block or inode--check file sys",(int)bit_returned);*/
XX    }
XX!   bp->b_int[w] &= ~(1 << bit);	/* turn the bit off */
XX    bp->b_dirt = DIRTY;
XX  }
XX  
XX--- 167,201 ----
XX   *===========================================================================*/
XX  PUBLIC void free_bit(map_ptr, bit_returned)
XX  struct buf *map_ptr[];		/* pointer to array of bit block pointers */
XX! bit_t bit_returned;		/* number of bit to insert into the map */
XX  {
XX  /* Return a zone or inode by turning off its bitmap bit. */
XX  
XX    int b, r, w, bit;
XX    struct buf *bp;
XX+   bitchunk_t k;
XX+   struct super_block *sp;
XX  
XX!   sp = get_super(map_ptr[0]->b_dev);	/* get the superblock pointer */
XX!   if (sp->s_rd_only) panic("can't free bit on read-only file system", NO_NUM);
XX! 
XX!   /* The truncations in the next two assignments are valid by the same
XX!    * reasoning as in alloc_bit.
XX!    */
XX!   b = (int) (bit_returned >> BIT_MAP_SHIFT);	/* which block it is in */
XX!   r = (int) (bit_returned - ((bit_t) b << BIT_MAP_SHIFT) );
XX!   w = r/BITCHUNK_BITS;		/* 'w' tells which word it is in */
XX!   bit = r % BITCHUNK_BITS;
XX    bp = map_ptr[b];
XX    if (bp == NIL_BUF) return;
XX! 
XX!   k = conv2(sp->s_native, (int) bp->b_bitmap[w]);
XX!   if (((k >> bit) & 1) == 0) {
XX! 	printf("Cannot free bit %ld\n", bit_returned);
XX! 	panic("freeing unused block or inode--check file sys", NO_NUM);
XX    }
XX!   k &= ~(1 << bit);	/* turn the bit off */
XX!   bp->b_bitmap[w] = conv2(sp->s_native, (int) k);
XX    bp->b_dirt = DIRTY;
XX  }
XX  
XX***************
XX*** 178,183 ****
XX--- 215,222 ----
XX  
XX    /* Search failed.  Something wrong. */
XX    panic("can't find superblock for device (in decimal)", (int) dev);
XX+ 
XX+   return(NIL_SUPER);		/* to keep the compiler and lint quiet */
XX  }
XX  
XX  
XX***************
XX*** 203,246 ****
XX  
XX  
XX  /*===========================================================================*
XX!  *				scale_factor				     *
XX   *===========================================================================*/
XX! PUBLIC int scale_factor(ip)
XX! struct inode *ip;		/* pointer to inode whose superblock needed */
XX! {
XX! /* Return the scale factor used for converting blocks to zones. */
XX!   register struct super_block *sp;
XX! 
XX!   sp = get_super(ip->i_dev);
XX!   return(sp->s_log_zone_size);
XX! }
XX! 
XX! 
XX! /*===========================================================================*
XX!  *				rw_super				     *
XX!  *===========================================================================*/
XX! PUBLIC void rw_super(sp, rw_flag)
XX  register struct super_block *sp; /* pointer to a superblock */
XX! int rw_flag;			 /* READING or WRITING */
XX  {
XX! /* Read or write a superblock. */
XX  
XX    register struct buf *bp;
XX    dev_t dev;
XX  
XX!   /* Check if this is a read or write, and do it. */
XX!   if (rw_flag == READING) {
XX! 	dev = sp->s_dev;	/* save device; it will be overwritten by copy*/
XX! 	bp = get_block(sp->s_dev, SUPER_BLOCK, NORMAL);
XX! 	copy( (char *) sp, bp->b_data, SUPER_SIZE);
XX! 	sp->s_dev = dev;	/* restore device number */
XX    } else {
XX! 	/* On a write, it is not necessary to go read superblock from disk. */
XX! 	bp = get_block(sp->s_dev, SUPER_BLOCK, NO_READ);
XX! 	copy(bp->b_data, (char *) sp, SUPER_SIZE);
XX! 	bp->b_dirt = DIRTY;
XX    }
XX  
XX-   sp->s_dirt = CLEAN;
XX    put_block(bp, ZUPER_BLOCK);
XX  }
XX--- 242,312 ----
XX  
XX  
XX  /*===========================================================================*
XX!  *				read_super				     *
XX   *===========================================================================*/
XX! PUBLIC void read_super(sp, offset)
XX  register struct super_block *sp; /* pointer to a superblock */
XX! block_t offset;			 /* block number where superblock is */
XX  {
XX! /* Read a superblock. */
XX  
XX    register struct buf *bp;
XX    dev_t dev;
XX+   int magic;
XX+   int version = 0, native = 0;	/* unknown file systems are version zero */
XX  
XX!   dev = sp->s_dev;		/* save device (will be overwritten by copy) */
XX!   bp = get_block(sp->s_dev, SUPER_BLOCK + offset, NORMAL);
XX!   memcpy( (char *) sp, bp->b_data, (size_t) SUPER_SIZE);
XX!   sp->s_dev = dev;		/* restore device number */
XX!   magic = sp->s_magic;		/* determines file system type */
XX! 
XX!   /* Get file system version and type. */
XX!   if (magic == SUPER_MAGIC || magic == conv2(BYTE_SWAP, SUPER_MAGIC)) {
XX! 	version = V1;
XX! 	native  = (magic == SUPER_MAGIC);
XX!   } else if (magic == SUPER_V2 || magic == conv2(BYTE_SWAP, SUPER_V2)) {
XX! 	version = V2;
XX! 	native  = (magic == SUPER_V2);
XX!   }
XX! 
XX!   /* If the super block has the wrong byte order, swap the fields; the magic
XX!    * number doesn't need conversion. */
XX!   sp->s_ninodes =       conv2(native, (int) sp->s_ninodes);
XX!   sp->s_nzones =        conv2(native, (int) sp->s_nzones);
XX!   sp->s_imap_blocks =   conv2(native, (int) sp->s_imap_blocks);
XX!   sp->s_zmap_blocks =   conv2(native, (int) sp->s_zmap_blocks);
XX!   sp->s_firstdatazone = conv2(native, (int) sp->s_firstdatazone);
XX!   sp->s_log_zone_size = conv2(native, (int) sp->s_log_zone_size);
XX!   sp->s_max_size =      conv4(native, sp->s_max_size);
XX!   sp->s_zones =         conv4(native, sp->s_zones);
XX! 
XX!   /* In V1, the device size was kept in a short, s_nzones, which limited
XX!    * devices to 32K zones.  For V2, it was decided to keep the size as a
XX!    * long.  However, just changing s_nzones to a long would not work, since
XX!    * then the position of s_magic in the super block would not be the same
XX!    * in V1 and V2 file systems, and there would be no way to tell whether
XX!    * a newly mounted file system was V1 or V2.  The solution was to introduce
XX!    * a new variable, s_zones, and copy the size there.
XX!    *
XX!    * Calculate some other numbers that depend on the version here too, to
XX!    * hide some of the differences.
XX!    */
XX!   if (version == V1) {
XX! 	sp->s_zones = sp->s_nzones;	/* only V1 needs this copy */
XX! 	sp->s_inodes_per_block = V1_INODES_PER_BLOCK;
XX! 	sp->s_ndzones = V1_NR_DZONES;
XX! 	sp->s_nindirs = V1_INDIRECTS;
XX    } else {
XX! 	sp->s_inodes_per_block = V2_INODES_PER_BLOCK;
XX! 	sp->s_ndzones = V2_NR_DZONES;
XX! 	sp->s_nindirs = V2_INDIRECTS;
XX    }
XX+   sp->s_isearch = 0;		/* inode searches initially start at 0 */
XX+   sp->s_zsearch = 0;		/* zone searches initially start at 0 */
XX+   sp->s_version = version;
XX+   sp->s_native  = native;
XX  
XX    put_block(bp, ZUPER_BLOCK);
XX  }
XX+ 
X/
Xecho x - super.h.d
Xsed '/^X/s///' > super.h.d << '/'
XX*** /home/top/ast/minix/1.5/fs/super.h  crc=36161   2071	Sat Apr 21 22:26:20 1990
XX--- /home/top/ast/minix/1.6.25/fs/super.h  crc=52264   2559	Tue Nov  3 21:19:17 1992
XX***************
XX*** 11,19 ****
XX   *    super block     1
XX   *    inode map     s_imap_blocks
XX   *    zone map      s_zmap_blocks
XX!  *    inodes        (s_ninodes + 1 + INODES_PER_BLOCK - 1)/INODES_PER_BLOCK
XX   *    unused        whatever is needed to fill out the current zone
XX!  *    data zones    (s_nzones - s_firstdatazone) << s_log_zone_size
XX   *
XX   * A super_block slot is free if s_dev == NO_DEV. 
XX   */
XX--- 11,19 ----
XX   *    super block     1
XX   *    inode map     s_imap_blocks
XX   *    zone map      s_zmap_blocks
XX!  *    inodes        (s_ninodes + 'inodes per block' - 1)/'inodes per block'
XX   *    unused        whatever is needed to fill out the current zone
XX!  *    data zones    (s_zones - s_firstdatazone) << s_log_zone_size
XX   *
XX   * A super_block slot is free if s_dev == NO_DEV. 
XX   */
XX***************
XX*** 21,43 ****
XX  
XX  EXTERN struct super_block {
XX    ino_t s_ninodes;		/* # usable inodes on the minor device */
XX!   zone_nr s_nzones;		/* total device size, including bit maps etc */
XX!   unshort s_imap_blocks;	/* # of blocks used by inode bit map */
XX!   unshort s_zmap_blocks;	/* # of blocks used by zone bit map */
XX!   zone_nr s_firstdatazone;	/* number of first data zone */
XX!   short int s_log_zone_size;	/* log2 of blocks/zone */
XX    off_t s_max_size;		/* maximum file size on this device */
XX    short s_magic;		/* magic number to recognize super-blocks */
XX  
XX    /* The following items are only used when the super_block is in memory. */
XX    struct buf *s_imap[I_MAP_SLOTS]; /* pointers to the in-core inode bit map */
XX!   struct buf *s_zmap[ZMAP_SLOTS]; /* pointers to the in-core zone bit map */
XX!   dev_t s_dev;			/* whose super block is this? */
XX    struct inode *s_isup;		/* inode for root dir of mounted file sys */
XX    struct inode *s_imount;	/* inode mounted on */
XX!   time_t s_time;		/* time of last update */
XX!   char s_rd_only;		/* set to 1 iff file sys mounted read only */
XX!   char s_dirt;			/* CLEAN or DIRTY */
XX  } super_block[NR_SUPERS];
XX  
XX  #define NIL_SUPER (struct super_block *) 0
XX--- 21,50 ----
XX  
XX  EXTERN struct super_block {
XX    ino_t s_ninodes;		/* # usable inodes on the minor device */
XX!   zone1_t  s_nzones;		/* total device size, including bit maps etc */
XX!   short s_imap_blocks;		/* # of blocks used by inode bit map */
XX!   short s_zmap_blocks;		/* # of blocks used by zone bit map */
XX!   zone1_t s_firstdatazone;	/* number of first data zone */
XX!   short s_log_zone_size;	/* log2 of blocks/zone */
XX    off_t s_max_size;		/* maximum file size on this device */
XX    short s_magic;		/* magic number to recognize super-blocks */
XX+   short s_pad;			/* try to avoid compiler-dependent padding */
XX+   zone_t s_zones;		/* number of zones (replaces s_nzones in V2) */
XX  
XX    /* The following items are only used when the super_block is in memory. */
XX    struct buf *s_imap[I_MAP_SLOTS]; /* pointers to the in-core inode bit map */
XX!   struct buf *s_zmap[Z_MAP_SLOTS]; /* pointers to the in-core zone bit map */
XX    struct inode *s_isup;		/* inode for root dir of mounted file sys */
XX    struct inode *s_imount;	/* inode mounted on */
XX!   unsigned s_inodes_per_block;	/* precalculated from magic number */
XX!   dev_t s_dev;			/* whose super block is this? */
XX!   int s_rd_only;		/* set to 1 iff file sys mounted read only */
XX!   int s_native;			/* set to 1 iff not byte swapped file system */
XX!   int s_version;		/* file system version, zero means bad magic */
XX!   int s_ndzones;		/* # direct zones in an inode */
XX!   int s_nindirs;		/* # indirect zones per indirect block */
XX!   bit_t s_isearch;		/* inodes below this bit number are in use */
XX!   bit_t s_zsearch;		/* all zones below this bit number are in use*/
XX  } super_block[NR_SUPERS];
XX  
XX  #define NIL_SUPER (struct super_block *) 0
X/
Xecho x - table.c.d
Xsed '/^X/s///' > table.c.d << '/'
XX*** /home/top/ast/minix/1.5/fs/table.c  crc=34978   3698	Sat Apr 21 22:26:20 1990
XX--- /home/top/ast/minix/1.6.25/fs/table.c  crc=13839   4272	Sat Apr 10 19:45:43 1993
XX***************
XX*** 5,12 ****
XX  #define _TABLE
XX  
XX  #include "fs.h"
XX- #include <sys/stat.h>
XX- 
XX  #include <minix/callnr.h>
XX  #include <minix/com.h>
XX  #include "buf.h"
XX--- 5,10 ----
XX***************
XX*** 18,24 ****
XX  
XX  PUBLIC char *stackpt = &fstack[FS_STACK_BYTES];	/* initial stack pointer */
XX  
XX! PUBLIC int (*call_vector[NCALLS])() = {
XX  	no_sys,		/*  0 = unused	*/
XX  	do_exit,	/*  1 = exit	*/
XX  	do_fork,	/*  2 = fork	*/
XX--- 16,22 ----
XX  
XX  PUBLIC char *stackpt = &fstack[FS_STACK_BYTES];	/* initial stack pointer */
XX  
XX! PUBLIC _PROTOTYPE (int (*call_vector[NCALLS]), (void) ) = {
XX  	no_sys,		/*  0 = unused	*/
XX  	do_exit,	/*  1 = exit	*/
XX  	do_fork,	/*  2 = fork	*/
XX***************
XX*** 30,36 ****
XX  	do_creat,	/*  8 = creat	*/
XX  	do_link,	/*  9 = link	*/
XX  	do_unlink,	/* 10 = unlink	*/
XX! 	no_sys,		/* 11 = exec	*/
XX  	do_chdir,	/* 12 = chdir	*/
XX  	do_time,	/* 13 = time	*/
XX  	do_mknod,	/* 14 = mknod	*/
XX--- 28,34 ----
XX  	do_creat,	/*  8 = creat	*/
XX  	do_link,	/*  9 = link	*/
XX  	do_unlink,	/* 10 = unlink	*/
XX! 	no_sys,		/* 11 = waitpid	*/
XX  	do_chdir,	/* 12 = chdir	*/
XX  	do_time,	/* 13 = time	*/
XX  	do_mknod,	/* 14 = mknod	*/
XX***************
XX*** 78,84 ****
XX  	no_sys,		/* 56 = (mpx)	*/
XX  	no_sys,		/* 57 = unused	*/
XX  	no_sys,		/* 58 = unused	*/
XX! 	no_sys,		/* 59 = exece	*/
XX  	do_umask,	/* 60 = umask	*/
XX  	do_chroot,	/* 61 = chroot	*/
XX  	no_sys,		/* 62 = unused	*/
XX--- 76,82 ----
XX  	no_sys,		/* 56 = (mpx)	*/
XX  	no_sys,		/* 57 = unused	*/
XX  	no_sys,		/* 58 = unused	*/
XX! 	do_exec,	/* 59 = exece	*/
XX  	do_umask,	/* 60 = umask	*/
XX  	do_chroot,	/* 61 = chroot	*/
XX  	no_sys,		/* 62 = unused	*/
XX***************
XX*** 90,95 ****
XX--- 88,99 ----
XX  	do_revive,	/* 67 = REVIVE	*/
XX  	no_sys,		/* 68 = TASK_REPLY	*/
XX  	no_sys,		/* 69 = unused */
XX+ 	no_sys,		/* 70 = unused */
XX+ 	no_sys,		/* 71 = SIGACTION */
XX+ 	no_sys,		/* 72 = SIGSUSPEND */
XX+ 	no_sys,		/* 73 = SIGPENDING */
XX+ 	no_sys,		/* 74 = SIGPROCMASK */
XX+ 	no_sys,		/* 75 = SIGRETURN */
XX  };
XX  
XX  
XX***************
XX*** 99,116 ****
XX   * intermixed at random.  If this ordering is changed, the devices in h/boot.h
XX   * must be changed to correspond to the new values.  Note that the major
XX   * device numbers used in /dev are NOT the same as the task numbers used
XX!  * inside the kernel (as defined in h/com.h).
XX   */
XX  PUBLIC struct dmap dmap[] = {
XX  /*  Open       Read/Write   Close       Task #      Device  File
XX      ----       ----------   -----       -------     ------  ----      */
XX      0,         0,           0,          0,           /* 0 = not used  */
XX!     no_call,   rw_dev,      no_call,    MEM,         /* 1 = /dev/mem  */
XX!     no_call,   rw_dev,      no_call,    FLOPPY,      /* 2 = /dev/fd0  */
XX!     no_call,   rw_dev,      no_call,    WINCHESTER,  /* 3 = /dev/hd0  */
XX!     tty_open,  rw_dev,      no_call,    TTY,         /* 4 = /dev/tty0 */
XX!     no_call,   rw_dev2,     no_call,    TTY,         /* 5 = /dev/tty  */
XX!     no_call,   rw_dev,      no_call,    PRINTER,     /* 6 = /dev/lp   */
XX  };
XX  
XX  PUBLIC int max_major = sizeof(dmap)/sizeof(struct dmap);
XX--- 103,128 ----
XX   * intermixed at random.  If this ordering is changed, the devices in h/boot.h
XX   * must be changed to correspond to the new values.  Note that the major
XX   * device numbers used in /dev are NOT the same as the task numbers used
XX!  * inside the kernel (as defined in h/com.h).  Also note that if /dev/mem
XX!  * is changed from 1, NULL_MAJOR must be changed in <include/minix/com.h>.
XX   */
XX  PUBLIC struct dmap dmap[] = {
XX  /*  Open       Read/Write   Close       Task #      Device  File
XX      ----       ----------   -----       -------     ------  ----      */
XX      0,         0,           0,          0,           /* 0 = not used  */
XX!     dev_opcl,  call_task,   dev_opcl,   MEM,         /* 1 = /dev/mem  */
XX!     dev_opcl,  call_task,   dev_opcl,   FLOPPY,      /* 2 = /dev/fd0  */
XX!     dev_opcl,  call_task,   dev_opcl,   WINCHESTER,  /* 3 = /dev/hd0  */
XX!     tty_open,  call_task,   tty_close,  TTY,         /* 4 = /dev/tty0 */
XX!     ctty_open, rw_dev2,     ctty_close, TTY,         /* 5 = /dev/tty  */
XX!     no_call,   call_task,   no_call,    PRINTER,     /* 6 = /dev/lp   */
XX!     dev_opcl,  call_task,   dev_opcl,   SCSI,        /* 7 = /dev/hdscsi0  */
XX! #if NETWORKING_ENABLED
XX!     nw_open,   nw_rw,       nw_close,	INET_PROC_NR, /* 8 = /dev/ip   */
XX! #if ALLOW_USER_SEND
XX!     nw_open,   nw_rw,       nw_close,   7,            /* 9 = debug /dev/ip */
XX! #endif
XX! #endif
XX  };
XX  
XX  PUBLIC int max_major = sizeof(dmap)/sizeof(struct dmap);
X/
Xecho x - time.c.d
Xsed '/^X/s///' > time.c.d << '/'
XX*** /home/top/ast/minix/1.5/fs/time.c  crc=03246   2440	Sat Apr 21 22:26:20 1990
XX--- /home/top/ast/minix/1.6.25/fs/time.c  crc=29279   2560	Sun Dec 20 17:24:32 1992
XX***************
XX*** 36,42 ****
XX    if (rip->i_uid != fp->fp_effuid && !super_user) r = EPERM;
XX    if (read_only(rip) != OK) r = EROFS;	/* not even su can touch if R/O */
XX    if (r == OK) {
XX! 	rip->i_mtime = updated_time;
XX  	rip->i_dirt = DIRTY;
XX    }
XX  
XX--- 36,44 ----
XX    if (rip->i_uid != fp->fp_effuid && !super_user) r = EPERM;
XX    if (read_only(rip) != OK) r = EROFS;	/* not even su can touch if R/O */
XX    if (r == OK) {
XX! 	rip->i_atime = utime_actime;
XX! 	rip->i_mtime = utime_modtime;
XX! 	rip->i_update = CTIME;	/* discard any stale ATIME and MTIME flags */
XX  	rip->i_dirt = DIRTY;
XX    }
XX  
XX***************
XX*** 71,77 ****
XX    clock_mess.m_type = SET_TIME;
XX    clock_mess.NEW_TIME = (long) tp;
XX    if ( (k = sendrec(CLOCK, &clock_mess)) != OK) panic("do_stime error", k);
XX!   return (OK);
XX  }
XX  
XX  
XX--- 73,79 ----
XX    clock_mess.m_type = SET_TIME;
XX    clock_mess.NEW_TIME = (long) tp;
XX    if ( (k = sendrec(CLOCK, &clock_mess)) != OK) panic("do_stime error", k);
XX!   return(OK);
XX  }
XX  
XX  
XX***************
XX*** 82,93 ****
XX  {
XX  /* Perform the times(buffer) system call. */
XX  
XX!   time_t t[4];
XX  
XX    sys_times(who, t);
XX    reply_t1 = t[0];
XX    reply_t2 = t[1];
XX    reply_t3 = t[2];
XX    reply_t4 = t[3];
XX    return(OK);
XX  }
XX--- 84,96 ----
XX  {
XX  /* Perform the times(buffer) system call. */
XX  
XX!   clock_t t[5];
XX  
XX    sys_times(who, t);
XX    reply_t1 = t[0];
XX    reply_t2 = t[1];
XX    reply_t3 = t[2];
XX    reply_t4 = t[3];
XX+   reply_t5 = t[4];
XX    return(OK);
XX  }
X/
Xecho x - type.h.d
Xsed '/^X/s///' > type.h.d << '/'
XX*** /home/top/ast/minix/1.5/fs/type.h  crc=62011    703	Sat Apr 21 22:26:21 1990
XX--- /home/top/ast/minix/1.6.25/fs/type.h  crc=63692   1144	Tue Nov  3 21:19:18 1992
XX***************
XX*** 1,17 ****
XX! /* Type definitions local to the File System. */
XX  
XX! typedef struct {		/* directory entry */
XX!   ino_t d_inum;			/* inode number */
XX!   char d_name[NAME_MAX];	/* character string */
XX! } dir_struct;
XX! 
XX! /* Declaration of the disk inode used in rw_inode(). */
XX! typedef struct {		/* disk inode.  Memory inode is in "inode.h" */
XX!   mode_t i_mode;		/* file type, protection, etc. */
XX!   uid_t i_uid;			/* user id of the file's owner */
XX!   off_t i_size;			/* current file size in bytes */
XX!   time_t i_mtime;		/* when was file data last changed */
XX!   gid_t i_gid;			/* group number */
XX!   nlink_t i_nlinks;		/* how many links to this file */
XX!   zone_nr i_zone[NR_ZONE_NUMS];	/* block nums for direct, ind, and dbl ind */
XX! } d_inode;
XX--- 1,23 ----
XX! /* Declaration of the V1 inode as it is on the disk (not in core). */
XX! typedef struct {		/* V1.x disk inode */
XX!   mode_t d1_mode;		/* file type, protection, etc. */
XX!   uid_t d1_uid;			/* user id of the file's owner */
XX!   off_t d1_size;		/* current file size in bytes */
XX!   time_t d1_mtime;		/* when was file data last changed */
XX!   gid_t d1_gid;			/* group number */
XX!   nlink_t d1_nlinks;		/* how many links to this file */
XX!   u16_t d1_zone[V1_NR_TZONES];	/* block nums for direct, ind, and dbl ind */
XX! } d1_inode;
XX  
XX! /* Declaration of the V2 inode as it is on the disk (not in core). */
XX! typedef struct {		/* V2.x disk inode */
XX!   mode_t d2_mode;		/* file type, protection, etc. */
XX!   u16_t d2_nlinks;		/* how many links to this file. HACK! */
XX!   uid_t d2_uid;			/* user id of the file's owner. */
XX!   u16_t d2_gid;			/* group number HACK! */
XX!   off_t d2_size;		/* current file size in bytes */
XX!   time_t d2_atime;		/* when was file data last accessed */
XX!   time_t d2_mtime;		/* when was file data last changed */
XX!   time_t d2_ctime;		/* when was inode data last changed */
XX!   zone_t d2_zone[V2_NR_TZONES];	/* block nums for direct, ind, and dbl ind */
XX! } d2_inode;
X/
Xecho x - utility.c.d
Xsed '/^X/s///' > utility.c.d << '/'
XX*** /home/top/ast/minix/1.5/fs/utility.c  crc=17381   4979	Sat Apr 21 22:26:21 1990
XX--- /home/top/ast/minix/1.6.25/fs/utility.c  crc=14101   6236	Mon Mar  1 20:59:45 1993
XX***************
XX*** 6,11 ****
XX--- 6,13 ----
XX   *   fetch_name:  go get a path name from user space
XX   *   no_sys:      reject a system call that FS does not handle
XX   *   panic:       something awful has occurred;  MINIX cannot continue
XX+  *   conv2:	  do byte swapping on a 16-bit int
XX+  *   conv4:	  do byte swapping on a 32-bit long
XX   */
XX  
XX  #include "fs.h"
XX***************
XX*** 16,22 ****
XX  #include "fproc.h"
XX  #include "inode.h"
XX  #include "param.h"
XX- #include "super.h"
XX  
XX  PRIVATE int panicking;		/* inhibits recursive panics during sync */
XX  PRIVATE message clock_mess;
XX--- 18,23 ----
XX***************
XX*** 32,95 ****
XX   */
XX  
XX    register int k;
XX-   register struct super_block *sp;
XX  
XX    clock_mess.m_type = GET_TIME;
XX    if ( (k = sendrec(CLOCK, &clock_mess)) != OK) panic("clock_time err", k);
XX  
XX!   /* Since we now have the time, update the super block.  It is almost free. */
XX!   sp = get_super(ROOT_DEV);
XX!   if (sp) {
XX! 	sp->s_time = clock_mess.NEW_TIME;	/* update super block time */
XX! 	if (sp->s_rd_only == FALSE) sp->s_dirt = DIRTY;
XX!   }
XX! 
XX!   return (time_t) clock_mess.NEW_TIME;
XX  }
XX  
XX  
XX  /*===========================================================================*
XX-  *				copy					     *
XX-  *===========================================================================*/
XX- PUBLIC void copy(dest, source, bytes)
XX- char *dest;			/* destination pointer */
XX- char *source;			/* source pointer */
XX- int bytes;			/* how much data to move */
XX- {
XX- /* Copy a byte string of length 'bytes' from 'source' to 'dest'.
XX-  * If all three parameters are exactly divisible by the integer size, copy them
XX-  * an integer at a time.  Otherwise copy character-by-character.
XX-  */
XX- 
XX-   int src, dst;
XX- 
XX-   if (bytes <= 0) return;	/* makes test-at-the-end possible */
XX-   src = (int) source;		/* only low-order bits needed */	
XX-   dst = (int) dest;		/* only low-order bits needed */
XX- 
XX-   if (bytes % sizeof(int) == 0 && src % sizeof(int) == 0 &&
XX- 						dst % sizeof(int) == 0) {
XX- 	/* Copy the string an integer at a time. */
XX- 	register int n = bytes/sizeof(int);
XX- 	register int *dpi = (int *) dest;
XX- 	register int *spi = (int *) source;
XX- 
XX- 	do { *dpi++ = *spi++; } while (--n);
XX- 
XX-   } else {
XX- 
XX- 	/* Copy the string character-by-character. */
XX- 	register int n = bytes;
XX- 	register char *dpc = (char *) dest;
XX- 	register char *spc = (char *) source;
XX- 
XX- 	do { *dpc++ = *spc++; } while (--n);
XX- 
XX-   }
XX- }
XX- 
XX- 
XX- /*===========================================================================*
XX   *				fetch_name				     *
XX   *===========================================================================*/
XX  PUBLIC int fetch_name(path, len, flag)
XX--- 33,47 ----
XX   */
XX  
XX    register int k;
XX  
XX    clock_mess.m_type = GET_TIME;
XX    if ( (k = sendrec(CLOCK, &clock_mess)) != OK) panic("clock_time err", k);
XX  
XX!   return( (time_t) clock_mess.NEW_TIME);
XX  }
XX  
XX  
XX  /*===========================================================================*
XX   *				fetch_name				     *
XX   *===========================================================================*/
XX  PUBLIC int fetch_name(path, len, flag)
XX***************
XX*** 103,130 ****
XX   */
XX  
XX    register char *rpu, *rpm;
XX    vir_bytes vpath;
XX  
XX    if (len <= 0) {
XX  	err_code = EINVAL;
XX  	return(ERROR);
XX    }
XX    if (flag == M3 && len <= M3_STRING) {
XX  	/* Just copy the path from the message to 'user_path'. */
XX  	rpu = &user_path[0];
XX  	rpm = pathname;		/* contained in input message */
XX  	do { *rpu++ = *rpm++; } while (--len);
XX! 	return(OK);
XX    }
XX  
XX!   /* String is not contained in the message.  Go get it from user space. */
XX!   if (len > PATH_MAX) {
XX! 	err_code = ENAMETOOLONG;
XX! 	return(ERROR);
XX    }
XX!   vpath = (vir_bytes) path;
XX!   err_code = rw_user(D, who, vpath, (vir_bytes) len, user_path, FROM_USER);
XX!   return(err_code);
XX  }
XX  
XX  
XX--- 55,105 ----
XX   */
XX  
XX    register char *rpu, *rpm;
XX+   int r, n;
XX    vir_bytes vpath;
XX  
XX+   /* Check name length for validity. */
XX    if (len <= 0) {
XX  	err_code = EINVAL;
XX  	return(ERROR);
XX    }
XX+ 
XX+   if (len > PATH_MAX) {
XX+ 	err_code = ENAMETOOLONG;
XX+ 	return(ERROR);
XX+   }
XX+ 
XX+   n = len - 1;			/* # chars not including 0 byte */
XX    if (flag == M3 && len <= M3_STRING) {
XX  	/* Just copy the path from the message to 'user_path'. */
XX  	rpu = &user_path[0];
XX  	rpm = pathname;		/* contained in input message */
XX  	do { *rpu++ = *rpm++; } while (--len);
XX! 	r = OK;
XX!   } else {
XX! 	/* String is not contained in the message.  Get it from user space. */
XX! 	vpath = (vir_bytes) path;
XX! 	r = rw_user(D, who, vpath, (vir_bytes) len, user_path, FROM_USER);
XX    }
XX  
XX!   /* Paths that end in "/." like "/a/b/." or "/" are a pain. Get rid of them */
XX!   if (r == OK) {
XX! 	rpu = &user_path[n - 1]; /* points to last char */
XX! 	while (n > 2) {
XX! 		if (*rpu == '/') 
XX! 		{
XX! 		    *rpu = '\0';	 /* remove the "/" */
XX! 		    n -= 1;
XX! 		    rpu -= 1;
XX! 		} else
XX! 		if (*rpu == '.' && *(--rpu) == '/') {
XX! 			*rpu = '\0';	 /* remove the "/." */
XX! 			n -= 2;
XX! 			rpu -= 1;
XX! 		} else break;
XX! 	}
XX    }
XX!   return(r);
XX  }
XX  
XX  
XX***************
XX*** 156,161 ****
XX    printf("File system panic: %s ", format);
XX    if (num != NO_NUM) printf("%d",num); 
XX    printf("\n");
XX!   (void) do_sync();			/* flush everything to the disk */
XX    sys_abort();
XX  }
XX--- 131,206 ----
XX    printf("File system panic: %s ", format);
XX    if (num != NO_NUM) printf("%d",num); 
XX    printf("\n");
XX!   (void) do_sync();		/* flush everything to the disk */
XX    sys_abort();
XX  }
XX+ 
XX+ 
XX+ 
XX+ /*===========================================================================*
XX+  *				conv2					     *
XX+  *===========================================================================*/
XX+ PUBLIC unsigned conv2(norm, w)
XX+ int norm;			/* TRUE if no swap, FALSE for byte swap */
XX+ int w;				/* promotion of 16-bit word to be swapped */
XX+ {
XX+ /* Possibly swap a 16-bit word between 8086 and 68000 byte order. */
XX+ 
XX+   if (norm) return( (unsigned) w & 0xFFFF);
XX+   return( ((w&BYTE) << 8) | ( (w>>8) & BYTE));
XX+ }
XX+ 
XX+ /*===========================================================================*
XX+  *				conv4					     *
XX+  *===========================================================================*/
XX+ PUBLIC long conv4(norm, x)
XX+ int norm;			/* TRUE if no swap, FALSE for byte swap */
XX+ long x;				/* 32-bit long to be byte swapped */
XX+ {
XX+ /* Possibly swap a 32-bit long between 8086 and 68000 byte order. */
XX+ 
XX+   unsigned lo, hi;
XX+   long l;
XX+   
XX+   if (norm) return(x);			/* byte order was already ok */
XX+   lo = conv2(FALSE, (int) x & 0xFFFF);	/* low-order half, byte swapped */
XX+   hi = conv2(FALSE, (int) (x>>16) & 0xFFFF);	/* high-order half, swapped */
XX+   l = ( (long) lo <<16) | hi;
XX+   return(l);
XX+ }
XX+ 
XX+ /*===========================================================================*
XX+  *				sys_times				     *
XX+  *===========================================================================*/
XX+ PUBLIC void sys_times(proc, ptr)
XX+ int proc;			/* proc whose times are needed */
XX+ clock_t ptr[5];			/* pointer to time buffer */
XX+ {
XX+ /* Fetch the accounting info for a proc. */
XX+   message m;
XX+ 
XX+   m.m1_i1 = proc;
XX+   m.m1_p1 = (char *)ptr;
XX+   (void) _taskcall(SYSTASK, SYS_TIMES, &m);
XX+   ptr[0] = m.USER_TIME;
XX+   ptr[1] = m.SYSTEM_TIME;
XX+   ptr[2] = m.CHILD_UTIME;
XX+   ptr[3] = m.CHILD_STIME;
XX+   ptr[4] = m.BOOT_TICKS;
XX+ }
XX+ 
XX+ /*===========================================================================*
XX+  *				sys_kill				     *
XX+  *===========================================================================*/
XX+ PUBLIC void sys_kill(proc, signr)
XX+ int proc;			/* which proc has exited */
XX+ int signr;			/* signal number: 1 - 16 */
XX+ {
XX+ /* A proc has to be signaled via MM.  Tell the kernel. */
XX+   message m;
XX+ 
XX+   m.m6_i1 = proc;
XX+   m.m6_i2 = signr;
XX+   (void) _taskcall(SYSTASK, SYS_KILL, &m);
XX+ }
XX+ 
X/
Xecho x - write.c.d
Xsed '/^X/s///' > write.c.d << '/'
XX*** /home/top/ast/minix/1.5/fs/write.c  crc=04724   7037	Sat Apr 21 22:26:21 1990
XX--- /home/top/ast/minix/1.6.25/fs/write.c  crc=15220   8248	Tue Nov  3 21:19:19 1992
XX***************
XX*** 3,28 ****
XX   *
XX   * The entry points into this file are
XX   *   do_write:     call read_write to perform the WRITE system call
XX-  *   write_map:    add a new zone to an inode
XX   *   clear_zone:   erase a zone in the middle of a file
XX   *   new_block:    acquire a new block
XX   */
XX  
XX  #include "fs.h"
XX  #include "buf.h"
XX  #include "file.h"
XX  #include "fproc.h"
XX  #include "inode.h"
XX  #include "super.h"
XX  
XX! FORWARD int write_map();
XX  
XX  /*===========================================================================*
XX   *				do_write				     *
XX   *===========================================================================*/
XX  PUBLIC int do_write()
XX  {
XX  /* Perform the write(fd, buffer, nbytes) system call. */
XX    return(read_write(WRITING));
XX  }
XX  
XX--- 3,32 ----
XX   *
XX   * The entry points into this file are
XX   *   do_write:     call read_write to perform the WRITE system call
XX   *   clear_zone:   erase a zone in the middle of a file
XX   *   new_block:    acquire a new block
XX   */
XX  
XX  #include "fs.h"
XX+ #include <string.h>
XX  #include "buf.h"
XX  #include "file.h"
XX  #include "fproc.h"
XX  #include "inode.h"
XX  #include "super.h"
XX  
XX! FORWARD _PROTOTYPE( int write_map, (struct inode *rip, off_t position,
XX! 			zone_t new_zone)				);
XX  
XX+ FORWARD _PROTOTYPE( void wr_indir, (struct buf *bp, int index, zone_t zone) );
XX+ 
XX  /*===========================================================================*
XX   *				do_write				     *
XX   *===========================================================================*/
XX  PUBLIC int do_write()
XX  {
XX  /* Perform the write(fd, buffer, nbytes) system call. */
XX+ 
XX    return(read_write(WRITING));
XX  }
XX  
XX***************
XX*** 33,116 ****
XX  PRIVATE int write_map(rip, position, new_zone)
XX  register struct inode *rip;	/* pointer to inode to be changed */
XX  off_t position;			/* file address to be mapped */
XX! zone_nr new_zone;		/* zone # to be inserted */
XX  {
XX  /* Write a new zone into an inode. */
XX!   int scale;
XX!   zone_nr z, *zp;
XX!   register block_nr b;
XX    long excess, zone;
XX-   int index;
XX    struct buf *bp;
XX-   int new_ind, new_dbl;
XX  
XX    rip->i_dirt = DIRTY;		/* inode will be changed */
XX    bp = NIL_BUF;
XX!   scale = scale_factor(rip);	/* for zone-block conversion */
XX    zone = (position/BLOCK_SIZE) >> scale;	/* relative zone # to insert */
XX  
XX    /* Is 'position' to be found in the inode itself? */
XX!   if (zone < NR_DZONE_NUM) {
XX! 	rip->i_zone[(int) zone] = new_zone;
XX! 	rip->i_update = MTIME;	/* mark mtime for update later */
XX  	return(OK);
XX    }
XX  
XX    /* It is not in the inode, so it must be single or double indirect. */
XX!   excess = zone - NR_DZONE_NUM;	/* first NR_DZONE_NUM don't count */
XX    new_ind = FALSE;
XX    new_dbl = FALSE;
XX  
XX!   if (excess < NR_INDIRECTS) {
XX  	/* 'position' can be located via the single indirect block. */
XX! 	zp = &rip->i_zone[NR_DZONE_NUM];
XX    } else {
XX  	/* 'position' can be located via the double indirect block. */
XX! 	if ( (z = rip->i_zone[NR_DZONE_NUM+1]) == NO_ZONE) {
XX  		/* Create the double indirect block. */
XX  		if ( (z = alloc_zone(rip->i_dev, rip->i_zone[0])) == NO_ZONE)
XX  			return(err_code);
XX! 		rip->i_zone[NR_DZONE_NUM+1] = z;
XX  		new_dbl = TRUE;	/* set flag for later */
XX  	}
XX  
XX  	/* Either way, 'z' is zone number for double indirect block. */
XX! 	excess -= NR_INDIRECTS;	/* single indirect doesn't count */
XX! 	index = excess / NR_INDIRECTS;
XX! 	excess = excess % NR_INDIRECTS;
XX! 	if (index >= NR_INDIRECTS) return(EFBIG);
XX! 	b = (block_nr) z << scale;
XX  	bp = get_block(rip->i_dev, b, (new_dbl ? NO_READ : NORMAL));
XX  	if (new_dbl) zero_block(bp);
XX! 	zp= &bp->b_ind[index];
XX    }
XX  
XX!   /* 'zp' now points to place where indirect zone # goes; 'excess' is index. */
XX!   if (*zp == NO_ZONE) {
XX! 	/* Create indirect block. */
XX! 	*zp = alloc_zone(rip->i_dev, rip->i_zone[0]);
XX  	new_ind = TRUE;
XX! 	if (bp != NIL_BUF) bp->b_dirt = DIRTY;	/* if double ind, it is dirty */
XX! 	if (*zp == NO_ZONE) {
XX  		put_block(bp, INDIRECT_BLOCK);	/* release dbl indirect blk */
XX  		return(err_code);	/* couldn't create single ind */
XX  	}
XX    }
XX    put_block(bp, INDIRECT_BLOCK);	/* release double indirect blk */
XX  
XX!   /* 'zp' now points to indirect block's zone number. */
XX!   b = (block_nr) *zp << scale;
XX    bp = get_block(rip->i_dev, b, (new_ind ? NO_READ : NORMAL) );
XX    if (new_ind) zero_block(bp);
XX!   bp->b_ind[(int) excess] = new_zone;
XX!   rip->i_update = MTIME;		/* mark mtime for update later */
XX    bp->b_dirt = DIRTY;
XX    put_block(bp, INDIRECT_BLOCK);
XX  
XX    return(OK);
XX  }
XX  
XX  /*===========================================================================*
XX   *				clear_zone				     *
XX   *===========================================================================*/
XX  PUBLIC void clear_zone(rip, pos, flag)
XX--- 37,150 ----
XX  PRIVATE int write_map(rip, position, new_zone)
XX  register struct inode *rip;	/* pointer to inode to be changed */
XX  off_t position;			/* file address to be mapped */
XX! zone_t new_zone;		/* zone # to be inserted */
XX  {
XX  /* Write a new zone into an inode. */
XX!   int scale, ind_ex, new_ind, new_dbl, zones, nr_indirects, single, zindex, ex;
XX!   zone_t z, z1;
XX!   register block_t b;
XX    long excess, zone;
XX    struct buf *bp;
XX  
XX    rip->i_dirt = DIRTY;		/* inode will be changed */
XX    bp = NIL_BUF;
XX!   scale = rip->i_sp->s_log_zone_size;		/* for zone-block conversion */
XX    zone = (position/BLOCK_SIZE) >> scale;	/* relative zone # to insert */
XX+   zones = rip->i_ndzones;	/* # direct zones in the inode */
XX+   nr_indirects = rip->i_nindirs;/* # indirect zones per indirect block */
XX  
XX    /* Is 'position' to be found in the inode itself? */
XX!   if (zone < zones) {
XX! 	zindex = (int) zone;	/* we need an integer here */
XX! 	rip->i_zone[zindex] = new_zone;
XX  	return(OK);
XX    }
XX  
XX    /* It is not in the inode, so it must be single or double indirect. */
XX!   excess = zone - zones;	/* first Vx_NR_DZONES don't count */
XX    new_ind = FALSE;
XX    new_dbl = FALSE;
XX  
XX!   if (excess < nr_indirects) {
XX  	/* 'position' can be located via the single indirect block. */
XX! 	z1 = rip->i_zone[zones];	/* single indirect zone */
XX! 	single = TRUE;
XX    } else {
XX  	/* 'position' can be located via the double indirect block. */
XX! 	if ( (z = rip->i_zone[zones+1]) == NO_ZONE) {
XX  		/* Create the double indirect block. */
XX  		if ( (z = alloc_zone(rip->i_dev, rip->i_zone[0])) == NO_ZONE)
XX  			return(err_code);
XX! 		rip->i_zone[zones+1] = z;
XX  		new_dbl = TRUE;	/* set flag for later */
XX  	}
XX  
XX  	/* Either way, 'z' is zone number for double indirect block. */
XX! 	excess -= nr_indirects;	/* single indirect doesn't count */
XX! 	ind_ex = (int) (excess / nr_indirects);
XX! 	excess = excess % nr_indirects;
XX! 	if (ind_ex >= nr_indirects) return(EFBIG);
XX! 	b = (block_t) z << scale;
XX  	bp = get_block(rip->i_dev, b, (new_dbl ? NO_READ : NORMAL));
XX  	if (new_dbl) zero_block(bp);
XX! 	z1 = rd_indir(bp, ind_ex);
XX! 	single = FALSE;
XX    }
XX  
XX!   /* z1 is now single indirect zone; 'excess' is index. */
XX!   if (z1 == NO_ZONE) {
XX! 	/* Create indirect block and store zone # in inode or dbl indir blk. */
XX! 	z1 = alloc_zone(rip->i_dev, rip->i_zone[0]);
XX! 	if (single)
XX! 		rip->i_zone[zones] = z1;	/* update inode */
XX! 	else
XX! 		wr_indir(bp, ind_ex, z1);	/* update dbl indir */
XX! 
XX  	new_ind = TRUE;
XX! 	if (bp != NIL_BUF) bp->b_dirt = DIRTY;	/* if double ind, it is dirty*/
XX! 	if (z1 == NO_ZONE) {
XX  		put_block(bp, INDIRECT_BLOCK);	/* release dbl indirect blk */
XX  		return(err_code);	/* couldn't create single ind */
XX  	}
XX    }
XX    put_block(bp, INDIRECT_BLOCK);	/* release double indirect blk */
XX  
XX!   /* z1 is indirect block's zone number. */
XX!   b = (block_t) z1 << scale;
XX    bp = get_block(rip->i_dev, b, (new_ind ? NO_READ : NORMAL) );
XX    if (new_ind) zero_block(bp);
XX!   ex = (int) excess;			/* we need an int here */
XX!   wr_indir(bp, ex, new_zone);
XX    bp->b_dirt = DIRTY;
XX    put_block(bp, INDIRECT_BLOCK);
XX  
XX    return(OK);
XX  }
XX  
XX+ 
XX  /*===========================================================================*
XX+  *				wr_indir				     *
XX+  *===========================================================================*/
XX+ PRIVATE void wr_indir(bp, index, zone)
XX+ struct buf *bp;			/* pointer to indirect block */
XX+ int index;			/* index into *bp */
XX+ zone_t zone;			/* zone to write */
XX+ {
XX+ /* Given a pointer to an indirect block, write one entry. */
XX+ 
XX+   struct super_block *sp;
XX+ 
XX+   sp = get_super(bp->b_dev);	/* need super block to find file sys type */
XX+ 
XX+   /* write a zone into an indirect block */
XX+   if (sp->s_version == V1)
XX+ 	bp->b_v1_ind[index] = (zone1_t) conv2(sp->s_native, (int)  zone);
XX+   else
XX+ 	bp->b_v2_ind[index] = (zone_t)  conv4(sp->s_native, (long) zone);
XX+ }
XX+ 
XX+ 
XX+ /*===========================================================================*
XX   *				clear_zone				     *
XX   *===========================================================================*/
XX  PUBLIC void clear_zone(rip, pos, flag)
XX***************
XX*** 124,139 ****
XX   */
XX  
XX    register struct buf *bp;
XX!   register block_nr b, blo, bhi;
XX    register off_t next;
XX    register int scale;
XX!   register zone_type zone_size;
XX  
XX    /* If the block size and zone size are the same, clear_zone() not needed. */
XX!   if ( (scale = scale_factor(rip)) == 0) return;
XX  
XX! 
XX!   zone_size = (zone_type) BLOCK_SIZE << scale;
XX    if (flag == 1) pos = (pos/zone_size) * zone_size;
XX    next = pos + BLOCK_SIZE - 1;
XX  
XX--- 158,173 ----
XX   */
XX  
XX    register struct buf *bp;
XX!   register block_t b, blo, bhi;
XX    register off_t next;
XX    register int scale;
XX!   register zone_t zone_size;
XX  
XX    /* If the block size and zone size are the same, clear_zone() not needed. */
XX!   scale = rip->i_sp->s_log_zone_size;
XX!   if (scale == 0) return;
XX  
XX!   zone_size = (zone_t) BLOCK_SIZE << scale;
XX    if (flag == 1) pos = (pos/zone_size) * zone_size;
XX    next = pos + BLOCK_SIZE - 1;
XX  
XX***************
XX*** 164,183 ****
XX   */
XX  
XX    register struct buf *bp;
XX!   block_nr b, base_block;
XX!   zone_nr z;
XX!   zone_type zone_size;
XX    int scale, r;
XX    struct super_block *sp;
XX  
XX    /* Is another block available in the current zone? */
XX    if ( (b = read_map(rip, position)) == NO_BLOCK) {
XX! 	/* Choose first zone if need be. */
XX! 	if (rip->i_size == 0) {
XX! 		sp = get_super(rip->i_dev);
XX  		z = sp->s_firstdatazone;
XX  	} else {
XX! 		z = rip->i_zone[0];
XX  	}
XX  	if ( (z = alloc_zone(rip->i_dev, z)) == NO_ZONE) return(NIL_BUF);
XX  	if ( (r = write_map(rip, position, z)) != OK) {
XX--- 198,221 ----
XX   */
XX  
XX    register struct buf *bp;
XX!   block_t b, base_block;
XX!   zone_t z;
XX!   zone_t zone_size;
XX    int scale, r;
XX    struct super_block *sp;
XX  
XX    /* Is another block available in the current zone? */
XX    if ( (b = read_map(rip, position)) == NO_BLOCK) {
XX! 	/* Choose first zone if possible. */
XX! 	/* Lose if the file is nonempty but the first zone number is NO_ZONE
XX! 	 * corresponding to a zone full of zeros.  It would be better to
XX! 	 * search near the last real zone.
XX! 	 */
XX! 	if (rip->i_zone[0] == NO_ZONE) {
XX! 		sp = rip->i_sp;
XX  		z = sp->s_firstdatazone;
XX  	} else {
XX! 		z = rip->i_zone[0];	/* hunt near first zone */
XX  	}
XX  	if ( (z = alloc_zone(rip->i_dev, z)) == NO_ZONE) return(NIL_BUF);
XX  	if ( (r = write_map(rip, position, z)) != OK) {
XX***************
XX*** 188,197 ****
XX  
XX  	/* If we are not writing at EOF, clear the zone, just to be safe. */
XX  	if ( position != rip->i_size) clear_zone(rip, position, 1);
XX! 	scale = scale_factor(rip);
XX! 	base_block = (block_nr) z << scale;
XX! 	zone_size = (zone_type) BLOCK_SIZE << scale;
XX! 	b = base_block + (block_nr)((position % zone_size)/BLOCK_SIZE);
XX    }
XX  
XX    bp = get_block(rip->i_dev, b, NO_READ);
XX--- 226,235 ----
XX  
XX  	/* If we are not writing at EOF, clear the zone, just to be safe. */
XX  	if ( position != rip->i_size) clear_zone(rip, position, 1);
XX! 	scale = rip->i_sp->s_log_zone_size;
XX! 	base_block = (block_t) z << scale;
XX! 	zone_size = (zone_t) BLOCK_SIZE << scale;
XX! 	b = base_block + (block_t)((position % zone_size)/BLOCK_SIZE);
XX    }
XX  
XX    bp = get_block(rip->i_dev, b, NO_READ);
XX***************
XX*** 208,219 ****
XX  {
XX  /* Zero a block. */
XX  
XX!   register int n;
XX!   register int *zip;
XX! 
XX!   n = INTS_PER_BLOCK;		/* number of integers in a block */
XX!   zip = bp->b_int;		/* where to start clearing */
XX! 
XX!   do { *zip++ = 0;}  while (--n);
XX    bp->b_dirt = DIRTY;
XX  }
XX--- 246,251 ----
XX  {
XX  /* Zero a block. */
XX  
XX!   memset(bp->b_data, 0, BLOCK_SIZE);
XX    bp->b_dirt = DIRTY;
XX  }
X/
/
