#include "sys/param.h"
#include "sys/inode.h"
#include "sys/user.h"
#include "sys/buf.h"
#include "sys/conf.h"
#include "sys/label.h"
#include "sys/log.h"
#include "sys/proc.h"

/*
 * default namei flagp argument
 * use as is for simple searches;
 * copy and fill in the blanks for more complicated things
 */
struct argnamei nilargnamei = {NI_SEARCH};

/*
 * Convert a pathname into a pointer to
 * a locked inode.
 *
 * str = address of pathname; might be user or kernel space address
 * seg = segment where str lives; save values as u_segflg
 * flagp = address of structure with miscellaneous parameters
 * follow = 1 if links are to be followed at the end of the name
 *
 * Most of the work is done in the different filesystem namei routines,
 * which are called with a structure full of value-result parameters
 * (in effect a bundle of global variables on the stack):
 *	dp, the current inode
 *	cp, the current character pointer
 *	nlink, the current symlink count (to catch loops)
 *	nbuf and nlen, the address and length of the buffer
 *		where the pathname is stored
 * If the fs namei routine returns 1, there is more work to do;
 * call the namei routine for the current dp->i_fstyp
 * (perhaps different from the one that returned)
 * If the routine returns 0, all is done;
 * p.dp contains the inode to return, which may be NULL
 * u.u_error may contain an error code
 */

struct inode *
namei(str, seg, flagp, follow)
char *str;
int seg;
struct argnamei	*flagp;
int follow;
{
	register char	*cp;
	struct nx	p;
	static long nnum = 0;
	long tnum;
	register struct buf *bp;

	bp = geteblk();
	p.nbuf = bp->b_un.b_addr;
	p.nlen = bp->b_bcount;
	p.dp = NULL;		/* in case of error */
	switch (seg) {
	case SEGSYS:
		/* assume it fits in the buffer for now */
		strcpy(p.nbuf, str);
		break;

	case SEGUDATA:
		if (fustrncpy(p.nbuf, str, p.nlen) < 0) {
			u.u_error = EFAULT;
			goto out;
		}
		break;

	default:
		u.u_error = EFAULT;
		goto out;
	}
	cp = p.nbuf;
	if(*cp == '/') {
		while(*cp == '/')
			cp++;
		if((p.dp = u.u_rdir) == NULL)
			p.dp = rootdir;
	} else
		p.dp = u.u_cdir;
	p.nlink = 0;
	p.cp = cp;
	plock(p.dp);
	p.dp->i_count++;
	
	tnum = nnum++;		/* to tie the 2 LOG_NAMEI's together */
	if(loggable(LN))
		seclog(LOG_NAMEI, 53, "4Is1", tnum, p.dp, cp, flagp->flag);
	do {
		if(p.dp!=0 && labRchk(p.dp)==0) {
			iput(p.dp);
			p.dp = NULL;
			break;
		}
	} while ((*fstypsw[p.dp->i_fstyp]->t_nami)(&p, flagp, follow));

	if( p.dp != NULL &&
		(
		( (u.u_labcheck & RCHN) && !labRchk(p.dp))
		||
		( (u.u_labcheck & WCHN) && !labWchk(p.dp))
		)
	) {
		iput(p.dp);
		p.dp = NULL;
	}
out:
	if(loggable(LN))
		seclog(LOG_NAMEI, 52, "4I", tnum, p.dp);
	brelse(bp);
	return (p.dp);
}

/*
 * for filesystems without namei code
 * allow ordinary lookups;
 * pretend create worked (hence open for write)
 * reject anything else
 */

int
nullnami(p, flagp, follow)
register struct nx *p;
register struct argnamei *flagp;
int follow;
{

	switch (flagp->flag) {
	case NI_CREAT:
		flagp->un.mode = ~flagp->un.mode;	/* magic */
		/* fall through */
	case NI_SEARCH:
		return (0);

	default:
		u.u_error = EACCES;
		iput(p->dp);
		p->dp = NULL;
		return (0);
	}
}
