minix/lib/libpuffs/path.c

169 lines
4.1 KiB
C
Raw Normal View History

/*
* This file contains the procedures that look up path names in the directory
* system and determine the pnode number that goes with a given path name.
*
* Created (based on MFS):
* June 2011 (Evgeniy Ivanov)
*/
#include "fs.h"
#include <sys/cdefs.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <assert.h>
#include <errno.h>
#include <puffs.h>
#include <stdlib.h>
#include <string.h>
#include "puffs.h"
#include "puffs_priv.h"
/*===========================================================================*
* fs_lookup *
*===========================================================================*/
int fs_lookup(ino_t dir_nr, char *name, struct fsdriver_node *node,
int *is_mountpt)
{
struct puffs_node *pn, *pn_dir;
/* Find the pnode of the directory node. */
if ((pn_dir = puffs_pn_nodewalk(global_pu, 0, &dir_nr)) == NULL) {
lpuffs_debug("nodewalk failed\n");
return(EINVAL);
}
if (!S_ISDIR(pn_dir->pn_va.va_mode))
return ENOTDIR;
if ((pn = advance(pn_dir, name)) == NULL)
return err_code;
pn->pn_count++; /* open pnode */
node->fn_ino_nr = pn->pn_va.va_fileid;
node->fn_mode = pn->pn_va.va_mode;
node->fn_size = pn->pn_va.va_size;
node->fn_uid = pn->pn_va.va_uid;
node->fn_gid = pn->pn_va.va_gid;
node->fn_dev = pn->pn_va.va_rdev;
*is_mountpt = pn->pn_mountpoint;
return OK;
}
/*===========================================================================*
* advance *
*===========================================================================*/
struct puffs_node *advance(
struct puffs_node *pn_dir, /* pnode for directory to be searched */
char string[NAME_MAX + 1] /* component name to look for */
)
{
/* Given a directory and a component of a path, look up the component in
* the directory, find the pnode, open it, and return a pointer to its pnode
* slot.
* TODO: instead of string, should get pcn.
*/
struct puffs_node *pn;
struct puffs_newinfo pni;
struct puffs_kcn pkcnp;
PUFFS_MAKECRED(pcr, &global_kcred);
2012-02-01 12:44:26 +01:00
struct puffs_cn pcn = {&pkcnp, (struct puffs_cred *) __UNCONST(pcr), {0,0,0}};
enum vtype node_vtype;
voff_t size;
dev_t rdev;
int error;
assert(pn_dir != NULL);
err_code = OK;
/* If 'string' is empty, return an error. */
if (string[0] == '\0') {
err_code = ENOENT;
return(NULL);
}
/* If dir has been removed return ENOENT. */
if (pn_dir->pn_va.va_nlink == NO_LINK) {
err_code = ENOENT;
return(NULL);
}
if (strcmp(string, ".") == 0) {
/* Otherwise we will fall into trouble: path for pnode to be looked up
* will be parent path (same pnode as the one to be looked up) +
* requested path. E.g. after several lookups we might get advance
* for "." with parent path "/././././././././.".
* FIXME: how is ".." handled then?
*
* Another problem is that after lookup pnode will be added
* to the pu_pnodelst, which already contains pnode instance for this
* pnode. It will cause lot of troubles.
* FIXME: check if this is actually correct, because if it is, we are
* in lots of trouble; there are many ways to reach already-open pnodes
*/
return pn_dir;
}
pni.pni_cookie = (void** )&pn;
pni.pni_vtype = &node_vtype;
pni.pni_size = &size;
pni.pni_rdev = &rdev;
pcn.pcn_namelen = strlen(string);
assert(pcn.pcn_namelen <= MAXPATHLEN);
strcpy(pcn.pcn_name, string);
if (buildpath) {
if (puffs_path_pcnbuild(global_pu, &pcn, pn_dir) != 0) {
lpuffs_debug("pathbuild error\n");
err_code = ENOENT;
return(NULL);
}
}
/* lookup *must* be present */
error = global_pu->pu_ops.puffs_node_lookup(global_pu, pn_dir, &pni, &pcn);
if (buildpath) {
if (error) {
global_pu->pu_pathfree(global_pu, &pcn.pcn_po_full);
err_code = ENOENT;
return(NULL);
} else {
struct puffs_node *_pn;
/*
* did we get a new node or a
* recycled node?
*/
_pn = PU_CMAP(global_pu, pn);
if (_pn->pn_po.po_path == NULL)
_pn->pn_po = pcn.pcn_po_full;
else
global_pu->pu_pathfree(global_pu, &pcn.pcn_po_full);
}
}
if (error) {
err_code = error < 0 ? error : -error;
return(NULL);
}
err_code = OK;
assert(pn != NULL);
return(pn);
}