stat of i-node

Chris Torek chris at mimsy.UUCP
Sun Sep 3 00:08:25 AEST 1989


>In article <19362 at mimsy.UUCP> I suggested:
>>fstat() is a very cheap operation.  stat() is a bit more expensive, but
>>(with name cacheing) not all that bad.

In article <179 at bmers58.UUCP> davem at bmers58.UUCP (Dave Mielke) writes:
>The problem with fstat is that it requires an open which also does a
>name lookup. This proves to be very slow when the directories get
>large. I need a way to get the information that stat would return
>without the expense of a name lookup. The i-node is the obvious key to
>the data, but I am unaware of any primitive that gives an application
>program direct access to the data via its actual key. I would
>appreciate any assistence that anyone can offer.

Okay, here it is (but you have to be root, and it does not work across
NFS).  Note that you would have to be root to use any `new' system call
that gives information by <dev,ino> pairs anyway, because otherwise you
could bypass system security.  (Find an unreadable directory?  Want to
know what is in it?  Guess what inodes are there, and look them up by
number.  This gives incomplete information, but it gives more than you
get now.)

Given the <dev_t dev, ino_t ino> pair, we want to find the inode on the
disk device.  Use the block device if you want to cooperate with the
buffer cache, or the raw device if you do not.  (Define RAW, or not, as
appropriate.)

/* NB: this code is untested */

#include <stdio.h>
#include <sys/param.h>
#ifdef NFS
#include <sys/vfs.h>
#include <sys/vnode.h>
#include <ufs/fs.h>
#include <ufs/inode.h>
#else
#include <sys/fs.h>
#include <sys/inode.h>
#endif

/*
 * Given a dev_t value, open the corresponding block (or raw) device
 * by searching mtab and trying devices.
 */
int
get_dev(dev)
	dev_t dev;
{
	FILE *fp;
	register char *p1;
#ifdef NFS
	char *p2;
#endif
	int fd;
	struct stat st;
	char buf[BUFSIZ];

	/* /etc/mtab changes, so just use the mount program */
	fp = popen("mount", "r");	/* /etc/mount or /sbin/mount */
	if (fp == NULL)
		return (-1);
	while (fgets(buf, sizeof buf, fp) != NULL) {
#ifdef RAW
		if (strncmp(buf, "/dev/", 5) != 0)
			continue;	/* strange line from mount */
#endif
		p1 = strchr(buf, ' ');
		if (p1 == NULL)
			break;
		if (strncmp(p1 + 1, " on ", 4) != 0)
			continue;	/* strange line from mount */
#ifdef NFS
		p2 = strchr(buf, ':');
		if (p2 != NULL && p2 < p1)
			continue;	/* must be an NFS mount */
#endif
		*p1 = 0;		/* buf now `/dev/ra0d', eg */
		if ((fd = open(buf, 0)) < 0)
			continue;
		if (fstat(fd, &st))
			panic("fstat fails");
		if (st.st_dev == dev) {
#ifdef RAW
			(void) close(fd);
			(void) sprintf(p1 + 1, "/dev/r%s", buf + 5);
			fd = open(p1 + 1, 0);
#endif
			return (fd);
		}
	}
	(void) fclose(fp);
	return (-1);
}

/*
 * Given a <dev,ino> pair, find the inode.  Store it through *dip.
 * Return -1 if not found, 0 if found.
 *
 * This version is BSD-specific.
 */
get_inode(dev, ino, dip)
	dev_t dev;
	ino_t ino;
	struct dinode *dip;
{
	static int fd = -1;
	static dev_t lastdev;
	static long lastoff;
	long off;
	static char buf[DEV_BSIZE];
	static union { struct fs usb; char ubuf[SBSIZE]; } u;
#define sblock u.usb

	if (fd < 0 || dev != lastdev) {
		fd = get_dev(dev);
		if (fd < 0)
			return (-1);
		lastdev = dev;
		(void) lseek(fd, (long)BBSIZE, 0);
		if (read(fd, (char *)&sblock, SBSIZE) != SBSIZE ||
		    sblock.fs_magic != FS_MAGIC) {
			(void) close(fd);
			fd = -1;
			return (-1);
		}
		lastoff = 0;	/* safe, because this is boot block */
	}
	off = (long)fsbtodb(&sblock, itod(&sblock, ino)) * DEV_BSIZE;
	if (off != lastoff) {
		(void) lseek(fd, off, 0);
		if (read(fd, buf, sizeof buf) != sizeof buf) {
			lastoff = 0;
			return (-1);
		}
		lastoff = off;
	}
	*dip = ((struct dinode *)buf)[itoo(&sblock, ino)];
	return (0);		/* got it at last */
}

/* For V7 file systems, such as those in SysV, the above is simpler,
   because the inodes are at a fixed offset, so the `itod'/`itoo'
   reduces to a single computation to find the inode offset.  This
   should then be converted to a 512-byte block, and the inode fished
   out as above (except that itoo becomes a relatively simple `%'). */
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris at mimsy.umd.edu	Path:	uunet!mimsy!chris



More information about the Comp.unix.wizards mailing list