Ultrix-3.1/sys/sys/nami.c
/**********************************************************************
* Copyright (c) Digital Equipment Corporation 1984, 1985, 1986. *
* All Rights Reserved. *
* Reference "/usr/src/COPYRIGHT" for applicable restrictions. *
**********************************************************************/
/*
* SCCSID: @(#)nami.c 3.0 4/21/86
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/inode.h>
#include <sys/filsys.h>
#include <sys/mount.h>
#include <sys/dir.h>
#include <sys/user.h>
#include <sys/buf.h>
#ifndef saveseg5
#include <sys/seg.h>
#endif
/*
* Convert a pathname into a pointer to
* an inode. Note that the inode is locked.
*
* func = function called to get next char of name
* &uchar if name is in user space
* &schar if name is in system space
* flag = LOOKUP if name is sought
* CREATE if name is to be created
* DELETE if name is to be deleted
* follow = 1 if to follow links at end of name
*/
struct inode *
namei(func, flag, follow)
int (*func)();
{
register struct direct *dirp;
register struct inode *dp;
int c;
struct buf *bp;
int nlink;
dev_t d;
off_t eo;
int mountflag;
unsigned ne;
mountflag = 0;
nlink = 0;
u.u_sbuf = 0;
/*
* If name starts with '/' start from
* root; otherwise start from current dir.
*/
dp = u.u_cdir;
{
register c2;
if((c2=(*func)()) == '/')
if ((dp = u.u_rdir) == NULL)
dp = rootdir;
iget(dp->i_dev, dp->i_number);
while(c2 == '/')
c2 = (*func)();
if(c2 == '\0' && flag != LOOKUP)
u.u_error = ENOENT;
c = c2;
}
for(;;) {
/*
* Here dp contains pointer
* to last component matched.
*/
if(u.u_error)
break;
if(c == '\0')
return(dp);
/*
* If there is another component,
* Gather up name into
* users' dir buffer.
*/
{
register c2 = c;
register char *cp;
cp = &u.u_dbuf[0];
while (c2 != '/' && c2 != '\0' && u.u_error == 0 ) {
if(cp < &u.u_dbuf[DIRSIZ])
*cp++ = c2;
c2 = (*func)();
}
while(cp < &u.u_dbuf[DIRSIZ])
*cp++ = '\0';
while(c2 == '/')
c2 = (*func)();
c = c2;
}
seloop:
/*
* dp must be a directory and
* must have X permission.
*/
if((dp->i_mode&IFMT) != IFDIR)
u.u_error = ENOTDIR;
/* we want to ignore permission bits of mounted on inode */
if (mountflag)
mountflag = 0;
else
access(dp, IEXEC);
if(u.u_error)
break;
/*
* set up to search a directory
*/
u.u_offset = 0;
u.u_segflg = 1;
eo = 0;
ne = 0;
bp = NULL;
if (dp == u.u_rdir && *((int *)u.u_dbuf) == '..' &&
u.u_dbuf[2] == 0)
continue;
for(;;) { /* eloop */
/*
* If at the end of the directory,
* the search failed. Report what
* is appropriate as per flag.
*/
if(u.u_offset >= dp->i_size) {
if(bp != NULL) {
mapout(bp);
brelse(bp);
}
if(flag==CREATE && c=='\0') {
if(access(dp, IWRITE))
goto out;
u.u_pdir = dp;
if(eo)
u.u_offset = eo-sizeof(struct direct);
else
dp->i_flag |= IUPD|ICHG;
goto out1;
}
u.u_error = ENOENT;
goto out;
}
/*
* If offset is on a block boundary,
* read the next directory block.
* Release previous if it exists.
*/
if((u.u_offset&BMASK) == 0) {
if(bp != NULL) {
mapout(bp);
brelse(bp);
}
bp = bread(dp->i_dev,
bmap(dp, (daddr_t)(u.u_offset>>BSHIFT),
B_READ));
if (bp->b_flags & B_ERROR) {
brelse(bp);
goto out;
}
dirp = (struct direct *)mapin(bp);
}
/*
* Note first empty directory slot
* in eo for possible creat.
* String compare the directory entry
* and the current component.
* If they do not match, go back to eloop.
*/
{
register struct direct *ndirp;
struct direct *srchd();
ndirp = srchd(dirp, u.u_dbuf, &ne);
if((ne != 0) && (eo == 0))
eo = u.u_offset + (ne - (unsigned)dirp);
if (ndirp == NULL) {
u.u_offset += BSIZE;
continue;
}
u.u_offset += (unsigned)ndirp - (unsigned)dirp +
sizeof(struct direct);
dirp = ndirp;
}
break;
}
u.u_dent = *dirp;
/*
* Here a component matched in a directory.
* If there is more pathname, go back to
* the top of the loop, otherwise return.
*/
if(bp != NULL) {
mapout(bp);
brelse(bp);
}
if(flag==DELETE && c=='\0') {
if(access(dp, IWRITE))
break;
return(dp);
}
d = dp->i_dev;
if (u.u_dent.d_ino == ROOTINO &&
dp->i_number == ROOTINO &&
u.u_dent.d_name[1] == '.') {
register int i;
for(i=1; i<nmount; i++)
if (mount[i].m_inodp != NULL && mount[i].m_dev == d) {
iput(dp);
dp = mount[i].m_inodp;
dp->i_count++;
plock(dp);
mountflag++;
goto seloop;
}
}
prele(dp);
{
register struct inode *pdp;
if ((pdp = iget(d, u.u_dent.d_ino)) == NULL) {
if (dp->i_flag & ILOCK)
dp->i_count--;
else
iput(dp);
goto out1;
}
if ((pdp->i_mode&IFMT)==IFLNK && (follow || c)) {
if (pdp->i_size >= BSIZE-2 || ++nlink>8 ||
u.u_sbuf || !pdp->i_size) {
u.u_error = ELOOP;
iput(pdp);
break;
}
u.u_sbuf = bread(pdp->i_dev, bmap(pdp, (daddr_t)0, B_READ));
if (u.u_sbuf->b_flags & B_ERROR) {
brelse(u.u_sbuf);
iput(pdp);
u.u_sbuf = 0;
break;
}
/* Save our readahead chars at end of buffer, */
/* get first symbolic link character */
{
segm save5;
char *cp;
if (c) /* space for readahead chars */
u.u_slength = pdp->i_size+2;
else u.u_slength = pdp->i_size+1;
u.u_soffset = 0;
saveseg5(save5);
mapin(u.u_sbuf);
cp = (char *)SEG5;
if (c)
cp[u.u_slength-2] = '/';
cp[u.u_slength-1] = c;
c = cp[u.u_soffset++];
mapout(u.u_sbuf);
restorseg5(save5);
}
/* Grab the top-level inode for the new path */
iput(pdp);
if (c == '/') {
iput(dp);
if ((dp = u.u_rdir) == NULL)
dp = rootdir;
while (c == '/')
c = (*func)();
iget(dp->i_dev, dp->i_number);
}
else plock(dp);
continue;
}
else {
if (dp->i_flag & ILOCK)
dp->i_count--;
else
iput(dp);
dp = pdp;
}
}
}
out:
iput(dp);
out1:
if (u.u_sbuf) {
brelse(u.u_sbuf);
u.u_sbuf = u.u_slength = u.u_soffset = 0;
}
return(NULL);
}
/*
* Return the next character from the
* kernel string pointed at by dirp.
*/
schar()
{
register c;
if (u.u_sbuf) {
c = symchar();
if (c >= 0)
return(c);
}
return(*u.u_dirp++ & 0377);
}
/*
* Return the next character from the
* user string pointed at by dirp.
*/
#ifdef notdef /* generated in assembly by mkuchar */
uchar()
{
register c;
if (u.u_sbuf) {
c = symchar();
if (c >= 0)
return(c);
}
c = fubyte(u.u_dirp++);
if(c == -1)
u.u_error = EFAULT;
else if (c&0200)
u.u_error = EINVAL;
return(c);
}
#endif notdef
/*
* Get a character from the symbolic name buffer
*/
symchar()
{
segm save5;
register char c;
register char *cp;
if (!u.u_sbuf) /* Protect ourselves */
return(-1);
if (u.u_soffset > u.u_slength) {
brelse(u.u_sbuf);
u.u_soffset = u.u_slength = u.u_sbuf = 0;
return(-1);
}
/* Get next character from symbolic link buffer */
saveseg5(save5);
mapin(u.u_sbuf);
cp = (char *)SEG5;
c = cp[u.u_soffset++];
mapout(u.u_sbuf);
restorseg5(save5);
if (u.u_soffset >= u.u_slength) {
brelse(u.u_sbuf);
u.u_soffset = u.u_slength = u.u_sbuf = 0;
}
return(c);
}; /* end of symchar */