diff options
Diffstat (limited to 'api/src/glfs-resolve.c')
| -rw-r--r-- | api/src/glfs-resolve.c | 244 | 
1 files changed, 244 insertions, 0 deletions
diff --git a/api/src/glfs-resolve.c b/api/src/glfs-resolve.c new file mode 100644 index 00000000000..c03c4154db0 --- /dev/null +++ b/api/src/glfs-resolve.c @@ -0,0 +1,244 @@ +/* +  Copyright (c) 2012 Red Hat, Inc. <http://www.redhat.com> +  This file is part of GlusterFS. + +  This file is licensed to you under your choice of the GNU Lesser +  General Public License, version 3 or any later version (LGPLv3 or +  later), or the GNU General Public License, version 2 (GPLv2), in all +  cases as published by the Free Software Foundation. +*/ + + +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <inttypes.h> +#include <limits.h> + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "glusterfs.h" +#include "logging.h" +#include "stack.h" +#include "event.h" +#include "glfs-mem-types.h" +#include "common-utils.h" +#include "syncop.h" +#include "call-stub.h" + +#include "glfs-internal.h" + + +void +glfs_first_lookup (xlator_t *subvol) +{ +	loc_t  loc = {0, }; +	int    ret = -1; + +	loc.inode = subvol->itable->root; +	memset (loc.gfid, 0, 16); +	loc.gfid[15] = 1; +	loc.path = "/"; +	loc.name = ""; + +	ret = syncop_lookup (subvol, &loc, 0, 0, 0, 0); + +	gf_log (subvol->name, GF_LOG_DEBUG, "first lookup complete %d", ret); + +	return; +} + + +int +glfs_loc_touchup (loc_t *loc) +{ +	char *path = NULL; +	int   ret = -1; +	char *bn = NULL; + +	ret = inode_path (loc->parent, loc->name, &path); + +	loc->path = path; + +	if (ret < 0 || !path) { +		ret = -1; +		errno = ENOMEM; +		goto out; +	} + +	bn = strrchr (path, '/'); +	if (bn) +		bn++; +	loc->name = bn; +	ret = 0; +out: +	return ret; +} + + +inode_t * +glfs_resolve_component (struct glfs *fs, xlator_t *subvol, inode_t *parent, +			const char *component, struct iatt *iatt) +{ +	loc_t        loc = {0, }; +	inode_t     *inode = NULL; +	int          reval = 0; +	int          ret = -1; +	int          glret = -1; +	struct iatt  ciatt = {0, }; +	uuid_t       gfid; +	dict_t      *xattr_req = NULL; + +	loc.name = component; + +	loc.parent = inode_ref (parent); +	uuid_copy (loc.pargfid, parent->gfid); + +	xattr_req = dict_new (); +	if (!xattr_req) { +		errno = ENOMEM; +		goto out; +	} + +	ret = dict_set_static_bin (xattr_req, "gfid-req", gfid, 16); +	if (ret) { +		errno = ENOMEM; +		goto out; +	} + +	loc.inode = inode_grep (parent->table, parent, component); + +	if (loc.inode) { +		uuid_copy (loc.gfid, loc.inode->gfid); +		reval = 1; +	} else { +		uuid_generate (gfid); +		loc.inode = inode_new (parent->table); +	} + +	if (!loc.inode) +		goto out; + + +	glret = glfs_loc_touchup (&loc); +	if (glret < 0) { +		ret = -1; +		goto out; +	} + +	ret = syncop_lookup (subvol, &loc, xattr_req, &ciatt, NULL, NULL); +	if (ret && reval) { +		inode_unref (loc.inode); +		loc.inode = inode_new (parent->table); +		if (!loc.inode) +			goto out; +		uuid_generate (gfid); +		ret = syncop_lookup (subvol, &loc, xattr_req, &ciatt, +				     NULL, NULL); +	} +	if (ret) +		goto out; + +	inode = inode_link (loc.inode, loc.parent, component, &ciatt); +	if (inode) +		inode_lookup (inode); +	if (iatt) +		*iatt = ciatt; +out: +	if (xattr_req) +		dict_destroy (xattr_req); + +	loc_wipe (&loc); + +	return inode; +} + + +int +glfs_resolve (struct glfs *fs, xlator_t *subvol, const char *origpath, +	      loc_t *loc, struct iatt *iatt) +{ +	inode_t    *inode = NULL; +	inode_t    *parent = NULL; +	char       *saveptr = NULL; +	char       *path = NULL; +	char       *component = NULL; +	char       *next_component = NULL; +	int         ret = -1; +	struct iatt ciatt = {0, }; + +	path = gf_strdup (origpath); +	if (!path) { +		errno = ENOMEM; +		return -1; +	} + +	parent = NULL; +	inode = inode_ref (subvol->itable->root); + +	for (component = strtok_r (path, "/", &saveptr); +	     component; component = next_component) { + +		next_component = strtok_r (NULL, "/", &saveptr); + +		if (parent) +			inode_unref (parent); + +		parent = inode; + +		inode = glfs_resolve_component (fs, subvol, parent, +						component, &ciatt); +		if (!inode) +			break; + +		if (!next_component) +			break; + +		if (!IA_ISDIR (ciatt.ia_type)) { +			/* next_component exists and this component is +			   not a directory +			*/ +			inode_unref (inode); +			inode = NULL; +			ret = -1; +			errno = ENOTDIR; +			break; +		} +	} + +	if (parent && next_component) +		/* resolution failed mid-way */ +		goto out; + +	/* At this point, all components up to the last parent directory +	   have been resolved successfully (@parent). Resolution of basename +	   might have failed (@inode) if at all. +	*/ + +	loc->parent = parent; +	if (parent) { +		uuid_copy (loc->pargfid, parent->gfid); +		loc->name = component; +	} + +	loc->inode = inode; +	if (inode) { +		uuid_copy (loc->gfid, inode->gfid); +		if (iatt) +			*iatt = ciatt; +		ret = 0; +	} + +	glfs_loc_touchup (loc); +out: +	GF_FREE (path); + +	/* do NOT loc_wipe here as only last component might be missing */ + +	return ret; +} +  | 
