From dc0fd6a6443e3cab879f7282f0491814be2f04c6 Mon Sep 17 00:00:00 2001 From: Matthew Larson Date: Fri, 3 Nov 2023 11:24:52 -0500 Subject: [PATCH 1/5] Document path handling of H5Lcreate_* API --- src/H5Lpublic.h | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/H5Lpublic.h b/src/H5Lpublic.h index 03b47c540fa..34a4e6bc44f 100644 --- a/src/H5Lpublic.h +++ b/src/H5Lpublic.h @@ -260,9 +260,10 @@ 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. 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 +322,8 @@ 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 /. * * 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 +1191,9 @@ 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. * * 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 +1310,8 @@ 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. * * \p lcpl_id is the link creation property list used in creating the * new link. From cd993732487a05b90796dfebab09ef07ff8f4a27 Mon Sep 17 00:00:00 2001 From: Matthew Larson Date: Tue, 7 Nov 2023 16:48:12 -0600 Subject: [PATCH 2/5] Document that link name is last part of path --- src/H5Lpublic.h | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/H5Lpublic.h b/src/H5Lpublic.h index 34a4e6bc44f..8b3ce19f7ba 100644 --- a/src/H5Lpublic.h +++ b/src/H5Lpublic.h @@ -261,8 +261,11 @@ H5_DLL herr_t H5Lcopy(hid_t src_loc, const char *src_name, hid_t dst_loc, const * * \p cur_name and \p dst_name are interpreted relative to \p cur_loc * and \p dst_loc, respectively. If a given name begins with \c \, - * then it will be interpreted as absolute path in the file. If - * \p cur_loc and \p dst_loc are the same location, the HDF5 macro + * 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 @@ -323,7 +326,9 @@ 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 * as a path relative to \p link_loc_id, or an absolute path if it - * begins with \c /. + * 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 @@ -1193,7 +1198,9 @@ H5_DLL herr_t H5Lvisit_by_name2(hid_t loc_id, const char *group_name, H5_index_t * * \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. + * 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 @@ -1311,7 +1318,9 @@ 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. If \p link_name begins with \c \, then it is - * interpreted as an absolute path in the file. + * 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. From 2b534eb844e780ee5e3824eedd823126dd8686ea Mon Sep 17 00:00:00 2001 From: Matthew Larson Date: Thu, 9 Nov 2023 12:08:13 -0600 Subject: [PATCH 3/5] Test H5Lcreate path handling behavior --- test/links.c | 250 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 250 insertions(+) diff --git a/test/links.c b/test/links.c index 99e011402c0..f8b835ee085 100644 --- a/test/links.c +++ b/test/links.c @@ -22623,6 +22623,253 @@ timestamps(hid_t fapl) return FAIL; } /* 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: ext_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 * @@ -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 From b0404def46d8192ebe3d934f184ce2288ce6c7b8 Mon Sep 17 00:00:00 2001 From: Matthew Larson Date: Fri, 10 Nov 2023 11:31:31 -0600 Subject: [PATCH 4/5] State that absolute paths require forward slash --- src/H5Lpublic.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/H5Lpublic.h b/src/H5Lpublic.h index 8b3ce19f7ba..2bf3c53b83e 100644 --- a/src/H5Lpublic.h +++ b/src/H5Lpublic.h @@ -260,7 +260,7 @@ 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 a given name begins with \c \, + * 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 @@ -1197,7 +1197,7 @@ H5_DLL herr_t H5Lvisit_by_name2(hid_t loc_id, const char *group_name, H5_index_t * user-specified data \p udata. * * \p link_name is interpreted relative to \p link_loc_id. If - * \p link_name begins with \c \, then it will be interpreted as + * \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. @@ -1317,7 +1317,7 @@ 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. If \p link_name begins with \c \, then it is + * 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. From f488916ba16123d1a255e10615fa0c1b248bfa78 Mon Sep 17 00:00:00 2001 From: Matthew Larson Date: Fri, 10 Nov 2023 14:35:04 -0600 Subject: [PATCH 5/5] Fix typo in test name --- test/links.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/links.c b/test/links.c index f8b835ee085..e068d71be8e 100644 --- a/test/links.c +++ b/test/links.c @@ -22780,7 +22780,7 @@ ext_link_path_handling(hid_t fapl, bool new_format) } /*------------------------------------------------------------------------- - * Function: ext_link_path_handling + * Function: ud_link_path_handling * * Purpose: Create user-defined links by relative and absolute paths *