From 37358db8ab62fa9c9057ea118b8576d5a4368ef1 Mon Sep 17 00:00:00 2001 From: Quincey Koziol Date: Tue, 10 Nov 2009 12:30:09 -0500 Subject: [svn-r17862] Description: Bring r17860 from trunk to 1.8 branch: "Normalize" object names for external links, making them into the same form as used for soft links. Begin the process of adding more printf-like information to library error reporting. HGOTO_ERROR() and HDONE_ERROR() macros can now use the last parameter (a string) like a printf() formatting string and pass extra parameters with additional information. (For example, see the HGOTO_ERROR macros in H5FD_sec2_read() in src/H5FDsec2.c) Bring the underlying H5E_printf_stack() routine from trunk to 1.8 branch also. Tested on: FreeBSD/32 6.3 (duty) in debug mode FreeBSD/64 6.3 (liberty) w/C++ & FORTRAN, in debug mode Linux/32 2.6 (jam) w/PGI compilers, w/default API=1.8.x, w/C++ & FORTRAN, w/threadsafe, in debug mode Linux/64-amd64 2.6 (smirom) w/Intel compilers, w/default API=1.6.x, w/C++ & FORTRAN, in production mode Solaris/32 2.10 (linew) w/deprecated symbols disabled, w/C++ & FORTRAN, w/szip filter, in production mode Linux/64-ia64 2.6 (cobalt) w/Intel compilers, w/C++ & FORTRAN, in production mode Linux/64-ia64 2.4 (tg-login3) w/parallel, w/FORTRAN, in debug mode Linux/64-amd64 2.6 (abe) w/parallel, w/FORTRAN, in production mode Mac OS X/32 10.6.2 (amazon) in debug mode Mac OS X/32 10.6.2 (amazon) w/C++ & FORTRAN, w/threadsafe, in production mode --- src/H5Eint.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/H5Eprivate.h | 20 ++++++----- src/H5FDsec2.c | 12 +++---- src/H5Gdeprec.c | 4 +-- src/H5L.c | 6 ++-- src/H5Lexternal.c | 11 ++++-- test/links.c | 47 +++++++++++++++++-------- 7 files changed, 163 insertions(+), 38 deletions(-) diff --git a/src/H5Eint.c b/src/H5Eint.c index f45e9fd..3265fc7 100644 --- a/src/H5Eint.c +++ b/src/H5Eint.c @@ -661,6 +661,107 @@ H5E_set_auto(H5E_t *estack, const H5E_auto_op_t *op, void *client_data) /*------------------------------------------------------------------------- + * Function: H5E_printf_stack + * + * Purpose: Printf-like wrapper around H5E_push_stack. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Tuesday, August 12, 2008 + * + *------------------------------------------------------------------------- + */ +herr_t +H5E_printf_stack(H5E_t *estack, const char *file, const char *func, unsigned line, + hid_t cls_id, hid_t maj_id, hid_t min_id, const char *fmt, ...) +{ + va_list ap; /* Varargs info */ +#ifndef H5_HAVE_VASPRINTF + int tmp_len; /* Current size of description buffer */ + int desc_len; /* Actual length of description when formatted */ +#endif /* H5_HAVE_VASPRINTF */ + char *tmp = NULL; /* Buffer to place formatted description in */ + herr_t ret_value = SUCCEED; /* Return value */ + + /* + * WARNING: We cannot call HERROR() from within this function or else we + * could enter infinite recursion. Furthermore, we also cannot + * call any other HDF5 macro or function which might call + * HERROR(). HERROR() is called by HRETURN_ERROR() which could + * be called by FUNC_ENTER(). + */ + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5E_printf_stack) + + /* Sanity check */ + HDassert(cls_id > 0); + HDassert(maj_id > 0); + HDassert(min_id > 0); + HDassert(fmt); + +/* Note that the variable-argument parsing for the format is identical in + * the H5Epush2() routine - correct errors and make changes in both + * places. -QAK + */ + + /* Start the variable-argument parsing */ + va_start(ap, fmt); + +#ifdef H5_HAVE_VASPRINTF + /* Use the vasprintf() routine, since it does what we're trying to do below */ + if(HDvasprintf(&tmp, fmt, ap) < 0) + HGOTO_DONE(FAIL) +#else /* H5_HAVE_VASPRINTF */ + /* Allocate space for the formatted description buffer */ + tmp_len = 128; + if(NULL == (tmp = H5MM_malloc((size_t)tmp_len))) + HGOTO_DONE(FAIL) + + /* If the description doesn't fit into the initial buffer size, allocate more space and try again */ + while((desc_len = HDvsnprintf(tmp, (size_t)tmp_len, fmt, ap)) +#ifdef H5_VSNPRINTF_WORKS + > +#else /* H5_VSNPRINTF_WORKS */ + >= +#endif /* H5_VSNPRINTF_WORKS */ + (tmp_len - 1) +#ifndef H5_VSNPRINTF_WORKS + || (desc_len < 0) +#endif /* H5_VSNPRINTF_WORKS */ + ) { + /* shutdown & restart the va_list */ + va_end(ap); + va_start(ap, fmt); + + /* Release the previous description, it's too small */ + H5MM_xfree(tmp); + + /* Allocate a description of the appropriate length */ +#ifdef H5_VSNPRINTF_WORKS + tmp_len = desc_len + 1; +#else /* H5_VSNPRINTF_WORKS */ + tmp_len = 2 * tmp_len; +#endif /* H5_VSNPRINTF_WORKS */ + if(NULL == (tmp = H5MM_malloc((size_t)tmp_len))) + HGOTO_DONE(FAIL) + } /* end while */ +#endif /* H5_HAVE_VASPRINTF */ + + va_end(ap); + + /* Push the error on the stack */ + if(H5E_push_stack(estack, file, func, line, cls_id, maj_id, min_id, tmp) < 0) + HGOTO_DONE(FAIL) + +done: + if(tmp) + H5MM_xfree(tmp); + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5E_printf_stack() */ + + +/*------------------------------------------------------------------------- * Function: H5E_push_stack * * Purpose: Pushes a new error record onto error stack for the current diff --git a/src/H5Eprivate.h b/src/H5Eprivate.h index 6b1c80c..42f2e9c 100644 --- a/src/H5Eprivate.h +++ b/src/H5Eprivate.h @@ -32,14 +32,14 @@ typedef struct H5E_t H5E_t; * and a FUNC_LEAVE() within a function body. The arguments are the major * error number, the minor error number, and a description of the error. */ -#define HERROR(maj_id, min_id, str) H5E_push_stack(NULL, __FILE__, FUNC, __LINE__, H5E_ERR_CLS_g, maj_id, min_id, str) +#define HERROR(maj_id, min_id, ...) H5E_printf_stack(NULL, __FILE__, FUNC, __LINE__, H5E_ERR_CLS_g, maj_id, min_id, __VA_ARGS__) /* * HCOMMON_ERROR macro, used by HDONE_ERROR and HGOTO_ERROR * (Shouldn't need to be used outside this header file) */ -#define HCOMMON_ERROR(maj, min, str) \ - HERROR(maj, min, str); \ +#define HCOMMON_ERROR(maj, min, ...) \ + HERROR(maj, min, __VA_ARGS__); \ err_occurred = TRUE; /* @@ -51,8 +51,8 @@ typedef struct H5E_t H5E_t; * (This macro can also be used to push an error and set the return value * without jumping to any labels) */ -#define HDONE_ERROR(maj, min, ret_val, str) { \ - HCOMMON_ERROR(maj, min, str); \ +#define HDONE_ERROR(maj, min, ret_val, ...) { \ + HCOMMON_ERROR(maj, min, __VA_ARGS__); \ ret_value = ret_val; \ } @@ -63,8 +63,8 @@ typedef struct H5E_t H5E_t; * error string. The return value is assigned to a variable `ret_value' and * control branches to the `done' label. */ -#define HGOTO_ERROR(maj, min, ret_val, str) { \ - HCOMMON_ERROR(maj, min, str); \ +#define HGOTO_ERROR(maj, min, ret_val, ...) { \ + HCOMMON_ERROR(maj, min, __VA_ARGS__); \ HGOTO_DONE(ret_val) \ } @@ -78,8 +78,10 @@ typedef struct H5E_t H5E_t; /* Library-private functions defined in H5E package */ H5_DLL herr_t H5E_init(void); -H5_DLL herr_t H5E_push_stack(H5E_t *estack, const char *file, const char *func, unsigned line, - hid_t cls_id, hid_t maj_id, hid_t min_id, const char *desc); +H5_DLL herr_t H5E_push_stack(H5E_t *estack, const char *file, const char *func, + unsigned line, hid_t cls_id, hid_t maj_id, hid_t min_id, const char *desc); +H5_DLL herr_t H5E_printf_stack(H5E_t *estack, const char *file, const char *func, + unsigned line, hid_t cls_id, hid_t maj_id, hid_t min_id, const char *fmt, ...); H5_DLL herr_t H5E_clear_stack(H5E_t *estack); H5_DLL herr_t H5E_dump_api_stack(int is_api); diff --git a/src/H5FDsec2.c b/src/H5FDsec2.c index f4c9947..921d49b 100644 --- a/src/H5FDsec2.c +++ b/src/H5FDsec2.c @@ -732,11 +732,11 @@ H5FD_sec2_read(H5FD_t *_file, H5FD_mem_t UNUSED type, hid_t UNUSED dxpl_id, /* Check for overflow conditions */ if(!H5F_addr_defined(addr)) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "addr undefined") + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "addr undefined, addr = %llu", (unsigned long long)addr) if(REGION_OVERFLOW(addr, size)) - HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow") + HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow, addr = %llu", (unsigned long long)addr) if((addr + size) > file->eoa) - HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow") + HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow, addr = %llu", (unsigned long long)addr) /* Seek to the correct location */ if((addr != file->pos || OP_READ != file->op) && @@ -813,11 +813,11 @@ H5FD_sec2_write(H5FD_t *_file, H5FD_mem_t UNUSED type, hid_t UNUSED dxpl_id, had /* Check for overflow conditions */ if(!H5F_addr_defined(addr)) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "addr undefined") + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "addr undefined, addr = %llu", (unsigned long long)addr) if(REGION_OVERFLOW(addr, size)) - HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow") + HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow, addr = %llu", (unsigned long long)addr) if((addr + size) > file->eoa) - HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow") + HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow, addr = %llu", (unsigned long long)addr) /* Seek to the correct location */ if((addr != file->pos || OP_WRITE != file->op) && diff --git a/src/H5Gdeprec.c b/src/H5Gdeprec.c index ddb5dfe..a18339b 100644 --- a/src/H5Gdeprec.c +++ b/src/H5Gdeprec.c @@ -890,7 +890,7 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5G_get_objinfo_cb(H5G_loc_t *grp_loc/*in*/, const char UNUSED *name, const H5O_link_t *lnk, +H5G_get_objinfo_cb(H5G_loc_t *grp_loc/*in*/, const char *name, const H5O_link_t *lnk, H5G_loc_t *obj_loc, void *_udata/*in,out*/, H5G_own_loc_t *own_loc/*out*/) { H5G_trav_goi_t *udata = (H5G_trav_goi_t *)_udata; /* User data passed in */ @@ -900,7 +900,7 @@ H5G_get_objinfo_cb(H5G_loc_t *grp_loc/*in*/, const char UNUSED *name, const H5O_ /* Check if the name in this group resolved to a valid link */ if(lnk == NULL && obj_loc == NULL) - HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "name doesn't exist") + HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "'%s' doesn't exist", name) /* Only modify user's buffer if it's available */ if(udata->statbuf) { diff --git a/src/H5L.c b/src/H5L.c index 0de2e10..b217abe 100644 --- a/src/H5L.c +++ b/src/H5L.c @@ -716,7 +716,7 @@ H5Lget_val(hid_t loc_id, const char *name, void *buf/*out*/, size_t size, /* Get the link value */ if(H5L_get_val(&loc, name, buf, size, lapl_id, H5AC_ind_dxpl_id) < 0) - HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to get link value") + HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to get link value for '%s'", name) done: FUNC_LEAVE_API(ret_value) @@ -2120,7 +2120,7 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5L_get_val_cb(H5G_loc_t UNUSED *grp_loc/*in*/, const char UNUSED *name, const H5O_link_t *lnk, +H5L_get_val_cb(H5G_loc_t UNUSED *grp_loc/*in*/, const char *name, const H5O_link_t *lnk, H5G_loc_t UNUSED *obj_loc, void *_udata/*in,out*/, H5G_own_loc_t *own_loc/*out*/) { H5L_trav_gv_t *udata = (H5L_trav_gv_t *)_udata; /* User data passed in */ @@ -2130,7 +2130,7 @@ H5L_get_val_cb(H5G_loc_t UNUSED *grp_loc/*in*/, const char UNUSED *name, const H /* 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") + HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "'%s' doesn't exist", name) /* Retrieve the value for the link */ if(H5L_get_val_real(lnk, udata->buf, udata->size) < 0) diff --git a/src/H5Lexternal.c b/src/H5Lexternal.c index 57414c7..640ac07 100644 --- a/src/H5Lexternal.c +++ b/src/H5Lexternal.c @@ -514,6 +514,7 @@ H5Lcreate_external(const char *file_name, const char *obj_name, hid_t link_loc_id, const char *link_name, hid_t lcpl_id, hid_t lapl_id) { H5G_loc_t link_loc; /* Group location to create link */ + char *norm_obj_name = NULL; /* Pointer to normalized current name */ void *ext_link_buf = NULL; /* Buffer to contain external link */ size_t buf_size; /* Size of buffer to hold external link */ uint8_t *p; /* Pointer into external link buffer */ @@ -533,8 +534,12 @@ H5Lcreate_external(const char *file_name, const char *obj_name, if(!link_name || !*link_name) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no link name specified") + /* Get normalized copy of the link target */ + if(NULL == (norm_obj_name = H5G_normalize(obj_name))) + HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "can't normalize object name") + /* Combine the filename and link name into a single buffer to give to the UD link */ - buf_size = 1 + (HDstrlen(file_name) + 1) + (HDstrlen(obj_name) + 1); + buf_size = 1 + (HDstrlen(file_name) + 1) + (HDstrlen(norm_obj_name) + 1); if(NULL == (ext_link_buf = H5MM_malloc(buf_size))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate udata buffer") @@ -543,14 +548,14 @@ H5Lcreate_external(const char *file_name, const char *obj_name, *p++ = (H5L_EXT_VERSION << 4) | H5L_EXT_FLAGS_ALL; /* External link version & flags */ HDstrcpy((char *)p, file_name); /* Name of file containing external link's object */ p += HDstrlen(file_name) + 1; - HDstrcpy((char *)p, obj_name); /* External link's object */ + HDstrcpy((char *)p, norm_obj_name); /* External link's object */ /* Create an external link */ if(H5L_create_ud(&link_loc, link_name, ext_link_buf, buf_size, H5L_TYPE_EXTERNAL, lcpl_id, lapl_id, H5AC_dxpl_id) < 0) HGOTO_ERROR(H5E_LINK, H5E_CANTINIT, FAIL, "unable to create link") done: - if(ext_link_buf != NULL) + if(norm_obj_name) H5MM_free(ext_link_buf); FUNC_LEAVE_API(ret_value) diff --git a/test/links.c b/test/links.c index 8ee16a6..04f2b90 100644 --- a/test/links.c +++ b/test/links.c @@ -1794,6 +1794,30 @@ external_link_root(hid_t fapl, hbool_t new_format) goto error; } + /* Create external link to object in first file */ + /* (add a few extra '/'s to make certain library normalizes external link object names) */ + if(H5Lcreate_external(filename1, "///", fid, "ext_link2", H5P_DEFAULT, H5P_DEFAULT) < 0) TEST_ERROR + + /* Check information for external link */ + if(H5Lget_info(fid, "ext_link", &linfo, H5P_DEFAULT) < 0) goto error; + if(H5L_TYPE_EXTERNAL != linfo.type) { + H5_FAILED(); + puts(" Unexpected object type - should have been an external link"); + goto error; + } + if(H5Lget_val(fid, "ext_link", objname, sizeof(objname), H5P_DEFAULT) < 0) TEST_ERROR + if(H5Lunpack_elink_val(objname, linfo.u.val_size, NULL, &file, &path) < 0) TEST_ERROR + if(HDstrcmp(file, filename1)) { + H5_FAILED(); + puts(" External link file name incorrect"); + goto error; + } + if(HDstrcmp(path, "/")) { + H5_FAILED(); + puts(" External link path incorrect"); + goto error; + } + /* Close and re-open file to ensure that data is written to disk */ if(H5Fclose(fid) < 0) TEST_ERROR if((fid = H5Fopen(filename2, H5F_ACC_RDWR, fapl)) < 0) TEST_ERROR @@ -3411,8 +3435,8 @@ external_link_reltar(hid_t fapl, hbool_t new_format) h5_fixname(FILENAME[26], fapl, filename2, sizeof filename2); /* Create the target file */ - if((fid=H5Fcreate(filename2, H5F_ACC_TRUNC, H5P_DEFAULT, fapl)) < 0) TEST_ERROR - if((gid=H5Gcreate2(fid, "A", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR + if((fid = H5Fcreate(filename2, H5F_ACC_TRUNC, H5P_DEFAULT, fapl)) < 0) TEST_ERROR + if((gid = H5Gcreate2(fid, "A", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR /* closing for target file */ if(H5Gclose(gid) < 0) TEST_ERROR @@ -3420,25 +3444,17 @@ external_link_reltar(hid_t fapl, hbool_t new_format) /* Create the main file */ - if((fid=H5Fcreate(filename1, H5F_ACC_TRUNC, H5P_DEFAULT, fapl)) < 0) TEST_ERROR + if((fid = H5Fcreate(filename1, H5F_ACC_TRUNC, H5P_DEFAULT, fapl)) < 0) TEST_ERROR /* Create external link to target file */ - if(H5Lcreate_external(filename2, "/A", fid, "ext_link", H5P_DEFAULT, H5P_DEFAULT) < 0) TEST_ERROR + if(H5Lcreate_external(filename2, "///A", fid, "ext_link", H5P_DEFAULT, H5P_DEFAULT) < 0) TEST_ERROR /* Open object through external link */ - H5E_BEGIN_TRY { - gid = H5Gopen2(fid, "ext_link", H5P_DEFAULT); - } H5E_END_TRY; - - /* - * Should be able to find the target file from: - * main file's current working directory + pathname of external linked targetfile - */ - if (gid < 0) { + if((gid = H5Gopen2(fid, "ext_link", H5P_DEFAULT)) < 0) { H5_FAILED(); puts(" Should have found the file in tmp directory."); goto error; - } + } /* end if */ /* closing for main file */ if(H5Gclose(gid) < 0) TEST_ERROR @@ -5301,7 +5317,8 @@ external_link_query(hid_t fapl, hbool_t new_format) if((fid=H5Fcreate(filename1, H5F_ACC_TRUNC, H5P_DEFAULT, fapl)) < 0) TEST_ERROR /* Create external link */ - if(H5Lcreate_external(filename2, "/dst", fid, "src", H5P_DEFAULT, H5P_DEFAULT) < 0) TEST_ERROR + /* (add a few extra '/'s to make certain library normalizes external link object names) */ + if(H5Lcreate_external(filename2, "///dst//", fid, "src", H5P_DEFAULT, H5P_DEFAULT) < 0) TEST_ERROR /* Get size of buffer for external link */ if(H5Lget_info(fid, "src", &li, H5P_DEFAULT) < 0) TEST_ERROR -- cgit v0.12