2.9BSD/usr/contrib/grab/src/find.c

/*
 * find.c
 *
 * Routines for descending the directory tree of a pathname.
 *
 *---------------------------------------------------------------------------
 *
 * $Header$
 * $Log$
 */

# include	"grab.h"



/*
 * tail( path ) -- return pointer to the terminal name of path.
 */
char *
tail( path )
    register char *path;
{
	register char *name	= path;

	while ( *path != '\0' )
		if ( *path++ == '/' )
			name	= path;
	return ( name );
}



/*
 * find( path ) -- return inode number corresponding to path.
 */
int
find( path )
    char   *path;
{
	register char  *p, *q;
	char		tmp;
	int		ino;
	struct inode	i;

	if ( path == NULL || *path == '\0' ) {
		fprintf( stderr, "grab: null filename\n" );
		return ( 0 );
	}
	p	= path;

	/*
	 * Fetch the root inode information from the disk.
	 */
	geti( ROOTINO, &i );

	/*
	 * Search the directories in the path for
	 * each pathname element in turn.
	 */
	while ( *p != '\0' ) {

		/*
		 * Find and separate out a pathname element.
		 */
		while ( *p == '/' )
			++p;
		q	= p;
		while ( *q != '/' && *q != '\0' )
			++q;
		tmp	= *q;
		*q	= '\0';

		/*
		 * Look in the directory.
		 */
		if ( ! isdir( &i ) ) {
			fprintf( stderr, "grab: bad directory in %s\n", path );
			return ( 0 );
		}

		if ( (ino = dlook( p, path, &i )) == 0 )
			return ( 0 );

		if ( tmp == '\0' )
			/*
			 * Found the terminal element.
			 */
			break;
		geti( ino, &i );
		*q	= tmp;
		p	= q;
	}

	return( ino );
}



/*
 * dlook( name, path, ip ) -- look for name in directory corresponding to the
 *	inode whose incore structure is pointed to by ip.  Path is used for
 *	error reporting.
 */
int
dlook( name, path,  ip )
    char           *name;
    char           *path;
    struct inode   *ip;
{
	register int		j, k;
	int			n, dpb, ino;
	register struct direct *dp;
	struct bmap		b;

	if ( ! chkaccess( ip ) ) {
		fprintf( stderr, "grab: %s read-protected\n", path );
		return ( 0 );
	}

	ino	= 0;
	n	= ip->i_size / sizeof (struct direct);
	dpb	= fsbsiz / sizeof (struct direct);

	allocbuf( ip, &b, B_SMALL );

	for ( j = 0; j < n; ++j ) {
		k	= j % dpb;
		if ( k == 0 )
			bread( &b );
		dp	= &((struct direct *) b.b_data)[ k ];
		if ( dp->d_ino == 0 )
			continue;
		if ( strncmp( name, dp->d_name, DIRSIZ ) == 0 ) {
			ino	= dp->d_ino;
			break;
		}
	}

	freebuf( &b );

	/*
	 * Did we find it?
	 */
	if ( ino == 0 )
		fprintf( stderr, "grab: %s not found\n", path );

	return ( ino );
}



/*
 * isreg( ip ) -- return true iff ip's inode corresponds to a regular file.
 */
int
isreg( ip )
    struct inode *ip;
{
	switch ( target_system ) {
	case V7_2BSD:
	case V7_4BSD:
		return ( (ip->i_mode & V7_IFMT) == V7_IFREG );
	case V6:
		return ( (ip->i_mode & V6_IFMT) == V6_IFREG );
	}
}




/*
 * isdir( ip ) -- return true iff ip's inode corresponds to a directory file.
 */
int
isdir( ip )
    struct inode *ip;
{
	switch ( target_system ) {
	case V7_2BSD:
	case V7_4BSD:
		return ( (ip->i_mode & V7_IFMT) == V7_IFDIR );
	case V6:
		return ( (ip->i_mode & V6_IFMT) == V6_IFDIR );
	}
}



/*
 * chkaccess( ip ) -- check permissions on readability of the given
 *	inode on the foreign system.  Return 1 if readable.
 */
int
chkaccess( ip )
    struct inode *ip;
{
	static int	uid = -1, gid = -1;
	int		iuid, igid, mode, ckmode;

	if ( uid == -1 ) {
		uid	= geteuid();
		gid	= getegid();
	}
	iuid	= ip->i_uid;
	igid	= ip->i_gid;

	if ( uid == 0 )
		return ( 1 );
	
	if ( isdir( ip ) )
		ckmode	= 05;		/* Read and execute on a directory */
	else
		ckmode	= 04;		/* Read on regular files */
	mode	= ip->i_mode & 0777;

	if ( uid == iuid && ((mode >> 6) & ckmode) == ckmode )
		return ( 1 );
	if ( gid == igid && ((mode >> 3) & ckmode) == ckmode )
		return ( 1 );
	if ( (mode & ckmode) == ckmode )
		return ( 1 );
	return ( 0 );
}