#include <u.h>
#include <libc.h>
#include <auth.h>
#include <fcall.h>
#include <bio.h>
#include "tapefs.h"

Idmap *
getpass(char *file)
{
	Biobuf *bp;
	char *cp;
	Idmap *up;
	int nid, maxid;
	char *line[4];

	if ((bp = Bopen(file, OREAD)) == 0)
		error("Can't open passwd/group");
	up = emalloc(1*sizeof(Idmap));
	maxid = 1;
	nid = 0;
	while ((cp = Brdline(bp, '\n'))) {
		int nf;
		cp[Blinelen(bp)-1] = 0;
		nf = getfields(cp, line, 3, 0, ":\n");
		if (nf<3) {
			fprint(2, "bad format in %s\n", file);
			break;
		}
		if (nid>=maxid) {
			maxid *= 2;
			up = (Idmap *)erealloc(up, maxid*sizeof(Idmap));
		}
		up[nid].id = atoi(line[2]);
		up[nid].name = strdup(line[0]);
		nid++;
	}		
	Bterm(bp);
	up[nid].name = 0;
	return up;
}

char *
mapid(Idmap *up, int id)
{
	char buf[16];

	if (up)
		while (up->name){
			if (up->id==id)
				return strdup(up->name);
			up++;
		}
	sprint(buf, "%d", id);
	return strdup(buf);
}

Ram *
poppath(Fileinf fi, int new)
{
	char *suffix, *origname;
	Ram *dir, *ent;
	Fileinf f;

	if (*fi.name=='\0')
		return 0;
	origname = estrdup(fi.name);
	if (suffix=strrchr(fi.name, '/')){
		*suffix = 0;
		suffix++;
		if (*suffix=='\0'){
			fi.mode |= DMDIR;
			free(origname);
			return poppath(fi, 1);
		}
		/*
		 * create parent directory of suffix;
		 * may recurse, thus shortening fi.name even further.
		 */
		f = fi;
		f.size = 0;
		f.addr = 0;
		f.mode = 0555|DMDIR;
		dir = poppath(f, 0);
		if (dir==0)
			dir = ram;
	} else {
		suffix = fi.name;
		dir = ram;
		if (strcmp(suffix, ".")==0) {
			free(origname);
			return dir;
		}
	}
	ent = lookup(dir, suffix);
	fi.mode |= 0400;			/* at least user read */
	if (ent){
		if (((fi.mode&DMDIR)!=0) != ((ent->qid.type&QTDIR)!=0)){
			fprint(2,
		"%s file type changed; probably due to union dir.; ignoring\n",
				origname);
			free(origname);
			return ent;
		}
		if (new)  {
			ent->ndata = fi.size;
			ent->addr = fi.addr;
			ent->data = fi.data;
			ent->perm = fi.mode;
			ent->mtime = fi.mdate;
			ent->user = mapid(uidmap, fi.uid);
			ent->group = mapid(gidmap, fi.gid);
		}
	} else {
		fi.name = suffix;
		ent = popfile(dir, fi);
	}
	free(origname);
	return ent;
}

Ram *
popfile(Ram *dir, Fileinf fi)
{
	Ram *ent = (Ram *)emalloc(sizeof(Ram));
	if (*fi.name=='\0')
		return 0;
	ent->busy = 1;
	ent->open = 0;
	ent->parent = dir;
	ent->next = dir->child;
	dir->child = ent;
	ent->child = 0;
	ent->qid.path = ++path;
	ent->qid.vers = 0;
	if(fi.mode&DMDIR)
		ent->qid.type = QTDIR;
	else
		ent->qid.type = QTFILE;
	ent->perm = fi.mode;
	ent->name = estrdup(fi.name);
	ent->atime = ent->mtime = fi.mdate;
	ent->user = mapid(uidmap, fi.uid);
	ent->group = mapid(gidmap, fi.gid);
	ent->ndata = fi.size;
	ent->data = fi.data;
	ent->addr = fi.addr;
	ent->replete |= replete;
	return ent;
}

Ram *
lookup(Ram *dir, char *name)
{
	Ram *r;

	if (dir==0)
		return 0;
	for (r=dir->child; r; r=r->next){
		if (r->busy==0 || strcmp(r->name, name)!=0)
			continue;
		return r;
	}
	return 0;
}
