From 5e0b59a70cc093b6ce17820a78de410201867226 Mon Sep 17 00:00:00 2001 From: mattjala <124107509+mattjala@users.noreply.github.com> Date: Fri, 10 Nov 2023 22:34:46 -0600 Subject: Test and document path handling of H5Lcreate_* API (#3829) --- src/H5Lpublic.h | 27 ++++-- test/links.c | 250 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 270 insertions(+), 7 deletions(-) diff --git a/src/H5Lpublic.h b/src/H5Lpublic.h index 03b47c5..2bf3c53 100644 --- a/src/H5Lpublic.h +++ b/src/H5Lpublic.h @@ -260,9 +260,13 @@ H5_DLL herr_t H5Lcopy(hid_t src_loc, const char *src_name, hid_t dst_loc, const * location and name, respectively, of the new hard link. * * \p cur_name and \p dst_name are interpreted relative to \p cur_loc - * and \p dst_loc, respectively. If \p cur_loc and \p dst_loc are the - * same location, the HDF5 macro #H5L_SAME_LOC can be used for either - * parameter (but not both). + * and \p dst_loc, respectively. If a given name begins with \c /, + * then it will be interpreted as absolute path in the file. + * The names of the created links will be the last element of + * each provided path. Prior elements in each path are used to + * locate the parent groups of each new link. If \p cur_loc and + * \p dst_loc are the same location, the HDF5 macro + * #H5L_SAME_LOC can be used for either parameter (but not both). * * \p lcpl_id and \p lapl_id are the link creation and access property * lists associated with the new link. @@ -321,8 +325,10 @@ H5_DLL herr_t H5Lcreate_hard_async(hid_t cur_loc_id, const char *cur_name, hid_t * * \p link_loc_id and \p link_name specify the location and name, * respectively, of the new soft link. \p link_name is interpreted - * relative to \p link_loc_id and must contain only the name of the soft - * link; \p link_name may not contain any additional path elements. + * as a path relative to \p link_loc_id, or an absolute path if it + * begins with \c /. The name of the created link will be the last + * element of the provided path. Prior elements in the path are + * used to locate the parent group of the new link. * * If \p link_loc_id is a group identifier, the object pointed to by * \p link_name will be accessed as a member of that group. If @@ -1190,7 +1196,11 @@ H5_DLL herr_t H5Lvisit_by_name2(hid_t loc_id, const char *group_name, H5_index_t * named \p link_name at the location specified in \p link_loc_id with * user-specified data \p udata. * - * \p link_name is interpreted relative to \p link_loc_id. + * \p link_name is interpreted relative to \p link_loc_id. If + * \p link_name begins with \c /, then it will be interpreted as + * an absolute path in the file. The name of the created link + * will be the last element of the provided path. Prior elements + * in the path are used to locate the parent group of the new link. * * Valid values for the link class of the new link, \p link_type, * include #H5L_TYPE_EXTERNAL and any user-defined link classes that @@ -1307,7 +1317,10 @@ H5_DLL herr_t H5Lunpack_elink_val(const void *ext_linkval /*in*/, size_t link_si * * \p link_loc_id and \p link_name specify the location and name, * respectively, of the new link. \p link_name is interpreted relative - * to \p link_loc_id. + * to \p link_loc_id. If \p link_name begins with \c /, then it is + * interpreted as an absolute path in the file. The name of the created + * link will be the last element of the provided path. Prior elements in + * the path are used to locate the parent group of the new link. * * \p lcpl_id is the link creation property list used in creating the * new link. diff --git a/test/links.c b/test/links.c index 99e0114..e068d71 100644 --- a/test/links.c +++ b/test/links.c @@ -22624,6 +22624,253 @@ error: } /* end timestamps() */ /*------------------------------------------------------------------------- + * Function: link_path_handling + * + * Purpose: Create hard and soft links by relative and absolute paths + * + * Return: Success: 0 + * Failure: -1 + *------------------------------------------------------------------------- + */ +static int +link_path_handling(hid_t fapl, bool new_format) +{ + + hid_t file_id = (H5I_INVALID_HID); + hid_t grp1 = (H5I_INVALID_HID), grp2 = (H5I_INVALID_HID); + char filename[NAME_BUF_SIZE]; + + if (new_format) + TESTING("H5Lcreate path handling (w/new group format)"); + else + TESTING("H5Lcreate path handling"); + + /* Create file */ + h5_fixname(FILENAME[0], fapl, filename, sizeof(filename)); + + if ((file_id = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl)) < 0) + TEST_ERROR; + + /* Create two groups */ + if ((grp1 = H5Gcreate2(file_id, "grp1", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) + TEST_ERROR; + if ((grp2 = H5Gcreate2(grp1, "grp2", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) + TEST_ERROR; + + /* Create hard link to grp1 that resides in grp2 by relative path */ + if (H5Lcreate_hard(file_id, "grp1", grp1, "grp2/relative_hard_link", H5P_DEFAULT, H5P_DEFAULT) < 0) + TEST_ERROR; + + if (H5Lexists(grp2, "relative_hard_link", H5P_DEFAULT) <= 0) + TEST_ERROR; + + /* Create soft link to grp1 that resides in grp2 by relative path */ + if (H5Lcreate_soft("/grp1", grp1, "grp2/relative_soft_link", H5P_DEFAULT, H5P_DEFAULT) < 0) + TEST_ERROR; + + if (H5Lexists(grp2, "relative_soft_link", H5P_DEFAULT) <= 0) + TEST_ERROR; + + /* Create hard link to grp1 that resides in grp2 by absolute path */ + if (H5Lcreate_hard(file_id, "grp1", grp1, "/grp1/grp2/absolute_hard_link", H5P_DEFAULT, H5P_DEFAULT) < 0) + TEST_ERROR; + + if (H5Lexists(grp2, "absolute_hard_link", H5P_DEFAULT) <= 0) + TEST_ERROR; + + /* Create soft link to grp1 that resides in grp2 by absolute path */ + if (H5Lcreate_soft("/grp1", grp1, "/grp1/grp2/absolute_soft_link", H5P_DEFAULT, H5P_DEFAULT) < 0) + TEST_ERROR; + + if (H5Lexists(grp2, "absolute_soft_link", H5P_DEFAULT) <= 0) + TEST_ERROR; + + /* Close groups and file */ + if (H5Gclose(grp1) < 0) + TEST_ERROR; + if (H5Gclose(grp2) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + return SUCCEED; + +error: + H5E_BEGIN_TRY + { + H5Gclose(grp1); + H5Gclose(grp2); + H5Fclose(file_id); + } + H5E_END_TRY + return FAIL; +} + +/*------------------------------------------------------------------------- + * Function: ext_link_path_handling + * + * Purpose: Create external links by relative and absolute paths + * + * Return: Success: 0 + * Failure: -1 + *------------------------------------------------------------------------- + */ +static int +ext_link_path_handling(hid_t fapl, bool new_format) +{ + + hid_t file_id = (H5I_INVALID_HID); + hid_t grp1 = (H5I_INVALID_HID), grp2 = (H5I_INVALID_HID); + char filename[NAME_BUF_SIZE]; + + if (new_format) + TESTING("H5Lcreate external link path handling (w/new group format)"); + else + TESTING("H5Lcreate external link path handling"); + + /* Create file */ + h5_fixname(FILENAME[0], fapl, filename, sizeof(filename)); + + if ((file_id = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl)) < 0) + TEST_ERROR; + + /* Create two groups */ + if ((grp1 = H5Gcreate2(file_id, "grp1", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) + TEST_ERROR; + if ((grp2 = H5Gcreate2(grp1, "grp2", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) + TEST_ERROR; + + /* Create external link to nonexistent object by relative path */ + if (H5Lcreate_external("nonexistent_file", "nonexistent_object", grp1, "grp2/relative_ext_link", + H5P_DEFAULT, H5P_DEFAULT) < 0) + TEST_ERROR; + + if (H5Lexists(grp2, "relative_ext_link", H5P_DEFAULT) <= 0) + TEST_ERROR; + + /* Create external link to nonexistent object by absolute path */ + if (H5Lcreate_external("nonexistent_file", "nonexistent_object", grp1, "/grp1/grp2/relative_soft_link", + H5P_DEFAULT, H5P_DEFAULT) < 0) + TEST_ERROR; + + if (H5Lexists(grp2, "relative_soft_link", H5P_DEFAULT) <= 0) + TEST_ERROR; + + /* Close groups and file */ + if (H5Gclose(grp1) < 0) + TEST_ERROR; + if (H5Gclose(grp2) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + return SUCCEED; + +error: + H5E_BEGIN_TRY + { + H5Gclose(grp1); + H5Gclose(grp2); + H5Fclose(file_id); + } + H5E_END_TRY + return FAIL; +} + +/*------------------------------------------------------------------------- + * Function: ud_link_path_handling + * + * Purpose: Create user-defined links by relative and absolute paths + * + * Return: Success: 0 + * Failure: -1 + *------------------------------------------------------------------------- + */ +static int +ud_link_path_handling(hid_t fapl, bool new_format) +{ + + hid_t file_id = (H5I_INVALID_HID); + hid_t grp1 = (H5I_INVALID_HID), grp2 = (H5I_INVALID_HID); + char filename[NAME_BUF_SIZE]; + H5L_info2_t li; + + if (new_format) + TESTING("H5Lcreate ud link path handling (w/new group format)"); + else + TESTING("H5Lcreate ud link path handling"); + + /* Create file */ + h5_fixname(FILENAME[0], fapl, filename, sizeof(filename)); + + if ((file_id = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl)) < 0) + TEST_ERROR; + + /* Create two groups */ + if ((grp1 = H5Gcreate2(file_id, "grp1", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) + TEST_ERROR; + if ((grp2 = H5Gcreate2(grp1, "grp2", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) + TEST_ERROR; + + /* Check that UD hard links are not registered */ + if (H5Lis_registered((H5L_type_t)UD_HARD_TYPE) != false) + TEST_ERROR; + + /* Register "user-defined hard links" with the library */ + if (H5Lregister(UD_hard_class) < 0) + TEST_ERROR; + + /* Check that UD hard links are registered */ + if (H5Lis_registered((H5L_type_t)UD_HARD_TYPE) != true) + TEST_ERROR; + + if (H5Lget_info2(file_id, "grp1", &li, H5P_DEFAULT) < 0) + TEST_ERROR; + + /* Create user-defined (hard) link to grp1 by relative path */ + if (H5Lcreate_ud(grp1, "grp2/relative_ud_link", (H5L_type_t)UD_HARD_TYPE, &(li.u.token), + sizeof(li.u.token), H5P_DEFAULT, H5P_DEFAULT) < 0) + TEST_ERROR; + + if (H5Lexists(grp2, "relative_ud_link", H5P_DEFAULT) <= 0) + TEST_ERROR; + + /* Create user-defined (hard) link to grp1 by absolute path */ + if (H5Lcreate_ud(grp1, "/grp1/grp2/absolute_ud_link", (H5L_type_t)UD_HARD_TYPE, &(li.u.token), + sizeof(li.u.token), H5P_DEFAULT, H5P_DEFAULT) < 0) + TEST_ERROR; + + if (H5Lexists(grp2, "absolute_ud_link", H5P_DEFAULT) <= 0) + TEST_ERROR; + + /* Close groups and file */ + if (H5Gclose(grp1) < 0) + TEST_ERROR; + if (H5Gclose(grp2) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + if (H5Lunregister((H5L_type_t)UD_HARD_TYPE) < 0) + TEST_ERROR; + + PASSED(); + return SUCCEED; + +error: + H5E_BEGIN_TRY + { + H5Gclose(grp1); + H5Gclose(grp2); + H5Fclose(file_id); + H5Lunregister((H5L_type_t)UD_HARD_TYPE); + } + H5E_END_TRY + return FAIL; +} + +/*------------------------------------------------------------------------- * Function: main * * Purpose: Test links @@ -22697,6 +22944,7 @@ main(void) nerrors += ck_new_links(my_fapl, new_format) < 0 ? 1 : 0; nerrors += long_links(my_fapl, new_format) < 0 ? 1 : 0; nerrors += toomany(my_fapl, new_format) < 0 ? 1 : 0; + nerrors += link_path_handling(my_fapl, new_format) < 0 ? 1 : 0; /* Test new H5L link creation routine */ nerrors += test_lcpl(my_fapl, new_format); @@ -22804,6 +23052,7 @@ main(void) nerrors += external_open_twice(my_fapl, new_format) < 0 ? 1 : 0; nerrors += external_link_with_committed_datatype(my_fapl, new_format) < 0 ? 1 : 0; nerrors += external_link_public_macros(my_fapl, new_format) < 0 ? 1 : 0; + nerrors += ext_link_path_handling(my_fapl, new_format) < 0 ? 1 : 0; } /* with/without external file cache */ } @@ -22826,6 +23075,7 @@ main(void) nerrors += ud_callbacks_deprec(my_fapl, new_format) < 0 ? 1 : 0; #endif /* H5_NO_DEPRECATED_SYMBOLS */ nerrors += ud_link_errors(my_fapl, new_format) < 0 ? 1 : 0; + nerrors += ud_link_path_handling(my_fapl, new_format) < 0 ? 1 : 0; nerrors += lapl_udata(my_fapl, new_format) < 0 ? 1 : 0; nerrors += lapl_nlinks(my_fapl, new_format) < 0 ? 1 : 0; #ifndef H5_NO_DEPRECATED_SYMBOLS -- cgit v0.12