2021-10-11 18:20:23 -03:00

202 lines
4.6 KiB
C

/* @(#)tmp_dir.c 1.1 92/07/30 SMI */
#include <sys/types.h>
#include <sys/param.h>
#include <sys/time.h>
#include <sys/vfs.h>
#include <sys/vnode.h>
#include <sys/errno.h>
#include <sys/ucred.h>
#include <sys/stat.h>
#include <debug/debug.h>
#include <tmpfs/tmpnode.h>
#include <tmpfs/tmp.h>
#include <tmpfs/tmpdir.h>
#include <sys/debug.h>
/*
* search directory 'parent' for entry 'name'
* return tmpnode LOCKED in 'foundtp'
* XXX should use dnlc
*/
tdirlookup(parent, name, foundtp, cred)
struct tmpnode *parent;
char *name;
struct tmpnode **foundtp;
struct ucred *cred;
{
int error;
struct tdirent *tdp;
extern func_t caller();
#ifdef TMPFSDEBUG
if (tmpfsdebug || tmpdirdebug)
printf("tdirlookup: parent %x name %s\n", parent, name);
#endif TMPFSDEBUG
if (error = taccess(parent, cred, VEXEC))
return (error);
if (error = tdiropen(parent, cred)) {
return (error);
}
for (tdp = parent->tn_dir; tdp; tdp = tdp->td_next) {
if (strcmp(tdp->td_name, name) == 0) {
*foundtp = tdp->td_tmpnode;
tmpnode_get(*foundtp);
#ifdef TMPFSDEBUG
if (tmpdirdebug)
printf("tdirlookup: returning %x\n", *foundtp);
#endif TMPFSDEBUG
tdirclose(parent);
return (0);
}
}
tdirclose(parent);
return (ENOENT);
}
/*
* enter 'name' and tmpnode * 'tp' into directory of tmpnode 'dir' on tmpfs 'tm'
*/
tdirenter(tm, dir, name, tp, cred)
struct tmount *tm;
struct tmpnode *dir;
char *name;
struct tmpnode *tp;
struct ucred *cred;
{
int error;
struct tdirent tdtemplate, *tdp;
struct tdirent *tpdp;
extern char *strcpy();
#ifdef TMPFSDEBUG
if (tmpfsdebug || tmpdirdebug)
printf("tdirenter: tm %x dir %x name %s tp %x\n", tm, dir,
name, tp);
#endif TMPFSDEBUG
/* check permissions */
if (error = taccess(dir, cred, VEXEC))
return (error);
if (error = tdiropen(dir, cred)) {
return (error);
}
if (error = taccess(dir, cred, VWRITE)) {
tdirclose(dir);
return (error);
}
/* set up the directory entry template */
tdtemplate.td_namelen = strlen(name);
tdtemplate.td_reclen = TDIRSIZ(&tdtemplate);
if ((tdp = (struct tdirent *)tmp_memalloc(tm,
tdtemplate.td_reclen)) == NULL) {
tdirclose(dir);
#ifdef TMPFSDEBUG
if (tmpdebugerrs || tmpdirdebug)
printf("tdirenter:- no space\n");
#endif TMPFSDEBUG
return (ENOSPC);
}
dir->tn_attr.va_size += tdtemplate.td_reclen;
/* now initialize the real dir entry */
tdp->td_namelen = tdtemplate.td_namelen;
tdp->td_reclen = tdtemplate.td_reclen;
tdp->td_tmpnode = tp;
tdp->td_next = NULL;
(void) strcpy(tdp->td_name, name);
/* check for virgin directory */
if ((tpdp = dir->tn_dir) == NULL)
dir->tn_dir = tdp;
else { /* install at end of of directory list */
/* XXX FIX ME should install after . && .. ?? */
while (tpdp->td_next != NULL)
tpdp = tpdp->td_next;
tpdp->td_next = tdp;
}
tdirclose(dir);
tp->tn_attr.va_nlink++;
tm->tm_direntries++;
return (0);
}
/*
* Delete entry whose tmpnode is tp from directory 'dir' on tmpfs 'tm'.
* Remember to free dir entry space and decrement link count on tmpnode 'tp'
*/
/*ARGSUSED*/
tdirdelete(tm, dir, tp, nm, cred)
register struct tmount *tm;
register struct tmpnode *dir, *tp;
register char *nm;
struct ucred *cred;
{
register struct tdirent *tpdp, *lasttdp = NULL;
register int error;
register u_int size;
#ifdef TMPFSDEBUG
if (tmpfsdebug || tmpdirdebug)
printf("tdirdelete: tm %x dir %x tp %x nm %s\n", tm, dir,
tp, nm);
#endif TMPFSDEBUG
if (error = tdiropen(dir, cred)) {
return (error);
}
if (error = taccess(dir, cred, VEXEC|VWRITE)) {
return (error);
}
if ((dir->tn_attr.va_mode & TSVTX) && cred->cr_uid != 0 &&
cred->cr_uid != dir->tn_attr.va_uid &&
tp->tn_attr.va_uid != cred->cr_uid) {
return (EPERM);
}
if ((tpdp = dir->tn_dir) == NULL)
panic("null directory list");
for (; tpdp; lasttdp = tpdp, tpdp = tpdp->td_next) {
if ((tp == tpdp->td_tmpnode) &&
(strcmp(tpdp->td_name, nm) == 0)) {
size = tpdp->td_reclen;
dir->tn_attr.va_size -= size;
tm->tm_direntries--;
lasttdp->td_next = tpdp->td_next;
tmp_memfree(tm, (char *)tpdp, size);
ASSERT(tp->tn_attr.va_nlink > 0);
tp->tn_attr.va_nlink--;
if (tp->tn_attr.va_type == VDIR && tp != dir) {
/*
* account for ".." entry in directory
*/
dir->tn_attr.va_nlink--;
}
return (0);
}
}
return (ENOENT);
}
/*
* check directory permission before doing an operation
*/
tdiropen(dir, cred)
struct tmpnode *dir;
struct ucred *cred;
{
int error;
if (error = taccess(dir, cred, VREAD)) {
return (error);
}
if (dir->tn_attr.va_type != VDIR) {
return (ENOTDIR);
}
return (0);
}
/*ARGSUSED*/
tdirclose(tp)
struct tmpnode *tp;
{
}