diff options
Diffstat (limited to 'src/H5Gname.c')
-rw-r--r-- | src/H5Gname.c | 880 |
1 files changed, 880 insertions, 0 deletions
diff --git a/src/H5Gname.c b/src/H5Gname.c new file mode 100644 index 0000000..1d1a141 --- /dev/null +++ b/src/H5Gname.c @@ -0,0 +1,880 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by the Board of Trustees of the University of Illinois. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the files COPYING and Copyright.html. COPYING can be found at the root * + * of the source code distribution tree; Copyright.html can be found at the * + * root level of an installed copy of the electronic HDF5 document set and * + * is linked from the top-level documents page. It can also be found at * + * http://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html. If you do not have * + * access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/*------------------------------------------------------------------------- + * + * Created: H5Gname.c + * Sep 12 2005 + * Quincey Koziol <koziol@ncsa.uiuc.edu> + * + * Purpose: Functions for handling group hierarchy paths. + * + *------------------------------------------------------------------------- + */ +#define H5F_PACKAGE /*suppress error about including H5Fpkg */ +#define H5G_PACKAGE /*suppress error about including H5Gpkg */ + + +/* Packages needed by this file... */ +#include "H5private.h" /* Generic Functions */ +#include "H5Dprivate.h" /* Datasets */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5Fpkg.h" /* File access */ +#include "H5FLprivate.h" /* Free Lists */ +#include "H5Gpkg.h" /* Groups */ +#include "H5Iprivate.h" /* IDs */ +#include "H5MMprivate.h" /* Memory management */ + +/* Private typedefs */ + +/* Struct used by change name callback function */ +typedef struct H5G_names_t { + H5G_loc_t *loc; + H5RS_str_t *src_name; + H5G_loc_t *src_loc; + H5RS_str_t *dst_name; + H5G_loc_t *dst_loc; + H5G_names_op_t op; +} H5G_names_t; + +/* Private macros */ + +/* Local variables */ + +/* Declare extern the PQ free list for the wrapped strings */ +H5FL_BLK_EXTERN(str_buf); + +/* PRIVATE PROTOTYPES */ +static htri_t H5G_common_path(const H5RS_str_t *fullpath_r, const H5RS_str_t *prefix_r); +static H5RS_str_t *H5G_build_fullpath(const char *prefix, const char *name); +static H5RS_str_t *H5G_build_fullpath_refstr_refstr(const H5RS_str_t *prefix_r, const H5RS_str_t *name_r); +static H5RS_str_t *H5G_build_fullpath_refstr_str(H5RS_str_t *path_r, const char *name); +static int H5G_name_replace_cb(void *obj_ptr, hid_t obj_id, void *key); + + +/*------------------------------------------------------------------------- + * Function: H5G_common_path + * + * Purpose: Determine if one path is a valid prefix of another path + * + * Return: TRUE for valid prefix, FALSE for not a valid prefix, FAIL + * on error + * + * Programmer: Quincey Koziol, koziol@ncsa.uiuc.edu + * + * Date: September 24, 2002 + * + *------------------------------------------------------------------------- + */ +static htri_t +H5G_common_path(const H5RS_str_t *fullpath_r, const H5RS_str_t *prefix_r) +{ + const char *fullpath; /* Pointer to actual fullpath string */ + const char *prefix; /* Pointer to actual prefix string */ + size_t nchars1,nchars2; /* Number of characters in components */ + htri_t ret_value=FALSE; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5G_common_path) + + /* Get component of each name */ + fullpath=H5RS_get_str(fullpath_r); + assert(fullpath); + fullpath=H5G_component(fullpath,&nchars1); + assert(fullpath); + prefix=H5RS_get_str(prefix_r); + assert(prefix); + prefix=H5G_component(prefix,&nchars2); + assert(prefix); + + /* Check if we have a real string for each component */ + while(*fullpath && *prefix) { + /* Check that the components we found are the same length */ + if(nchars1==nchars2) { + /* Check that the two components are equal */ + if(HDstrncmp(fullpath,prefix,nchars1)==0) { + /* Advance the pointers in the names */ + fullpath+=nchars1; + prefix+=nchars2; + + /* Get next component of each name */ + fullpath=H5G_component(fullpath,&nchars1); + assert(fullpath); + prefix=H5G_component(prefix,&nchars2); + assert(prefix); + } /* end if */ + else + HGOTO_DONE(FALSE) + } /* end if */ + else + HGOTO_DONE(FALSE) + } /* end while */ + + /* If we reached the end of the prefix path to check, it must be a valid prefix */ + if(*prefix=='\0') + ret_value=TRUE; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5G_common_path() */ + + +/*------------------------------------------------------------------------- + * Function: H5G_build_fullpath + * + * Purpose: Build a full path from a prefix & base pair of strings + * + * Return: Pointer to reference counted string on success, NULL on error + * + * Programmer: Quincey Koziol, koziol@ncsa.uiuc.edu + * + * Date: August 19, 2005 + * + *------------------------------------------------------------------------- + */ +static H5RS_str_t * +H5G_build_fullpath(const char *prefix, const char *name) +{ + char *full_path; /* Full user path built */ + size_t path_len; /* Length of the path */ + unsigned need_sep; /* Flag to indicate if separator is needed */ + H5RS_str_t *ret_value; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5G_build_fullpath) + + /* Sanity check */ + HDassert(prefix); + HDassert(name); + + /* Get the length of the prefix */ + path_len = HDstrlen(prefix); + + /* Determine if there is a trailing separator in the name */ + if(prefix[path_len - 1] == '/') + need_sep = 0; + else + need_sep = 1; + + /* Add in the length needed for the '/' separator and the relative path */ + path_len += HDstrlen(name) + need_sep; + + /* Allocate space for the path */ + if(NULL == (full_path = H5FL_BLK_MALLOC(str_buf, path_len + 1))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") + + /* Build full path */ + HDstrcpy(full_path, prefix); + if(need_sep) + HDstrcat(full_path, "/"); + HDstrcat(full_path, name); + + /* Create reference counted string for path */ + if((ret_value = H5RS_own(full_path)) == NULL) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5G_build_fullpath() */ + + +/*------------------------------------------------------------------------- + * Function: H5G_build_fullpath_refstr_str + * + * Purpose: Append an object path to an existing ref-counted path + * + * Return: Success: Non-NULL, combined path + * Failure: NULL + * + * Programmer: Quincey Koziol, koziol@ncsa.uiuc.edu + * Tuesday, October 11, 2005 + * + *------------------------------------------------------------------------- + */ +static H5RS_str_t * +H5G_build_fullpath_refstr_str(H5RS_str_t *prefix_r, const char *name) +{ + const char *prefix; /* Pointer to raw string for path */ + H5RS_str_t *ret_value; + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5G_build_fullpath_refstr_str) + + HDassert(prefix_r); + HDassert(name); + + /* Get the raw string for the user path */ + prefix = H5RS_get_str(prefix_r); + HDassert(prefix); + + /* Create reference counted string for path */ + ret_value = H5G_build_fullpath(prefix, name); + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5G_build_fullpath_refstr_str() */ + + +/*------------------------------------------------------------------------- + * Function: H5G_name_concat_refstr_refstr + * + * Purpose: Build a full path from a prefix & base pair of reference counted + * strings + * + * Return: Pointer to reference counted string on success, NULL on error + * + * Programmer: Quincey Koziol, koziol@ncsa.uiuc.edu + * + * Date: August 19, 2005 + * + *------------------------------------------------------------------------- + */ +static H5RS_str_t * +H5G_build_fullpath_refstr_refstr(const H5RS_str_t *prefix_r, const H5RS_str_t *name_r) +{ + const char *prefix; /* Pointer to raw string of prefix */ + const char *name; /* Pointer to raw string of name */ + H5RS_str_t *ret_value; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5G_build_fullpath_refstr_refstr) + + /* Get the pointer to the prefix */ + prefix = H5RS_get_str(prefix_r); + + /* Get the pointer to the raw src user path */ + name = H5RS_get_str(name_r); + + /* Create reference counted string for path */ + ret_value = H5G_build_fullpath(prefix, name); + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5G_build_fullpath_refstr_refstr() */ + + +/*------------------------------------------------------------------------- + * Function: H5G_name_init + * + * Purpose: Set the initial path for a group hierarchy name + * + * Return: Success: Non-negative + * Failure: Negative + * + * Programmer: Quincey Koziol + * Monday, September 12, 2005 + * + *------------------------------------------------------------------------- + */ +herr_t +H5G_name_init(H5G_name_t *name, const char *path) +{ + FUNC_ENTER_NOAPI_NOFUNC(H5G_name_init) + + /* Check arguments */ + HDassert(name); + + /* Set the initial paths for a name object */ + name->user_path_r=H5RS_create(path); + HDassert(name->user_path_r); + name->canon_path_r=H5RS_create(path); + HDassert(name->canon_path_r); + name->user_path_hidden=0; + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5G_name_init() */ + + +/*------------------------------------------------------------------------- + * Function: H5G_name_set + * + * Purpose: Set the name of a symbol entry OBJ, located at LOC + * + * Return: Success: Non-negative + * Failure: Negative + * + * Programmer: Pedro Vicente, pvn@ncsa.uiuc.edu + * Thursday, August 22, 2002 + * + *------------------------------------------------------------------------- + */ +herr_t +H5G_name_set(H5G_name_t *loc, H5G_name_t *obj, const char *name) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI(H5G_name_set, FAIL) + + HDassert(loc); + HDassert(obj); + HDassert(name); + + /* Free & reset the object's previous paths info (if they exist) */ + H5G_name_free(obj); + + /* Create the object's user path, if a user path exists in the location */ + if(loc->user_path_r) { + /* Go build the new user path */ + if((obj->user_path_r = H5G_build_fullpath_refstr_str(loc->user_path_r, name)) == NULL) + HGOTO_ERROR(H5E_SYM, H5E_PATH, FAIL, "can't build user path name") + } /* end if */ + + /* Create the object's canonical path, if a canonical path exists in the location */ + if(loc->canon_path_r) { + /* Go build the new canonical path */ + if((obj->canon_path_r = H5G_build_fullpath_refstr_str(loc->canon_path_r, name)) == NULL) + HGOTO_ERROR(H5E_SYM, H5E_PATH, FAIL, "can't build canonical path name") + } /* end if */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5G_name_set() */ + + +/*------------------------------------------------------------------------- + * Function: H5G_name_copy + * + * Purpose: Do a copy of group hier. names + * + * Return: Success: Non-negative + * Failure: Negative + * + * Programmer: Quincey Koziol + * Monday, September 12, 2005 + * + * Notes: 'depth' parameter determines how much of the group entry + * structure we want to copy. The new depths are: + * H5G_COPY_SHALLOW - Copy all the fields from the source + * to the destination, including the user path and + * canonical path. (Destination "takes ownership" of + * user and canonical paths) + * H5G_COPY_CANON - Deep copy the canonical path and leave + * the user path alone + * H5G_COPY_DEEP - Copy all the fields from the source to + * the destination, deep copying the user and canonical + * paths. + * + *------------------------------------------------------------------------- + */ +herr_t +H5G_name_copy(H5G_name_t *dst, const H5G_name_t *src, H5G_copy_depth_t depth) +{ + H5RS_str_t *tmp_user_path_r = NULL; /* Temporary string pointer for entry's user path */ + + FUNC_ENTER_NOAPI_NOFUNC(H5G_name_copy) + + /* Check arguments */ + HDassert(src); + HDassert(dst); + HDassert(depth == H5G_COPY_SHALLOW || depth == H5G_COPY_DEEP || depth == H5G_COPY_CANON); + + /* If only copying the canonical path, keep the old user path */ + if(depth == H5G_COPY_CANON) { + tmp_user_path_r = dst->user_path_r; + if(dst->canon_path_r) + H5RS_decr(dst->canon_path_r); + } /* end if */ + + /* Copy the top level information */ + HDmemcpy(dst, src, sizeof(H5G_name_t)); + + /* Deep copy the names */ + if(depth == H5G_COPY_DEEP) { + dst->user_path_r = H5RS_dup(src->user_path_r); + dst->canon_path_r = H5RS_dup(src->canon_path_r); + } else if(depth == H5G_COPY_CANON) { + dst->user_path_r = tmp_user_path_r; + dst->canon_path_r = H5RS_dup(src->canon_path_r); + } else { + /* Discarding 'const' qualifier OK - QAK */ + H5G_name_reset((H5G_name_t *)src); + } /* end if */ + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5G_name_copy() */ + + +/*------------------------------------------------------------------------- + * Function: H5G_name_reset + * + * Purpose: Reset a group hierarchy name to an empty state + * + * Return: Success: Non-negative + * Failure: Negative + * + * Programmer: Quincey Koziol + * Monday, September 12, 2005 + * + *------------------------------------------------------------------------- + */ +herr_t +H5G_name_reset(H5G_name_t *name) +{ + FUNC_ENTER_NOAPI_NOFUNC(H5G_name_reset) + + /* Check arguments */ + HDassert(name); + + /* Clear the group hier. name to an empty state */ + HDmemset(name, 0, sizeof(H5G_name_t)); + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5G_name_reset() */ + + +/*------------------------------------------------------------------------- + * Function: H5G_name_free + * + * Purpose: Free the 'ID to name' buffers. + * + * Return: Success + * + * Programmer: Pedro Vicente, pvn@ncsa.uiuc.edu + * + * Date: August 22, 2002 + * + *------------------------------------------------------------------------- + */ +herr_t +H5G_name_free(H5G_name_t *name) +{ + FUNC_ENTER_NOAPI_NOFUNC(H5G_name_free) + + /* Check args */ + HDassert(name); + + if(name->user_path_r) { + H5RS_decr(name->user_path_r); + name->user_path_r=NULL; + } /* end if */ + if(name->canon_path_r) { + H5RS_decr(name->canon_path_r); + name->canon_path_r=NULL; + } /* end if */ + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5G_name_free() */ + + +/*------------------------------------------------------------------------- + * Function: H5G_name_replace_cb + * + * Purpose: H5I_search callback function to replace group entry names + * + * Return: Success: 0, Failure: -1 + * + * Programmer: Pedro Vicente, pvn@ncsa.uiuc.edu + * + * Date: June 5, 2002 + * + *------------------------------------------------------------------------- + */ +static int +H5G_name_replace_cb(void *obj_ptr, hid_t obj_id, void *key) +{ + const H5G_names_t *names = (const H5G_names_t *)key; /* Get operation's information */ + H5O_loc_t *oloc; /* Object location for object that the ID refers to */ + H5G_name_t *obj_path; /* Pointer to group hier. path for obj */ + H5F_t *top_ent_file; /* Top file in entry's mounted file chain */ + H5F_t *top_loc_file; /* Top file in location's mounted file chain */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5G_name_replace_cb) + + HDassert(obj_ptr); + + /* Get the symbol table entry */ + switch(H5I_get_type(obj_id)) { + case H5I_GROUP: + oloc = H5G_oloc((H5G_t *)obj_ptr); + obj_path = H5G_nameof((H5G_t *)obj_ptr); + break; + + case H5I_DATASET: + oloc = H5D_oloc((H5D_t *)obj_ptr); + obj_path = H5D_nameof((H5D_t *)obj_ptr); + break; + + case H5I_DATATYPE: + /* Avoid non-named datatypes */ + if(!H5T_is_named((H5T_t *)obj_ptr)) + HGOTO_DONE(SUCCEED) /* Do not exit search over IDs */ + + oloc = H5T_oloc((H5T_t *)obj_ptr); + obj_path = H5T_nameof((H5T_t *)obj_ptr); + break; + + default: + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "unknown data object") + } /* end switch */ + HDassert(oloc); + HDassert(obj_path); + + switch(names->op) { + /*------------------------------------------------------------------------- + * OP_MOUNT + *------------------------------------------------------------------------- + */ + case OP_MOUNT: + if(obj_path->user_path_r) { + if(oloc->file->mtab.parent && H5RS_cmp(obj_path->user_path_r, obj_path->canon_path_r)) { + /* Find the "top" file in the chain of mounted files */ + top_ent_file = oloc->file->mtab.parent; + while(top_ent_file->mtab.parent != NULL) + top_ent_file = top_ent_file->mtab.parent; + } /* end if */ + else + top_ent_file = oloc->file; + + /* Check for entry being in correct file (or mounted file) */ + if(top_ent_file->shared == names->loc->oloc->file->shared) { + /* Check if the source is along the entry's path */ + /* (But not actually the entry itself) */ + if(H5G_common_path(obj_path->user_path_r, names->src_name) && + H5RS_cmp(obj_path->user_path_r, names->src_name) != 0) { + /* Hide the user path */ + (obj_path->user_path_hidden)++; + } /* end if */ + } /* end if */ + } /* end if */ + break; + + /*------------------------------------------------------------------------- + * OP_UNMOUNT + *------------------------------------------------------------------------- + */ + case OP_UNMOUNT: + if(obj_path->user_path_r) { + if(oloc->file->mtab.parent) { + /* Find the "top" file in the chain of mounted files for the entry */ + top_ent_file = oloc->file->mtab.parent; + while(top_ent_file->mtab.parent != NULL) + top_ent_file=top_ent_file->mtab.parent; + } /* end if */ + else + top_ent_file = oloc->file; + + if(names->loc->oloc->file->mtab.parent) { + /* Find the "top" file in the chain of mounted files for the location */ + top_loc_file = names->loc->oloc->file->mtab.parent; + while(top_loc_file->mtab.parent != NULL) + top_loc_file = top_loc_file->mtab.parent; + } /* end if */ + else + top_loc_file = names->loc->oloc->file; + + /* If the ID's entry is not in the file we operated on, skip it */ + if(top_ent_file->shared == top_loc_file->shared) { + if(obj_path->user_path_hidden) { + if(H5G_common_path(obj_path->user_path_r, names->src_name)) { + /* Un-hide the user path */ + (obj_path->user_path_hidden)--; + } /* end if */ + } /* end if */ + else { + if(H5G_common_path(obj_path->user_path_r, names->src_name)) { + /* Free user path */ + H5RS_decr(obj_path->user_path_r); + obj_path->user_path_r = NULL; + } /* end if */ + } /* end else */ + } /* end if */ + } /* end if */ + break; + + /*------------------------------------------------------------------------- + * OP_UNLINK + *------------------------------------------------------------------------- + */ + case OP_UNLINK: + /* If the ID's entry is not in the file we operated on, skip it */ + if(oloc->file->shared == names->loc->oloc->file->shared && + names->loc->path->canon_path_r && obj_path->canon_path_r && obj_path->user_path_r) { + /* Check if we are referring to the same object */ + if(H5F_addr_eq(oloc->addr, names->loc->oloc->addr)) { + /* Check if the object was opened with the same canonical path as the one being moved */ + if(H5RS_cmp(obj_path->canon_path_r, names->loc->path->canon_path_r) == 0) { + /* Free user path */ + H5RS_decr(obj_path->user_path_r); + obj_path->user_path_r=NULL; + } /* end if */ + } /* end if */ + else { + /* Check if the location being unlinked is in the canonical path for the current object */ + if(H5G_common_path(obj_path->canon_path_r, names->loc->path->canon_path_r)) { + /* Free user path */ + H5RS_decr(obj_path->user_path_r); + obj_path->user_path_r=NULL; + } /* end if */ + } /* end else */ + } /* end if */ + break; + + /*------------------------------------------------------------------------- + * OP_MOVE + *------------------------------------------------------------------------- + */ + case OP_MOVE: /* H5Gmove case, check for relative names case */ + /* If the ID's entry is not in the file we operated on, skip it */ + if(oloc->file->shared == names->loc->oloc->file->shared) { + if(obj_path->user_path_r && names->loc->path->user_path_r && + names->src_loc->path->user_path_r && names->dst_loc->path->user_path_r) { + H5RS_str_t *src_path_r; /* Full user path of source name */ + H5RS_str_t *dst_path_r; /* Full user path of destination name */ + H5RS_str_t *canon_src_path_r; /* Copy of canonical part of source path */ + H5RS_str_t *canon_dst_path_r; /* Copy of canonical part of destination path */ + + /* Sanity check */ + HDassert(names->src_name); + HDassert(names->dst_name); + + /* Make certain that the source and destination names are full (not relative) paths */ + if(*(H5RS_get_str(names->src_name)) != '/') { + /* Create reference counted string for full src path */ + if((src_path_r = H5G_build_fullpath_refstr_refstr(names->src_loc->path->user_path_r, names->src_name)) == NULL) + HGOTO_ERROR(H5E_SYM, H5E_PATH, FAIL, "can't build source path name") + } /* end if */ + else + src_path_r = H5RS_dup(names->src_name); + if(*(H5RS_get_str(names->dst_name)) != '/') { + /* Create reference counted string for full dst path */ + if((dst_path_r = H5G_build_fullpath_refstr_refstr(names->dst_loc->path->user_path_r, names->dst_name)) == NULL) + HGOTO_ERROR(H5E_SYM, H5E_PATH, FAIL, "can't build destination path name") + } /* end if */ + else + dst_path_r = H5RS_dup(names->dst_name); + + /* Get the canonical parts of the source and destination names */ + + /* Check if the object being moved was accessed through a mounted file */ + if(H5RS_cmp(names->loc->path->user_path_r, names->loc->path->canon_path_r) != 0) { + size_t non_canon_name_len; /* Length of non-canonical part of name */ + + /* Get current string lengths */ + non_canon_name_len = H5RS_len(names->loc->path->user_path_r) - H5RS_len(names->loc->path->canon_path_r); + + canon_src_path_r = H5RS_create(H5RS_get_str(src_path_r) + non_canon_name_len); + canon_dst_path_r = H5RS_create(H5RS_get_str(dst_path_r) + non_canon_name_len); + } /* end if */ + else { + canon_src_path_r = H5RS_dup(src_path_r); + canon_dst_path_r = H5RS_dup(dst_path_r); + } /* end else */ + + /* Check if the link being changed in the file is along the canonical path for this object */ + if(H5G_common_path(obj_path->canon_path_r, canon_src_path_r)) { + size_t user_dst_len; /* Length of destination user path */ + size_t canon_dst_len; /* Length of destination canonical path */ + const char *old_user_path; /* Pointer to previous user path */ + char *new_user_path; /* Pointer to new user path */ + char *new_canon_path; /* Pointer to new canonical path */ + const char *tail_path; /* Pointer to "tail" of path */ + size_t tail_len; /* Pointer to "tail" of path */ + char *src_canon_prefix; /* Pointer to source canonical path prefix of component which is moving */ + size_t src_canon_prefix_len;/* Length of the source canonical path prefix */ + char *dst_canon_prefix; /* Pointer to destination canonical path prefix of component which is moving */ + size_t dst_canon_prefix_len;/* Length of the destination canonical path prefix */ + char *user_prefix; /* Pointer to user path prefix of component which is moving */ + size_t user_prefix_len; /* Length of the user path prefix */ + char *src_comp; /* The source name of the component which is actually changing */ + char *dst_comp; /* The destination name of the component which is actually changing */ + const char *canon_src_path; /* pointer to canonical part of source path */ + const char *canon_dst_path; /* pointer to canonical part of destination path */ + + /* Get the pointers to the raw strings */ + canon_src_path = H5RS_get_str(canon_src_path_r); + canon_dst_path = H5RS_get_str(canon_dst_path_r); + + /* Get the source & destination components */ + src_comp = HDstrrchr(canon_src_path, '/'); + HDassert(src_comp); + dst_comp = HDstrrchr(canon_dst_path, '/'); + HDassert(dst_comp); + + /* Find the canonical prefixes for the entry */ + src_canon_prefix_len = HDstrlen(canon_src_path) - HDstrlen(src_comp); + if(NULL == (src_canon_prefix = H5MM_malloc(src_canon_prefix_len + 1))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") + HDstrncpy(src_canon_prefix, canon_src_path, src_canon_prefix_len); + src_canon_prefix[src_canon_prefix_len] = '\0'; + + dst_canon_prefix_len = HDstrlen(canon_dst_path) - HDstrlen(dst_comp); + if(NULL == (dst_canon_prefix = H5MM_malloc(dst_canon_prefix_len + 1))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") + HDstrncpy(dst_canon_prefix, canon_dst_path, dst_canon_prefix_len); + dst_canon_prefix[dst_canon_prefix_len] = '\0'; + + /* Hold this for later use */ + old_user_path = H5RS_get_str(obj_path->user_path_r); + + /* Find the user prefix for the entry */ + user_prefix_len = HDstrlen(old_user_path) - H5RS_len(obj_path->canon_path_r); + if(NULL == (user_prefix = H5MM_malloc(user_prefix_len + 1))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") + HDstrncpy(user_prefix, old_user_path, user_prefix_len); + user_prefix[user_prefix_len] = '\0'; + + /* Set the tail path info */ + tail_path = old_user_path+user_prefix_len + src_canon_prefix_len + HDstrlen(src_comp); + tail_len = HDstrlen(tail_path); + + /* Get the length of the destination paths */ + user_dst_len = user_prefix_len + dst_canon_prefix_len + HDstrlen(dst_comp) + tail_len; + canon_dst_len = dst_canon_prefix_len + HDstrlen(dst_comp) + tail_len; + + /* Allocate space for the new user path */ + if(NULL == (new_user_path = H5FL_BLK_MALLOC(str_buf, user_dst_len + 1))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") + + /* Allocate space for the new canonical path */ + if(NULL == (new_canon_path = H5FL_BLK_MALLOC(str_buf, canon_dst_len + 1))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") + + /* Create the new names */ + HDstrcpy(new_user_path, user_prefix); + HDstrcat(new_user_path, dst_canon_prefix); + HDstrcat(new_user_path, dst_comp); + HDstrcat(new_user_path, tail_path); + HDstrcpy(new_canon_path, dst_canon_prefix); + HDstrcat(new_canon_path, dst_comp); + HDstrcat(new_canon_path, tail_path); + + /* Release the old user & canonical paths */ + H5RS_decr(obj_path->user_path_r); + H5RS_decr(obj_path->canon_path_r); + + /* Take ownership of the new user & canonical paths */ + obj_path->user_path_r = H5RS_own(new_user_path); + obj_path->canon_path_r = H5RS_own(new_canon_path); + + /* Free the extra paths allocated */ + H5MM_xfree(src_canon_prefix); + H5MM_xfree(dst_canon_prefix); + H5MM_xfree(user_prefix); + } /* end if */ + + + /* Free the extra paths allocated */ + H5RS_decr(src_path_r); + H5RS_decr(dst_path_r); + H5RS_decr(canon_src_path_r); + H5RS_decr(canon_dst_path_r); + } /* end if */ + else { + /* Release the old user path */ + if(obj_path->user_path_r) { + H5RS_decr(obj_path->user_path_r); + obj_path->user_path_r = NULL; + } /* end if */ + } /* end else */ + } /* end if */ + break; + + default: + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid call") + } /* end switch */ + +done: + FUNC_LEAVE_NOAPI(ret_value); +} /* end H5G_name_replace_cb() */ + + +/*------------------------------------------------------------------------- + * Function: H5G_name_replace + * + * Purpose: Search the list of open IDs and replace names according to a + * particular operation. The operation occured on the LOC + * entry, which had SRC_NAME previously. The new name (if there + * is one) is DST_NAME. Additional entry location information + * (currently only needed for the 'move' operation) is passed + * in SRC_LOC and DST_LOC. + * + * Return: Success: 0, Failure: -1 + * + * Programmer: Pedro Vicente, pvn@ncsa.uiuc.edu + * + * Date: June 11, 2002 + * + *------------------------------------------------------------------------- + */ +herr_t +H5G_name_replace(H5G_obj_t type, H5G_loc_t *loc, + H5RS_str_t *src_name, H5G_loc_t *src_loc, + H5RS_str_t *dst_name, H5G_loc_t *dst_loc, H5G_names_op_t op) +{ + H5G_names_t names; /* Structure to hold operation information for callback */ + unsigned search_group = 0; /* Flag to indicate that groups are to be searched */ + unsigned search_dataset = 0; /* Flag to indicate that datasets are to be searched */ + unsigned search_datatype = 0; /* Flag to indicate that datatypes are to be searched */ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI(H5G_name_replace, FAIL) + + /* Set up common information for callback */ + names.src_name = src_name; + names.dst_name = dst_name; + names.loc = loc; + names.src_loc = src_loc; + names.dst_loc = dst_loc; + names.op = op; + + /* Determine which types of IDs need to be operated on */ + switch(type) { + /* Object is a group */ + case H5G_GROUP: + /* Search and replace names through group IDs */ + search_group = 1; + break; + + /* Object is a dataset */ + case H5G_DATASET: + /* Search and replace names through dataset IDs */ + search_dataset = 1; + break; + + /* Object is a named datatype */ + case H5G_TYPE: + /* Search and replace names through datatype IDs */ + search_datatype = 1; + break; + + case H5G_UNKNOWN: /* We pass H5G_UNKNOWN as object type when we need to search all IDs */ + case H5G_LINK: /* Symbolic links might resolve to any object, so we need to search all IDs */ + /* Check if we will need to search groups */ + if(H5I_nmembers(H5I_GROUP) > 0) + search_group = 1; + + /* Check if we will need to search datasets */ + if(H5I_nmembers(H5I_DATASET) > 0) + search_dataset = 1; + + /* Check if we will need to search datatypes */ + if(H5I_nmembers(H5I_DATATYPE) > 0) + search_datatype = 1; + break; + + default: + HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, FAIL, "not valid object type"); + } /* end switch */ + + /* Search through group IDs */ + if(search_group) + H5I_search(H5I_GROUP, H5G_name_replace_cb, &names); + + /* Search through dataset IDs */ + if(search_dataset) + H5I_search(H5I_DATASET, H5G_name_replace_cb, &names); + + /* Search through datatype IDs */ + if(search_datatype) + H5I_search(H5I_DATATYPE, H5G_name_replace_cb, &names); + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5G_name_replace() */ + |