/*------------------------------------------------------------------------- * Function: H5G_namei * * Purpose: Translates a name to a symbol table entry. * * If the specified name can be fully resolved, then this * function returns the symbol table entry for the named object * through the OBJ_ENT argument. The symbol table entry for the * group containing the named object is returned through the * GRP_ENT argument if it is non-null. However, if the name * refers to the root object then the GRP_ENT will be * initialized with an undefined object header address. The * REST argument, if present, will point to the null terminator * of NAME. * * If the specified name cannot be fully resolved, then OBJ_ENT * is initialized with the undefined object header address. The * REST argument will point into the NAME argument to the start * of the component that could not be located. The GRP_ENT will * contain the entry for the symbol table that was being * searched at the time of the failure and will have an * undefined object header address if the search failed at the * root object. For instance, if NAME is `/foo/bar/baz' and the * root directory exists and contains an entry for `foo', and * foo is a group that contains an entry for bar, but bar is not * a group, then the results will be that REST points to `baz', * OBJ_ENT has an undefined object header address, and GRP_ENT * is the symbol table entry for `bar' in `/foo'. * * Every file has a root group whose name is `/'. Components of * a name are separated from one another by one or more slashes * (/). Slashes at the end of a name are ignored. If the name * begins with a slash then the search begins at the root group * of the file containing LOC_ENT. Otherwise it begins at * LOC_ENT. The component `.' is a no-op, but `..' is not * understood by this function (unless it appears as an entry in * the symbol table). * * Symbolic links are followed automatically, but if TARGET * includes the H5G_TARGET_SLINK bit and the last component of * the name is a symbolic link then that link is not followed. * The *NLINKS value is decremented each time a link is followed * and link traversal fails if the value would become negative. * If NLINKS is the null pointer then a default value is used. * * Mounted files are handled by calling H5F_mountpoint() after * each step of the translation. If the input argument to that * function is a mount point then the argument shall be replaced * with information about the root group of the mounted file. * But if TARGET includes the H5G_TARGET_MOUNT bit and the last * component of the name is a mount point then H5F_mountpoint() * is not called and information about the mount point itself is * returned. * * Errors: * * Return: Success: Non-negative if name can be fully resolved. * See above for values of REST, GRP_ENT, and * OBJ_ENT. NLINKS has been decremented for * each symbolic link that was followed. * * Failure: Negative if the name could not be fully * resolved. See above for values of REST, * GRP_ENT, and OBJ_ENT. * * Programmer: Robb Matzke * [email protected] * Aug 11 1997 * * Modifications: * Robb Matzke, 2002-03-28 * The component name buffer on the stack has been replaced by * a dynamically allocated buffer on the heap in order to * remove limitations on the length of a name component. * There are two reasons that the buffer pointer is global: * (1) We want to be able to reuse the buffer without * allocating and freeing it each time this function is * called. * (2) We need to be able to free it from H5G_term_interface() * when the library terminates. * * Pedro Vicente, <*****@*****.**> 22 Aug 2002 * Modified to deep copies of symbol table entries * Added `id to name' support. * * Quincey Koziol, 2003-01-06 * Added "action" and "ent" parameters to allow different actions when * working on the last component of a name. (Specifically, this allows * inserting an entry into a group, instead of trying to look it up) * *------------------------------------------------------------------------- */ herr_t H5G_namei(const H5G_entry_t *loc_ent, const char *name, const char **rest/*out*/, H5G_entry_t *grp_ent/*out*/, H5G_entry_t *obj_ent/*out*/, unsigned target, int *nlinks/*out*/, H5G_namei_act_t action, H5G_entry_t *ent, hid_t dxpl_id) { H5G_entry_t _grp_ent; /*entry for current group */ H5G_entry_t _obj_ent; /*entry found */ size_t nchars; /*component name length */ int _nlinks = H5G_NLINKS; const char *s = NULL; unsigned null_obj; /* Flag to indicate this function was called with obj_ent set to NULL */ unsigned null_grp; /* Flag to indicate this function was called with grp_ent set to NULL */ unsigned obj_copy = 0; /* Flag to indicate that the object entry is copied */ unsigned group_copy = 0; /* Flag to indicate that the group entry is copied */ unsigned last_comp = 0; /* Flag to indicate that a component is the last component in the name */ unsigned did_insert = 0; /* Flag to indicate that H5G_stab_insert was called */ herr_t ret_value=SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5G_namei); /* Set up "out" parameters */ if (rest) *rest = name; if (!grp_ent) { grp_ent = &_grp_ent; null_grp = 1; } /* end if */ else null_grp = 0; if (!obj_ent) { obj_ent = &_obj_ent; null_obj = 1; } /* end if */ else null_obj = 0; if (!nlinks) nlinks = &_nlinks; /* Check args */ if (!name || !*name) HGOTO_ERROR (H5E_SYM, H5E_NOTFOUND, FAIL, "no name given"); if (!loc_ent) HGOTO_ERROR (H5E_SYM, H5E_NOTFOUND, FAIL, "no current working group"); /* * Where does the searching start? For absolute names it starts at the * root of the file; for relative names it starts at CWG. */ /* Check if we need to get the root group's entry */ if('/' == *name) { H5G_t *tmp_grp; /* Temporary pointer to root group of file */ /* Look up root group for starting location */ tmp_grp = H5G_rootof(loc_ent->file); HDassert(tmp_grp); /* Set the location entry to the root group's entry*/ loc_ent = &(tmp_grp->ent); } /* end if */ /* Deep copy of the symbol table entry (duplicates strings) */ if(H5G_ent_copy(obj_ent, loc_ent, H5_COPY_DEEP) < 0) HGOTO_ERROR(H5E_DATATYPE, H5E_CANTOPENOBJ, FAIL, "unable to copy entry") obj_copy = 1; H5G_ent_reset(grp_ent); /* Check for needing a larger buffer for the individual path name components */ if((HDstrlen(name) + 1) > H5G_comp_alloc_g) { char *new_comp; /* New component buffer */ size_t new_alloc; /* New component buffer size */ new_alloc = MAX3(1024, (2 * H5G_comp_alloc_g), (HDstrlen(name) + 1)); if(NULL == (new_comp = H5MM_realloc(H5G_comp_g, new_alloc))) HGOTO_ERROR(H5E_SYM, H5E_NOSPACE, FAIL, "unable to allocate component buffer") H5G_comp_g = new_comp; H5G_comp_alloc_g = new_alloc; } /* end if */ /* traverse the name */ while ((name = H5G_component(name, &nchars)) && *name) { /* Update the "rest of name" pointer */ if(rest) *rest = name; /* * Copy the component name into a null-terminated buffer so * we can pass it down to the other symbol table functions. */ HDmemcpy(H5G_comp_g, name, nchars); H5G_comp_g[nchars] = '\0'; /* * The special name `.' is a no-op. */ if ('.' == H5G_comp_g[0] && !H5G_comp_g[1]) { name += nchars; continue; } /* end if */ /* * Advance to the next component of the name. */ /* If we've already copied a new entry into the group entry, * it needs to be freed before overwriting it with another entry */ if(group_copy) H5G_name_free(grp_ent); /* Transfer "ownership" of the entry's information to the group entry */ H5G_ent_copy(grp_ent, obj_ent, H5_COPY_SHALLOW); H5G_ent_reset(obj_ent); /* Set flag that we've copied a new entry into the group entry */ group_copy = 1; /* Check if this is the last component of the name */ if(!((s=H5G_component(name+nchars, NULL)) && *s)) last_comp=1; switch(action) { case H5G_NAMEI_TRAVERSE: if (H5G_stab_find(grp_ent, H5G_comp_g, obj_ent/*out*/, dxpl_id )<0) { /* * Component was not found in the current symbol table, possibly * because GRP_ENT isn't a symbol table. */ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "component not found"); } break; case H5G_NAMEI_INSERT: if(!last_comp) { if (H5G_stab_find(grp_ent, H5G_comp_g, obj_ent/*out*/, dxpl_id )<0) { /* * Component was not found in the current symbol table, possibly * because GRP_ENT isn't a symbol table. */ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "component not found"); } } /* end if */ else { did_insert = 1; if(H5G_stab_insert(grp_ent, H5G_comp_g, ent, TRUE, dxpl_id) < 0) HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, FAIL, "unable to insert name") HGOTO_DONE(SUCCEED); } /* end else */ break; } /* end switch */ /* * If we found a symbolic link then we should follow it. But if this * is the last component of the name and the H5G_TARGET_SLINK bit of * TARGET is set then we don't follow it. */ if(H5G_CACHED_SLINK==obj_ent->type && (0==(target & H5G_TARGET_SLINK) || !last_comp)) { if ((*nlinks)-- <= 0) HGOTO_ERROR (H5E_SYM, H5E_SLINK, FAIL, "too many links"); if (H5G_traverse_slink (grp_ent, obj_ent, nlinks, dxpl_id)<0) HGOTO_ERROR (H5E_SYM, H5E_NOTFOUND, FAIL, "symbolic link traversal failed"); } /* * Resolve mount points to the mounted group. Do not do this step if * the H5G_TARGET_MOUNT bit of TARGET is set and this is the last * component of the name. */ if (0==(target & H5G_TARGET_MOUNT) || !last_comp) H5F_mountpoint(obj_ent/*in,out*/); /* next component */ name += nchars; } /* end while */ /* Update the "rest of name" pointer */ if (rest) *rest = name; /*final null */ /* If this was an insert, make sure that the insert function was actually * called (this catches no-op names like "." and "/") */ if(action == H5G_NAMEI_INSERT && !did_insert) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "group already exists"); done: /* If we started with a NULL obj_ent, free the entry information */ if(null_obj || (ret_value < 0 && obj_copy)) H5G_name_free(obj_ent); /* If we started with a NULL grp_ent and we copied something into it, free the entry information */ if(null_grp && group_copy) H5G_name_free(grp_ent); FUNC_LEAVE_NOAPI(ret_value); }
/*------------------------------------------------------------------------- * Function: H5G_namei * * Purpose: Translates a name to a symbol table entry. * * If the specified name can be fully resolved, then this * function returns the symbol table entry for the named object * through the OBJ_ENT argument. The symbol table entry for the * group containing the named object is returned through the * GRP_ENT argument if it is non-null. However, if the name * refers to the root object then the GRP_ENT will be * initialized with an undefined object header address. The * REST argument, if present, will point to the null terminator * of NAME. * * If the specified name cannot be fully resolved, then OBJ_ENT * is initialized with the undefined object header address. The * REST argument will point into the NAME argument to the start * of the component that could not be located. The GRP_ENT will * contain the entry for the symbol table that was being * searched at the time of the failure and will have an * undefined object header address if the search failed at the * root object. For instance, if NAME is `/foo/bar/baz' and the * root directory exists and contains an entry for `foo', and * foo is a group that contains an entry for bar, but bar is not * a group, then the results will be that REST points to `baz', * OBJ_ENT has an undefined object header address, and GRP_ENT * is the symbol table entry for `bar' in `/foo'. * * Every file has a root group whose name is `/'. Components of * a name are separated from one another by one or more slashes * (/). Slashes at the end of a name are ignored. If the name * begins with a slash then the search begins at the root group * of the file containing LOC_ENT. Otherwise it begins at * LOC_ENT. The component `.' is a no-op, but `..' is not * understood by this function (unless it appears as an entry in * the symbol table). * * Symbolic links are followed automatically, but if TARGET * includes the H5G_TARGET_SLINK bit and the last component of * the name is a symbolic link then that link is not followed. * The *NLINKS value is decremented each time a link is followed * and link traversal fails if the value would become negative. * If NLINKS is the null pointer then a default value is used. * * Mounted files are handled by calling H5F_mountpoint() after * each step of the translation. If the input argument to that * function is a mount point then the argument shall be replaced * with information about the root group of the mounted file. * But if TARGET includes the H5G_TARGET_MOUNT bit and the last * component of the name is a mount point then H5F_mountpoint() * is not called and information about the mount point itself is * returned. * * Errors: * * Return: Success: Non-negative if name can be fully resolved. * See above for values of REST, GRP_ENT, and * OBJ_ENT. NLINKS has been decremented for * each symbolic link that was followed. * * Failure: Negative if the name could not be fully * resolved. See above for values of REST, * GRP_ENT, and OBJ_ENT. * * Programmer: Robb Matzke * [email protected] * Aug 11 1997 * * Modifications: * Robb Matzke, 2002-03-28 * The component name buffer on the stack has been replaced by * a dynamically allocated buffer on the heap in order to * remove limitations on the length of a name component. * There are two reasons that the buffer pointer is global: * (1) We want to be able to reuse the buffer without * allocating and freeing it each time this function is * called. * (2) We need to be able to free it from H5G_term_interface() * when the library terminates. * * Pedro Vicente, <*****@*****.**> 22 Aug 2002 * Modified to deep copies of symbol table entries * Added `id to name' support. * * Quincey Koziol, 2003-01-06 * Added "action" and "ent" parameters to allow different actions when * working on the last component of a name. (Specifically, this allows * inserting an entry into a group, instead of trying to look it up) * *------------------------------------------------------------------------- */ herr_t H5G_namei(const H5G_entry_t *loc_ent, const char *name, const char **rest/*out*/, H5G_entry_t *grp_ent/*out*/, H5G_entry_t *obj_ent/*out*/, unsigned target, int *nlinks/*out*/, H5G_namei_act_t action, H5G_entry_t *ent, hid_t dxpl_id) { H5G_entry_t _grp_ent; /*entry for current group */ H5G_entry_t _obj_ent; /*entry found */ size_t nchars; /*component name length */ int _nlinks = H5G_NLINKS; const char *s = NULL; unsigned null_obj; /* Flag to indicate this function was called with obj_ent set to NULL */ unsigned null_grp; /* Flag to indicate this function was called with grp_ent set to NULL */ unsigned obj_copy = 0; /* Flag to indicate that the object entry is copied */ unsigned group_copy = 0; /* Flag to indicate that the group entry is copied */ unsigned last_comp = 0; /* Flag to indicate that a component is the last component in the name */ unsigned did_insert = 0; /* Flag to indicate that H5G_stab_insert was called */ herr_t ret_value=SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5G_namei); /* Set up "out" parameters */ if (rest) *rest = name; if (!grp_ent) { grp_ent = &_grp_ent; null_grp = 1; } /* end if */ else null_grp = 0; if (!obj_ent) { obj_ent = &_obj_ent; null_obj = 1; } /* end if */ else null_obj = 0; if (!nlinks) nlinks = &_nlinks; /* Check args */ if (!name || !*name) HGOTO_ERROR (H5E_SYM, H5E_NOTFOUND, FAIL, "no name given"); if (!loc_ent) HGOTO_ERROR (H5E_SYM, H5E_NOTFOUND, FAIL, "no current working group"); /* * Where does the searching start? For absolute names it starts at the * root of the file; for relative names it starts at CWG. */ /* Check if we need to get the root group's entry */ if('/' == *name) { H5G_t *tmp_grp; /* Temporary pointer to root group of file */ /* Look up root group for starting location */ tmp_grp = H5G_rootof(loc_ent->file); HDassert(tmp_grp); /* Set the location entry to the root group's entry*/ loc_ent = &(tmp_grp->ent); } /* end if */ /* Deep copy of the symbol table entry (duplicates strings) */ if(H5G_ent_copy(obj_ent, loc_ent, H5_COPY_DEEP) < 0) HGOTO_ERROR(H5E_DATATYPE, H5E_CANTOPENOBJ, FAIL, "unable to copy entry") obj_copy = 1; H5G_ent_reset(grp_ent); /* Check for needing a larger buffer for the individual path name components */ if(HDstrlen(name) + 1 > H5G_comp_alloc_g) { H5G_comp_alloc_g = MAX3(1024, 2 * H5G_comp_alloc_g, HDstrlen(name) + 1); H5G_comp_g = H5MM_realloc(H5G_comp_g, H5G_comp_alloc_g); if(!H5G_comp_g) { H5G_comp_alloc_g = 0; HGOTO_ERROR(H5E_SYM, H5E_NOSPACE, FAIL, "unable to allocate component buffer") } /* end if */