From 509b8f645deadb880ea09ca5d89f9a28526d78ec Mon Sep 17 00:00:00 2001 From: Quincey Koziol Date: Tue, 6 Mar 2007 10:06:05 -0500 Subject: [svn-r13465] Description: Fix bug in external links when "strong" file close degree is used. Make external link callbacks use standard error reporting mechanisms. Other minor code cleanups... Tested on: Mac OS X/32 10.4.8 (amazon) FreeBSD/32 6.2 (duty) --- src/H5F.c | 168 ++++++++++++++++++++++++++++-------------------------- src/H5Fpkg.h | 1 - src/H5Fprivate.h | 8 ++- src/H5Fsuper.c | 4 +- src/H5Gloc.c | 70 ++++++++++++++++++----- src/H5Gpkg.h | 1 + src/H5I.c | 12 ++-- src/H5Lexternal.c | 158 ++++++++++++++++++++++++++++++++------------------ src/H5O.c | 71 +++++++++++++++++------ src/H5Oprivate.h | 1 + test/links.c | 89 ++++++++++++++++++++++++++++- 11 files changed, 398 insertions(+), 185 deletions(-) diff --git a/src/H5F.c b/src/H5F.c index fd8dc24..bd51aa9 100644 --- a/src/H5F.c +++ b/src/H5F.c @@ -972,27 +972,6 @@ done: * matzke@llnl.gov * Jul 18 1997 * - * Modifications: - * - * Robb Matzke, 1998-10-14 - * Nothing happens unless the reference count for the H5F_t goes to - * zero. The reference counts are decremented here. - * - * Robb Matzke, 1999-02-19 - * More careful about decrementing reference counts so they don't go - * negative or wrap around to some huge value. Nothing happens if a - * reference count is already zero. - * - * Robb Matzke, 2000-10-31 - * H5FL_FREE() aborts if called with a null pointer (unlike the - * original H5MM_free()). - * - * Pedro Vicente, 18 Sep 2002 - * Added `id to name' support. - * - * James Laird, 2007-1-29 - * H5F_dest now frees superblock extension oloc. - * *------------------------------------------------------------------------- */ static herr_t @@ -1004,6 +983,7 @@ H5F_dest(H5F_t *f, hid_t dxpl_id) /* Sanity check */ HDassert(f); + HDassert(f->shared); if(1 == f->shared->nrefs) { /* Flush at this point since the file will be closed */ @@ -1085,6 +1065,7 @@ H5F_dest(H5F_t *f, hid_t dxpl_id) f->mtab.nalloc = 0; if(H5FO_top_dest(f) < 0) HDONE_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "problems closing file") + f->shared = NULL; H5FL_FREE(H5F_t, f); FUNC_LEAVE_NOAPI(ret_value) @@ -1566,9 +1547,8 @@ H5Fopen(const char *filename, unsigned flags, hid_t fapl_id) new_file->file_id = ret_value; done: - if(ret_value < 0 && new_file) - if(H5F_close(new_file) < 0) - HDONE_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "problems closing file") + if(ret_value < 0 && new_file && H5F_try_close(new_file) < 0) + HDONE_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "problems closing file") FUNC_LEAVE_API(ret_value) } /* end H5Fopen() */ @@ -1674,50 +1654,6 @@ done: * matzke@llnl.gov * Aug 29 1997 * - * Modifications: - * rky 1998-08-28 - * Only p0 writes metadata to disk. - * - * Robb Matzke, 1998-10-16 - * Added the `scope' argument to indicate what should be - * flushed. If the value is H5F_SCOPE_GLOBAL then the entire - * virtual file is flushed; a value of H5F_SCOPE_LOCAL means - * that only the specified file is flushed. A value of - * H5F_SCOPE_DOWN means flush the specified file and all - * children. - * - * Robb Matzke, 1999-08-02 - * If ALLOC_ONLY is non-zero then all this function does is - * allocate space for the userblock and superblock. Also - * rewritten to use the virtual file layer. - * - * Robb Matzke, 1999-08-16 - * The driver information block is encoded and either allocated - * or written to disk. - * - * Raymond Lu, 2001-10-14 - * Changed to new generic property list. - * - * Quincey Koziol, 2002-05-20 - * Added 'closing' parameter - * - * Quincey Koziol, 2002-06-05 - * Added boot block & driver info block checksumming, to avoid - * writing them out when they haven't changed. - * - * Quincey Koziol, 2002-06-06 - * Return the remainders of the metadata & "small data" blocks to - * the free list of blocks for the file. - * - * Bill Wendling, 2003-03-18 - * Modified the flags being passed in to be one flag instead - * of several. - * - * John Mainzer, 2005-01-07 - * H5AC (and H5C) now have their own system of flags. Hence - * we must now translate between the H5F_FLUSH flags and the - * H5AC flags. Added code to handle this detail. - * *------------------------------------------------------------------------- */ static herr_t @@ -1835,19 +1771,6 @@ done: * Programmer: Robb Matzke * Tuesday, September 23, 1997 * - * Modifications: - * Robb Matzke, 1998-10-14 - * Nothing happens unless the H5F_t reference count is one (the - * file is flushed anyway). The reference count is decremented - * by H5F_dest(). - * - * Robb Matzke, 1999-08-02 - * Modified to use the virtual file layer. - * - * Bill Wendling, 2003-03-18 - * Modified H5F_flush call to take one flag instead of - * several Boolean flags. - * *------------------------------------------------------------------------- */ static herr_t @@ -1919,6 +1842,7 @@ H5F_try_close(H5F_t *f) /* Sanity check */ HDassert(f); + HDassert(f->shared); /* Check if this file is already in the process of closing */ if(f->closing) @@ -2903,6 +2827,88 @@ H5F_use_latest_format(const H5F_t *f) /*------------------------------------------------------------------------- + * Function: H5F_get_fc_degree + * + * Purpose: Retrieve the 'file close degree' for the file. + * + * Return: Success: Non-negative, the 'file close degree' + * + * Failure: (can't happen) + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * Mar 5 2007 + * + *------------------------------------------------------------------------- + */ +H5F_close_degree_t +H5F_get_fc_degree(const H5F_t *f) +{ + /* Use FUNC_ENTER_NOAPI_NOINIT_NOFUNC here to avoid performance issues */ + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5F_get_fc_degree) + + HDassert(f); + HDassert(f->shared); + + FUNC_LEAVE_NOAPI(f->shared->fc_degree) +} /* end H5F_get_fc_degree() */ + + +/*------------------------------------------------------------------------- + * Function: H5F_incr_nopen_objs + * + * Purpose: Increment the number of open objects for a file. + * + * Return: Success: The number of open objects, after the increment + * + * Failure: (can't happen) + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * Mar 6 2007 + * + *------------------------------------------------------------------------- + */ +unsigned +H5F_incr_nopen_objs(H5F_t *f) +{ + /* Use FUNC_ENTER_NOAPI_NOINIT_NOFUNC here to avoid performance issues */ + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5F_incr_nopen_objs) + + HDassert(f); + + FUNC_LEAVE_NOAPI(++f->nopen_objs) +} /* end H5F_incr_nopen_objs() */ + + +/*------------------------------------------------------------------------- + * Function: H5F_decr_nopen_objs + * + * Purpose: Decrement the number of open objects for a file. + * + * Return: Success: The number of open objects, after the decrement + * + * Failure: (can't happen) + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * Mar 6 2007 + * + *------------------------------------------------------------------------- + */ +unsigned +H5F_decr_nopen_objs(H5F_t *f) +{ + /* Use FUNC_ENTER_NOAPI_NOINIT_NOFUNC here to avoid performance issues */ + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5F_decr_nopen_objs) + + HDassert(f); + + FUNC_LEAVE_NOAPI(--f->nopen_objs) +} /* end H5F_decr_nopen_objs() */ + + +/*------------------------------------------------------------------------- * Function: H5F_block_read * * Purpose: Reads some data from a file/server/etc into a buffer. diff --git a/src/H5Fpkg.h b/src/H5Fpkg.h index e8df026..616bb81 100644 --- a/src/H5Fpkg.h +++ b/src/H5Fpkg.h @@ -162,7 +162,6 @@ H5FL_EXTERN(H5F_file_t); /* General routines */ H5_DLL herr_t H5F_init(void); -H5_DLL herr_t H5F_try_close(H5F_t *f); H5_DLL haddr_t H5F_locate_signature(H5FD_t *file, hid_t dxpl_id); /* File mount related routines */ diff --git a/src/H5Fprivate.h b/src/H5Fprivate.h index 1084ab5..264218f 100644 --- a/src/H5Fprivate.h +++ b/src/H5Fprivate.h @@ -255,7 +255,7 @@ typedef struct H5F_t H5F_t; #define H5F_RDCC_NBYTES(F) ((F)->shared->rdcc_nbytes) #define H5F_RDCC_W0(F) ((F)->shared->rdcc_w0) /* Check for file driver feature enabled */ -#define H5F_HAS_FEATURE(F,FL) ((F)->shared->lf->feature_flags&(FL)) +#define H5F_HAS_FEATURE(F,FL) ((F)->shared->lf->feature_flags & (FL)) /* B-tree node raw page */ #define H5F_GRP_BTREE_SHARED(F) ((F)->shared->grp_btree_shared) /* Base address of file */ @@ -265,6 +265,7 @@ typedef struct H5F_t H5F_t; #define H5F_GC_REF(F) ((F)->shared->gc_ref) #define H5F_USE_LATEST_FORMAT(F) ((F)->shared->latest_format) #define H5F_INTENT(F) ((F)->intent) +#define H5F_GET_FC_DEGREE(F) ((F)->shared->fc_degree) #else /* H5F_PACKAGE */ #define H5F_FCPL(F) (H5F_get_fcpl(F)) #define H5F_SIZEOF_ADDR(F) (H5F_sizeof_addr(F)) @@ -281,6 +282,7 @@ typedef struct H5F_t H5F_t; #define H5F_GC_REF(F) (H5F_gc_ref(F)) #define H5F_USE_LATEST_FORMAT(F) (H5F_use_latest_format(F)) #define H5F_INTENT(F) (H5F_get_intent(F)) +#define H5F_GET_FC_DEGREE(F) (H5F_get_fc_degree(F)) #endif /* H5F_PACKAGE */ @@ -405,6 +407,7 @@ struct H5RC_t; /* Private functions */ H5_DLL H5F_t *H5F_open(const char *name, unsigned flags, hid_t fcpl_id, hid_t fapl_id, hid_t dxpl_id); +H5_DLL herr_t H5F_try_close(H5F_t *f); /* Functions than retrieve values from the file struct */ H5_DLL hid_t H5F_get_driver_id(const H5F_t *f); @@ -421,6 +424,8 @@ H5_DLL int H5F_mpi_get_rank(const H5F_t *f); H5_DLL MPI_Comm H5F_mpi_get_comm(const H5F_t *f); H5_DLL int H5F_mpi_get_size(const H5F_t *f); #endif /* H5_HAVE_PARALLEL */ +H5_DLL unsigned H5F_incr_nopen_objs(H5F_t *f); +H5_DLL unsigned H5F_decr_nopen_objs(H5F_t *f); /* Functions than check file mounting information */ H5_DLL hbool_t H5F_is_mount(const H5F_t *file); @@ -440,6 +445,7 @@ H5_DLL struct H5RC_t *H5F_grp_btree_shared(const H5F_t *f); H5_DLL size_t H5F_sieve_buf_size(const H5F_t *f); H5_DLL unsigned H5F_gc_ref(const H5F_t *f); H5_DLL hbool_t H5F_use_latest_format(const H5F_t *f); +H5_DLL H5F_close_degree_t H5F_get_fc_degree(const H5F_t *f); /* Functions that operate on blocks of bytes wrt super block */ H5_DLL herr_t H5F_block_read(const H5F_t *f, H5FD_mem_t type, haddr_t addr, diff --git a/src/H5Fsuper.c b/src/H5Fsuper.c index 547502d..0df22bb 100644 --- a/src/H5Fsuper.c +++ b/src/H5Fsuper.c @@ -613,8 +613,8 @@ H5F_super_read(H5F_t *f, hid_t dxpl_id, H5G_loc_t *root_loc) H5O_msg_reset(H5O_DRVINFO_ID, &drvinfo); } /* end else */ - /* Close the extension. Bump the version number to avoid closing the - * file (since this will be the only open object). + /* Close the extension. Twiddle the number of open objects to avoid + * closing the file (since this will be the only open object). */ f->nopen_objs++; if(H5O_close(&ext_loc) < 0) diff --git a/src/H5Gloc.c b/src/H5Gloc.c index d447d20..247f185 100644 --- a/src/H5Gloc.c +++ b/src/H5Gloc.c @@ -133,23 +133,13 @@ H5G_loc(hid_t loc_id, H5G_loc_t *loc) { H5F_t *f; + /* Get the file struct */ if(NULL == (f = H5I_object(loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid file ID") - if(NULL == (loc->oloc = H5G_oloc(H5G_rootof(f)))) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get object location for root group") - if(NULL == (loc->path = H5G_nameof(H5G_rootof(f)))) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get path for root group") - - /* Patch up root group's object location to reflect this file */ - /* (Since the root group info is only stored once for files which - * share an underlying low-level file) - */ - /* (but only for non-mounted files) */ - if(!H5F_is_mount(f)) - { - loc->oloc->file = f; - loc->oloc->holding_file = FALSE; - } + + /* Construct a group location for root group of the file */ + if(H5G_loc_root(f, loc) < 0) + HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "unable to create location for file") } /* end case */ break; @@ -230,6 +220,56 @@ done: /*------------------------------------------------------------------------- + * Function: H5G_loc_root + * + * Purpose: Construct a "group location" for the root group of a file + * + * Return: Success: Non-negative + * Failure: Negative + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * Mar 5 2007 + * + *------------------------------------------------------------------------- + */ +herr_t +H5G_loc_root(H5F_t *f, H5G_loc_t *loc) +{ + H5G_t *root_grp; /* Pointer to root group's info */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5G_loc_root, FAIL) + + HDassert(f); + HDassert(loc); + + /* Retrieve the root group for the file */ + root_grp = H5G_rootof(f); + HDassert(root_grp); + + /* Build the group location for the root group */ + if(NULL == (loc->oloc = H5G_oloc(root_grp))) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get object location for root group") + if(NULL == (loc->path = H5G_nameof(root_grp))) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get path for root group") + + /* Patch up root group's object location to reflect this file */ + /* (Since the root group info is only stored once for files which + * share an underlying low-level file) + */ + /* (but only for non-mounted files) */ + if(!H5F_is_mount(f)) { + loc->oloc->file = f; + loc->oloc->holding_file = FALSE; + } /* end if */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5G_loc_root() */ + + +/*------------------------------------------------------------------------- * Function: H5G_loc_copy * * Purpose: Copy over information for a location diff --git a/src/H5Gpkg.h b/src/H5Gpkg.h index b02155d..181d5e4 100644 --- a/src/H5Gpkg.h +++ b/src/H5Gpkg.h @@ -533,6 +533,7 @@ H5_DLL H5RS_str_t *H5G_build_fullpath_refstr_str(H5RS_str_t *path_r, const char /* * These functions operate on group "locations" */ +H5_DLL herr_t H5G_loc_root(H5F_t *f, H5G_loc_t *loc); H5_DLL herr_t H5G_loc_copy(H5G_loc_t *dst, const H5G_loc_t *src, H5_copy_depth_t depth); H5_DLL herr_t H5G_loc_insert(H5G_loc_t *grp_loc, const char *name, H5G_loc_t *obj_loc, hid_t dxpl_id); diff --git a/src/H5I.c b/src/H5I.c index 771e45d..195bb38 100644 --- a/src/H5I.c +++ b/src/H5I.c @@ -2077,15 +2077,11 @@ H5I_get_file_id(hid_t obj_id) if(H5I_inc_ref(ret_value) < 0) HGOTO_ERROR(H5E_ATOM, H5E_CANTSET, FAIL, "incrementing file ID failed") } - else if(type == H5I_DATATYPE) { + else if(type == H5I_DATATYPE || type == H5I_GROUP || type == H5I_DATASET || type == H5I_ATTR) { if(H5G_loc(obj_id, &loc) < 0) - HGOTO_ERROR(H5E_ATOM, H5E_CANTGET, FAIL, "not a named datatype") - ret_value = H5F_get_id(loc.oloc->file); - } - else if(type == H5I_GROUP || type == H5I_DATASET || type == H5I_ATTR) { - if(H5G_loc(obj_id, &loc) < 0) - HGOTO_ERROR(H5E_ATOM, H5E_CANTGET, FAIL, "can't get symbol table info") - ret_value = H5F_get_id(loc.oloc->file); + HGOTO_ERROR(H5E_ATOM, H5E_CANTGET, FAIL, "can't get object location") + if((ret_value = H5F_get_id(loc.oloc->file)) < 0) + HGOTO_ERROR(H5E_ATOM, H5E_CANTGET, FAIL, "can't get file ID") } else HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "invalid object ID") diff --git a/src/H5Lexternal.c b/src/H5Lexternal.c index 5357f6a..074cb47 100644 --- a/src/H5Lexternal.c +++ b/src/H5Lexternal.c @@ -13,19 +13,20 @@ * access to either file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#define H5L_PACKAGE /*suppress error about including H5Lpkg */ #define H5G_PACKAGE /*suppress error about including H5Gpkg */ +#define H5L_PACKAGE /*suppress error about including H5Lpkg */ /* Interface initialization */ #define H5_INTERFACE_INIT_FUNC H5L_init_extern_interface #include "H5private.h" /* Generic Functions */ -#include "H5Lpkg.h" /* Links */ #include "H5Eprivate.h" /* Error handling */ +#include "H5Gpkg.h" /* Groups */ +#include "H5Iprivate.h" /* IDs */ +#include "H5Lpkg.h" /* Links */ #include "H5MMprivate.h" /* Memory management */ #include "H5Opublic.h" /* File objects */ -#include "H5Ppublic.h" /* Property lists */ -#include "H5Gpkg.h" /* Groups */ +#include "H5Pprivate.h" /* Property lists */ static hid_t H5L_extern_traverse(const char UNUSED *link_name, hid_t cur_group, void * udata, size_t UNUSED udata_size, hid_t lapl_id); @@ -92,74 +93,117 @@ static hid_t H5L_extern_traverse(const char UNUSED *link_name, hid_t cur_group, void * udata, size_t UNUSED udata_size, hid_t lapl_id) { - hid_t fid; - char *file_name; - char *obj_name; - ssize_t prefix_len; /* External link prefix length */ - size_t fname_len; - hbool_t fname_alloc = FALSE; - unsigned intent; - hid_t fapl_id; - hid_t ret_value = -1; - - file_name = (char *) udata; + H5P_genplist_t *plist; /* Property list pointer */ + char *my_prefix; /* Library's copy of the prefix */ + H5G_loc_t root_loc; /* Location of root group in external file */ + H5G_loc_t loc; /* Location of object */ + H5F_t *ext_file = NULL; /* File struct for external file */ + char *file_name = (char *)udata; + char *obj_name; + size_t fname_len; + hbool_t fname_alloc = FALSE; + unsigned intent; + hid_t fapl_id = -1; + hid_t ret_value = -1; + + FUNC_ENTER_NOAPI(H5L_extern_traverse, FAIL) + + /* Sanity checks */ + HDassert(file_name); + + /* Gather some information from the external link's user data */ fname_len = HDstrlen(file_name); - obj_name = ((char *) udata) + fname_len + 1; + obj_name = ((char *)udata) + fname_len + 1; + + /* Get the plist structure */ + if(NULL == (plist = H5P_object_verify(lapl_id, H5P_LINK_ACCESS))) + HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID") + + /* Get the current prefix */ + if(H5P_get(plist, H5L_ACS_ELINK_PREFIX_NAME, &my_prefix) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get external link prefix") - /* See if the external link prefix property is set */ - if((prefix_len = H5Pget_elink_prefix(lapl_id, NULL, (size_t)0)) < 0) - goto error; + /* Check for prefix being set, if so, prepend it to the filename */ + if(my_prefix) { + size_t prefix_len = HDstrlen(my_prefix); - /* If so, prepend it to the filename */ - if(prefix_len > 0) - { /* Allocate a buffer to hold the filename plus prefix */ - file_name = H5MM_malloc(prefix_len + fname_len + 1); + if(NULL == (file_name = H5MM_malloc(prefix_len + fname_len + 1))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate filename buffer") fname_alloc = TRUE; /* Copy the prefix into the buffer */ - if(H5Pget_elink_prefix(lapl_id, file_name, (size_t)(prefix_len + 1)) < 0) - goto error; + HDstrcpy(file_name, my_prefix); /* Add the external link's filename to the prefix supplied */ HDstrcat(file_name, udata); - } + } /* end if */ + + /* Get the location for the group holding the external link */ + if(H5G_loc(cur_group, &loc) < 0) + HGOTO_ERROR(H5E_LINK, H5E_CANTGET, FAIL, "can't get object location") /* Whatever access properties and intent the user used on the old file, * use the same ones to open the new file. If this is a bad default, * users can override this callback using H5Lregister. */ - if((fid = H5Iget_file_id(cur_group)) < 0) - goto error; - if(H5Fget_intent(fid, &intent) < 0) - goto error; - if((fapl_id = H5Fget_access_plist(fid)) < 0) - goto error; - if(H5Fclose(fid) < 0) - goto error; - - if((fid = H5Fopen(file_name, intent, fapl_id)) < 0) - goto error; - - ret_value = H5Oopen(fid, obj_name, lapl_id); /* If this fails, our return value will be negative. */ - if(H5Pclose(fapl_id) < 0) - goto error; - if(H5Fclose(fid) < 0) - goto error; + intent = H5F_INTENT(loc.oloc->file); + if((fapl_id = H5F_get_access_plist(loc.oloc->file)) < 0) + HGOTO_ERROR(H5E_LINK, H5E_CANTGET, FAIL, "can't get file access property list") + + /* Check for non-"weak" file close degree for parent file */ + if(H5F_GET_FC_DEGREE(loc.oloc->file) != H5F_CLOSE_WEAK) { + H5P_genplist_t *fa_plist; /* Property list pointer */ + H5F_close_degree_t fc_degree = H5F_CLOSE_WEAK; /* File close degree */ + + /* Get the plist structure */ + if(NULL == (fa_plist = H5P_object_verify(fapl_id, H5P_FILE_ACCESS))) + HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID") + + /* Set file close degree for new file to "weak" */ + if(H5P_set(fa_plist, H5F_ACS_CLOSE_DEGREE_NAME, &fc_degree) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set file close degree") + } /* end if */ + + /* Open the external file */ + /* (extra work with file intent to mask off inappropriate flags) */ + if(NULL == (ext_file = H5F_open(file_name, ((intent & H5F_ACC_RDWR) ? H5F_ACC_RDWR : H5F_ACC_RDONLY), H5P_FILE_CREATE_DEFAULT, fapl_id, H5AC_dxpl_id))) + HGOTO_ERROR(H5E_LINK, H5E_CANTOPENFILE, FAIL, "unable to open external file") + + /* Increment the number of open objects, to hold the file open */ + H5F_incr_nopen_objs(ext_file); + + /* Retrieve the "group location" for the file's root group */ + if(H5G_loc_root(ext_file, &root_loc) < 0) + HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "unable to create location for file") + + /* Open the object referenced in the external file */ + if((ret_value = H5O_open_name(&root_loc, obj_name, lapl_id)) < 0) { + H5F_decr_nopen_objs(ext_file); + HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open object") + } /* end if */ + + /* Decrement the number of open objects, to let the file close */ + H5F_decr_nopen_objs(ext_file); + + /* Close the external file */ + if(H5F_try_close(ext_file) < 0) + HGOTO_ERROR(H5E_LINK, H5E_CANTCLOSEFILE, FAIL, "problem closing external file") + ext_file = NULL; - /* Free file_name if it's been allocated */ - if(fname_alloc) - H5MM_xfree(file_name); - - return ret_value; +done: + /* Release resources */ + if(fapl_id > 0 && H5I_dec_ref(fapl_id) < 0) + HDONE_ERROR(H5E_ATOM, H5E_CANTRELEASE, FAIL, "unable to close atom for file access property list") + if(ext_file && H5F_try_close(ext_file) < 0) + HDONE_ERROR(H5E_LINK, H5E_CANTCLOSEFILE, FAIL, "problem closing external file") -error: /* Free file_name if it's been allocated */ if(fname_alloc) H5MM_xfree(file_name); - return -1; -} + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5L_extern_traverse() */ /*------------------------------------------------------------------------- @@ -183,18 +227,20 @@ static ssize_t H5L_extern_query(const char UNUSED * link_name, void * udata, size_t udata_size, void * buf /*out*/, size_t buf_size) { + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5L_extern_query) + /* If the buffer is NULL, skip writing anything in it and just return * the size needed */ if(buf) { if(udata_size < buf_size) buf_size = udata_size; - /* Copy the udata verbatim up to buf_size*/ + /* Copy the udata verbatim up to buf_size */ HDmemcpy(buf, udata, buf_size); - } + } /* end if */ - return udata_size; -} + FUNC_LEAVE_NOAPI(udata_size) +} /* end H5L_extern_query() */ /*------------------------------------------------------------------------- @@ -254,7 +300,7 @@ H5Lcreate_external(const char *file_name, const char *obj_name, done: if(temp_name != NULL) H5MM_free(temp_name); - FUNC_LEAVE_API(ret_value); + FUNC_LEAVE_API(ret_value) } /* end H5Lcreate_external() */ diff --git a/src/H5O.c b/src/H5O.c index 874b4c8..ca740de 100644 --- a/src/H5O.c +++ b/src/H5O.c @@ -195,10 +195,6 @@ hid_t H5Oopen(hid_t loc_id, const char *name, hid_t lapl_id) { H5G_loc_t loc; - H5G_loc_t obj_loc; /* Location used to open group */ - H5G_name_t obj_path; /* Opened object group hier. path */ - H5O_loc_t obj_oloc; /* Opened object object location */ - hbool_t loc_found = FALSE; /* Entry at 'name' found */ hid_t ret_value = FAIL; FUNC_ENTER_API(H5Oopen, FAIL) @@ -210,25 +206,11 @@ H5Oopen(hid_t loc_id, const char *name, hid_t lapl_id) if(!name || !*name) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name") - /* Set up opened group location to fill in */ - obj_loc.oloc = &obj_oloc; - obj_loc.path = &obj_path; - H5G_loc_reset(&obj_loc); - - /* Find the object's location */ - if(H5G_loc_find(&loc, name, &obj_loc/*out*/, lapl_id, H5AC_dxpl_id) < 0) - HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "object not found") - loc_found = TRUE; - /* Open the object */ - if((ret_value = H5O_open_by_loc(&obj_loc, H5AC_dxpl_id)) < 0) + if((ret_value = H5O_open_name(&loc, name, lapl_id)) < 0) HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open object") done: - if(ret_value < 0 && loc_found) - if(H5G_loc_free(&obj_loc) < 0) - HDONE_ERROR(H5E_SYM, H5E_CANTRELEASE, FAIL, "can't free location") - FUNC_LEAVE_API(ret_value) } /* end H5Oopen() */ @@ -817,6 +799,57 @@ done: /*------------------------------------------------------------------------- + * Function: H5O_open_name + * + * Purpose: Opens an object within an HDF5 file. + * + * Return: Success: An open object identifier + * Failure: Negative + * + * Programmer: Quincey Koziol + * March 5 2007 + * + *------------------------------------------------------------------------- + */ +hid_t +H5O_open_name(H5G_loc_t *loc, const char *name, hid_t lapl_id) +{ + H5G_loc_t obj_loc; /* Location used to open group */ + H5G_name_t obj_path; /* Opened object group hier. path */ + H5O_loc_t obj_oloc; /* Opened object object location */ + hbool_t loc_found = FALSE; /* Entry at 'name' found */ + hid_t ret_value = FAIL; + + FUNC_ENTER_NOAPI(H5O_open_name, FAIL) + + /* Check args */ + HDassert(loc); + HDassert(name && *name); + + /* Set up opened group location to fill in */ + obj_loc.oloc = &obj_oloc; + obj_loc.path = &obj_path; + H5G_loc_reset(&obj_loc); + + /* Find the object's location */ + if(H5G_loc_find(loc, name, &obj_loc/*out*/, lapl_id, H5AC_dxpl_id) < 0) + HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "object not found") + loc_found = TRUE; + + /* Open the object */ + if((ret_value = H5O_open_by_loc(&obj_loc, H5AC_dxpl_id)) < 0) + HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open object") + +done: + if(ret_value < 0 && loc_found) + if(H5G_loc_free(&obj_loc) < 0) + HDONE_ERROR(H5E_SYM, H5E_CANTRELEASE, FAIL, "can't free location") + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5O_open_name() */ + + +/*------------------------------------------------------------------------- * Function: H5O_open_by_loc * * Purpose: Opens an object and returns an ID given its group loction. diff --git a/src/H5Oprivate.h b/src/H5Oprivate.h index c08b97d..3fb2255 100644 --- a/src/H5Oprivate.h +++ b/src/H5Oprivate.h @@ -435,6 +435,7 @@ H5_DLL herr_t H5O_delete(H5F_t *f, hid_t dxpl_id, haddr_t addr); H5_DLL herr_t H5O_get_info(H5O_loc_t *oloc, H5O_info_t *oinfo, hid_t dxpl_id); H5_DLL herr_t H5O_obj_type(const H5O_loc_t *loc, H5O_type_t *obj_type, hid_t dxpl_id); H5_DLL herr_t H5O_get_create_plist(const H5O_loc_t *loc, hid_t dxpl_id, struct H5P_genplist_t *oc_plist); +H5_DLL hid_t H5O_open_name(H5G_loc_t *loc, const char *name, hid_t lapl_id); /* Object header message routines */ H5_DLL herr_t H5O_msg_create(const H5O_loc_t *loc, unsigned type_id, unsigned mesg_flags, diff --git a/test/links.c b/test/links.c index 6b7e5b2..813b232 100644 --- a/test/links.c +++ b/test/links.c @@ -2367,7 +2367,7 @@ external_link_toomany(hid_t fapl, hbool_t new_format) } H5E_END_TRY; if (gid >= 0) { H5_FAILED(); - puts(" Should have failed for sequence of too many nested links."); + printf("%d: Should have failed for sequence of too many nested links.", __LINE__); goto error; } @@ -3531,7 +3531,7 @@ error: return -1; } - + /*------------------------------------------------------------------------- * Function: ext_link_endian * @@ -3621,6 +3621,90 @@ error: } H5E_END_TRY; return -1; } + + +/*------------------------------------------------------------------------- + * Function: external_link_strong + * + * Purpose: Check that external links work properly when they opened in + * a file with "strong" file close degree. + * + * Return: Success: 0 + * Failure: -1 + * + * Programmer: Quincey Koziol + * Monday, March 5, 2007 + * + *------------------------------------------------------------------------- + */ +static int +external_link_strong(hid_t fapl, hbool_t new_format) +{ + hid_t my_fapl; /* File access property list */ + hid_t fid1 = (-1), fid2 = (-1); /* File ID */ + hid_t gid1 = (-1), gid2 = (-1); /* Group IDs */ + char objname[NAME_BUF_SIZE]; /* Object name */ + ssize_t name_len; /* Length of object name */ + char filename1[NAME_BUF_SIZE], + filename2[NAME_BUF_SIZE]; + + if(new_format) + TESTING("that external files work with strong file close degree (w/new group format)") + else + TESTING("that external files work with strong file close degree") + + /* Set up filenames */ + h5_fixname(FILENAME[0], fapl, filename1, sizeof filename1); + h5_fixname(FILENAME[1], fapl, filename2, sizeof filename2); + + /* Copy file access property list */ + if((my_fapl = H5Pcopy(fapl)) < 0) TEST_ERROR + + /* Set strong file close degree */ + if(H5Pset_fclose_degree(my_fapl, H5F_CLOSE_STRONG) < 0) TEST_ERROR + + /* Create a group at /A/B/C in first file */ + if((fid1 = H5Fcreate(filename1, H5F_ACC_TRUNC, H5P_DEFAULT, my_fapl)) < 0) TEST_ERROR + if((gid1 = H5Gcreate(fid1, "A", (size_t)0)) < 0) TEST_ERROR + if(H5Gclose(gid1) < 0) TEST_ERROR + if((gid1 = H5Gcreate(fid1, "A/B", (size_t)0)) < 0) TEST_ERROR + if(H5Gclose(gid1) < 0) TEST_ERROR + if((gid1 = H5Gcreate(fid1, "A/B/C", (size_t)0)) < 0) TEST_ERROR + if(H5Gclose(gid1) < 0) TEST_ERROR + if(H5Fclose(fid1) < 0) TEST_ERROR + + /* Create an external link /W/X/DLINK in second file to :/A/B/C */ + if((fid2 = H5Fcreate(filename2, H5F_ACC_TRUNC, H5P_DEFAULT, fapl)) < 0) TEST_ERROR + if((gid2 = H5Gcreate(fid2, "/W", (size_t)0)) < 0) TEST_ERROR + if(H5Gclose(gid2) < 0) TEST_ERROR + if((gid2 = H5Gcreate(fid2, "/W/X", (size_t)0)) < 0) TEST_ERROR + if(H5Lcreate_external(filename1, "/A/B/C", gid2, "DLINK", H5P_DEFAULT, H5P_DEFAULT) < 0) TEST_ERROR + if(H5Gclose(gid2) < 0) TEST_ERROR + if(H5Fclose(fid2) < 0) TEST_ERROR + + /* Access external link from file #1 */ + if((fid2 = H5Fopen(filename2, H5F_ACC_RDONLY, fapl)) < 0) TEST_ERROR + if((gid2 = H5Gopen(fid2, "/W/X/DLINK")) < 0) TEST_ERROR + if((name_len = H5Iget_name(gid2, objname, (size_t)NAME_BUF_SIZE )) < 0) TEST_ERROR + if(HDstrcmp(objname, "/A/B/C")) TEST_ERROR + if(H5Gclose(gid2) < 0) TEST_ERROR + if(H5Fclose(fid2) < 0) TEST_ERROR + + + PASSED(); + return 0; + +error: + H5E_BEGIN_TRY { + H5Gclose(fapl); + H5Gclose(gid2); + H5Gclose(gid1); + H5Fclose(fid2); + H5Fclose(fid1); + } H5E_END_TRY; + return -1; +} /* end external_link_strong() */ + /*------------------------------------------------------------------------- * Function: ud_hard_links @@ -9552,6 +9636,7 @@ main(void) nerrors += external_link_closing((new_format ? fapl2 : fapl), new_format) < 0 ? 1 : 0; #endif /* H5_CANNOT_OPEN_TWICE */ nerrors += external_link_endian((new_format ? fapl2 : fapl), new_format) < 0 ? 1 : 0; + nerrors += external_link_strong((new_format ? fapl2 : fapl), new_format) < 0 ? 1 : 0; /* These tests assume that external links are a form of UD links, * so assume that everything that passed for external links -- cgit v0.12