diff options
author | James Laird <jlaird@hdfgroup.org> | 2006-07-05 19:01:50 (GMT) |
---|---|---|
committer | James Laird <jlaird@hdfgroup.org> | 2006-07-05 19:01:50 (GMT) |
commit | 801ca2f9cb803b368b36a6c280684c1f6624f169 (patch) | |
tree | ed2543e9bc1f2beb9857f442fc8b52b3c371299f /src/H5L.c | |
parent | d582c7bc8ac8679911e4787f5f92cc37b1c9989c (diff) | |
download | hdf5-801ca2f9cb803b368b36a6c280684c1f6624f169.zip hdf5-801ca2f9cb803b368b36a6c280684c1f6624f169.tar.gz hdf5-801ca2f9cb803b368b36a6c280684c1f6624f169.tar.bz2 |
[svn-r12452] Purpose:
Feature
Description:
Revised Link APIs.
Solution:
New link APIs use H5L*
H5*create_expand do not create links to the objects created; this must
be done manually with H5Llink.
Added APIs to link an object given its ID (H5Llink), to copy links (H5Lcopy),
and changed creation APIs (H5Lcreate_hard and H5Lcreate_soft) and query
API (H5Lget_linkinfo instead of H5Gget_objinfo).
All old APIs are still supported in H5Gdeprec.c .
Platforms tested:
sol, mir, copper
Misc. update:
Forgot to update MANIFEST and release docs. Will do after checkin.
Diffstat (limited to 'src/H5L.c')
-rw-r--r-- | src/H5L.c | 1547 |
1 files changed, 1547 insertions, 0 deletions
diff --git a/src/H5L.c b/src/H5L.c new file mode 100644 index 0000000..fe52dc9 --- /dev/null +++ b/src/H5L.c @@ -0,0 +1,1547 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#define H5F_PACKAGE /*suppress error about including H5Fpkg */ +#define H5G_PACKAGE /*suppress error about including H5Gpkg */ +#define H5L_PACKAGE /*suppress error about including H5Gpkg */ + +/* Interface initialization */ +#define H5_INTERFACE_INIT_FUNC H5L_init_interface + +#include "H5private.h" /* Generic Functions */ +#include "H5Lpkg.h" /* Links */ +#include "H5Fpkg.h" /* File access */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5Iprivate.h" /* IDs */ +#include "H5MMprivate.h" /* Memory management */ +#include "H5Oprivate.h" /* File objects */ +#include "H5Dprivate.h" /* Datasets */ +#include "H5Pprivate.h" /* Property lists */ +#include "H5Gpkg.h" /* Groups */ + +/* Local typedefs */ +#define H5L_MOVE_OP 1 +#define H5L_RENAME_OP 2 + +/* User data for path traversal routine for getting link metadata */ +typedef struct { + H5L_linkinfo_t *linfo; /* Buffer to return to user */ + hid_t dxpl_id; /* dxpl to use in callback */ +} H5L_trav_ud1_t; + +/* User data for path traversal callback to creating a link */ +typedef struct { + H5F_t *file; /* Pointer to the file */ + hid_t dxpl_id; /* Dataset transfer property list */ + H5G_name_t *path; /* Path to object being linked */ + H5O_link_t *lnk; /* Pointer to link information to insert */ +} H5L_trav_ud3_t; + +/* User data for path traversal routine for moving and renaming a link */ +typedef struct { + const char *dst_name; /* Destination name for moving object */ + H5T_cset_t cset; /* Char set for new name */ + H5G_loc_t *dst_loc; /* Destination location for moving object */ + hbool_t copy; /* TRUE if this is a copy operation */ + hid_t dxpl_id; /* dxpl to use in callback */ +} H5L_trav_ud4_t; + +/* User data for path traversal routine for getting soft link value */ +typedef struct { + size_t size; /* Size of user buffer */ + char *buf; /* User buffer */ +} H5L_trav_ud5_t; + +/* User data for path traversal routine for removing link (i.e. unlink) */ +typedef struct { + hid_t dxpl_id; /* Dataset transfer property list */ +} H5L_trav_ud6_t; + +/* User data for path traversal routine for retrieving link creation property list */ +typedef struct { + H5P_genplist_t *lcpl; /* Copy of default property list to be set */ +} H5L_trav_ud8_t; + +/* User data for path traversal routine for moving and renaming an object */ +typedef struct { + H5F_t *file; /* Pointer to the file */ + H5O_link_t *lnk; /* Pointer to link information to insert */ + hid_t dxpl_id; /* Dataset transfer property list */ +} H5L_trav_ud10_t; + +/* Package variables */ + +/* Local variables */ + +/* Private prototypes */ +static herr_t H5L_link_cb(H5G_loc_t *grp_loc/*in*/, const char *name, + const H5O_link_t *lnk, H5G_loc_t *obj_loc, void *_udata/*in,out*/); +static herr_t H5L_create_real(H5G_loc_t *link_loc, const char *link_name, + H5G_name_t *obj_path, H5F_t *obj_file, H5O_link_t *lnk, hid_t dxpl_id, + hid_t lcpl_id); +static herr_t H5L_create_hard(H5G_loc_t *cur_loc, const char *cur_name, + H5G_loc_t *link_loc, const char *link_name, hid_t dxpl_id, hid_t lcpl_id); +static herr_t H5L_create_soft(const char *target_path, H5G_loc_t *loc, + const char *name, hid_t dxpl_id, hid_t lcpl_id); +static herr_t H5L_linkval_cb(H5G_loc_t *grp_loc/*in*/, const char *name, + const H5O_link_t *lnk, H5G_loc_t *obj_loc, void *_udata/*in,out*/); +static herr_t H5L_linkval(H5G_loc_t *loc, const char *name, size_t size, + char *buf/*out*/, hid_t dxpl_id); +static herr_t H5L_unlink_cb(H5G_loc_t *grp_loc/*in*/, const char *name, + const H5O_link_t *lnk, H5G_loc_t *obj_loc, void *_udata/*in,out*/); +static herr_t H5L_unlink(H5G_loc_t *loc, const char *name, hid_t dxpl_id); +static herr_t H5L_move(H5G_loc_t *src_loc, const char *src_name, + H5G_loc_t *dst_loc, const char *dst_name, hbool_t copy_flag, + hid_t lcpl_id, hid_t dxpl_id); +static herr_t H5L_move_rename_cb(H5G_loc_t *grp_loc/*in*/, const char *name, + const H5O_link_t *lnk, H5G_loc_t *obj_loc, void *_udata/*in,out*/); +static herr_t H5L_move_rename_dest_cb(H5G_loc_t *grp_loc/*in*/, + const char *name, const H5O_link_t *lnk, H5G_loc_t *obj_loc, void *_udata/*in,out*/); +static herr_t H5L_get_linkinfo(H5G_loc_t *loc, const char *name, + H5L_linkinfo_t *linkbuf/*out*/, hid_t dxpl_id); +static herr_t H5L_get_linfo_cb(H5G_loc_t UNUSED *grp_loc/*in*/, const char UNUSED *name, + const H5O_link_t *lnk, H5G_loc_t UNUSED *obj_loc, void *_udata/*in,out*/); + + +/*------------------------------------------------------------------------- + * Function: H5L_init_interface + * + * Purpose: Initialize information specific to H5L interface. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: James Laird + * Tuesday, January 24, 2006 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5L_init_interface(void) +{ + H5P_genclass_t *crt_pclass; + size_t nprops; /* Number of properties */ + unsigned intmd_group = H5L_CRT_INTERMEDIATE_GROUP_DEF; + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5L_init_interface) + + /* =========Link Creation Property Class Initialization========= */ + /* Register the default attribute creation properties */ + assert(H5P_CLS_LINK_CREATE_g!=(-1)); + + /* Get the pointer to the link creation class */ + if (NULL == (crt_pclass = H5I_object(H5P_CLS_LINK_CREATE_g))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list class") + + /* Get the number of properties in the class */ + if(H5P_get_nprops_pclass(crt_pclass,&nprops,FALSE)<0) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "can't query number of properties") + + /* Assume that if there are properties in the class, they are the default ones */ + if(nprops==0) { + /* Register create intermediate groups property */ + if(H5P_register(crt_pclass,H5L_CRT_INTERMEDIATE_GROUP_NAME,H5L_CRT_INTERMEDIATE_GROUP_SIZE, + &intmd_group,NULL,NULL,NULL,NULL,NULL,NULL,NULL)<0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class") + } + + /* Only register the default property list if it hasn't been created yet */ + if(H5P_LST_LINK_CREATE_g==(-1)) { + /* Register the default link creation property list */ + if ((H5P_LST_LINK_CREATE_g = H5P_create_id (crt_pclass))<0) + HGOTO_ERROR (H5E_PLIST, H5E_CANTREGISTER, FAIL, "can't register default property list") + } /* end if */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} + + +/*------------------------------------------------------------------------- + * Function: H5L_term_interface + * + * Purpose: Terminate any resources allocated in H5L_init_interface. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: James Laird + * Tuesday, January 24, 2006 + * + *------------------------------------------------------------------------- + */ +int +H5L_term_interface(void) +{ + int n=0; + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5L_term_interface) + + /* The H5L interface currently has no resources that need to be freed. */ + + FUNC_LEAVE_NOAPI(n) +} + +/*------------------------------------------------------------------------- + * Function: H5Lmove + * + * Purpose: Renames an object within an HDF5 file and moves it to a new + * group using H5Lrename and H5Lmove. The original name SRC + * is unlinked from the group graph and the inserted with the new + * name DST (which can specify a new path for the object) as an atomic + * operation. The names are interpreted relative to SRC_LOC_ID and + * DST_LOC_ID, which are either file IDs or group ID. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: James Laird + * Wednesday, March 29, 2006 + * + *------------------------------------------------------------------------- + */ +herr_t +H5Lmove(hid_t src_loc_id, const char *src_name, hid_t dst_loc_id, + const char *dst_name, hid_t lcpl_id) +{ + H5G_loc_t src_loc, *src_loc_p; + H5G_loc_t dst_loc, *dst_loc_p; + herr_t ret_value=SUCCEED; /* Return value */ + + FUNC_ENTER_API(H5Lmove, FAIL) + H5TRACE5("e","isisi",src_loc_id,src_name,dst_loc_id,dst_name,lcpl_id); + + /* Check arguments */ + if(src_loc_id != H5L_SAME_LOC && H5G_loc(src_loc_id, &src_loc) < 0) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location") + if(dst_loc_id != H5L_SAME_LOC && H5G_loc(dst_loc_id, &dst_loc) < 0) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location") + if(!src_name || !*src_name) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no current name specified") + if(!dst_name || !*dst_name) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no destination name specified") + + /* Set up src & dst location pointers */ + src_loc_p = &src_loc; + dst_loc_p = &dst_loc; + if(src_loc_id == H5L_SAME_LOC && dst_loc_id == H5L_SAME_LOC) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "source and destination should not both be H5L_SAME_LOC") + else if(src_loc_id == H5L_SAME_LOC) + src_loc_p = dst_loc_p; + else if(dst_loc_id == H5L_SAME_LOC) + dst_loc_p = src_loc_p; + + if(lcpl_id != H5P_DEFAULT && (TRUE != H5P_isa_class(lcpl_id, H5P_LINK_CREATE))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a link creation property list") + + if(H5L_move(src_loc_p, src_name, dst_loc_p, dst_name, + FALSE, lcpl_id, H5AC_dxpl_id) < 0) + HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to move link") + +done: + FUNC_LEAVE_API(ret_value) +} + + +/*------------------------------------------------------------------------- + * Function: H5Lcopy + * + * Purpose: Creates an identical copy of a link with the same creation + * time and target. The new link can have a different name + * and be in a different location than the original. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: James Laird + * Wednesday, March 29, 2006 + * + *------------------------------------------------------------------------- + */ +herr_t +H5Lcopy(hid_t src_loc_id, const char *src_name, hid_t dst_loc_id, + const char *dst_name, hid_t lcpl_id) +{ + H5G_loc_t src_loc, *src_loc_p; + H5G_loc_t dst_loc, *dst_loc_p; + herr_t ret_value=SUCCEED; /* Return value */ + + FUNC_ENTER_API(H5Lcopy, FAIL) + H5TRACE5("e","isisi",src_loc_id,src_name,dst_loc_id,dst_name,lcpl_id); + + /* Check arguments */ + if(src_loc_id != H5L_SAME_LOC && H5G_loc(src_loc_id, &src_loc) < 0) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location") + if(dst_loc_id != H5L_SAME_LOC && H5G_loc(dst_loc_id, &dst_loc) < 0) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location") + if(!src_name || !*src_name) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no current name specified") + if(!dst_name || !*dst_name) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no destination name specified") + + /* Set up src & dst location pointers */ + src_loc_p = &src_loc; + dst_loc_p = &dst_loc; + if(src_loc_id == H5L_SAME_LOC && dst_loc_id == H5L_SAME_LOC) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "source and destination should not both be H5L_SAME_LOC") + else if(src_loc_id == H5L_SAME_LOC) + src_loc_p = dst_loc_p; + else if(dst_loc_id == H5L_SAME_LOC) + dst_loc_p = src_loc_p; + + if(lcpl_id != H5P_DEFAULT && (TRUE != H5P_isa_class(lcpl_id, H5P_LINK_CREATE))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a link creation property list") + + if(H5L_move(src_loc_p, src_name, dst_loc_p, dst_name, TRUE, lcpl_id, H5AC_dxpl_id) < 0) + HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to move link") + +done: + FUNC_LEAVE_API(ret_value) +} + + +/*------------------------------------------------------------------------- + * Function: H5Llink + * + * Purpose: Creates a hard link from NEW_NAME to the object specified + * by OBJ_ID using properties defined in the Link Creation + * Property List LCPL. + * + * This function should be used to link objects that have just + * been created. + * + * CUR_NAME and NEW_NAME are interpreted relative to + * CUR_LOC_ID and NEW_LOC_ID, which is either a file ID or a + * group ID. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: James Laird + * Tuesday, December 13, 2005 + * + *------------------------------------------------------------------------- + */ +herr_t +H5Llink(hid_t new_loc_id, const char *new_name, hid_t obj_id, hid_t lcpl_id) +{ + H5G_loc_t new_loc; + H5G_loc_t obj_loc; + herr_t ret_value=SUCCEED; /* Return value */ + + FUNC_ENTER_API(H5Llink, FAIL) + H5TRACE4("e","isii",new_loc_id,new_name,obj_id,lcpl_id); + + /* Check arguments */ + if(new_loc_id == H5L_SAME_LOC) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "cannot use H5L_SAME_LOC when only one location is specified") + if(H5G_loc(new_loc_id, &new_loc) < 0) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location") + if(H5G_loc(obj_id, &obj_loc) < 0) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location") + if(!new_name || !*new_name) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name specified") + + if(lcpl_id != H5P_DEFAULT && (TRUE != H5P_isa_class(lcpl_id, H5P_LINK_CREATE))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a link creation property list") + + if(H5L_link(&new_loc, new_name, &obj_loc, H5AC_dxpl_id, lcpl_id ) < 0) + HGOTO_ERROR(H5E_SYM, H5E_LINK, FAIL, "unable to create link") + +done: + FUNC_LEAVE_API(ret_value) +} /* end H5Llink() */ + + +/*------------------------------------------------------------------------- + * Function: H5Lcreate_soft + * + * Purpose: Creates a soft link from NEW_NAME to TARGET_PATH. + * + * TARGET_PATH can be anything and is interpreted at lookup + * time relative to the group which contains the final component + * of NEW_NAME. For instance, if TARGET_PATH is `./foo' and + * NEW_NAME is `./x/y/bar' and a request is made for `./x/y/bar' + * then the actual object looked up is `./x/y/./foo'. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Robb Matzke + * Monday, April 6, 1998 + * + *------------------------------------------------------------------------- + */ +herr_t +H5Lcreate_soft(const char *target_path, + hid_t loc_id, const char *name, hid_t lcpl_id) +{ + H5G_loc_t new_loc, *new_loc_p; + herr_t ret_value=SUCCEED; /* Return value */ + + FUNC_ENTER_API(H5Lcreate_soft, FAIL) + H5TRACE4("e","sisi",target_path,loc_id,name,lcpl_id); + + /* Check arguments */ + if(H5G_loc(loc_id, &new_loc) < 0) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location") + if(!target_path || !*target_path) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no target specified") + if(!name || !*name) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no new name specified") + + if(lcpl_id != H5P_DEFAULT && (TRUE != H5P_isa_class(lcpl_id, H5P_LINK_CREATE))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a link creation property list") + + new_loc_p = &new_loc; + + if(H5L_create_soft(target_path, new_loc_p, name, H5AC_dxpl_id, lcpl_id) < 0) + HGOTO_ERROR(H5E_SYM, H5E_LINK, FAIL, "unable to create link") + +done: + FUNC_LEAVE_API(ret_value) +} /* end H5Lcreate_soft() */ + + +/*------------------------------------------------------------------------- + * Function: H5Lcreate_hard + * + * Purpose: Creates a hard link from NEW_NAME to CUR_NAME. + * + * CUR_NAME must name an existing object. CUR_NAME and + * NEW_NAME are interpreted relative to CUR_LOC_ID and + * NEW_LOC_ID, which are either file IDs or group IDs. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Robb Matzke + * Monday, April 6, 1998 + * + *------------------------------------------------------------------------- + */ +herr_t +H5Lcreate_hard(hid_t cur_loc_id, const char *cur_name, + hid_t new_loc_id, const char *new_name, hid_t lcpl_id) +{ + H5G_loc_t cur_loc, *cur_loc_p; + H5G_loc_t new_loc, *new_loc_p; + herr_t ret_value=SUCCEED; /* Return value */ + + FUNC_ENTER_API(H5Lcreate_hard, FAIL) + H5TRACE5("e","isisi",cur_loc_id,cur_name,new_loc_id,new_name,lcpl_id); + + /* Check arguments */ + if(cur_loc_id != H5L_SAME_LOC && H5G_loc(cur_loc_id, &cur_loc) < 0) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location") + if(new_loc_id != H5L_SAME_LOC && H5G_loc(new_loc_id, &new_loc) < 0) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location") + if(!cur_name || !*cur_name) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no current name specified") + if(!new_name || !*new_name) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no new name specified") + + if(lcpl_id != H5P_DEFAULT && (TRUE != H5P_isa_class(lcpl_id, H5P_LINK_CREATE))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a link creation property list") + + /* Set up current & new location pointers */ + cur_loc_p = &cur_loc; + new_loc_p = &new_loc; + if(cur_loc_id == H5L_SAME_LOC && new_loc_id == H5L_SAME_LOC) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "source and destination should not be both H5L_SAME_LOC") + else if(cur_loc_id == H5L_SAME_LOC) + cur_loc_p = new_loc_p; + else if(new_loc_id == H5L_SAME_LOC) + new_loc_p = cur_loc_p; + else if(cur_loc_p->oloc->file != new_loc_p->oloc->file) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "source and destination should be in the same file.") + + if(H5L_create_hard(cur_loc_p, cur_name, new_loc_p, new_name, H5AC_dxpl_id, lcpl_id) < 0) + HGOTO_ERROR(H5E_SYM, H5E_LINK, FAIL, "unable to create link") + +done: + FUNC_LEAVE_API(ret_value) +} /* end H5Lcreate_hard() */ + + +/*------------------------------------------------------------------------- + * Function: H5Lunlink + * + * Purpose: Removes the specified NAME from the group graph and + * decrements the link count for the object to which NAME + * points. If the link count reaches zero then all file-space + * associated with the object will be reclaimed (but if the + * object is open, then the reclamation of the file space is + * delayed until all handles to the object are closed). + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Robb Matzke + * Monday, April 6, 1998 + * + *------------------------------------------------------------------------- + */ +herr_t +H5Lunlink(hid_t loc_id, const char *name) +{ + H5G_loc_t loc; + herr_t ret_value=SUCCEED; /* Return value */ + + FUNC_ENTER_API(H5Lunlink, FAIL) + H5TRACE2("e","is",loc_id,name); + + /* Check arguments */ + if(H5G_loc(loc_id, &loc) < 0) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location") + if(!name || !*name) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name") + + /* Unlink */ + if(H5L_unlink(&loc, name, H5AC_dxpl_id) < 0) + HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to unlink object") + +done: + FUNC_LEAVE_API(ret_value) +} /* end H5Lunlink() */ + + +/*------------------------------------------------------------------------- + * Function: H5Lget_linkval + * + * Purpose: Returns the link value of a link whose name is NAME. For + * symbolic links, this is the path to which the link points, + * including the null terminator. For user-defined links, it + * is the link buffer. + * + * At most SIZE bytes are copied to the BUF result buffer. + * + * Return: Success: Non-negative with the link value in BUF. + * + * Failure: Negative + * + * Programmer: Robb Matzke + * Monday, April 13, 1998 + * + *------------------------------------------------------------------------- + */ +herr_t +H5Lget_linkval(hid_t loc_id, const char *name, size_t size, char *buf/*out*/) +{ + H5G_loc_t loc; + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_API(H5Lget_linkval, FAIL) + H5TRACE4("e","iszx",loc_id,name,size,buf); + + /* Check arguments */ + if(H5G_loc(loc_id, &loc)) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location") + if(!name || !*name) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name specified") + + /* Get the link value */ + if(H5L_linkval(&loc, name, size, buf, H5AC_ind_dxpl_id) < 0) + HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to get link value") + +done: + FUNC_LEAVE_API(ret_value) +} /* end H5Lget_linkval() */ + + +/*------------------------------------------------------------------------- + * Function: H5Lget_linkinfo + * + * Purpose: Gets metadata for a link. + * + * Return: Success: Non-negative with information in LINKBUF + * + * Failure: Negative + * + * Programmer: James Laird + * Wednesday, June 21, 2006 + * + *------------------------------------------------------------------------- + */ +herr_t +H5Lget_linkinfo(hid_t loc_id, const char *name, H5L_linkinfo_t *linkbuf /*out*/) +{ + H5G_loc_t loc; + herr_t ret_value = SUCCEED; + FUNC_ENTER_API(H5Lget_linkinfo, FAIL) + H5TRACE3("e","isx",loc_id,name,linkbuf); + + /* Check arguments */ + if(H5G_loc(loc_id, &loc)) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location") + if(!name || !*name) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name specified") + + /* Get the creation time */ + if(H5L_get_linkinfo(&loc, name, linkbuf, H5AC_ind_dxpl_id) < 0) + HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to get link info") + +done: + FUNC_LEAVE_API(ret_value) +} + + + +/* + *------------------------------------------------------------------------- + *------------------------------------------------------------------------- + * N O A P I F U N C T I O N S B E Y O N D T H I S P O I N T + *------------------------------------------------------------------------- + *------------------------------------------------------------------------- + */ + +/*------------------------------------------------------------------------- + * Function: H5L_link + * + * Purpose: Creates a link from OBJ_ID to CUR_NAME. See H5Llink() for + * full documentation. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: James Laird + * Tuesday, December 13, 2005 + * + *------------------------------------------------------------------------- + */ +herr_t +H5L_link(H5G_loc_t *new_loc, const char *new_name, H5G_loc_t *obj_loc, + hid_t dxpl_id, hid_t lcpl_id) +{ + char *norm_new_name = NULL; /* Pointer to normalized new name */ + H5F_t *file = NULL; /* File link will be in */ + H5O_link_t lnk; /* Link to insert */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5L_link) + + /* Check args */ + HDassert(new_loc); + HDassert(obj_loc); + HDassert(new_name && *new_name); + + /* Check that the object is not being hard linked into a different file */ + if(NULL == (file = H5G_insertion_file(new_loc, new_name, dxpl_id))) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to identify insertion file") + if(obj_loc->oloc->file != file) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "cannot link an object from another file") + + /* Construct link information for eventual insertion */ + lnk.type = H5L_LINK_HARD; + lnk.u.hard.addr = obj_loc->oloc->addr; + + /* Create the link */ + if( H5L_create_real(new_loc, new_name, obj_loc->path, obj_loc->oloc->file, &lnk, dxpl_id, lcpl_id) <0) + HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to register new name for object") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5L_link() */ + + +/*------------------------------------------------------------------------- + * Function: H5L_link_cb + * + * Purpose: Callback for creating a link to an object. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Monday, September 19, 2005 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5L_link_cb(H5G_loc_t *grp_loc/*in*/, const char *name, const H5O_link_t UNUSED *lnk, + H5G_loc_t *obj_loc, void *_udata/*in,out*/) +{ + H5L_trav_ud3_t *udata = (H5L_trav_ud3_t *)_udata; /* User data passed in */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5L_link_cb) + + /* Check if the name in this group resolved to a valid location */ + /* (which is not what we want) */ + if(obj_loc != NULL) + HGOTO_ERROR(H5E_SYM, H5E_EXISTS, FAIL, "name already exists") + + /* Check for crossing file boundaries with a new hard link */ + if(udata->lnk->type == H5L_LINK_HARD) { + /* Check that both objects are in same file */ + if(grp_loc->oloc->file->shared != udata->file->shared) + HGOTO_ERROR(H5E_SYM, H5E_LINK, FAIL, "interfile hard links are not allowed") + } /* end if */ + + /* Set the link's name correctly */ + /* Casting away const OK -QAK */ + udata->lnk->name = name; + + /* Insert link into group */ + if(H5G_obj_insert(grp_loc->oloc, name, udata->lnk, (hbool_t)(udata->lnk->type == H5L_LINK_HARD ? TRUE : FALSE), udata->dxpl_id) < 0) + HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to create new name/link for object") + + /* Set object's path if it has been passed in and is not set */ + if(udata->path != NULL && udata->path->user_path_r == NULL) + { + if(H5G_name_set(grp_loc->path, udata->path, name) < 0) + HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "cannot set name") + } + +done: + if(ret_value < 0) { + /* Release the group location for the object */ + /* (Group traversal callbacks are responsible for either taking ownership + * of the group location for the object, or freeing it. - QAK) + */ + if(obj_loc) + H5G_loc_free(obj_loc); + } /* end if */ + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5L_link_cb() */ + + +/*------------------------------------------------------------------------- + * Function: H5L_create_real + * + * Purpose: Creates a link at a path location + * + * lnk should have linkclass-specific information already + * set, but this function will take care of setting + * creation time and name. + * + * obj_path can be NULL if the object's path doesn't need to + * be set, and obj_file can be NULL if the object is not a + * hard link. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Monday, December 5, 2005 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5L_create_real(H5G_loc_t *link_loc, const char *link_name, H5G_name_t *obj_path, + H5F_t *obj_file, H5O_link_t *lnk, hid_t dxpl_id, hid_t lcpl_id) +{ + char *norm_link_name = NULL; /* Pointer to normalized link name */ + unsigned target_flags = H5G_TARGET_NORMAL; /* Flags to pass to group traversal function */ + H5T_cset_t char_encoding = H5F_CRT_DEFAULT_CSET; /* Character encoding for link */ + H5P_genplist_t* lc_plist; /* Link creation property list */ + H5L_trav_ud3_t udata; /* User data for callback */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5L_create_real) + + /* Check args */ + HDassert(link_loc); + HDassert(link_name && *link_name); + HDassert(lnk); + + /* Get normalized link name */ + if((norm_link_name = H5G_normalize(link_name)) == NULL) + HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "can't normalize name") + + /* Check for flags present in creation property list */ + if(lcpl_id != H5P_DEFAULT) + { + unsigned crt_intmd_group; + + if(NULL == (lc_plist = H5I_object(lcpl_id))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list") + + /* Get intermediate group creation property */ + if(H5P_get(lc_plist, H5L_CRT_INTERMEDIATE_GROUP_NAME, &crt_intmd_group) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get property value for creating missing groups") + + if (crt_intmd_group > 0) + target_flags |= H5G_CRT_INTMD_GROUP; + + /* Get character encoding property */ + if(H5P_get(lc_plist, H5P_CHAR_ENCODING_NAME, &char_encoding) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get property value for character encoding") + } /* end if */ + + /* Fill in common data for the link struct */ + lnk->cset = char_encoding; +#ifdef H5_HAVE_GETTIMEOFDAY + { + struct timeval now_tv; + + HDgettimeofday(&now_tv, NULL); + lnk->ctime = now_tv.tv_sec; + } +#else /* H5_HAVE_GETTIMEOFDAY */ + lnk->ctime = HDtime(NULL); +#endif /* H5_HAVE_GETTIMEOFDAY */ + + /* Set up user data + * file is used to make sure that hard links don't cross files, and + * should be NULL for other link types. + * lnk is the link struct passed into this function. At this point all + * of its fields should be populated except for name, which is set when + * inserting it in the callback. + * dxpl_id is the dxpl ID that needs to be used during writes and reads. + * path is a pointer to the path of the object being inserted if this is + * a hard link; this is used to set the paths to objects when they are + * created. For other link types, this is NULL. + */ + udata.file = obj_file; + udata.lnk = lnk; + udata.dxpl_id = dxpl_id; + udata.path = obj_path; + + /* Traverse the destination path & create new link */ + if(H5G_traverse(link_loc, link_name, target_flags, H5L_link_cb, &udata, dxpl_id) < 0) + HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, FAIL, "can't insert link") + +done: + /* Free the normalized path name */ + if(norm_link_name) + H5MM_xfree(norm_link_name); + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5L_create_real() */ + + +/*------------------------------------------------------------------------- + * Function: H5L_create_hard + * + * Purpose: Creates a hard link from NEW_NAME to CUR_NAME. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Robb Matzke + * Monday, April 6, 1998 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5L_create_hard(H5G_loc_t *cur_loc, const char *cur_name, + H5G_loc_t *link_loc, const char *link_name, hid_t dxpl_id, hid_t lcpl_id) +{ + char *norm_cur_name = NULL; /* Pointer to normalized current name */ + H5F_t *link_file = NULL; /* Pointer to file to link to */ + H5O_link_t lnk; /* Link to insert */ + H5O_loc_t obj_oloc; /* Location of object to link to */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5L_create_hard) + + /* Check args */ + HDassert(cur_loc); + HDassert(link_loc); + HDassert(cur_name && *cur_name); + HDassert(link_name && *link_name); + + /* Get normalized copy of the current name */ + if((norm_cur_name = H5G_normalize(cur_name)) == NULL) + HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "can't normalize name") + + /* Set up link data specific to hard links */ + lnk.type = H5L_LINK_HARD; + + /* Get object location for object pointed to */ + if(H5G_obj_find(cur_loc, norm_cur_name, H5G_TARGET_NORMAL, NULL, &obj_oloc, dxpl_id) < 0) + HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "source object not found") + + /* Construct link information for eventual insertion */ + lnk.u.hard.addr = obj_oloc.addr; + + /* Set destination's file information */ + link_file = obj_oloc.file; + + /* Create actual link to the object. Pass in NULL for the path, since this + * function shouldn't change an object's user path. */ + if(H5L_create_real(link_loc, link_name, NULL, link_file, &lnk, dxpl_id, lcpl_id) < 0) + HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to register new name for object") + +done: + /* Free the normalized path name */ + if(norm_cur_name) + H5MM_xfree(norm_cur_name); + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5L_create_hard() */ + + +/*------------------------------------------------------------------------- + * Function: H5L_create_soft + * + * Purpose: Creates a soft link from NEW_NAME to CUR_NAME. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Robb Matzke + * Monday, April 6, 1998 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5L_create_soft( const char *target_path, H5G_loc_t *link_loc, + const char *link_name, hid_t dxpl_id, hid_t lcpl_id) +{ + char *norm_target = NULL; /* Pointer to normalized current name */ + H5O_link_t lnk; /* Link to insert */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5L_create_soft) + + /* Check args */ + HDassert(link_loc); + HDassert(target_path && *target_path); + HDassert(link_name && *link_name); + + /* Get normalized copy of the link target */ + if((norm_target = H5G_normalize(target_path)) == NULL) + HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "can't normalize name") + + /* Set up link data specific to soft links */ + lnk.type = H5L_LINK_SOFT; + lnk.u.soft.name = norm_target; + + /* Create actual link to the object */ + if(H5L_create_real(link_loc, link_name, NULL, NULL, &lnk, dxpl_id, lcpl_id) < 0) + HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to register new name for object") + +done: + /* Free the normalized target name */ + if(norm_target) + H5MM_xfree(norm_target); + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5L_create_soft() */ + + +/*------------------------------------------------------------------------- + * Function: H5L_linkval_cb + * + * Purpose: Callback for retrieving soft link value for an object. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Tuesday, September 20, 2005 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5L_linkval_cb(H5G_loc_t UNUSED *grp_loc/*in*/, const char UNUSED *name, const H5O_link_t *lnk, + H5G_loc_t UNUSED *obj_loc, void *_udata/*in,out*/) +{ + H5L_trav_ud5_t *udata = (H5L_trav_ud5_t *)_udata; /* User data passed in */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5L_linkval_cb) + + /* Check if the name in this group resolved to a valid link */ + if(lnk == NULL) + HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "name doesn't exist") + + if(H5L_LINK_SOFT != lnk->type) + HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "object is not a symbolic link") + + /* Copy to output buffer */ + if(udata->size > 0 && udata->buf) { + HDstrncpy(udata->buf, lnk->u.soft.name, udata->size); + if(HDstrlen(lnk->u.soft.name) >= udata->size) + udata->buf[udata->size - 1] = '\0'; + } /* end if */ + +done: + /* Release the group location for the object */ + /* (Group traversal callbacks are responsible for either taking ownership + * of the group location for the object, or freeing it. - QAK) + */ + if(obj_loc) + H5G_loc_free(obj_loc); + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5L_linkval_cb() */ + + +/*------------------------------------------------------------------------- + * Function: H5L_linkval + * + * Purpose: Returns the value of a symbolic link. + * + * Return: Success: Non-negative, with at most SIZE bytes of the + * link value copied into the BUF buffer. If the + * link value is larger than SIZE characters + * counting the null terminator then the BUF + * result will not be null terminated. + * + * Failure: Negative + * + * Programmer: Robb Matzke + * Monday, April 13, 1998 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5L_linkval(H5G_loc_t *loc, const char *name, size_t size, char *buf/*out*/, hid_t dxpl_id) +{ + H5L_trav_ud5_t udata; /* User data for callback */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5L_linkval) + + /* Set up user data for retrieving information */ + udata.size = size; + udata.buf = buf; + + /* Traverse the group hierarchy to locate the object to get info about */ + if(H5G_traverse(loc, name, H5G_TARGET_SLINK, H5L_linkval_cb, &udata, dxpl_id) < 0) + HGOTO_ERROR(H5E_SYM, H5E_EXISTS, FAIL, "name doesn't exist") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5L_linkval() */ + + +/*------------------------------------------------------------------------- + * Function: H5L_unlink_cb + * + * Purpose: Callback for unlinking an object. This routine + * deletes the link + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Monday, September 19, 2005 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5L_unlink_cb(H5G_loc_t *grp_loc/*in*/, const char *name, const H5O_link_t UNUSED *lnk, + H5G_loc_t *obj_loc, void *_udata/*in,out*/) +{ + H5L_trav_ud6_t *udata = (H5L_trav_ud6_t *)_udata; /* User data passed in */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5L_unlink_cb) + + /* Check if the name in this group resolved to a valid link */ + if(obj_loc == NULL) + HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "name doesn't exist") + + /* Check for removing '.' */ + if(lnk == NULL) + HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "can't delete self") + + /* Remove the link from the group */ + if(H5G_loc_remove(grp_loc, name, obj_loc, udata->dxpl_id) < 0) + HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to unlink name from group") + +done: + /* Release the group location for the object */ + /* (Group traversal callbacks are responsible for either taking ownership + * of the group location for the object, or freeing it. - QAK) + */ + if(obj_loc) + H5G_loc_free(obj_loc); + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5L_unlink_cb() */ + + +/*------------------------------------------------------------------------- + * Function: H5L_unlink + * + * Purpose: Unlink a name from a group. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Robb Matzke + * Thursday, September 17, 1998 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5L_unlink(H5G_loc_t *loc, const char *name, hid_t dxpl_id) +{ + H5L_trav_ud6_t udata; /* User data for callback */ + char *norm_name = NULL; /* Pointer to normalized name */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5L_unlink) + + /* Sanity check */ + HDassert(loc); + HDassert(name && *name); + + /* Get normalized copy of the name */ + if((norm_name = H5G_normalize(name)) == NULL) + HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "can't normalize name") + + /* Set up user data for unlink operation */ + udata.dxpl_id = dxpl_id; + + if(H5G_traverse(loc, norm_name, H5G_TARGET_SLINK|H5G_TARGET_MOUNT, H5L_unlink_cb, &udata, dxpl_id) < 0) + HGOTO_ERROR(H5E_SYM, H5E_EXISTS, FAIL, "name doesn't exist") + +done: + /* Free the normalized path name */ + if(norm_name) + H5MM_xfree(norm_name); + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5L_unlink() */ + + +/*------------------------------------------------------------------------- + * Function: H5L_move_rename_dest_cb + * + * Purpose: Second callback for moving and renaming an object. This routine + * inserts a new link into the group returned by the traversal. + * It is called by H5L_move_rename_cb. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: James Laird + * Monday, April 3, 2006 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5L_move_rename_dest_cb(H5G_loc_t *grp_loc/*in*/, const char *name, const H5O_link_t *lnk, + H5G_loc_t *obj_loc, void *_udata/*in,out*/) +{ + H5L_trav_ud10_t *udata = (H5L_trav_ud10_t *)_udata; /* User data passed in */ + H5RS_str_t *dst_name_r = NULL; /* Ref-counted version of dest name */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5L_move_rename_dest_cb) + + /* Make sure an object with this name doesn't already exist */ + if(obj_loc != NULL) + HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "an object with that name already exists") + + /* Check for crossing file boundaries with a new hard link */ + if(udata->lnk->type == H5L_LINK_HARD) { + /* Check that both objects are in same file */ + if(grp_loc->oloc->file->shared != udata->file->shared) + HGOTO_ERROR(H5E_SYM, H5E_LINK, FAIL, "moving a link across files is not allowed") + } /* end if */ + + /* Give the object its new name */ + /* Casting away const okay -JML */ + udata->lnk->name = H5MM_xfree(udata->lnk->name); + udata->lnk->name=name; + + /* Insert the link into the group */ + if(H5G_obj_insert(grp_loc->oloc, name, udata->lnk, (hbool_t)(udata->lnk->type == H5L_LINK_HARD ? TRUE : FALSE), udata->dxpl_id) < 0) + HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to create new name/link for object") + +done: + /* Release the group location for the object */ + /* (Group traversal callbacks are responsible for either taking ownership + * of the group location for the object, or freeing it. - QAK) + */ + if(obj_loc) + H5G_loc_free(obj_loc); + if(dst_name_r) + H5RS_decr(dst_name_r); + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5L_move_dest_cb() */ + + +/*------------------------------------------------------------------------- + * Function: H5L_move_rename_cb + * + * Purpose: Callback for moving and renaming an object. This routine + * replaces the names of open objects with the moved object + * in the path + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: James Laird + * Friday, April 3, 2006 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5L_move_rename_cb(H5G_loc_t *grp_loc/*in*/, const char *name, const H5O_link_t *lnk, + H5G_loc_t *obj_loc, void *_udata/*in,out*/) +{ + H5L_trav_ud4_t *udata = (H5L_trav_ud4_t *)_udata; /* User data passed in */ + H5L_trav_ud10_t udata_out; /* User data for H5L_move_dest_cb traversal */ + H5G_obj_t type; /* Type of object being moved */ + H5RS_str_t *dst_name_r = NULL; /* Ref-counted version of dest name */ + char * orig_name = NULL; /* The name of the link in this group */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5L_move_rename_cb) + + /* Check if the name in this group resolved to a valid link */ + if(obj_loc == NULL) + HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "name doesn't exist") + + /* Check for operations on '.' */ + if(lnk == NULL) + HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "the name of a link must be supplied to move or rename") + + /* Get object type */ + switch(lnk->type) { + case H5L_LINK_HARD: + if(H5G_UNKNOWN == (type = H5O_obj_type(obj_loc->oloc, udata->dxpl_id))) + HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "unable to get object type to move") + break; + + case H5L_LINK_SOFT: + type = H5G_LINK; + break; + + default: + HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "unrecognized link type") + } /* end switch */ + + /* Set up user data for move_dest_cb */ + if((udata_out.lnk = H5O_link_copy(lnk, NULL, 0)) == NULL) + HGOTO_ERROR(H5E_SYM, H5E_CANTCOPY, FAIL, "unable to copy link to be moved"); + udata_out.lnk->cset = udata->cset; + udata_out.file = grp_loc->oloc->file; + udata_out.dxpl_id = udata->dxpl_id; + + /* Remember the link's original name (in case it's changed by H5G_name_replace) */ + orig_name = H5MM_xstrdup(name); + + /* Insert the link into its new location */ + if(H5G_traverse(udata->dst_loc, udata->dst_name, H5G_TARGET_NORMAL, H5L_move_rename_dest_cb, &udata_out, udata->dxpl_id) < 0) + HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to follow symbolic link") + + /* If this is a move and not a copy operation, change the object's name and remove the old link */ + if(!udata->copy) + { + /* Fix names up */ + dst_name_r = H5RS_wrap(udata->dst_name); + HDassert(dst_name_r); + if(H5G_name_replace(type, obj_loc, dst_name_r, udata->dst_loc, H5G_NAME_MOVE) < 0) + HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to replace name ") + + /* Remove the old link */ + if(H5G_obj_remove(grp_loc->oloc, orig_name, &type, udata->dxpl_id) < 0) + HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to remove old name") + } + +done: + /* Cleanup */ + if(orig_name) + H5MM_xfree(orig_name); + + /* Release the group location for the object */ + /* (Group traversal callbacks are responsible for either taking ownership + * of the group location for the object, or freeing it. - QAK) + */ + if(obj_loc) + H5G_loc_free(obj_loc); + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5L_move_cb() */ + + +/*------------------------------------------------------------------------- + * Function: H5L_move + * + * Purpose: Atomically move and rename or copy a link. + * + * Creates a copy of a link in a new destination with a new name. + * SRC_LOC and SRC_NAME together define the link's original + * location, while DST_LOC and DST_NAME together define its + * final location. + * + * If copy_flag is FALSE, the original link is removed + * (effectively moving the link). + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: James Laird + * Monday, May 1, 2006 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5L_move(H5G_loc_t *src_loc, const char *src_name, H5G_loc_t *dst_loc, + const char *dst_name, hbool_t copy_flag, hid_t lcpl_id, hid_t dxpl_id) +{ + unsigned target_flags = H5G_TARGET_MOUNT|H5G_TARGET_SLINK; /* Flags to pass to group traversal function */ + H5T_cset_t char_encoding = H5F_CRT_DEFAULT_CSET; /* Character encoding for link */ + H5P_genplist_t* lc_plist; /* Link creation property list */ + H5L_trav_ud4_t udata; /* User data for traversal */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5L_move) + + /* Sanity check */ + HDassert(src_loc); + HDassert(dst_loc); + HDassert(src_name && *src_name); + HDassert(dst_name && *dst_name); + + /* Check for flags present in creation property list */ + if(lcpl_id != H5P_DEFAULT) + { + unsigned crt_intmd_group; + + if(NULL == (lc_plist = H5I_object(lcpl_id))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list") + + /* Get intermediate group creation property */ + if(H5P_get(lc_plist, H5L_CRT_INTERMEDIATE_GROUP_NAME, &crt_intmd_group) < +0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get property value for creating missing groups") + + if (crt_intmd_group > 0) + target_flags |= H5G_CRT_INTMD_GROUP; + + /* Get character encoding property */ + if(H5P_get(lc_plist, H5P_CHAR_ENCODING_NAME, &char_encoding) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get property value for character encoding") + } /* end if */ + + /* Set up user data */ + udata.dst_loc = dst_loc; + udata.dst_name= dst_name; + udata.cset = char_encoding; + udata.copy = copy_flag; + udata.dxpl_id = dxpl_id; + + /* Do the move */ + if(H5G_traverse(src_loc, src_name, H5G_TARGET_MOUNT|H5G_TARGET_SLINK, H5L_move_rename_cb, &udata, dxpl_id) < 0) + HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to find link") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5L_move() */ + + +/*------------------------------------------------------------------------- + * Function: H5L_get_lcpl_cb + * + * Purpose: Callback for getting a link's creation property list. This + * routine gets properties from the link and sets them on the + * copy of the default property list passed in. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: James Laird + * Friday, January 27, 2006 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5L_get_lcpl_cb(H5G_loc_t UNUSED *grp_loc/*in*/, const char UNUSED *name, const H5O_link_t *lnk, + H5G_loc_t UNUSED *obj_loc, void *_udata/*in,out*/) +{ + H5L_trav_ud8_t *udata = (H5L_trav_ud8_t *)_udata; /* User data passed in */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5L_get_lcpl_cb) + + /* Check if the name in this group resolved to a valid link */ + if(lnk == NULL) + HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "name doesn't exist") + + /* Set appropriate character encoding */ + if(H5P_set(udata->lcpl, H5P_CHAR_ENCODING_NAME, &(lnk->cset)) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set property value for character encoding") + +done: + /* Release the group location for the object */ + /* (Group traversal callbacks are responsible for either taking ownership + * of the group location for the object, or freeing it. - QAK) + */ + if(obj_loc) + H5G_loc_free(obj_loc); + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5L_get_lcpl_cb() */ + + +/*------------------------------------------------------------------------- + * Function: H5L_get_create_plist + * + * Purpose: Returns a copy of the link's creation property list given + * given a link's location and name. + * + * Return: Success: ID of the property list + * + * Failure: Negative + * + * Programmer: James Laird + * Friday, January 27, 2006 + * + *------------------------------------------------------------------------- + */ +hid_t H5L_get_create_plist(H5G_loc_t *loc, const char* name) +{ + H5P_genplist_t *plist; /* Default property list */ + H5P_genplist_t *plist_copy; /* Copy of list to be modified */ + hid_t lcpl_id=-1; + H5L_trav_ud8_t udata; /* User data for traversal */ + char *norm_name = NULL; /* Pointer to normalized name */ + hid_t ret_value; + + FUNC_ENTER_NOAPI(H5L_get_create_plist, FAIL) + + /* Check arguments */ + HDassert(loc); + HDassert(name && *name); + + /* Get normalized copy of the name */ + if((norm_name = H5G_normalize(name)) == NULL) + HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "can't normalize name") + + /* Get copy of default lcpl */ + if (NULL==(plist=H5I_object(H5P_LST_LINK_CREATE_g))) + HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, FAIL, "can't get default LCPL") + if((lcpl_id=H5P_copy_plist(plist)) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "unable to copy attribute creation properties") + if (NULL==(plist_copy=H5I_object(lcpl_id))) + HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, FAIL, "can't get copy of LCPL") + + /* Set up user data */ + udata.lcpl = plist_copy; + + if(H5G_traverse(loc, norm_name, H5G_TARGET_SLINK|H5G_TARGET_MOUNT, H5L_get_lcpl_cb, &udata, H5AC_dxpl_id) < 0) + HGOTO_ERROR(H5E_SYM, H5E_EXISTS, FAIL, "name doesn't exist") + + ret_value = lcpl_id; + +done: + /* Free the normalized path name */ + if(norm_name) + H5MM_xfree(norm_name); + /* If we've created a new lcpl, close it */ + if(ret_value <0 && lcpl_id >= 0) + H5P_close(H5I_object(lcpl_id)); + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5L_get_create_plist */ + + +/*------------------------------------------------------------------------- + * Function: H5L_get_linfo_cb + * + * Purpose: Callback for retrieving a link's metadata + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: James Laird + * Monday, April 17 2006 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5L_get_linfo_cb(H5G_loc_t UNUSED *grp_loc/*in*/, const char UNUSED *name, const H5O_link_t *lnk, + H5G_loc_t UNUSED *obj_loc, void *_udata/*in,out*/) +{ + H5L_trav_ud1_t *udata = (H5L_trav_ud1_t *)_udata; /* User data passed in */ + H5L_linkinfo_t *linfo = udata->linfo; + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5L_get_linfo_cb) + + /* Check if the name in this group resolved to a valid link */ + if(lnk == NULL) + HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "name doesn't exist") + + /* Get information from the link */ + linfo->cset = lnk->cset; + linfo->ctime = lnk->ctime; + linfo->linkclass = lnk->type; + + switch(lnk->type) + { + case H5L_LINK_HARD: + linfo->u.objno = lnk->u.hard.addr; + break; + + case H5L_LINK_SOFT: + linfo->u.link_size = HDstrlen(lnk->u.soft.name) + 1; /*count the null terminator*/ + break; + + default: + HGOTO_ERROR(H5E_SYM, H5E_BADTYPE, FAIL, "unknown link type"); + } + +done: + /* Release the group location for the object */ + /* (Group traversal callbacks are responsible for either taking ownership + * of the group location for the object, or freeing it. - QAK) + */ + if(obj_loc) + H5G_loc_free(obj_loc); + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5L_get_linfo_cb() */ + + +/*------------------------------------------------------------------------- + * Function: H5L_get_linkinfo + * + * Purpose: Returns metadata about a link. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: James Laird + * Monday, April 17 2006 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5L_get_linkinfo(H5G_loc_t *loc, const char *name, H5L_linkinfo_t *linkbuf/*out*/, hid_t dxpl_id) +{ + H5L_trav_ud1_t udata; + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5L_get_linkinfo) + + udata.linfo = linkbuf; + udata.dxpl_id = dxpl_id; + + /* Traverse the group hierarchy to locate the object to get info about */ + if(H5G_traverse(loc, name, H5G_TARGET_SLINK, H5L_get_linfo_cb, &udata, dxpl_id) < 0) + HGOTO_ERROR(H5E_SYM, H5E_EXISTS, FAIL, "name doesn't exist") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5L_get_linkinfo() */ + + +/*------------------------------------------------------------------------- + * Function: H5L get_default_lcpl + * + * Purpose: Accessor for the default Link Creation Property List + * + * Return: Success: ID of the deafult lcpl + * + * Failure: Negative + * + * Programmer: James Laird + * Tuesday, July 4, 2006 + * + *------------------------------------------------------------------------- + */ +hid_t +H5L_get_default_lcpl() +{ + hid_t ret_value = FAIL; /* Return value */ + + FUNC_ENTER_NOAPI(H5L_get_default_lcpl, FAIL) + + ret_value = H5P_LINK_CREATE_DEFAULT; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5L_get_default_lcpl */ + |