File:  [MW Coherent from dump] / coherent / b / STREAMS / coh.386 / fs1.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Wed May 29 04:56:36 2019 UTC (7 years, 2 months ago) by root
Branches: MarkWilliams, MAIN
CVS tags: relic, HEAD
coherent

/* $Header: /var/lib/cvsd/repos/coherent/coherent/b/STREAMS/coh.386/fs1.c,v 1.1.1.1 2019/05/29 04:56:36 root Exp $ */
/* (lgl-
 *	The information contained herein is a trade secret of Mark Williams
 *	Company, and  is confidential information.  It is provided  under a
 *	license agreement,  and may be  copied or disclosed  only under the
 *	terms of  that agreement.  Any  reproduction or disclosure  of this
 *	material without the express written authorization of Mark Williams
 *	Company or persuant to the license agreement is unlawful.
 *
 *	COHERENT Version 2.3.37
 *	Copyright (c) 1982, 1983, 1984.
 *	An unpublished work by Mark Williams Company, Chicago.
 *	All rights reserved.
 -lgl) */
/*
 * Coherent.
 * Filesystem (mostly handling of in core inodes).
 *
 * $Log: fs1.c,v $
 * Revision 1.1.1.1  2019/05/29 04:56:36  root
 * coherent
 *
 * Revision 2.5  93/08/09  13:35:29  bin
 * Kernel 82 changes
 * 
 * Revision 2.2  93/07/26  15:19:00  nigel
 * Nigel's R80
 * 
 * Revision 1.8  93/04/14  10:06:28  root
 * r75
 * 
 * Revision 1.7  93/02/23  15:50:51  root
 * after caddr_t change, before blclear
 * 
 * Revision 1.4  92/07/16  16:33:32  hal
 * Kernel #58
 * 
 * Revision 1.3  92/02/06  17:55:36  vlad
 * Fix typo in ialloc panic.
 * 
 * Revision 1.2  92/01/06  11:59:17  hal
 * Compile with cc.mwc.
 * 
 * Revision 1.1	88/03/24  16:13:47	src
 * Initial revision
 * 
 * 86/12/13	Allan Cornish		/usr/src/sys/coh/fs1.c
 * isync() no longer updates the disk image of a character device inode.
 *
 * 86/11/19	Allan Cornish		/usr/src/sys/coh/fs1.c
 * idirent() initializes the (new) (IO).io_flag field to 0.
 */
#include <sys/coherent.h>
#include <sys/buf.h>
#include <canon.h>
#include <dirent.h>
#include <sys/errno.h>
#include <sys/filsys.h>
#include <sys/ino.h>
#include <sys/inode.h>
#include <sys/io.h>
#include <sys/mount.h>>
#include <sys/stat.h>
#include <sys/file.h>

/*
 * Get character for `ftoi' depending on what space the characters are
 * coming from.
 */

#define ftoic(p,seg)	((seg) == IOSYS ? * (p) : getubd (p))

/*
 * Map the given filename to an inode.  If an error is encountered,
 * `u.u_error' is set.  `u.u_error' is always returned.  As this routine
 * needs to set several things, depending on the type of access, `t',
 * there are places in the processes' user area reserved for this routine
 * to set.  These are defined in the user process structure.  The seek
 * position is always set to the position of the directory entry of the
 * child if the child exists or the first free position if it doesn't.
 *  'r' =>  Reference.  A pointer to the child's inode is returned locked.
 *  'c' =>  Create.  If the child exists, a pointer to the inode is returned
 *          locked.  Otherwise if the parent directory exists, a pointer to
 *          the parent directory is returned locked.  Otherwise, an error.
 *  'u' =>  Unlink.  The parent directory is returned unlocked.  The child's
 *          inode number is returned.  The seek position is also set.
 */

int
ftoi (np, t, iop, dirent)
char	      *	np;
int		t;
IO	      *	iop;
struct direct *	dirent;
{
	return file_to_inode (np, t, 0, iop, dirent);
}

/*
 * Does main ftoi job. Was created to solve the problem with rmdir.
 * doRmdir is 0 for all cases except when called from rmdir.
 */

int
file_to_inode (np, t, doRmdir, iop, dirent)
char	      *	np;
int		t;
int		doRmdir;
IO	      *	iop;
struct direct *	dirent;
{
	register INODE *cip;
	register char *cp;
	register int c;
	register struct direct *dp;
	register BUF *bp;
	off_t cseek, fseek, s;
	int fflag, mflag;
	dev_t dev;
	ino_t ino;
	daddr_t b;

	u.u_cdirn = 0;
	u.u_cdiri = NULL;
	u.u_pdiri = NULL;

	if ((c = ftoic (np ++, iop->io_seg)) != '/') {
		cip = u.u_cdir;
	} else {
		c = ftoic (np ++, iop->io_seg);
		cip = u.u_rdir;
	}
	while (c == '/')
		c = ftoic (np ++, iop->io_seg);
	ilock (cip);
	cip->i_refc ++;

	if (c == '\0') {
		if (t == 'r') {
			u.u_cdiri = cip;
			return u.u_error;
		}

		idetach (cip);
		return u.u_error = ENOENT;
	}

	for (;;) {
		cp = dirent->d_name;
		while (c != '/' && c != '\0') {
			if (cp < & dirent->d_name [sizeof (dirent->d_name)])
				* cp ++ = c;
			c = ftoic (np ++, iop->io_seg);
		}

		while (c == '/')
			c = ftoic (np ++, iop->io_seg);

		while (cp < & dirent->d_name [sizeof (dirent->d_name)])
			* cp ++ = '\0';

		if ((cip->i_mode & IFMT) != IFDIR)
			u.u_error = ENOTDIR;
		else {
			/* For rmdir we need only write */
			if (doRmdir)
				iaccess (cip, IPW);
			else
				iaccess (cip, IPE);
		}

		if (u.u_error) {
			idetach (cip);
			return u.u_error;
		}

		cp = dirent->d_name;

		if (cip->i_ino == ROOTIN && cip->i_dev != rootdev &&
		    * cp ++ == '.' && * cp ++ == '.' && * cp ++ == '\0')
			cip = ftoim (cip);

		b = 0;
		fflag = 0;
		mflag = 0;
		cseek = 0;
		s = cip->i_size;

		while (s > 0) {
			if ((bp = vread (cip, b ++)) == NULL) {
				idetach (cip);
				return u.u_error;
			}

			dp = bp->b_vaddr;
			while (dp < bp->b_vaddr + BSIZE) {

				if ((s -= sizeof (* dp)) < 0)
					break;

				if ((ino = dp->d_ino) == 0) {
					if (fflag == 0) {
						fflag++;
						fseek = cseek;
					}
				} else if (direq (dp, dirent)) {
					canino (ino);
					mflag = 1;
					s = 0;
					break;
				}
				cseek += sizeof (* dp);
				dp ++;
			}
			brelease (bp);
		}

		dev = cip->i_dev;
		if (fflag == 0)
			fseek = cseek;

		if (mflag == 0) {
			if (c == '\0' && t == 'c') {
				u.u_pdiri = cip;
				iop->io_seek = fseek;
			} else {
				u.u_error = ENOENT;
				idetach (cip);
			}
			return u.u_error;
		}

		if (c == '\0') {
			if (t == 'u') {
				u.u_cdirn = ino;
				u.u_pdiri = cip;
				iop->io_seek = cseek;
				return u.u_error;
			}

			idetach (cip);
			u.u_cdiri = iattach (dev, ino);
			return u.u_error;
		}

		idetach (cip);
		if ((cip = iattach (dev, ino)) == NULL)
			return u.u_error;
	}
}


/*
 * Given an inode which is the root of a file system, return the inode
 * on which the file system was mounted.
 */
INODE *
ftoim(ip)
register INODE *ip;
{
	register MOUNT *mp;

	for (mp = mountp ; mp != NULL ; mp = mp->m_next) {
		if (mp->m_dev == ip->i_dev) {
			idetach (ip);
			ip = mp->m_ip;
			ilock (ip);
			ip->i_refc ++;
			break;
		}
	}
	return ip;
}


/*
 * Compare the string in `u.u_direct.d_name' with the name in the
 * given directory pointer.
 */

direq (dp1, dp2)
struct direct *	dp1;
struct direct * dp2;
{
	return dp1->d_ino == 0 ? 0 :
		strncmp (dp1->d_name, dp2->d_name, sizeof (dp1->d_name)) == 0;
}


/*
 * Make an inode of the given mode and device.  The parent directory,
 * name and such stuff is set by ftoi.
 */

INODE *
imake (mode, rdev, iop, dirent)
unsigned mode;
dev_t rdev;
IO	      *	iop;
struct direct *	dirent;
{
	register INODE *ip;

	ip = NULL;
	mode &= ~ u.u_umask;
	if ((mode & ISVTXT) != 0 && super () == 0)
		goto det;

	if (iaccess (u.u_pdiri, IPW) == 0)
		goto det;

	if ((ip = ialloc (u.u_pdiri->i_dev, mode)) == NULL)
		goto det;

	ip->i_nlink = 1;
	ip->i_a.i_rdev = rdev;
	idirent (ip->i_ino, iop, dirent);
	iamc (ip);	/* creat/mknod - atime/mtime/ctime */
det:
	idetach (u.u_pdiri);
	return ip;
}


/*
 * Write a directory entry out.  Everything necessary has been conveniently
 * set by `ftoi', except the new inode number of this directory entry.
 */

idirent (ino, iop, dirent)
IO	      *	iop;
struct direct *	dirent;
{
	dirent->d_ino = ino;
	canino (dirent->d_ino);

	iop->io_ioc = sizeof (struct direct);
	iop->io.vbase = dirent;
	iop->io_seg = IOSYS;
	iop->io_flag = 0;

	iwrite (u.u_pdiri, iop);
}


/*
 * Return a pointer to a locked inode in core containing the given
 * inode number and device.
 */

INODE *
iattach (dev, ino)
{
	register INODE *ip;
	register INODE *fip;
	register unsigned lrt;
	register MOUNT *mp;

	for (;;) {
		fip = NULL;
		for (ip = & inodep [NINODE - 1] ; ip >= inodep ; -- ip) {
			if (ip->i_ino == ino && ip->i_dev == dev)
				break;
			if (ip->i_refc == 0) {
				if (fip == NULL || ip->i_lrt < lrt) {
					fip = ip;
					lrt = ip->i_lrt;
				}
			}
		}

		if (ip < inodep) {
			if ((ip = fip) == NULL) {
				devmsg (dev, "Inode table overflow");
				u.u_error = ENFILE;
				return NULL;
			}
			ilock (ip);
			if (ip->i_refc != 0) {
				iunlock (ip);
				continue;
			}
			ip->i_dev = dev;
			ip->i_ino = ino;
			ip->i_refc = 1;
			ip->i_lrt = timer.t_time;
			ip->i_lastblock = -1;
			if (icopydm (ip) == 0) {
				ip->i_ino = 0;
				ip->i_refc = 0;
				iunlock (ip);
				return NULL;
			}
			return ip;
		}
		if ((ip->i_flag & IFMNT) != 0) {
			for (mp = mountp ; mp != NULL ; mp = mp->m_next) {
				if (mp->m_ip == ip) {
					ino = ROOTIN;
					dev = mp->m_dev;
					break;
				}
			}
			continue;
		}
		ilock (ip);
		if (ip->i_ino != ino || ip->i_dev != dev) {
			iunlock (ip);
			continue;
		}
		if (ip->i_refc < 0)
			panic ("iattach(%x)", ip);
		ip->i_refc ++;
		ip->i_lrt = timer.t_time;
		return ip;
	}
}

/*
 * Given a locked inode, deaccess it.
 */
idetach(ip)
register INODE *ip;
{
#if 0
	if (ilocked (ip) == 0 || ip->i_refc <= 0)
		panic("idetach(%p)", ip);
#else
	if (ilocked (ip) == 0) {
		printf ("bad unlocked inode, dev=%x, ino=%d, flags=%x\n",
			ip->i_dev, ip->i_ino, ip->i_flag);
		panic ("idetach(%p)", ip);
	}
	if (ip->i_refc <= 0) {
		printf ("negative refc, dev=%x, ino=%d, flags=%x, refc=%d\n",
			ip->i_dev, ip->i_ino, ip->i_flag, ip->i_refc);
		panic ("idetach(%p)", ip);
	}
#endif
	if (-- ip->i_refc == 0) {
#if	1
		if (ip->i_rl)
			panic ("idetach(%p) with locked records", ip);
#endif
		if ((ip->i_flag & (IFACC | IFMOD | IFCRT)) != 0 ||
		    ip->i_nlink == 0)
			icopymd (ip);
	}
	iunlock (ip);
}

/*
 * Given a inode which isn't locked, lock it and then deaccess.
 */
ldetach(ip)
register INODE *ip;
{
	ilock (ip);
	idetach (ip);
}

/*
 * A specialized routine for finding whether the given inode may be unlinked.
 * Quite simple you say, but we already have an inode locked and could run
 * into gating problems if we were to lock another.  So we look through the
 * cache to see if the inode is there.  If it is, we can easily tell.  If it
 * isn't, `icopydm' is called with a static.  This routine is only used by
 * `uunlink'.
 */
iucheck(dev, ino)
register dev_t dev;
register ino_t ino;
{
	register INODE *ip;
	INODE inode;

	for (ip = & inodep [NINODE - 1] ; ip >= inodep; -- ip) {
		if (ip->i_ino == ino && ip->i_dev == dev)
			break;
	}
	if (ip < inodep) {
		ip = & inode;
		ip->i_dev = dev;
		ip->i_ino = ino;
		if (icopydm (ip) == 0)
			return 0;
	}
	if ((ip->i_mode & IFMT) == IFDIR) {
		if (super () == 0)
			return 0;
	}
	return 1;
}

/*
 * Copy an inode from disk to memory performing canonization.
 */
icopydm(ip)
register INODE *ip;
{
	register struct dinode *dip;
	register BUF *bp;
	register ino_t ino;
	struct dinode dinode;
	caddr_t v;

	ip->i_flag = 0;
	ino = ip->i_ino;

	if ((bp = bread (ip->i_dev, (daddr_t) iblockn (ino),
			 BUF_SYNC)) == NULL)
		return 0;

	dip = & dinode;
	v = (char *) ((struct dinode *) bp->b_vaddr + iblocko (ino));
	memcpy (dip, v, sizeof (dinode));
	brelease (bp);

	ip->i_mode = dip->di_mode;
	canshort (ip->i_mode);
	ip->i_nlink = dip->di_nlink;
	canshort (ip->i_nlink);
	ip->i_uid = dip->di_uid;
	canshort (ip->i_uid);
	ip->i_gid = dip->di_gid;
	canshort (ip->i_gid);
	ip->i_size = dip->di_size;
	cansize (ip->i_size);

	switch (ip->i_mode & IFMT) {
	case IFBLK:
	case IFCHR:
		ip->i_a.i_rdev = dip->di_a.di_rdev;
		candev (ip->i_a.i_rdev);
		break;

	case IFREG:
	case IFDIR:
		l3tol (ip->i_a.i_addr, dip->di_a.di_addb, NADDR);
		break;

	case IFPIPE:
		l3tol (ip->i_pipe, dip->di_addp, ND);
		ip->i_pnc = dip->di_pnc;
		canshort (ip->i_pnc);
		ip->i_prx = dip->di_prx;
		canshort (ip->i_prx);
		ip->i_pwx = dip->di_pwx;
		canshort (ip->i_pwx);
		break;

	default:
		kclear (& ip->i_a, sizeof (ip->i_a));
		break;
	}

	ip->i_atime = dip->di_atime;
	cantime (ip->i_atime);
	ip->i_mtime = dip->di_mtime;
	cantime (ip->i_mtime);
	ip->i_ctime = dip->di_ctime;
	cantime (ip->i_ctime);
	ip->i_rl = NULL;
	return 1;
}

/*
 * Copy an inode from memory back on to disk performing canonization.
 */
icopymd(ip)
register INODE *ip;
{
	register struct dinode *dip;
	register BUF *bp;
	register ino_t ino;
	struct dinode dinode;
	caddr_t v;

	if (getment (ip->i_dev, 0) == NULL)
		return;

	ino = ip->i_ino;
	if (ip->i_refc == 0 && ip->i_nlink == 0 && ino != BADFIN &&
	    ino != ROOTIN) {
		iclear (ip);
		ip->i_lrt = 0;
		ip->i_mode = 0;
	}

	dip = & dinode;
	dip->di_mode = ip->i_mode;
	canshort (dip->di_mode);
	dip->di_nlink = ip->i_nlink;
	canshort (dip->di_nlink);
	dip->di_uid = ip->i_uid;
	canshort (dip->di_uid);
	dip->di_gid = ip->i_gid;
	canshort (dip->di_gid);
	dip->di_size = ip->i_size;
	cansize (dip->di_size);

	switch (ip->i_mode & IFMT) {
	case IFBLK:
	case IFCHR:
		dip->di_a.di_rdev = ip->i_a.i_rdev;
		candev (dip->di_a.di_rdev);
		break;

	case IFREG:
	case IFDIR:
		ltol3 (dip->di_addr, ip->i_a.i_addr, NADDR);
		break;

	case IFPIPE:
		ltol3 (dip->di_addp, ip->i_pipe, ND);
		dip->di_pnc = ip->i_pnc;
		canshort (dip->di_pnc);
		dip->di_prx = ip->i_prx;
		canshort (dip->di_prx);
		dip->di_pwx = ip->i_pwx;
		canshort (dip->di_pwx);
		break;

	default:
		kclear (& dip->di_a, sizeof (dip->di_a));
		break;
	}

	dip->di_atime = ip->i_atime;
	cantime (dip->di_atime);
	dip->di_mtime = ip->i_mtime;
	cantime (dip->di_mtime);
	dip->di_ctime = ip->i_ctime;
	cantime (dip->di_ctime);

	if ((bp = bread (ip->i_dev, (daddr_t) iblockn (ino),
			 BUF_SYNC)) == NULL)
		return;

	v = (char *) ((struct dinode *) bp->b_vaddr + iblocko (ino));
	memcpy (v, dip, sizeof (dinode));
	bp->b_flag |= BFMOD;
	brelease (bp);
	ip->i_flag &= ~ (IFACC | IFMOD | IFCRT);
	if (ip->i_refc == 0 && ip->i_nlink == 0 && ino != BADFIN &&
	    ino != ROOTIN)
		ifree (ip->i_dev, ino);
}

/*
 * Copy all relevant inodes out on device `dev'.
 */
isync(dev)
register dev_t dev;
{
	register INODE *ip;

	for (ip = & inodep [NINODE - 1] ; ip >= inodep ; -- ip) {
		if (ip->i_refc == 0)
			continue;
		if (ip->i_dev != dev)
			continue;
		if ((ip->i_mode & IFMT) == IFCHR)
			continue;
		if ((ip->i_flag & (IFACC | IFMOD | IFCRT)) == 0)
			continue;
		icopymd (ip);
	}
}

/*
 * Clear the given inode and all space associated with it.
 */

iclear (ip)
register INODE *ip;
{
	register int n;
	register daddr_t b;

	switch (ip->i_mode & IFMT) {
	case IFPIPE:
		ip->i_pnc = ip->i_prx = ip->i_pwx = 0;
		n = ND;
		while (n > 0) {
			if ((b = ip->i_pipe [-- n]) != 0)
				bfree (ip->i_dev, b);
		}
		memset (ip->i_pipe, 0, sizeof (ip->i_pipe));
		break;

	case IFDIR:
	case IFREG:
		n = NADDR;
		while (n > ND) {
			if ((b = ip->i_a.i_addr [-- n]) != 0)
				indfree (ip->i_dev, b, 1 + n - ND);
		}
		while (n > 0) {
			if ((b = ip->i_a.i_addr [-- n]) != 0)
				bfree (ip->i_dev, b);
		}
		memset (ip->i_a.i_addr, 0, sizeof (ip->i_a.i_addr));
		break;

	default:
		return;
	}
	ip->i_size = 0;
	iamc (ip);	/* creat/pipe - atime/mtime/ctime */
}

/*
 * blclear(ip, lbn)  --  Clear all blocks in inode ip beginning with
 * logical blocks number lbn.  Called from uchsize() in sys5.c
 */
blclear(ip, lbn)
register INODE *ip;
fsize_t lbn;
{}

/*
 * Copy the appropriate information from the inode to the stat buffer.
 */
istat(ip, sbp)
register INODE *ip;
register struct stat *sbp;
{
	sbp->st_dev = ip->i_dev;
	sbp->st_ino = ip->i_ino;
	sbp->st_mode = ip->i_mode;
	sbp->st_nlink = ip->i_nlink;
	sbp->st_uid = ip->i_uid;
	sbp->st_gid = ip->i_gid;
	sbp->st_rdev = NODEV;
	sbp->st_size = ip->i_size;
	sbp->st_atime = ip->i_atime;
	sbp->st_mtime = ip->i_mtime;
	sbp->st_ctime = ip->i_ctime;

	switch (ip->i_mode & IFMT) {
	case IFBLK:
	case IFCHR:
		sbp->st_rdev = ip->i_a.i_rdev;
		sbp->st_size = 0;
		break;

	case IFPIPE:
		sbp->st_size = ip->i_pnc;
		break;
	}
}

/*
 * See if it is possible to access the given inode with the bits in
 * the given mode.
 * If the mode includes writing, and i_refc is > 1, then check for
 * shared text problems.
 */
iaccess(ip, mode)
register INODE *ip;
register int mode;
{
	/* Super user can do everything with directories */
	if (((ip->i_mode & IFMT) != IFDIR) || u.u_uid)
		if ((imode (ip, u.u_uid, u.u_gid) & mode) != mode) {
			u.u_error = EACCES;
			return 0;
		}

	if ((mode & IPW) != 0 && ip->i_refc > 1 && sbusy (ip)) {
		u.u_error = ETXTBSY;
		return 0;
	}
	return 1;
}


/*
 * Get the maximum allowable mode on a file.
 */

imode(ip, uid, gid)
register INODE *ip;
{
	if (uid == 0) {
		/* Superuser can read or write anything. */
		int ret = IPR | IPW;
		/*
		 * If superuser, say the file is executable if any
		 * of the 'x' perm bits is set.
		 */
		if ((ip->i_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0)
			ret |= IPE;
		return ret;
	}
	if (uid == ip->i_uid)
		return (ip->i_mode & S_IRWXU) >> 6;
	if (gid == ip->i_gid)
		return (ip->i_mode & S_IRWXG) >> 3;
	return ip->i_mode & S_IRWXO;
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.