diff -rc --new-file linux-0.99.13/config.in linux/config.in
*** linux-0.99.13/config.in	Sat Sep 25 12:10:05 1993
--- linux/config.in	Sat Sep 25 13:58:37 1993
***************
*** 78,83 ****
--- 78,84 ----
  bool '/proc filesystem support' CONFIG_PROC_FS y
  bool 'NFS filesystem support' CONFIG_NFS_FS y
  bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS n
+ bool 'Disk QUOTA support' CONFIG_QUOTA y
  *
  *  character devices
  *
diff -rc --new-file linux-0.99.13/fs/Makefile linux/fs/Makefile
*** linux-0.99.13/fs/Makefile	Sat Sep 25 12:09:54 1993
--- linux/fs/Makefile	Sat Sep 25 13:01:38 1993
***************
*** 47,53 ****
  
  OBJS=	open.o read_write.o inode.o devices.o file_table.o buffer.o super.o \
  	block_dev.o stat.o exec.o pipe.o namei.o fcntl.o ioctl.o \
! 	select.o fifo.o locks.o filesystems.o $(BINFMTS)
  
  all: fs.o filesystems.a
  
--- 47,53 ----
  
  OBJS=	open.o read_write.o inode.o devices.o file_table.o buffer.o super.o \
  	block_dev.o stat.o exec.o pipe.o namei.o fcntl.o ioctl.o \
! 	select.o fifo.o locks.o quota.o filesystems.o $(BINFMTS)
  
  all: fs.o filesystems.a
  
diff -rc --new-file linux-0.99.13/fs/buffer.c linux/fs/buffer.c
*** linux-0.99.13/fs/buffer.c	Sat Sep 25 12:09:54 1993
--- linux/fs/buffer.c	Sat Sep 25 13:01:38 1993
***************
*** 25,30 ****
--- 25,33 ----
  #include <linux/string.h>
  #include <linux/locks.h>
  #include <linux/errno.h>
+ #ifdef CONFIG_QUOTA
+ #include <linux/quota.h>
+ #endif
  
  #include <asm/system.h>
  #include <asm/io.h>
***************
*** 150,155 ****
--- 153,161 ----
  	sync_supers(dev);
  	sync_inodes(dev);
  	sync_buffers(dev, 0);
+ #ifdef CONFIG_QUOTA
+ 	sync_quota(dev, -1);
+ #endif
  }
  
  int fsync_dev(dev_t dev)
diff -rc --new-file linux-0.99.13/fs/exec.c linux/fs/exec.c
*** linux-0.99.13/fs/exec.c	Sat Sep 25 12:09:54 1993
--- linux/fs/exec.c	Sat Sep 25 13:47:45 1993
***************
*** 38,43 ****
--- 38,47 ----
  #include <linux/user.h>
  #include <linux/segment.h>
  #include <asm/system.h>
+ #include <linux/config.h>
+ #ifdef CONFIG_QUOTA
+ #include <linux/quota.h>
+ #endif
  
  #include <linux/binfmts.h>
  
***************
*** 92,99 ****
--- 96,124 ----
   * These are the only things you should do on a core-file: use only these
   * macros to write out all the necessary info.
   */
+ #ifdef CONFIG_QUOTA
+ #define DUMP_WRITE(addr,nr) \
+ bytes = (nr); \
+ cur_blocks = isize_to_blocks(inode->i_size, inode->i_blksize); \
+ wanted_blocks = isize_to_blocks((file.f_pos + bytes), inode->i_blksize) - cur_blocks; \
+ if (quota_alloc(inode->i_dev, inode->i_uid, inode->i_gid, 0, \
+                 wanted_blocks, &avail_blocks) == NO_QUOTA) \
+    goto close_coredump; \
+ if (avail_blocks < wanted_blocks) \
+    bytes = blocks_to_isize((cur_blocks + avail_blocks), inode->i_blksize) - file.f_pos; \
+ oldisize = inode->i_size; \
+ if (file.f_op->write(inode,&file,(char *)(addr),bytes) != bytes) { \
+    quota_remove(inode->i_dev, inode->i_uid, inode->i_gid, 0, avail_blocks - \
+                (isize_to_blocks(inode->i_size, inode->i_blksize) - \
+                 isize_to_blocks(oldisize, inode->i_blksize))); \
+    goto close_coredump; \
+ } \
+ if (avail_blocks < wanted_blocks) \
+    goto close_coredump;
+ #else
  #define DUMP_WRITE(addr,nr) \
  while (file.f_op->write(inode,&file,(char *)(addr),(nr)) != (nr)) goto close_coredump
+ #endif
  
  #define DUMP_SEEK(offset) \
  if (file.f_op->lseek) { \
***************
*** 119,124 ****
--- 144,154 ----
  	char corefile[6+sizeof(current->comm)];
  	register int dump_start, dump_size;
  	struct user dump;
+ #ifdef CONFIG_QUOTA
+ 	size_t oldisize;
+ 	long bytes;
+ 	u_long cur_blocks, wanted_blocks, avail_blocks;
+ #endif
  
  	if (!current->dumpable)
  		return 0;
***************
*** 152,157 ****
--- 182,188 ----
  	if (!file.f_op->write)
  		goto close_coredump;
  	has_dumped = 1;
+ 	current->flags |= PF_DUMPCORE;
  /* changed the size calculations - should hopefully work better. lbt */
  	dump.magic = CMAGIC;
  	dump.start_code = 0;
***************
*** 744,749 ****
--- 775,781 ----
  	
  	/* OK, This is the point of no return */
  	flush_old_exec(bprm);
+ 	current->flags &= ~PF_FORKNOEXEC;
  	current->start_brk = current->brk = ex.a_bss +
  		(current->end_data = ex.a_data +
  		 (current->end_code = N_TXTADDR(ex) + ex.a_text));
diff -rc --new-file linux-0.99.13/fs/namei.c linux/fs/namei.c
*** linux-0.99.13/fs/namei.c	Sat Sep 25 12:09:54 1993
--- linux/fs/namei.c	Sat Sep 25 13:50:17 1993
***************
*** 16,21 ****
--- 16,25 ----
  #include <linux/string.h>
  #include <linux/fcntl.h>
  #include <linux/stat.h>
+ #include <linux/config.h>
+ #ifdef CONFIG_QUOTA
+ #include <linux/quota.h>
+ #endif
  
  #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE])
  
***************
*** 281,286 ****
--- 285,293 ----
  	int namelen,error,i;
  	struct inode * dir, *inode;
  	struct task_struct ** p;
+ #ifdef CONFIG_QUOTA
+ 	size_t oldisize;
+ #endif
  
  	mode &= S_IALLUGO & ~current->umask;
  	mode |= S_IFREG;
***************
*** 321,328 ****
--- 328,346 ----
  			iput(dir);
  			return -EROFS;
  		}
+ #ifdef CONFIG_QUOTA
+ 		if (quota_alloc(dir->i_dev, current->euid,
+                                 current->egid, 1, 0, (u_long *)0) == NO_QUOTA) {
+ 			iput(dir);
+ 			return -EDQUOT;
+ 		}
+ #endif
  		dir->i_count++;		/* create eats the dir */
  		error = dir->i_op->create(dir,basename,namelen,mode,res_inode);
+ #ifdef CONFIG_QUOTA
+ 		if (error)
+ 			quota_remove(dir->i_dev, current->euid, current->egid, 1, 0);
+ #endif
  		if (error != -EEXIST) {
  			iput(dir);
  			return error;
***************
*** 379,384 ****
--- 397,405 ----
   		}
   	}
  	if (flag & O_TRUNC) {
+ #ifdef CONFIG_QUOTA
+ 	      oldisize = inode->i_size;
+ #endif
  	      inode->i_size = 0;
  	      if (inode->i_op && inode->i_op->truncate)
  	           inode->i_op->truncate(inode);
***************
*** 386,391 ****
--- 407,416 ----
  		   iput(inode);
  		   return error;
  	      }
+ #ifdef CONFIG_QUOTA
+ 	      quota_remove(inode->i_dev, inode->i_uid, inode->i_gid, 0,
+                            isize_to_blocks(oldisize, inode->i_blksize));
+ #endif
  	      inode->i_dirt = 1;
  	}
  	*res_inode = inode;
***************
*** 418,424 ****
--- 443,464 ----
  		iput(dir);
  		return -EPERM;
  	}
+ 
+ #ifdef CONFIG_QUOTA
+ 	if (quota_alloc(dir->i_dev, current->euid,
+                         current->egid, 1, 0, (u_long *)0) == NO_QUOTA) {
+ 	   iput(dir);
+ 	   return -EDQUOT;
+ 	}
+ 	dir->i_count++; /* mknod uses up dir */
+ 	error = dir->i_op->mknod(dir,basename,namelen,mode,dev);
+ 	if (error)
+            quota_remove(dir->i_dev, current->euid, current->egid, 1, 0);
+ 	iput(dir);
+ 	return error;
+ #else
  	return dir->i_op->mknod(dir,basename,namelen,mode,dev);
+ #endif
  }
  
  asmlinkage int sys_mknod(const char * filename, int mode, dev_t dev)
***************
*** 461,467 ****
--- 501,522 ----
  		iput(dir);
  		return -EPERM;
  	}
+ 
+ #ifdef CONFIG_QUOTA
+ 	if (quota_alloc(dir->i_dev, current->euid,
+                         current->egid, 1, 1, (u_long *)0) == NO_QUOTA) {
+ 	   iput(dir);
+ 	   return -EDQUOT;
+ 	}
+ 	dir->i_count++; /* mkdir uses up dir */
+ 	error = dir->i_op->mkdir(dir,basename,namelen,mode);
+ 	if (error)
+            quota_remove(dir->i_dev, current->euid, current->egid, 1, 1);
+ 	iput(dir);
+ 	return error;
+ #else
  	return dir->i_op->mkdir(dir,basename,namelen,mode);
+ #endif
  }
  
  asmlinkage int sys_mkdir(const char * pathname, int mode)
***************
*** 482,487 ****
--- 537,548 ----
  	const char * basename;
  	int namelen, error;
  	struct inode * dir;
+ #ifdef CONFIG_QUOTA
+ 	struct inode *inode;
+ 	dev_t dev;
+ 	uid_t uid;
+ 	gid_t gid;
+ #endif
  
  	error = dir_namei(name,&namelen,&basename,NULL,&dir);
  	if (error)
***************
*** 502,508 ****
--- 563,586 ----
  		iput(dir);
  		return -EPERM;
  	}
+ #ifdef CONFIG_QUOTA
+ 	/* Need inode entry of directory */
+ 	dir->i_count++;	/* lookup uses up dir */
+ 	if ((error = lookup(dir,basename,namelen,&inode))) {
+ 	   iput(dir);
+ 	   return error;
+         }
+ 	dev = inode->i_dev;
+ 	uid = inode->i_uid;
+ 	gid = inode->i_gid;
+ 	iput(inode);
+ 	error = dir->i_op->rmdir(dir,basename,namelen);
+ 	if (!error)
+ 	   quota_remove(dev, uid, gid, 1, 1);
+ 	return error;
+ #else
  	return dir->i_op->rmdir(dir,basename,namelen);
+ #endif
  }
  
  asmlinkage int sys_rmdir(const char * pathname)
***************
*** 523,528 ****
--- 601,609 ----
  	const char * basename;
  	int namelen, error;
  	struct inode * dir;
+ #ifdef CONFIG_QUOTA
+ 	struct inode *inode;
+ #endif
  
  	error = dir_namei(name,&namelen,&basename,NULL,&dir);
  	if (error)
***************
*** 543,549 ****
--- 624,646 ----
  		iput(dir);
  		return -EPERM;
  	}
+ #ifdef CONFIG_QUOTA
+ 	/* Need inode info for quota operations */
+ 	dir->i_count++;	/* lookup uses up dir */
+ 	if ((error = lookup(dir,basename,namelen,&inode))) {
+ 	   iput(dir);
+ 	   return error;
+         }
+ 	error = dir->i_op->unlink(dir,basename,namelen);
+ 	/* Remove block and inode. Only if link-count is 0 ! */
+ 	if (!error && inode->i_nlink == 0)
+ 	   quota_remove(inode->i_dev, inode->i_uid, inode->i_gid, 1,
+                         isize_to_blocks(inode->i_size, inode->i_blksize));
+ 	iput(inode);
+ 	return error;
+ #else
  	return dir->i_op->unlink(dir,basename,namelen);
+ #endif
  }
  
  asmlinkage int sys_unlink(const char * pathname)
***************
*** 584,590 ****
--- 681,702 ----
  		iput(dir);
  		return -EPERM;
  	}
+ 
+ #ifdef CONFIG_QUOTA
+ 	if (quota_alloc(dir->i_dev, current->euid,
+                         current->egid, 1, 1, (u_long *)0) == NO_QUOTA) {
+ 	   iput(dir);
+ 	   return -EDQUOT;
+ 	}
+ 	dir->i_count++; /* symlink uses up dir */
+ 	error = dir->i_op->symlink(dir,basename,namelen,oldname);
+ 	if (error)
+ 	   quota_remove(dir->i_dev, current->euid, current->egid, 1, 1);
+ 	iput(dir);
+ 	return error;
+ #else
  	return dir->i_op->symlink(dir,basename,namelen,oldname);
+ #endif
  }
  
  asmlinkage int sys_symlink(const char * oldname, const char * newname)
diff -rc --new-file linux-0.99.13/fs/open.c linux/fs/open.c
*** linux-0.99.13/fs/open.c	Sat Sep 25 12:09:54 1993
--- linux/fs/open.c	Sat Sep 25 13:26:19 1993
***************
*** 16,21 ****
--- 16,25 ----
  #include <linux/signal.h>
  #include <linux/tty.h>
  #include <linux/time.h>
+ #include <linux/config.h>
+ #ifdef CONFIG_QUOTA
+ #include <linux/quota.h>
+ #endif
  
  #include <asm/segment.h>
  
***************
*** 69,74 ****
--- 73,81 ----
  {
  	struct inode * inode;
  	int error;
+ #ifdef CONFIG_QUOTA
+ 	size_t oldsize;
+ #endif
  
  	error = namei(path,&inode);
  	if (error)
***************
*** 81,92 ****
--- 88,108 ----
  		iput(inode);
  		return -EROFS;
  	}
+ #ifdef CONFIG_QUOTA
+ 	oldsize = inode->i_size;
+ #endif
  	inode->i_size = length;
  	if (inode->i_op && inode->i_op->truncate)
  		inode->i_op->truncate(inode);
  	inode->i_atime = inode->i_mtime = CURRENT_TIME;
  	inode->i_dirt = 1;
  	error = notify_change(NOTIFY_SIZE, inode);
+ #ifdef CONFIG_QUOTA
+ 	if (!error)
+ 	   quota_remove(inode->i_dev, inode->i_uid, inode->i_gid, 0,
+                         isize_to_blocks(oldsize, inode->i_blksize) -
+                         isize_to_blocks(length, inode->i_blksize));
+ #endif
  	iput(inode);
  	return error;
  }
***************
*** 95,100 ****
--- 111,120 ----
  {
  	struct inode * inode;
  	struct file * file;
+ #ifdef CONFIG_QUOTA
+ 	int error;
+ 	size_t oldsize;
+ #endif
  
  	if (fd >= NR_OPEN || !(file = current->filp[fd]))
  		return -EBADF;
***************
*** 102,113 ****
--- 122,145 ----
  		return -ENOENT;
  	if (S_ISDIR(inode->i_mode) || !(file->f_mode & 2))
  		return -EACCES;
+ #ifdef CONFIG_QUOTA
+ 	oldsize = inode->i_size;
+ #endif
  	inode->i_size = length;
  	if (inode->i_op && inode->i_op->truncate)
  		inode->i_op->truncate(inode);
  	inode->i_atime = inode->i_mtime = CURRENT_TIME;
  	inode->i_dirt = 1;
+ #ifdef CONFIG_QUOTA
+ 	error = notify_change(NOTIFY_SIZE, inode);
+ 	if (!error)
+ 	   quota_remove(inode->i_dev, inode->i_uid, inode->i_gid, 0,
+                         isize_to_blocks(oldsize, inode->i_blksize) -
+                         isize_to_blocks(length, inode->i_blksize));
+ 	return error;
+ #else
  	return notify_change(NOTIFY_SIZE, inode);
+ #endif
  }
  
  /* If times==NULL, set access and modification to current time,
***************
*** 282,287 ****
--- 314,325 ----
  {
  	struct inode * inode;
  	struct file * file;
+ #ifdef CONFIG_QUOTA
+ 	int error;
+ 	uid_t olduid;
+ 	gid_t oldgid;
+ #endif
+ 	
  
  	if (fd >= NR_OPEN || !(file = current->filp[fd]))
  		return -EBADF;
***************
*** 294,306 ****
  	if (group == (gid_t) -1)
  		group = inode->i_gid;
  	if ((current->euid == inode->i_uid && user == inode->i_uid &&
! 	     (in_group_p(group) || group == inode->i_gid)) ||
! 	    suser()) {
  		inode->i_uid = user;
  		inode->i_gid = group;
  		inode->i_ctime = CURRENT_TIME;
  		inode->i_dirt = 1;
  		return notify_change(NOTIFY_UIDGID, inode);
  	}
  	return -EPERM;
  }
--- 332,360 ----
  	if (group == (gid_t) -1)
  		group = inode->i_gid;
  	if ((current->euid == inode->i_uid && user == inode->i_uid &&
! 	     (in_group_p(group) || group == inode->i_gid)) || suser()) {
! #ifdef CONFIG_QUOTA
! 		olduid = inode->i_uid;
! 		oldgid = inode->i_gid;
! 		if (quota_transfer(inode->i_dev, olduid, user, oldgid, group, 1,
!                                    isize_to_blocks(inode->i_size, inode->i_blksize)) == NO_QUOTA) {
! 		   iput(inode);
! 		   return -EDQUOT;
! 		}
! #endif
  		inode->i_uid = user;
  		inode->i_gid = group;
  		inode->i_ctime = CURRENT_TIME;
  		inode->i_dirt = 1;
+ #ifdef CONFIG_QUOTA
+ 		error = notify_change(NOTIFY_UIDGID, inode);
+ 		if (error)
+ 		   quota_transfer(inode->i_dev, user, olduid, group, oldgid, 1,
+                                    isize_to_blocks(inode->i_size, inode->i_blksize));
+ 		return error;
+ #else
  		return notify_change(NOTIFY_UIDGID, inode);
+ #endif
  	}
  	return -EPERM;
  }
***************
*** 309,314 ****
--- 363,372 ----
  {
  	struct inode * inode;
  	int error;
+ #ifdef CONFIG_QUOTA
+ 	uid_t olduid;
+ 	gid_t oldgid;
+ #endif
  
  	error = lnamei(filename,&inode);
  	if (error)
***************
*** 322,334 ****
  	if (group == (gid_t) -1)
  		group = inode->i_gid;
  	if ((current->euid == inode->i_uid && user == inode->i_uid &&
! 	     (in_group_p(group) || group == inode->i_gid)) ||
! 	    suser()) {
  		inode->i_uid = user;
  		inode->i_gid = group;
  		inode->i_ctime = CURRENT_TIME;
  		inode->i_dirt = 1;
  		error = notify_change(NOTIFY_UIDGID, inode);
  		iput(inode);
  		return error;
  	}
--- 380,405 ----
  	if (group == (gid_t) -1)
  		group = inode->i_gid;
  	if ((current->euid == inode->i_uid && user == inode->i_uid &&
! 	     (in_group_p(group) || group == inode->i_gid)) || suser()) {
! #ifdef CONFIG_QUOTA
! 		olduid = inode->i_uid;
! 		oldgid = inode->i_gid;
! 		if (quota_transfer(inode->i_dev, olduid, user, oldgid, group, 1,
!                                    isize_to_blocks(inode->i_size, inode->i_blksize)) == NO_QUOTA) {
! 		   iput(inode);
! 		   return -EDQUOT;
! 		}
! #endif
  		inode->i_uid = user;
  		inode->i_gid = group;
  		inode->i_ctime = CURRENT_TIME;
  		inode->i_dirt = 1;
  		error = notify_change(NOTIFY_UIDGID, inode);
+ #ifdef CONFIG_QUOTA
+ 		if (error)
+ 		   quota_transfer(inode->i_dev, user, olduid, group, oldgid, 1,
+                                    isize_to_blocks(inode->i_size, inode->i_blksize));
+ #endif
  		iput(inode);
  		return error;
  	}
diff -rc --new-file linux-0.99.13/fs/quota.c linux/fs/quota.c
*** linux-0.99.13/fs/quota.c
--- linux/fs/quota.c	Sat Sep 25 13:52:35 1993
***************
*** 0 ****
--- 1,1150 ----
+ /*
+  * QUOTA    An implementation of the diskquota system for the LINUX
+  *          operating system. QUOTA is implemented using the BSD systemcall
+  *          interface as the means of communication with the user level. Should
+  *          work for all filesystems because of integration into the VFS layer
+  *          of the operating system. This is based on the Melbourne quota system
+  *          wich uses both user and group quota files.
+  * 
+  *          Main layer of quota management
+  * 
+  * Version: $Id: quota.c,v 3.1 1993/09/25 11:52:05 mvw Exp mvw $
+  * 
+  * Authors: Marco van Wieringen <v892273@si.hhs.nl> <mvw@hacktic.nl>
+  *          Edvard Tuinder <v892231@si.hhs.nl> <etuinder@hacktic.nl>
+  *          Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
+  * 
+  *          This program is free software; you can redistribute it and/or
+  *          modify it under the terms of the GNU General Public License as
+  *          published by the Free Software Foundation; either version 2 of the
+  *          License, or (at your option) any later version.
+  */
+ 
+ #include <linux/config.h>
+ #include <linux/errno.h>
+ #include <linux/kernel.h>
+ 
+ #ifdef CONFIG_QUOTA
+ #include <linux/types.h>
+ #include <linux/sched.h>
+ #include <linux/quota.h>
+ #include <linux/string.h>
+ #include <linux/fcntl.h>
+ #include <linux/stat.h>
+ #include <linux/segment.h>
+ #include <linux/fs.h>
+ #include <linux/tty.h>
+ 
+ #include <asm/segment.h>
+ #include <sys/sysmacros.h>
+ 
+ /* Linked list with enabled devices */
+ static struct device_list *devicelist[MAXQUOTAS];
+ 
+ /* Most recent used device */
+ static struct device_list *mru_device[MAXQUOTAS];
+ 
+ /* Most recent used id on the device in mru_device */
+ static struct dquot *mru_dquot[MAXQUOTAS];
+ 
+ static inline char *typetoname(int type)
+ {
+    if (type == USRQUOTA)
+       return "uid";
+    else
+       return "gid";
+ }
+ 
+ /*
+  * Kick the message in quotamessage to the tty.
+  */
+ static void quota_message(char *quotamessage)
+ {
+    struct tty_struct *tty;
+ 
+    if (current->tty >= 0) {
+       tty = TTY_TABLE(current->tty);
+       (void) tty_write_data(tty, quotamessage, strlen(quotamessage),
+                             (void *)0, (void *)0);
+    }
+ }
+ 
+ /*
+  * Functions for management of devices.
+  */
+ static struct device_list *lookup_device(dev_t dev, int type)
+ {
+    register struct device_list *lptr;
+ 
+    if (devicelist[type] == (struct device_list *) 0)
+       return ((struct device_list *) 0);
+ 
+    if (mru_device[type] != (struct device_list *) 0 &&
+        mru_device[type]->dq_dev == dev)
+       return (mru_device[type]);
+ 
+    for (lptr = devicelist[type]; lptr != (struct device_list *)0; lptr = lptr->next)
+       if (lptr->dq_dev == dev)
+          return (lptr);
+ 
+    return ((struct device_list *) 0);
+ }
+ 
+ static struct device_list *add_device(dev_t dev, int type)
+ {
+    register struct device_list *lptr;
+ 
+    if ((lptr = (struct device_list *) kmalloc(sizeof(struct device_list),
+         GFP_KERNEL)) == (struct device_list *) 0)
+       return ((struct device_list *) 0);
+    memset(lptr, 0, sizeof(struct device_list));
+ 
+    lptr->dq_dev = dev;
+    lptr->dq_dirt = 0;
+    lptr->dq_quota = (struct dquot *) 0;
+ 
+    lptr->next = devicelist[type];
+    devicelist[type] = lptr;
+ 
+    return (lptr);
+ }
+ 
+ static inline int device_can_be_removed(struct device_list *device)
+ {
+    register struct dquot *lptr;
+ 
+    for(lptr = device->dq_quota; lptr != (struct dquot *)0; lptr = lptr->next)
+       if (lptr->dq_flags & DQ_LOCKED)
+          return 0;
+    return 1;
+ }
+ 
+ static void remove_device(dev_t dev, int type)
+ {
+    register struct device_list *lptr, *tmp;
+    register struct dquot *idp, *tofree;
+ 
+    if (devicelist[type] == (struct device_list *) 0)
+       return;
+ 
+    if (mru_device[type] != (struct device_list *) 0 &&
+        mru_device[type]->dq_dev == dev) {
+       mru_device[type] = (struct device_list *) 0;
+       mru_dquot[type] = (struct dquot *) 0;
+    }
+ 
+    lptr = devicelist[type];
+    if (lptr->dq_dev == dev)
+       devicelist[type] = lptr->next;
+    else {
+       while (lptr->next != (struct device_list *) 0) {
+          if (lptr->next->dq_dev == dev)
+             break;
+          lptr = lptr->next;
+       }
+       tmp = lptr->next;
+       lptr->next = lptr->next->next;
+       lptr = tmp;
+    }
+ 
+    idp = lptr->dq_quota;
+    while (idp != (struct dquot *) 0) {
+       tofree = idp;
+       idp = idp->next;
+       kfree_s(tofree, sizeof(struct dquot));
+    }
+ 
+    kfree_s(lptr, sizeof(struct device_list));
+ }
+ 
+ /*
+  * Functions for management of dquot structs
+  * 
+  * Locking of dqblk for a user or group.
+  */
+ static void wait_on_dqblk(struct dquot * dquot)
+ {
+    struct wait_queue wait = {current, NULL};
+ 
+    add_wait_queue(&dquot->dq_wait, &wait);
+    while (dquot->dq_flags & DQ_LOCKED) {
+       current->state = TASK_UNINTERRUPTIBLE;
+       schedule();
+    }
+    remove_wait_queue(&dquot->dq_wait, &wait);
+    current->state = TASK_RUNNING;
+ }
+ 
+ static inline void lock_dquot(struct dquot * dquot)
+ {
+    if (dquot != (struct dquot *)0) {
+       while (dquot->dq_flags & DQ_LOCKED) {
+          dquot->dq_flags |= DQ_WANT;
+          wait_on_dqblk(dquot);
+       }
+       dquot->dq_flags |= DQ_LOCKED;
+    }
+ }
+ 
+ static inline void unlock_dquot(struct dquot * dquot)
+ {
+    if (dquot != (struct dquot *)0) {
+       dquot->dq_flags &= ~DQ_LOCKED;
+       if (dquot->dq_flags & DQ_WANT) {
+          dquot->dq_flags &= ~DQ_WANT;
+          wake_up(&dquot->dq_wait);
+       }
+    }
+ }
+ 
+ /*
+  * Functions for management of dquot's
+  */
+ static struct dquot *lookup_dquot(struct device_list *device, int id, int type)
+ {
+    register struct dquot *lptr = (struct dquot *) 0;
+ 
+    if (id <= ID_NO_QUOTA)
+       return ((struct dquot *) 0);
+ 
+    /*
+     * First fast lookup when same as used before.
+     */
+    if (mru_device[type] != (struct device_list *) 0 &&
+        mru_dquot[type] != (struct dquot *) 0 &&
+        mru_dquot[type]->dq_id == id &&
+        mru_device[type]->dq_dev == device->dq_dev) {
+       lock_dquot(mru_dquot[type]);
+       return (mru_dquot[type]);
+    }
+ 
+    for (lptr = device->dq_quota; lptr != (struct dquot *) 0; lptr = lptr->next)
+       if (lptr->dq_id == id) {
+          mru_device[type] = device;
+          mru_dquot[type] = lptr;
+          lock_dquot(lptr);
+          return (lptr);
+       }
+    return ((struct dquot *) 0);
+ }
+ 
+ static struct dquot *add_dquot(struct device_list * device, int id)
+ {
+    register struct dquot *lptr;
+ 
+    if ((lptr = (struct dquot *) kmalloc(sizeof(struct dquot),
+                                 GFP_KERNEL)) == (struct dquot *) 0)
+       return ((struct dquot *) 0);
+    memset(lptr, 0, sizeof(struct dquot));
+ 
+    lptr->dq_id = id;
+    lptr->dq_btime = lptr->dq_itime = (time_t) 0;
+    lptr->dq_flags |= DQ_LOCKED; /* lock it right away */
+ 
+    /*
+     * Stuff it in at front of the dquot list.
+     */
+    lptr->next = device->dq_quota;
+    device->dq_quota = lptr;
+ 
+    return (lptr);
+ }
+ 
+ static void remove_dquot(struct device_list * device, int id, int type)
+ {
+    register struct dquot *lptr, *tmp;
+ 
+    /*
+     * Remove fast lookup references.
+     */
+    if (mru_dquot[type] != (struct dquot *) 0 && mru_dquot[type]->dq_id == id)
+       mru_dquot[type] = (struct dquot *) 0;
+ 
+    lptr = device->dq_quota;
+    if (lptr->dq_id == id)
+       device->dq_quota = lptr->next;
+    else {
+       while (lptr->next != (struct dquot *) 0) {
+          if (lptr->next->dq_id == id)
+             break;
+          lptr = lptr->next;
+       }
+ 
+       tmp = lptr->next;
+       lptr->next = lptr->next->next;
+       lptr = tmp;
+    }
+ 
+    kfree_s(lptr, sizeof(struct dquot));
+ }
+ 
+ /*
+  * Check quota for inodes. Returns QUOTA_OK if can allocate and
+  * NO_QUOTA if it can't.
+  */
+ static int check_idq(struct device_list * device, struct dquot * dquot,
+                      int id, int type, u_long wanted_inodes)
+ {
+    static char message[MAX_QUOTA_MESSAGE];
+ 
+    if (wanted_inodes == 0 ||
+       (dquot->dq_isoftlimit == 0 && dquot->dq_ihardlimit == 0))
+       return QUOTA_OK;
+ 
+    if (dquot->dq_ihardlimit &&
+       (dquot->dq_curinodes + wanted_inodes) >= dquot->dq_ihardlimit) {
+       if ((dquot->dq_flags & DQ_INODES) == 0) {
+          sprintf(message,
+                 "File LIMIT reached on device (%d,%d) for %s %d. !! NO MORE !!\n\r",
+                 major(device->dq_dev), minor(device->dq_dev),
+                 typetoname(type), id);
+          quota_message(message);
+          dquot->dq_flags &= DQ_INODES;
+       }
+       return NO_QUOTA;
+    }
+ 
+    if (dquot->dq_isoftlimit &&
+       (dquot->dq_curinodes + wanted_inodes) >= dquot->dq_isoftlimit &&
+        dquot->dq_itime && CURRENT_TIME >= dquot->dq_itime) {
+       sprintf(message,
+               "File QUOTA exceeded TOO long on device (%d,%d) for %s %d. !! NO MORE !!\n\r",
+               major(device->dq_dev), minor(device->dq_dev),
+               typetoname(type), id);
+       quota_message(message);
+       return NO_QUOTA;
+    }
+ 
+    if (dquot->dq_isoftlimit &&
+       (dquot->dq_curinodes + wanted_inodes) >= dquot->dq_isoftlimit &&
+        dquot->dq_itime == 0) {
+       sprintf(message,
+               "File QUOTA exceeded on device (%d,%d) for %s %d\n\r",
+               major(device->dq_dev), minor(device->dq_dev),
+               typetoname(type), id);
+       quota_message(message);
+       dquot->dq_itime = CURRENT_TIME + device->dq_iexp;
+    }
+ 
+    return QUOTA_OK;
+    /* NOTREACHED */
+ }
+ 
+ /*
+  * Check quota for blocks. Returns QUOTA_OK if can allocate and
+  * NO_QUOTA if it can't. When we can't allocate wanted_blocks you get
+  * the number we can allocate in avail_blocks.
+  */
+ static int check_bdq(struct device_list * device, struct dquot * dquot, int id,
+                      int type, u_long wanted_blocks, u_long *avail_blocks)
+ {
+    static char message[MAX_QUOTA_MESSAGE];
+ 
+    if (wanted_blocks == 0 ||
+       (dquot->dq_bsoftlimit == 0 && dquot->dq_bhardlimit == 0))
+       return QUOTA_OK;
+ 
+    if (dquot->dq_bhardlimit &&
+       (dquot->dq_curblocks + wanted_blocks) >= dquot->dq_bhardlimit) {
+       if ((dquot->dq_flags & DQ_BLKS) == 0) {
+          sprintf(message,
+                  "Block LIMIT reached on device (%d,%d) for %s %d. !! NO MORE !!\n\r",
+                  major(device->dq_dev), minor(device->dq_dev),
+                  typetoname(type), id);
+          quota_message(message);
+          dquot->dq_flags &= DQ_BLKS;
+       }
+       if (dquot->dq_curblocks != dquot->dq_bhardlimit) {
+          *avail_blocks = dquot->dq_bhardlimit - dquot->dq_curblocks;
+          return QUOTA_OK;
+       } else
+          return NO_QUOTA;
+    }
+ 
+    if (dquot->dq_bsoftlimit &&
+       (dquot->dq_curblocks + wanted_blocks) >= dquot->dq_bsoftlimit &&
+        dquot->dq_btime && CURRENT_TIME >= dquot->dq_btime) {
+       sprintf(message,
+               "Block QUOTA exceeded TOO long on device (%d,%d) for %s %d. !! NO MORE !!\n\r",
+               major(device->dq_dev), minor(device->dq_dev),
+               typetoname(type), id);
+          quota_message(message);
+       return NO_QUOTA;
+    }
+ 
+    if (dquot->dq_bsoftlimit &&
+       (dquot->dq_curblocks + wanted_blocks) >= dquot->dq_bsoftlimit &&
+        dquot->dq_btime == 0) {
+       sprintf(message,
+               "Block QUOTA exceeded on (%d,%d) for %s %d\n\r",
+               major(device->dq_dev), minor(device->dq_dev),
+               typetoname(type), id);
+       quota_message(message);
+       dquot->dq_btime = CURRENT_TIME + device->dq_bexp;
+    }
+ 
+    *avail_blocks = wanted_blocks;
+    return QUOTA_OK;
+    /* NOTREACHED */
+ }
+ 
+ /*
+  * Remove inodes from a quota. Resets grace times if we go below
+  * inode softlimit.
+  */
+ static void remove_idq(struct dquot * dquot, u_long inodes)
+ {
+    if (dquot->dq_curinodes >= inodes)
+       dquot->dq_curinodes -= inodes;
+    else
+       dquot->dq_curinodes = 0;
+ 
+    if (dquot->dq_curinodes < dquot->dq_isoftlimit) {
+       dquot->dq_itime = (time_t) 0;
+       dquot->dq_flags &= ~DQ_INODES;
+    }
+    dquot->dq_flags |= DQ_MOD;
+ }
+ 
+ /*
+  * Remove blocks from a quota. Resets grace times if we go below
+  * block softlimit.
+  */
+ static void remove_bdq(struct dquot * dquot, u_long blocks)
+ {
+    if (dquot->dq_curblocks >= blocks)
+       dquot->dq_curblocks -= blocks;
+    else
+       dquot->dq_curblocks = 0;
+ 
+    if (dquot->dq_curblocks < dquot->dq_bhardlimit) {
+       dquot->dq_btime = (time_t) 0;
+       dquot->dq_flags &= ~DQ_BLKS;
+    }
+    dquot->dq_flags |= DQ_MOD;
+ }
+ 
+ /*
+  * Realy sync the quota info to the quota file.
+  */
+ static int sync_device(struct device_list * device, int type)
+ {
+    register struct dquot *dquot = (struct dquot *) 0;
+    struct dqblk exp_times;
+    unsigned short fs;
+ 
+    if (device->dq_dirt == 0)
+       return 0;
+ 
+    if (!device->dq_file.f_op->write)
+       return -EIO;
+ 
+    fs = get_fs();
+ 
+    /* First write expire times */
+    memset(&exp_times, 0, sizeof(struct dqblk));
+    exp_times.dqb_itime = device->dq_iexp;
+    exp_times.dqb_btime = device->dq_bexp;
+ 
+    /*
+     * Seek to absolute begin point of quota file.
+     */
+    if (device->dq_file.f_op->lseek) {
+       if (device->dq_file.f_op->lseek(device->dq_file.f_inode,
+                                       &device->dq_file, 0, 0) != 0)
+          goto end_sync;
+    } else
+       device->dq_file.f_pos = 0;
+ 
+    set_fs(KERNEL_DS);
+    if (device->dq_file.f_op->write(device->dq_file.f_inode, &device->dq_file,
+        (char *)&exp_times, sizeof(struct dqblk)) != sizeof(struct dqblk))
+       goto end_sync;
+ 
+    /*
+     * Write out all quota-structs that are marked with DQ_MOD, those
+     * are modified since the last time the were written to disk.
+     */
+    dquot = device->dq_quota;
+    while (dquot != (struct dquot *)0) {
+       if (dquot->dq_flags & DQ_MOD) {
+          if (device->dq_file.f_op->lseek) {
+             if (device->dq_file.f_op->lseek(device->dq_file.f_inode,
+                                             &device->dq_file,
+                                             dqoff(dquot->dq_id), 0) !=
+                                             dqoff(dquot->dq_id))
+                goto end_sync;
+          } else
+             device->dq_file.f_pos = dqoff(dquot->dq_id);
+ 
+          if (device->dq_file.f_op->write(device->dq_file.f_inode,
+                                          &device->dq_file,
+                                          (char *) &dquot->dq_dqb,
+                                          sizeof(struct dqblk)) !=
+                                          sizeof(struct dqblk))
+             goto end_sync;
+          dquot->dq_flags &= ~DQ_MOD;
+       }
+       dquot = dquot->next;
+    }
+ 
+    set_fs(fs);
+    device->dq_dirt = 0;
+    return 0;
+ 
+ end_sync:
+    set_fs(fs);
+    return -EIO;
+ }
+ 
+ /*
+  * Initialize a dquot-struct with new quota info. This is used by the
+  * systemcall interface functions.
+  */ 
+ static int set_dqblk(struct device_list * device, int id, int type, int flags,
+                      struct dqblk *dqblk)
+ {
+    register struct dquot *dquot = (struct dquot *) 0;
+    struct dqblk dq_dqblk;
+    int error;
+ 
+    /* No quota enabled for users and groups below ID_NO_QUOTA */
+    if (id > 0 && id <= ID_NO_QUOTA)
+       return 0;
+ 
+    if (dqblk == (struct dqblk *)0)
+       return -EFAULT;
+ 
+    if (flags & QUOTA_SYSCALL) {
+       if ((error = verify_area(VERIFY_READ, dqblk, sizeof(struct dqblk))) != 0)
+          return error;
+       memcpy_fromfs(&dq_dqblk, dqblk, sizeof(struct dqblk));
+    } else {
+       memcpy(&dq_dqblk, dqblk, sizeof(struct dqblk));
+    }
+ 
+    /* set expiration times */
+    if (id == 0) {
+       device->dq_iexp = (dq_dqblk.dqb_itime) ? dq_dqblk.dqb_itime : MAX_IQ_TIME;
+       device->dq_bexp = (dq_dqblk.dqb_btime) ? dq_dqblk.dqb_btime : MAX_DQ_TIME;
+       device->dq_dirt = 1;
+       return 0;
+    }
+ 
+    dquot = lookup_dquot(device, id, type);
+    if (dq_dqblk.dqb_bhardlimit == 0 && dq_dqblk.dqb_bsoftlimit == 0 &&
+        dq_dqblk.dqb_ihardlimit == 0 && dq_dqblk.dqb_isoftlimit == 0) {
+       if (dquot == (struct dquot *) 0)
+          return 0; /* No quota set */
+ 
+       dquot->dq_flags |= DQ_REMOVE; /* sync and remove at the end */
+    }
+ 
+    if (dquot == (struct dquot *) 0)
+       if ((dquot = add_dquot(device, id)) == (struct dquot *) 0)
+          return -EUSERS;
+ 
+    if ((flags & SET_QUOTA) || (flags & SET_QLIMIT)) {
+       dquot->dq_bhardlimit = dq_dqblk.dqb_bhardlimit;
+       dquot->dq_bsoftlimit = dq_dqblk.dqb_bsoftlimit;
+       dquot->dq_ihardlimit = dq_dqblk.dqb_ihardlimit;
+       dquot->dq_isoftlimit = dq_dqblk.dqb_isoftlimit;
+       if ((flags & QUOTA_SYSCALL) == 0) {
+          dquot->dq_btime = dq_dqblk.dqb_btime;
+          dquot->dq_itime = dq_dqblk.dqb_itime;
+       }
+    }
+ 
+    if ((flags & SET_QUOTA) || (flags & SET_USE)) {
+       dquot->dq_curblocks = dq_dqblk.dqb_curblocks;
+       dquot->dq_curinodes = dq_dqblk.dqb_curinodes;
+       if (dquot->dq_btime && dquot->dq_curblocks < dquot->dq_bsoftlimit)
+          dquot->dq_btime = (time_t) 0;
+       if (dquot->dq_itime && dquot->dq_curinodes < dquot->dq_isoftlimit)
+          dquot->dq_itime = (time_t) 0;
+    }
+ 
+    device->dq_dirt = 1;
+    dquot->dq_flags |= DQ_MOD;
+ 
+    if (dquot->dq_flags & DQ_REMOVE) {
+       sync_device(device, type);
+       remove_dquot(device, id, type);
+    } else
+       unlock_dquot(dquot);
+ 
+    return 0;
+ }
+ 
+ /*
+  * ====================== Entry points of module ======================
+  * All functions under this line are callable from within the kernel.
+  */
+ 
+ /*
+  * This are two simple algorithms that calculates the size of a file in blocks
+  * and from a number of blocks to a isize.
+  * It is not perfect but works most of the time.
+  */
+ u_long isize_to_blocks(size_t isize, size_t blksize)
+ {
+    u_long blocks;
+    u_long indirect;
+ 
+    if (!blksize)
+       blksize = BLOCK_SIZE;
+ 
+    blocks = (isize / blksize) + ((isize % blksize) ? 1 : 0);
+    if (blocks > 10) {
+       indirect = ((blocks - 11) >> 8) + 1; /* single indirect blocks */
+       if (blocks > (10 + 256)) {
+          indirect += ((blocks - 267) >> 16) + 1; /* double indirect blocks */
+          if (blocks > (10 + 256 + (256 << 8)))
+             indirect++; /* triple indirect blocks */
+       }
+       blocks += indirect;
+    }
+    return blocks;
+ }
+ 
+ /*
+  * And this works the other way around to calculate the inodesize
+  * of a file if it may consume a certain number of blocks.
+  */ 
+ size_t blocks_to_isize(u_long blocks, size_t blksize)
+ {
+    size_t isize;
+    u_long indirect;
+ 
+    if (!blksize)
+       blksize = BLOCK_SIZE;
+ 
+    isize = blocks * blksize;
+    if (blocks > 10) {
+       indirect = ((blocks - 11) >> 8) + 1; /* single indirect blocks */
+       if (blocks > (10 + 256)) {
+          indirect += ((blocks - 267) >> 16) + 1; /* double indirect blocks */
+          if (blocks > (10 + 256 + (256 << 8)))
+             indirect++; /* triple indirect blocks */
+       }
+       isize -= indirect * blksize;
+    }
+    return isize;
+ }
+ 
+ /*
+  * Allocate the number of inodes and blocks from a diskquota.
+  */
+ int quota_alloc(dev_t dev, uid_t uid, gid_t gid, u_long wanted_inodes,
+                 u_long wanted_blocks, u_long *avail_blocks)
+ {
+    u_long availblocks = 0, usr_avail = 0, grp_avail = 0;
+    struct device_list *usr_device = (struct device_list *) 0,
+                       *grp_device = (struct device_list *) 0;
+    struct dquot *usr_dquot = (struct dquot *) 0,
+                 *grp_dquot = (struct dquot *) 0;
+ 
+    availblocks = wanted_blocks;
+    if (wanted_inodes > 0 || wanted_blocks > 0) {
+       if ((usr_device = lookup_device(dev, USRQUOTA)) !=
+           (struct device_list *)0) {
+          if ((usr_dquot = lookup_dquot(usr_device, uid, USRQUOTA)) !=
+              (struct dquot *) 0) {
+             if (check_idq(usr_device, usr_dquot, uid, USRQUOTA,
+                           wanted_inodes) == NO_QUOTA ||
+                 check_bdq(usr_device, usr_dquot, uid, USRQUOTA,
+                           wanted_blocks, &usr_avail) == NO_QUOTA) {
+                unlock_dquot(usr_dquot);
+                return NO_QUOTA;
+             }
+             availblocks = usr_avail;
+          }
+       }
+ 
+       if ((grp_device = lookup_device(dev, GRPQUOTA)) !=
+           (struct device_list *)0) {
+          if ((grp_dquot = lookup_dquot(grp_device, gid, GRPQUOTA)) !=
+              (struct dquot *) 0) {
+             if (check_idq(grp_device, grp_dquot, gid, GRPQUOTA,
+                           wanted_inodes) == NO_QUOTA ||
+                 check_bdq(grp_device, grp_dquot, gid, GRPQUOTA,
+                           wanted_blocks, &grp_avail) == NO_QUOTA) {
+                unlock_dquot(usr_dquot);
+                unlock_dquot(grp_dquot);
+                return NO_QUOTA;
+             }
+             availblocks = (usr_avail == 0) ? grp_avail : \
+                           min(usr_avail, grp_avail);
+          }
+       }
+ 
+       /* Have exclusive lock on both quotas if needed and can allocate */
+       if (usr_dquot != (struct dquot *) 0) {
+          usr_dquot->dq_curinodes += wanted_inodes;
+          usr_dquot->dq_curblocks += availblocks;
+          usr_dquot->dq_flags |= DQ_MOD;
+          unlock_dquot(usr_dquot);
+          usr_device->dq_dirt = 1;
+       }
+ 
+       if (grp_dquot != (struct dquot *) 0) {
+          grp_dquot->dq_curinodes += wanted_inodes;
+          grp_dquot->dq_curblocks += availblocks;
+          grp_dquot->dq_flags |= DQ_MOD;
+          unlock_dquot(grp_dquot);
+          grp_device->dq_dirt = 1;
+       }
+    }
+ 
+    if (avail_blocks != (u_long *)0)
+       *avail_blocks = availblocks;
+ 
+    return QUOTA_OK;
+    /* NOTREACHED */
+ }
+ 
+ /*
+  * Transfer the number of inode and blocks from one diskquota to an other.
+  */
+ int quota_transfer(dev_t dev, uid_t olduid, uid_t newuid, gid_t oldgid,
+                    gid_t newgid, u_long inodes, u_long blocks)
+ {
+    u_long availblocks = 0;
+    struct device_list *usr_device = (struct device_list *) 0,
+                       *grp_device = (struct device_list *) 0;
+    struct dquot *old_usr_dquot = (struct dquot *) 0,
+                 *new_usr_dquot = (struct dquot *) 0,
+                 *old_grp_dquot = (struct dquot *) 0,
+                 *new_grp_dquot = (struct dquot *) 0;
+ 
+    if (olduid != newuid && (usr_device = lookup_device(dev, USRQUOTA)) !=
+       (struct device_list *)0) {
+       if ((new_usr_dquot = lookup_dquot(usr_device, newuid, USRQUOTA)) !=
+           (struct dquot *) 0) {
+          if (check_idq(usr_device, new_usr_dquot, newuid, USRQUOTA,
+                        inodes) == NO_QUOTA ||
+              check_bdq(usr_device, new_usr_dquot, newuid, USRQUOTA,
+                        blocks, &availblocks) == NO_QUOTA ||
+              availblocks != blocks) {
+             unlock_dquot(new_usr_dquot);
+             return NO_QUOTA;
+          }
+       }
+    }
+ 
+    if (oldgid != newgid && (grp_device = lookup_device(dev, GRPQUOTA)) !=
+       (struct device_list *)0) {
+       if ((new_grp_dquot = lookup_dquot(grp_device, newgid, GRPQUOTA)) !=
+           (struct dquot *) 0) {
+          if (check_idq(grp_device, new_grp_dquot, newgid,
+                        GRPQUOTA, inodes) == NO_QUOTA ||
+              check_bdq(grp_device, new_grp_dquot, newgid, GRPQUOTA,
+                        blocks, &availblocks) == NO_QUOTA ||
+              availblocks != blocks) {
+             unlock_dquot(new_usr_dquot);
+             unlock_dquot(new_grp_dquot);
+             return NO_QUOTA;
+          }
+       }
+    }
+ 
+    /* Have exclusive lock on both quotas if needed and can allocate */
+    if (olduid != newuid && usr_device != (struct device_list *)0) {
+       if ((old_usr_dquot = lookup_dquot(usr_device, olduid, USRQUOTA)) !=
+           (struct dquot *) 0) {
+          /* Remove it from old */
+          if (inodes)
+             remove_idq(old_usr_dquot, inodes);
+          if (blocks)
+             remove_bdq(old_usr_dquot, blocks);
+          unlock_dquot(old_usr_dquot);
+       }
+ 
+       /* Move it to new diskquota */
+       if (new_usr_dquot != (struct dquot *)0) {
+          new_usr_dquot->dq_curinodes += inodes;
+          new_usr_dquot->dq_curblocks += blocks;
+          new_usr_dquot->dq_flags |= DQ_MOD;
+          unlock_dquot(new_usr_dquot);
+       }
+       usr_device->dq_dirt = 1;
+    }
+    
+ 
+    if (oldgid != newgid && grp_device != (struct device_list *)0) {
+       if ((old_grp_dquot = lookup_dquot(grp_device, oldgid, GRPQUOTA)) !=
+           (struct dquot *) 0) {
+          /* Remove it from old */
+          if (inodes)
+             remove_idq(old_grp_dquot, inodes);
+          if (blocks)
+             remove_bdq(old_grp_dquot, blocks);
+          unlock_dquot(old_grp_dquot);
+       }
+ 
+       /* Move it to new diskquota */
+       if (new_grp_dquot != (struct dquot *) 0) {
+          new_grp_dquot->dq_curinodes += inodes;
+          new_grp_dquot->dq_curblocks += blocks;
+          new_grp_dquot->dq_flags |= DQ_MOD;
+          unlock_dquot(new_grp_dquot);
+       }
+       grp_device->dq_dirt = 1;
+    }
+    return QUOTA_OK;
+    /* NOTREACHED */
+ }
+ 
+ /*
+  * Remove the number of inodes and blocks from a diskquota.
+  */
+ void quota_remove(dev_t dev, uid_t uid, gid_t gid, u_long inodes, u_long blocks
+ )
+ {
+    struct device_list *usr_device, *grp_device;
+    struct dquot *usr_dquot, *grp_dquot;
+ 
+    if (inodes > 0 || blocks > 0) {
+       if ((usr_device = lookup_device(dev, USRQUOTA)) !=
+           (struct device_list *)0) {
+          if ((usr_dquot = lookup_dquot(usr_device, uid, USRQUOTA)) !=
+              (struct dquot *) 0) {
+             if (inodes)
+                remove_idq(usr_dquot, inodes);
+             if (blocks)
+                remove_bdq(usr_dquot, blocks);
+             unlock_dquot(usr_dquot);
+             usr_device->dq_dirt = 1;
+          }
+       }
+ 
+       if ((grp_device = lookup_device(dev, GRPQUOTA)) !=
+           (struct device_list *)0) {
+          if ((grp_dquot = lookup_dquot(grp_device, gid, GRPQUOTA)) !=
+              (struct dquot *) 0) {
+             if (inodes)
+                remove_idq(grp_dquot, inodes);
+             if (blocks)
+                remove_bdq(grp_dquot, blocks);
+             unlock_dquot(grp_dquot);
+             grp_device->dq_dirt = 1;
+          }
+       }
+    }
+ }
+ 
+ /*
+  * Following functions used by systemcall interface don't use it your self !!
+  */
+ int set_quota(dev_t dev, int id, int type, struct dqblk * dqblk)
+ {
+    register struct device_list *device;
+ 
+    if ((device = lookup_device(dev, type)) != (struct device_list *) 0)
+       return set_dqblk(device, id, type, SET_QUOTA | QUOTA_SYSCALL, dqblk);
+    else
+       return -ESRCH;
+ }
+ 
+ int set_use(dev_t dev, int id, int type, struct dqblk * dqblk)
+ {
+    register struct device_list *device;
+ 
+    if ((device = lookup_device(dev, type)) != (struct device_list *) 0)
+       return set_dqblk(device, id, type, SET_USE | QUOTA_SYSCALL, dqblk);
+    else
+       return -ESRCH;
+ }
+ 
+ int set_qlimit(dev_t dev, int id, int type, struct dqblk * dqblk)
+ {
+    register struct device_list *device;
+ 
+    if ((device = lookup_device(dev, type)) != (struct device_list *) 0)
+       return set_dqblk(device, id, type, SET_QLIMIT | QUOTA_SYSCALL, dqblk);
+    else
+       return -ESRCH;
+ }
+ 
+ int get_quota(dev_t dev, int id, int type, struct dqblk * dqblk)
+ {
+    register struct device_list *device;
+    register struct dquot *dquot;
+    struct dqblk exp_times;
+    int error;
+ 
+    if ((device = lookup_device(dev, type)) != (struct device_list *) 0) {
+       if (dqblk == (struct dqblk *) 0)
+          return -EFAULT;
+ 
+       if ((error = verify_area(VERIFY_WRITE, dqblk, sizeof(struct dqblk))) != 0)
+          return (error);
+ 
+       if (id > ID_NO_QUOTA &&
+          (dquot = lookup_dquot(device, id, type)) != (struct dquot *) 0) {
+          memcpy_tofs(dqblk, (char *) &dquot->dq_dqb, sizeof(struct dqblk));
+          unlock_dquot(dquot);
+          return 0;
+       } else {
+          if (id == 0) {
+             /*
+              * Special case for getting of expiration times.
+              */
+             memset(&exp_times, 0, sizeof(struct dqblk));
+             exp_times.dqb_btime = device->dq_iexp;
+             exp_times.dqb_itime = device->dq_bexp;
+             memcpy_tofs(dqblk, &exp_times, sizeof(struct dqblk));
+             return 0;
+          }
+          return -ESRCH;
+       }
+    } else
+       return -ESRCH;
+ }
+ 
+ /*
+  * Sync quota on a device. Dev == 0 ==> sync all quotafiles.
+  * Type == -1 ==> sync all types.
+  */
+ int sync_quota(dev_t dev, int type)
+ {
+    register struct device_list *device;
+    int cnt, retval = 0;
+ 
+    if (dev) {
+       if (type != -1) {
+          if ((device = lookup_device(dev, type)) == (struct device_list *) 0)
+             return -ESRCH;
+          return sync_device(device, type);
+       } else {
+          for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+             if ((device = lookup_device(dev, cnt)) == (struct device_list *) 0)
+                continue;
+             retval |= sync_device(device, cnt);
+          }
+          return retval;
+       }
+    } else {
+       for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+          device = devicelist[cnt];
+          while (device != (struct device_list *) 0) {
+             retval |= sync_device(device, cnt);
+             device = device->next;
+          }
+       }
+       return retval;
+    }
+    /* NOTREACHED */
+ }
+ 
+ /*
+  * Turn quota off on a device. type == -1 ==> quotaoff for all types (umount)
+  */
+ int quota_off(dev_t dev, int type)
+ {
+    register struct device_list *device;
+    register struct inode *inode = (struct inode *) 0;
+    int cnt;
+ 
+    if (type != -1) {
+       if ((device = lookup_device(dev, type)) == (struct device_list *) 0)
+          return -ESRCH;
+ 
+       if (!device_can_be_removed(device))
+          return -EBUSY;
+ 
+       (void) sync_device(device, type);   /* Yes, just like Q_SYNC... */
+ 
+       if (device->dq_file.f_op->release)
+          device->dq_file.f_op->release(device->dq_file.f_inode,
+                                        &device->dq_file);
+ 
+       if ((inode = device->dq_file.f_inode) != (struct inode *) 0)
+          iput(device->dq_file.f_inode);   /* Now release the inode */
+ 
+       remove_device(dev, type);
+    } else {
+       for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+          if ((device = lookup_device(dev, cnt)) == (struct device_list *) 0)
+             continue;
+ 
+          if (!device_can_be_removed(device))
+             return -EBUSY;
+ 
+          (void) sync_device(device, cnt);   /* Yes, just like Q_SYNC... */
+ 
+          if (device->dq_file.f_op->release)
+             device->dq_file.f_op->release(device->dq_file.f_inode,
+                                           &device->dq_file);
+ 
+          if ((inode = device->dq_file.f_inode) != (struct inode *) 0)
+             iput(device->dq_file.f_inode);   /* Now release the inode */
+ 
+          remove_device(dev, cnt);
+       }
+    }
+    return 0;
+ }
+ 
+ int quota_on(dev_t dev, int type, char *path)
+ {
+    register struct device_list *device;
+    struct dqblk dq_dqb;
+    struct inode *inode;
+    char *tmp;
+    int error, maxid, id = ID_NO_QUOTA;
+    unsigned short  fs;
+ 
+    /* Quota already enabled */
+    if ((device = lookup_device(dev, type)) != (struct device_list *) 0)
+       return -EBUSY;
+ 
+    if ((error = getname(path, &tmp)) != 0)
+       return (error);
+ 
+    error = open_namei(tmp, O_RDWR, 0600, &inode, 0);
+    putname(tmp);
+ 
+    if (error)
+       return (error);
+ 
+    if (!S_ISREG(inode->i_mode) || inode->i_dev != dev) {
+       iput(inode);
+       return -EACCES;
+    }
+ 
+    if ((device = add_device(dev, type)) == (struct device_list *) 0) {
+       iput(inode);
+       return -EUSERS;
+    }
+ 
+    fs = get_fs();
+    if (!inode->i_op || !inode->i_op->default_file_ops)
+       goto end_quotaon;
+ 
+    device->dq_file.f_mode = 3;
+    device->dq_file.f_flags = 0;
+    device->dq_file.f_count = 1;
+    device->dq_file.f_inode = inode;
+    device->dq_file.f_pos = 0;
+    device->dq_file.f_reada = 0;
+    device->dq_file.f_op = inode->i_op->default_file_ops;
+ 
+    if (device->dq_file.f_op->open)
+       if (device->dq_file.f_op->open(device->dq_file.f_inode, &device->dq_file))
+          goto end_quotaon;
+ 
+    if (!device->dq_file.f_op->read)
+       goto end_quotaon;
+ 
+    maxid = inode->i_size / sizeof(struct dqblk);
+ 
+    set_fs(KERNEL_DS);
+ 
+    /* First read expire times */
+    if (device->dq_file.f_op->read(inode, &device->dq_file,
+        (char *)&dq_dqb, sizeof(struct dqblk)) != sizeof(struct dqblk))
+       goto end_quotaon;
+    set_dqblk(device, 0, type, SET_QUOTA, &dq_dqb);
+ 
+    /* Seek to first real entry */
+    if (device->dq_file.f_op->lseek) {
+       if (device->dq_file.f_op->lseek(inode, &device->dq_file,
+           dqoff(id), 0) != dqoff(id))
+          goto end_quotaon;
+    } else
+       device->dq_file.f_pos = dqoff(id);
+ 
+    while (id < maxid) {
+       if (device->dq_file.f_op->read(inode, &device->dq_file, (char *)&dq_dqb,
+           sizeof(struct dqblk)) != sizeof(struct dqblk))
+          goto end_quotaon;
+       set_dqblk(device, id++, type, SET_QUOTA, &dq_dqb);
+    }
+    set_fs(fs);
+ 
+    return 0;
+ 
+ end_quotaon:
+    set_fs(fs);
+    iput(inode);
+    remove_device(device->dq_dev, type);
+    return -EIO;
+ }
+ 
+ void quota_init(void)
+ {
+    unsigned short  cnt;
+ 
+    for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+       devicelist[cnt] = (struct device_list *) 0;
+       mru_dquot[cnt] = (struct dquot *) 0;
+       mru_device[cnt] = (struct device_list *) 0;
+    }
+ }
+ 
+ asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t * addr)
+ {
+    int cmds = 0, type = 0;
+    struct inode *ino;
+    dev_t dev;
+ 
+    cmds = cmd >> SUBCMDSHIFT;
+    type = cmd & SUBCMDMASK;
+    switch (cmds) {
+       case Q_GETQUOTA:
+       case Q_SYNC:
+          if (((type == USRQUOTA && current->uid != id) ||
+               (type == GRPQUOTA && current->gid != id)) && !suser())
+             return -EPERM;
+       default:
+          if (!suser())
+             return -EPERM;
+    }
+ 
+    if (special == (char *)0 && cmds == Q_SYNC)
+       dev = 0;
+    else {
+       if (namei(special, &ino))
+          return -EINVAL;
+       dev = ino->i_rdev;
+       if (!S_ISBLK(ino->i_mode)) {
+          iput(ino);
+          return -ENOTBLK;
+       }
+       iput(ino);
+    }
+ 
+    if ((u_int) type >= MAXQUOTAS)
+       return -EINVAL;
+ 
+    switch (cmds) {
+       case Q_QUOTAON:
+          return quota_on(dev, type, (char *) addr);
+       case Q_QUOTAOFF:
+          return quota_off(dev, type);
+       case Q_GETQUOTA:
+          return get_quota(dev, id, type, (struct dqblk *) addr);
+       case Q_SETQUOTA:
+          return set_quota(dev, id, type, (struct dqblk *) addr);
+       case Q_SETUSE:
+          return set_use(dev, id, type, (struct dqblk *) addr);
+       case Q_SETQLIM:
+          return set_qlimit(dev, id, type, (struct dqblk *) addr);
+       case Q_SYNC:
+          return sync_quota(dev, type);
+       default:
+          return -EINVAL;
+    }
+    /* NOTREACHED */
+ }
+ 
+ #else
+ 
+ asmlinkage int sys_quotactl(int cmd, const char *special, int id, char *addr)
+ {
+    return -EINVAL;
+ }
+ 
+ #endif /* CONFIG_QUOTA */
+ 
diff -rc --new-file linux-0.99.13/fs/read_write.c linux/fs/read_write.c
*** linux-0.99.13/fs/read_write.c	Sat Sep 25 12:09:54 1993
--- linux/fs/read_write.c	Sat Sep 25 13:01:39 1993
***************
*** 9,14 ****
--- 9,18 ----
  #include <linux/stat.h>
  #include <linux/kernel.h>
  #include <linux/sched.h>
+ #include <linux/config.h>
+ #ifdef CONFIG_QUOTA
+ #include <linux/quota.h>
+ #endif
  
  #include <asm/segment.h>
  
***************
*** 92,97 ****
--- 96,106 ----
  	int error;
  	struct file * file;
  	struct inode * inode;
+ #ifdef CONFIG_QUOTA
+ 	size_t oldisize = 0;
+ 	int written;
+         u_long cur_blocks, wanted_blocks, avail_blocks;
+ #endif
  	
  	if (fd>=NR_OPEN || !(file=current->filp[fd]) || !(inode=file->f_inode))
  		return -EBADF;
***************
*** 104,108 ****
--- 113,139 ----
  	error = verify_area(VERIFY_READ,buf,count);
  	if (error)
  		return error;
+ #ifdef CONFIG_QUOTA
+ 	if (S_ISREG(inode->i_mode)) {
+ 	   if (file->f_pos + count > inode->i_size) {
+               cur_blocks = isize_to_blocks(inode->i_size, inode->i_blksize);
+               wanted_blocks = isize_to_blocks((file->f_pos + count),
+ 	                                      inode->i_blksize) - cur_blocks;
+ 	      if (quota_alloc(inode->i_dev, inode->i_uid, inode->i_gid, 0,
+                               wanted_blocks, &avail_blocks) == NO_QUOTA)
+ 	         return -EDQUOT;
+ 	      if (avail_blocks < wanted_blocks)
+ 	         count = blocks_to_isize((cur_blocks + avail_blocks),
+ 	                                 inode->i_blksize) - file->f_pos;
+ 	      oldisize = inode->i_size;
+ 	      if ((written = file->f_op->write(inode,file,buf,count)) != count)
+ 	         quota_remove(inode->i_dev, inode->i_uid, inode->i_gid, 0, avail_blocks -
+ 	                     (isize_to_blocks(inode->i_size, inode->i_blksize) -
+ 	                      isize_to_blocks(oldisize, inode->i_blksize)));
+ 	      return (wanted_blocks == avail_blocks) ? written : -EDQUOT;
+            }
+ 	}
+ #endif
  	return file->f_op->write(inode,file,buf,count);
  }
+ 
diff -rc --new-file linux-0.99.13/fs/super.c linux/fs/super.c
*** linux-0.99.13/fs/super.c	Sat Sep 25 12:09:54 1993
--- linux/fs/super.c	Sat Sep 25 13:01:39 1993
***************
*** 14,19 ****
--- 14,22 ----
  #include <linux/errno.h>
  #include <linux/string.h>
  #include <linux/locks.h>
+ #ifdef CONFIG_QUOTA
+ #include <linux/quota.h>
+ #endif
  
  #include <asm/system.h>
  #include <asm/segment.h>
***************
*** 214,219 ****
--- 217,225 ----
  		}
  		return 0;
  	}
+ #ifdef CONFIG_QUOTA
+ 	quota_off(dev, -1); /* Turn off all quotas first */
+ #endif
  	if (!(sb=get_super(dev)) || !(sb->s_covered))
  		return -ENOENT;
  	if (!sb->s_covered->i_mount)
diff -rc --new-file linux-0.99.13/include/linux/acct.h linux/include/linux/acct.h
*** linux-0.99.13/include/linux/acct.h
--- linux/include/linux/acct.h	Sat Sep 25 13:03:29 1993
***************
*** 0 ****
--- 1,29 ----
+ #ifndef __LINUX_ACCT_H
+ #define __LINUX_ACCT_H
+ 
+ #define ACCT_COMM 16
+ 
+ struct acct
+ {
+ 	char	ac_comm[ACCT_COMM];	/* Accounting command name */
+ 	time_t	ac_utime;		/* Accounting user time */
+ 	time_t	ac_stime;		/* Accounting system time */
+ 	time_t	ac_etime;		/* Accounting elapsed time */
+ 	time_t	ac_btime;		/* Beginning time */
+ 	uid_t	ac_uid;			/* Accounting user ID */
+ 	gid_t	ac_gid;			/* Accounting group ID */
+ 	dev_t	ac_tty;			/* controlling tty */
+ 	char	ac_flag;		/* Accounting flag */
+ 	long	ac_minflt;		/* Accounting minor pagefaults */
+ 	long	ac_majflt;		/* Accounting major pagefaults */
+ 	long	ac_exitcode;		/* Accounting process exitcode */
+ };
+ 
+ #define AFORK	0001	/* has executed fork, but no exec */
+ #define ASU	0002	/* used super-user privileges */
+ #define ACORE	0004	/* dumped core */
+ #define AXSIG	0010	/* killed by a signal */
+ 
+ #define AHZ     100
+ 
+ #endif
diff -rc --new-file linux-0.99.13/include/linux/kernel.h linux/include/linux/kernel.h
*** linux-0.99.13/include/linux/kernel.h	Sat Sep 25 12:10:00 1993
--- linux/include/linux/kernel.h	Sat Sep 25 13:02:23 1993
***************
*** 53,69 ****
  #define kcheck(x) kcheck_s((x), 0)
  
  #endif
- 
- 
- /*
-  * This is defined as a macro, but at some point this might become a
-  * real subroutine that sets a flag if it returns true (to do
-  * BSD-style accounting where the process is flagged if it uses root
-  * privs).  The implication of this is that you should do normal
-  * permissions checks first, and check suser() last.
-  */
- #define suser() (current->euid == 0)
- 
  #endif /* __KERNEL__ */
  
  #define SI_LOAD_SHIFT	16
--- 53,58 ----
diff -rc --new-file linux-0.99.13/include/linux/quota.h linux/include/linux/quota.h
*** linux-0.99.13/include/linux/quota.h
--- linux/include/linux/quota.h	Sat Sep 25 13:03:54 1993
***************
*** 0 ****
--- 1,210 ----
+ /*
+  * Copyright (c) 1982, 1986 Regents of the University of California.
+  * All rights reserved.
+  *
+  * This code is derived from software contributed to Berkeley by
+  * Robert Elz at The University of Melbourne.
+  *
+  * Redistribution and use in source and binary forms, with or without
+  * modification, are permitted provided that the following conditions
+  * are met:
+  * 1. Redistributions of source code must retain the above copyright
+  *    notice, this list of conditions and the following disclaimer.
+  * 2. Redistributions in binary form must reproduce the above copyright
+  *    notice, this list of conditions and the following disclaimer in the
+  *    documentation and/or other materials provided with the distribution.
+  * 3. All advertising materials mentioning features or use of this software
+  *    must display the following acknowledgement:
+  *   This product includes software developed by the University of
+  *   California, Berkeley and its contributors.
+  * 4. Neither the name of the University nor the names of its contributors
+  *    may be used to endorse or promote products derived from this software
+  *    without specific prior written permission.
+  *
+  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+  * SUCH DAMAGE.
+  *
+  * Version: $Id: quota.h,v 1.3 1993/07/01 21:12:50 root Exp root $
+  */
+ 
+ #ifndef _LINUX_QUOTA_
+ #define _LINUX_QUOTA_
+ 
+ #include <linux/errno.h>
+ 
+ /*
+  * Convert diskblocks to blocks and the other way around.
+  * currently only to fool the BSD source. :-)
+  */
+ #define dbtob(num) (num << 10)
+ #define btodb(num) (num >> 10)
+ 
+ /*
+  * Some nice macros to determine min and max of two values
+  */
+ #define min(a,b) ((a) < (b)) ? (a) : (b)
+ #define max(a,b) ((a) > (b)) ? (a) : (b)
+ 
+ /*
+  * Definitions for disk quotas imposed on the average user
+  * (big brother finally hits UNIX).
+  *
+  * The following constants define the amount of time given a user
+  * before the soft limits are treated as hard limits (usually resulting
+  * in an allocation failure). The timer is started when the user crosses
+  * their soft limit, it is reset when they go below their soft limit.
+  */
+ #define MAX_IQ_TIME  604800 /* (7*24*60*60) 1 week */
+ #define MAX_DQ_TIME  604800 /* (7*24*60*60) 1 week */
+ 
+ #define MAXQUOTAS 2
+ #define USRQUOTA  0 /* element used for user quotas */
+ #define GRPQUOTA  1 /* element used for group quotas */
+ 
+ #define ID_NO_QUOTA 10 /* ids for which quota isn't enabled (<=)*/
+ 
+ /*
+  * Definitions for the default names of the quotas files.
+  */
+ #define INITQFNAMES { \
+    "user",      /* USRQUOTA */ \
+    "group",   /* GRPQUOTA */ \
+    "undefined", \
+ };
+ #define QUOTAFILENAME "quota"
+ #define QUOTAGROUP "staff"
+ 
+ /*
+  * Command definitions for the 'quotactl' system call.
+  * The commands are broken into a main command defined below
+  * and a subcommand that is used to convey the type of
+  * quota that is being manipulated (see above).
+  */
+ #define SUBCMDMASK  0x00ff
+ #define SUBCMDSHIFT 8
+ #define QCMD(cmd, type)  (((cmd) << SUBCMDSHIFT) | ((type) & SUBCMDMASK))
+ 
+ #define Q_QUOTAON  0x0100   /* enable quotas */
+ #define Q_QUOTAOFF 0x0200   /* disable quotas */
+ #define Q_GETQUOTA 0x0300   /* get limits and usage */
+ #define Q_SETQUOTA 0x0400   /* set limits and usage */
+ #define Q_SETUSE   0x0500   /* set usage */
+ #define Q_SYNC     0x0600   /* sync disk copy of a filesystems quotas */
+ #define Q_SETQLIM  0x0700   /* set limits */
+ 
+ /*
+  * The following structure defines the format of the disk quota file
+  * (as it appears on disk) - the file is an array of these structures
+  * indexed by user or group number.
+  */
+ struct dqblk {
+    u_long dqb_bhardlimit;   /* absolute limit on disk blks alloc */
+    u_long dqb_bsoftlimit;   /* preferred limit on disk blks */
+    u_long dqb_curblocks;    /* current block count */
+    u_long dqb_ihardlimit;   /* maximum # allocated inodes */
+    u_long dqb_isoftlimit;   /* preferred inode limit */
+    u_long dqb_curinodes;    /* current # allocated inodes */
+    time_t dqb_btime;        /* time limit for excessive disk use */
+    time_t dqb_itime;        /* time limit for excessive files */
+ };
+ 
+ /*
+  * Shorthand notation.
+  */
+ #define	dq_bhardlimit	dq_dqb.dqb_bhardlimit
+ #define	dq_bsoftlimit	dq_dqb.dqb_bsoftlimit
+ #define	dq_curblocks	dq_dqb.dqb_curblocks
+ #define	dq_ihardlimit	dq_dqb.dqb_ihardlimit
+ #define	dq_isoftlimit	dq_dqb.dqb_isoftlimit
+ #define	dq_curinodes	dq_dqb.dqb_curinodes
+ #define	dq_btime	dq_dqb.dqb_btime
+ #define	dq_itime	dq_dqb.dqb_itime
+ 
+ #define dqoff(UID)      ((off_t)((UID) * sizeof (struct dqblk)))
+ 
+ #ifdef __KERNEL__
+ 
+ #ifndef EDQUOT
+ #define EDQUOT  EROFS      /* Need some useful errno.. */
+ #endif
+ 
+ /*
+  * Maximum lenght of a message generated in the quota system,
+  * that needs to be kicked onto the tty.
+  */
+ #define MAX_QUOTA_MESSAGE 75
+ 
+ #include <linux/fs.h>
+ 
+ struct device_list {
+    dev_t               dq_dev;   /* device number */
+    char                dq_dirt;  /* quotas are updated since last write */
+    time_t              dq_iexp;  /* expiration time of inode softlimit */
+    time_t              dq_bexp;  /* expiration time of block softlimit */
+    struct file         dq_file;  /* filepointer to quotafile on the device */ 
+    struct dquot       *dq_quota; /* list of ids with quota on this device */
+    struct device_list *next;     /* pointer to next device */
+ };
+ 
+ #define DQ_LOCKED     0x01       /* locked for I/O */
+ #define DQ_WANT       0x02       /* wanted */
+ #define DQ_MOD        0x04       /* this quota modified since read */
+ #define DQ_BLKS       0x10       /* has been warned about blk limit */
+ #define DQ_INODES     0x20       /* has been warned about inode limit */
+ #define DQ_REMOVE     0x40       /* sync this dqblk and remove from list */
+ 
+ struct dquot {
+    int                dq_id;     /* id this applies to (uid, gid) */
+    short              dq_flags;  /* see DQ_* */
+    struct dqblk       dq_dqb;    /* diskquota for id */
+    struct wait_queue *dq_wait;   /* pointer to waitqueue */
+    struct dquot      *next;      /* pointer to next id */
+ };
+ 
+ /*
+  * Flags used for set_dqblk.
+  */
+ #define QUOTA_SYSCALL     0x01
+ #define SET_QUOTA         0x02
+ #define SET_USE           0x04
+ #define SET_QLIMIT        0x08
+ 
+ /*
+  * Return values when requesting quota.
+  */
+ #define NO_QUOTA 0  /* no more quota available */
+ #define QUOTA_OK 1  /* can allocate the space */
+ 
+ /*
+  * declaration of quota_function calls in kernel.
+  */
+ u_long isize_to_blocks(size_t isize, size_t blksize);
+ size_t blocks_to_isize(u_long blocks, size_t blksize);
+ int    quota_alloc(dev_t dev, uid_t uid, gid_t gid, u_long inodes,
+                    u_long wantedblocks, u_long *availblocks);
+ int    quota_transfer(dev_t dev, uid_t olduid, uid_t newuid, gid_t oldgid,
+                       gid_t newgid, u_long inodes, u_long blocks);
+ void   quota_remove(dev_t dev, uid_t uid, gid_t gid, u_long inodes,
+                     u_long blocks);
+ int    sync_quota(dev_t dev, int type);
+ int    quota_off(dev_t dev, int type);
+ 
+ #else
+ 
+ #include <sys/cdefs.h>
+ 
+ __BEGIN_DECLS
+ int   quotactl __P((int, const char *, int, caddr_t *));
+ __END_DECLS
+ 
+ #endif /* __KERNEL__ */
+ #endif /* _QUOTA_ */
diff -rc --new-file linux-0.99.13/include/linux/sched.h linux/include/linux/sched.h
*** linux-0.99.13/include/linux/sched.h	Sat Sep 25 12:10:00 1993
--- linux/include/linux/sched.h	Sat Sep 25 13:02:23 1993
***************
*** 229,234 ****
--- 229,238 ----
  					/* Not implemented yet, only for 486*/
  #define PF_PTRACED	0x00000010	/* set if ptrace (0) has been called. */
  #define PF_TRACESYS	0x00000020	/* tracing system calls */
+ #define PF_FORKNOEXEC	0x00000040	/* forked but didn't exec */
+ #define PF_SUPERPREV	0x00000100	/* used super-user privileges */
+ #define PF_DUMPCORE	0x00000200	/* dumped core */
+ #define PF_SIGNALED	0x00000400	/* killed by a signal */
  
  /*
   * cloning flags:
***************
*** 384,389 ****
--- 388,406 ----
  #define set_base(ldt,base) _set_base( ((char *)&(ldt)) , base )
  #define set_limit(ldt,limit) _set_limit( ((char *)&(ldt)) , (limit-1)>>12 )
  
+ /*
+  * This has now become a routine instead of a macro, it sets a flag if
+  * it returns true (to do BSD-style accounting where the process is flagged
+  * if it uses root privs). The implication of this is that you should do
+  * normal permissions checks first, and check suser() last.
+  */
+ extern inline int suser(void)
+ {
+ 	if (current->euid == 0)
+ 		current->flags |= PF_SUPERPREV;
+ 	return (current->euid == 0);
+ }
+ 
  /*
   * The wait-queues are circular lists, and you have to be *very* sure
   * to keep them correct. Use only these two functions to add/remove
diff -rc --new-file linux-0.99.13/include/linux/sys.h linux/include/linux/sys.h
*** linux-0.99.13/include/linux/sys.h	Sat Sep 25 12:10:00 1993
--- linux/include/linux/sys.h	Sat Sep 25 13:02:23 1993
***************
*** 132,137 ****
--- 132,138 ----
  extern int sys_olduname();
  extern int sys_old_syscall();
  extern int sys_modify_ldt();
+ extern int sys_quotactl();
  
  /*
   * These are system calls that will be removed at some time
***************
*** 170,176 ****
  sys_syslog, sys_setitimer, sys_getitimer, sys_newstat, sys_newlstat,
  sys_newfstat, sys_uname, sys_iopl, sys_vhangup, sys_idle, sys_vm86,
  sys_wait4, sys_swapoff, sys_sysinfo, sys_ipc, sys_fsync, sys_sigreturn,
! sys_clone, sys_setdomainname, sys_newuname, sys_modify_ldt};
  
  #ifdef __cplusplus
  }
--- 171,177 ----
  sys_syslog, sys_setitimer, sys_getitimer, sys_newstat, sys_newlstat,
  sys_newfstat, sys_uname, sys_iopl, sys_vhangup, sys_idle, sys_vm86,
  sys_wait4, sys_swapoff, sys_sysinfo, sys_ipc, sys_fsync, sys_sigreturn,
! sys_clone, sys_setdomainname, sys_newuname, sys_modify_ldt, sys_quotactl};
  
  #ifdef __cplusplus
  }
diff -rc --new-file linux-0.99.13/include/linux/unistd.h linux/include/linux/unistd.h
*** linux-0.99.13/include/linux/unistd.h	Sat Sep 25 12:10:00 1993
--- linux/include/linux/unistd.h	Sat Sep 25 13:02:23 1993
***************
*** 123,135 ****
  #define __NR_wait4		114
  #define __NR_swapoff		115
  #define __NR_sysinfo		116
! #define __NR_ipc		117	/* not implemented yet */
  #define __NR_fsync		118
  #define __NR_sigreturn		119
  #define __NR_clone		120
  #define __NR_setdomainname	121
  #define __NR_uname		122
  #define __NR_modify_ldt		123
  
  extern int errno;
  
--- 123,136 ----
  #define __NR_wait4		114
  #define __NR_swapoff		115
  #define __NR_sysinfo		116
! #define __NR_ipc		117
  #define __NR_fsync		118
  #define __NR_sigreturn		119
  #define __NR_clone		120
  #define __NR_setdomainname	121
  #define __NR_uname		122
  #define __NR_modify_ldt		123
+ #define __NR_quotactl		124
  
  extern int errno;
  
diff -rc --new-file linux-0.99.13/init/main.c linux/init/main.c
*** linux-0.99.13/init/main.c	Sat Sep 25 12:09:55 1993
--- linux/init/main.c	Sat Sep 25 13:02:23 1993
***************
*** 85,90 ****
--- 85,93 ----
  #ifdef CONFIG_SYSVIPC
  extern void ipc_init(void);
  #endif
+ #ifdef CONFIG_QUOTA
+ extern void quota_init(void);
+ #endif
  #ifdef CONFIG_SCSI
  extern unsigned long scsi_dev_init(unsigned long, unsigned long);
  #endif
***************
*** 387,392 ****
--- 390,398 ----
  #ifdef CONFIG_SYSVIPC
  	ipc_init();
  #endif
+ #ifdef CONFIG_QUOTA
+ 	quota_init();
+ #endif
  	sti();
  	calibrate_delay();
  	/*
diff -rc --new-file linux-0.99.13/kernel/exit.c linux/kernel/exit.c
*** linux-0.99.13/kernel/exit.c	Sat Sep 25 12:09:55 1993
--- linux/kernel/exit.c	Sat Sep 25 13:02:23 1993
***************
*** 18,23 ****
--- 18,24 ----
  #include <asm/segment.h>
  extern void shm_exit (void);
  extern void sem_exit (void);
+ extern void acct_process (long exitcode);
  
  int getrusage(struct task_struct *, int, struct rusage *);
  
***************
*** 353,358 ****
--- 354,360 ----
  	int i;
  
  fake_volatile:
+ 	acct_process(code);
  	if (current->semun)
  		sem_exit();
  	if (current->shm)
diff -rc --new-file linux-0.99.13/kernel/fork.c linux/kernel/fork.c
*** linux-0.99.13/kernel/fork.c	Sat Sep 25 12:09:55 1993
--- linux/kernel/fork.c	Sat Sep 25 13:02:23 1993
***************
*** 135,141 ****
  	*p = *current;
  	p->kernel_stack_page = 0;
  	p->state = TASK_UNINTERRUPTIBLE;
! 	p->flags &= ~(PF_PTRACED|PF_TRACESYS);
  	p->pid = last_pid;
  	p->swappable = 1;
  	p->p_pptr = p->p_opptr = current;
--- 135,142 ----
  	*p = *current;
  	p->kernel_stack_page = 0;
  	p->state = TASK_UNINTERRUPTIBLE;
! 	p->flags &= ~(PF_PTRACED|PF_TRACESYS|PF_SUPERPREV);
! 	p->flags |= PF_FORKNOEXEC;
  	p->pid = last_pid;
  	p->swappable = 1;
  	p->p_pptr = p->p_opptr = current;
diff -rc --new-file linux-0.99.13/kernel/signal.c linux/kernel/signal.c
*** linux-0.99.13/kernel/signal.c	Sat Sep 25 12:09:55 1993
--- linux/kernel/signal.c	Sat Sep 25 13:02:23 1993
***************
*** 327,332 ****
--- 327,333 ----
  				/* fall through */
  			default:
  				current->signal |= _S(signr & 0x7f);
+ 				current->flags |= PF_SIGNALED;
  				do_exit(signr);
  			}
  		}
diff -rc --new-file linux-0.99.13/kernel/sys.c linux/kernel/sys.c
*** linux-0.99.13/kernel/sys.c	Sat Sep 25 12:09:55 1993
--- linux/kernel/sys.c	Sat Sep 25 13:02:23 1993
***************
*** 17,22 ****
--- 17,26 ----
  #include <linux/string.h>
  #include <linux/ptrace.h>
  #include <linux/stat.h>
+ #include <linux/fcntl.h>
+ #include <linux/stat.h>
+ #include <linux/acct.h>
+ #include <sys/sysmacros.h>
  
  #include <asm/segment.h>
  #include <asm/io.h>
***************
*** 298,306 ****
  	return 0;
  }
  
! asmlinkage int sys_acct(void)
! {
! 	return -ENOSYS;
  }
  
  asmlinkage int sys_phys(void)
--- 302,413 ----
  	return 0;
  }
  
!   
! static char acct_active = 0;
! static struct file acct_file;
! 
! int acct_process(long exitcode)
! {
!    struct acct ac;
!    unsigned short fs;
! 
!    if (acct_active) {
!       strncpy(ac.ac_comm, current->comm, ACCT_COMM);
!       ac.ac_comm[ACCT_COMM] = '\0';
!       ac.ac_utime = current->utime;
!       ac.ac_stime = current->stime;
!       ac.ac_btime = CT_TO_SECS(current->start_time) + startup_time;
!       ac.ac_etime = CURRENT_TIME - ac.ac_btime;
!       ac.ac_uid   = current->uid;
!       ac.ac_gid   = current->gid;
!       ac.ac_tty   = makedev(4, current->tty);
!       ac.ac_flag  = 0;
!       if (current->flags & PF_FORKNOEXEC)
!          ac.ac_flag |= AFORK;
!       if (current->flags & PF_SUPERPREV)
!          ac.ac_flag |= ASU;
!       if (current->flags & PF_DUMPCORE)
!          ac.ac_flag |= ACORE;
!       if (current->flags & PF_SIGNALED)
!          ac.ac_flag |= AXSIG;
!       ac.ac_minflt = current->min_flt;
!       ac.ac_majflt = current->maj_flt;
!       ac.ac_exitcode = exitcode;
! 
!       /* Kernel segment override */
!       fs = get_fs();
!       set_fs(KERNEL_DS);
! 
!       acct_file.f_op->write(acct_file.f_inode, &acct_file,
!                              (char *)&ac, sizeof(struct acct));
! 
!       set_fs(fs);
!    }
!    return 0;
! }
! 
! asmlinkage int sys_acct(const char *name)
! {
!    struct inode *inode = (struct inode *)0;
!    char *tmp;
!    int error;
! 
!    if (!suser())
!       return -EPERM;
! 
!    if (name == (char *)0) {
!       if (acct_active) {
!          if (acct_file.f_op->release)
!             acct_file.f_op->release(acct_file.f_inode, &acct_file);
! 
!          if (acct_file.f_inode != (struct inode *) 0)
!             iput(acct_file.f_inode);
! 
!          acct_active = 0;
!       }
!       return 0;
!    } else {
!       if (!acct_active) {
! 
!          if ((error = getname(name, &tmp)) != 0)
!             return (error);
! 
!          error = open_namei(tmp, O_RDWR, 0600, &inode, 0);
!          putname(tmp);
! 
!          if (error)
!             return (error);
! 
!          if (!S_ISREG(inode->i_mode)) {
!             iput(inode);
!             return -EACCES;
!          }
! 
!          if (!inode->i_op || !inode->i_op->default_file_ops || 
!              !inode->i_op->default_file_ops->write) {
!             iput(inode);
!             return -EIO;
!          }
! 
!          acct_file.f_mode = 3;
!          acct_file.f_flags = 0;
!          acct_file.f_count = 1;
!          acct_file.f_inode = inode;
!          acct_file.f_pos = inode->i_size;
!          acct_file.f_reada = 0;
!          acct_file.f_op = inode->i_op->default_file_ops;
! 
!          if (acct_file.f_op->open)
!             if (acct_file.f_op->open(acct_file.f_inode, &acct_file)) {
!                iput(inode);
!                return -EIO;
!             }
! 
!          acct_active = 1;
!          return 0;
!       } else
!          return -EBUSY;
!    }
  }
  
  asmlinkage int sys_phys(void)
