[comp.unix.wizards] stat of i-node

davem@bmers58.UUCP (Dave Mielke) (09/01/89)

How can I get stat information for an i-node? I would like to avoid the
need to have a directory scanned for a name if I already know the file
number.

chris@mimsy.UUCP (Chris Torek) (09/01/89)

In article <172@bmers58.UUCP> davem@bmers58.UUCP (Dave Mielke) writes:
>How can I get stat information for an i-node? I would like to avoid the
>need to have a directory scanned for a name if I already know the file
>number.

Then open the disk and read the on-disk copy of the inode.

fstat() is a very cheap operation.  stat() is a bit more expensive, but
(with name cacheing) not all that bad.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

davem@bmers58.UUCP (Dave Mielke) (09/02/89)

In article <19362@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
>fstat() is a very cheap operation.  stat() is a bit more expensive, but
>(with name cacheing) not all that bad.
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.

chris@mimsy.UUCP (Chris Torek) (09/02/89)

>In article <19362@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@bmers58.UUCP> davem@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@mimsy.umd.edu	Path:	uunet!mimsy!chris

cpcahil@virtech.UUCP (Conor P. Cahill) (09/02/89)

In article <179@bmers58.UUCP>, davem@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.

There is no system call primitive that gives you the capability to access a file
based upon it's inode number.  In fact one of the *true* blessings of UNIX is
it's concept of accessing everyting (including devices) through the same 
namespace. (Of course they broke this with the system V IPC implementations)


If your problem is that it is taking too long to search a really big
directory, you probably should change the software that is maintaining
that directory so that it uses some sub-directories.  I worked on a project
that had the same problem with mail message attachments.  These attachments
were put into a single attachment directory on the system.  Over time,
this directory would grow to have thousands of entries which caused
access time to be outragously high.  The solution was to change the 
software to use a series of sub-directories (100 of them) which resulted
in a significant performace gain.
message attachments 


-- 
+-----------------------------------------------------------------------+
| Conor P. Cahill     uunet!virtech!cpcahil      	703-430-9247	!
| Virtual Technologies Inc.,    P. O. Box 876,   Sterling, VA 22170     |
+-----------------------------------------------------------------------+

mike@thor.acc.stolaf.edu (Mike Haertel) (09/03/89)

In article <179@bmers58.UUCP> davem@bmers58.UUCP (Dave Mielke) writes:
>In article <19362@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
>>fstat() is a very cheap operation.  stat() is a bit more expensive, but
>>(with name cacheing) not all that bad.
>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.

stat() in a simple file name in the current directory ought to be pretty
fast.  in 4.3BSD if you stat() the files of a directory in sequence of
the actual directory entries, the kernel remembers where the previous
search left off and does even better.
-- 
Mike Haertel <mike@stolaf.edu>
``There's nothing remarkable about it.  All one has to do is hit the right
  keys at the right time and the instrument plays itself.'' -- J. S. Bach

jbm@eos.UUCP (Jeffrey Mulligan) (09/06/89)

davem@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
					    ^ i-node number?
+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.

Well, if you can live with the security holes generated by having
your program run setuid root (or worse still, making /dev/disk readable),
you can just seek and read on the raw file system.  See filsys(5).


-- 

	Jeff Mulligan (jbm@aurora.arc.nasa.gov)
	NASA/Ames Research Ctr., Mail Stop 239-3, Moffet Field CA, 94035
	(415) 694-3745