/*
 * $Id$
 *
 * This file implements some sort of filename -> un_index conversion
 * cache. Speeds up for real FS's (where the inode numbers are NOT
 * junk) and slows down for the silly FS's where the inode numbers
 * are junk.
 *
 * 12/12/93, kay roemer.
 */

# include "ipc_unix_cache.h"

# include "mint/proc.h"
# include "mint/stat.h"

# include "dosdir.h"
# include "dosfile.h"
# include "ipc_unix.h"


# define CACHE_ENTRIES	10

struct lookup_cache
{
	short	valid;
# define CACHE_VALID	1
# define CACHE_DIRTY	0
	short	dev;
	long	inode;
	long	stamp;
# define MK_STAMP(time, date)	((((long)(date)) << 16) | (time))
	long	un_index;
};

static struct lookup_cache f_cache[CACHE_ENTRIES];

long
un_cache_lookup (char *name, long *index)
{
	XATTR attr;
	short dirty_idx, i;
	long r, stamp, fd;
	static short last_deleted = 0;

	r = sys_f_xattr (1, name, &attr);
	if (r)
	{
		DEBUG (("unix: un_cache_lookup: Fxattr(%s) -> %ld", name, r));
		return r;
	}

	dirty_idx = -1;
	stamp = MK_STAMP (attr.mtime, attr.mdate);
	for (i = 0; i < CACHE_ENTRIES; i++)
	{
		if (f_cache[i].valid == CACHE_DIRTY)
		{
			dirty_idx = i;
			continue;
		}

		if (f_cache[i].inode == attr.index
			&& f_cache[i].dev == attr.dev)
		{
			if (f_cache[i].stamp == stamp)
			{
				*index = f_cache[i].un_index;
				return 0;
			}
			else
			{
				f_cache[i].valid = CACHE_DIRTY;
				dirty_idx = i;
				break;
			}
		}
	}

	/* No matching entry found. We drop dirty_entry or some other entry
	 * in a round robin manner if no dirty entry is left.
	 */
	fd = sys_f_open (name, O_RDWR);
	if (fd < 0)
	{
		DEBUG (("unix: un_cache_lookup: Fopen(%s) -> %ld", name, fd));
		return fd;
	}

	r = sys_f_read (fd, sizeof (*index), (char *) index);
	sys_f_close (fd);

	if (r >= 0 && r != sizeof (*index))
		r = EACCES;

	if (r < 0)
	{
		DEBUG (("unix: un_namei: Could not read idx from %s", name));
		return r;
	}

	if (dirty_idx == -1)
	{
		dirty_idx = last_deleted++;
		if (last_deleted >= CACHE_ENTRIES)
			last_deleted = 0;
	}

	f_cache[dirty_idx].dev = attr.dev;
	f_cache[dirty_idx].inode = attr.index;
	f_cache[dirty_idx].stamp = stamp;
	f_cache[dirty_idx].un_index = *index;
	f_cache[dirty_idx].valid = CACHE_VALID;

	return 0;
}

void
un_cache_remove (char *name)
{
	XATTR attr;
	long r;
	short i;

	r = sys_f_xattr (1, name, &attr);
	if (r) return;

	for (i = 0; i < CACHE_ENTRIES; i++)
	{
		if (f_cache[i].valid == CACHE_VALID
			&& f_cache[i].inode == attr.index
			&& f_cache[i].dev == attr.dev)
		{
			f_cache[i].valid = CACHE_DIRTY;
			return;
		}
	}
}
