From 0aa2e6d2d374d37063bfdfacfc3d5ea91013e9d8 Mon Sep 17 00:00:00 2001 From: Matthew Larson Date: Wed, 12 Jul 2023 12:41:39 -0500 Subject: [PATCH] Implement H5Iget_name Assocating a path/name with each open object goes against the spirit of the API, but the alternative is traversing every link in the domain, which is already slow in the library and would be slower here. --- src/rest_vol.c | 2 + src/rest_vol.h | 2 + src/rest_vol_attr.c | 85 ++++++++++++++++++++++++++++++++++++++++- src/rest_vol_dataset.c | 57 +++++++++++++++++++++++++++ src/rest_vol_datatype.c | 57 +++++++++++++++++++++++++++ src/rest_vol_file.c | 4 +- src/rest_vol_group.c | 66 +++++++++++++++++++++++++++++++- src/rest_vol_object.c | 29 +++++++++++++- 8 files changed, 298 insertions(+), 4 deletions(-) diff --git a/src/rest_vol.c b/src/rest_vol.c index ba42acca..c470bca3 100644 --- a/src/rest_vol.c +++ b/src/rest_vol.c @@ -2437,6 +2437,8 @@ RV_copy_object_loc_info_callback(char *HTTP_response, void *callback_data_in, vo new_domain->u.file.fapl_id = H5Pcopy(loc_info_out->domain->u.file.fapl_id); new_domain->u.file.fcpl_id = H5Pcopy(loc_info_out->domain->u.file.fcpl_id); new_domain->u.file.ref_count = 1; + new_domain->u.file.server_version = found_domain.u.file.server_version; + new_domain->handle_path = "/"; /* Assume that original domain and external domain have the same server version. * This will always be true unless it becomes possible for external links to point to diff --git a/src/rest_vol.h b/src/rest_vol.h index f544d027..91a096b1 100644 --- a/src/rest_vol.h +++ b/src/rest_vol.h @@ -473,6 +473,7 @@ typedef struct RV_attr_t { hid_t aapl_id; hid_t acpl_id; char *attr_name; + char *parent_name; } RV_attr_t; typedef struct RV_datatype_t { @@ -485,6 +486,7 @@ struct RV_object_t { RV_object_t *domain; H5I_type_t obj_type; char URI[URI_MAX_LENGTH]; + char *handle_path; union { RV_datatype_t datatype; diff --git a/src/rest_vol_attr.c b/src/rest_vol_attr.c index 852e4c90..10d5e314 100644 --- a/src/rest_vol_attr.c +++ b/src/rest_vol_attr.c @@ -58,6 +58,8 @@ RV_attr_create(void *obj, const H5VL_loc_params_t *loc_params, const char *attr_ size_t host_header_len = 0; size_t datatype_body_len = 0; size_t attr_name_len = 0; + size_t path_size = 0; + size_t path_len = 0; char *host_header = NULL; char *create_request_body = NULL; char *datatype_body = NULL; @@ -114,6 +116,41 @@ RV_attr_create(void *obj, const H5VL_loc_params_t *loc_params, const char *attr_ new_attribute->domain = parent->domain; parent->domain->u.file.ref_count++; + new_attribute->handle_path = NULL; + + if (attr_name) { + /* Parent name is included if it is not the root */ + hbool_t include_parent_name = strcmp(parent->handle_path, "/"); + + path_size = (include_parent_name ? strlen(parent->handle_path) + 1 + strlen(attr_name) + 1 : 1 + strlen(attr_name) + 1); + + if ((new_attribute->handle_path = RV_malloc(path_size)) == NULL) + FUNC_GOTO_ERROR(H5E_SYM, H5E_CANTALLOC, NULL, "can't allocate space for handle path"); + + if (include_parent_name) { + strncpy(new_attribute->handle_path, parent->handle_path, strlen(parent->handle_path)); + path_len += strlen(parent->handle_path); + } + + /* Add leading slash if not in attribute name */ + if (attr_name[0] != '/') { + new_attribute->handle_path[path_len] = '/'; + path_len += 1; + } + + strncpy(new_attribute->handle_path + path_len, attr_name, strlen(attr_name) + 1); + path_len += (strlen(attr_name) + 1); + } + + new_attribute->u.attribute.parent_name = NULL; + + if (parent->handle_path) { + if ((new_attribute->u.attribute.parent_name = RV_malloc(strlen(parent->handle_path) + 1)) == NULL) + FUNC_GOTO_ERROR(H5E_ATTR, H5E_CANTALLOC, NULL, "can't allocate space for attribute parent name"); + + strncpy(new_attribute->u.attribute.parent_name, parent->handle_path, strlen(parent->handle_path) + 1); + } + /* If this is a call to H5Acreate_by_name, locate the real parent object */ if (H5VL_OBJECT_BY_NAME == loc_params->type) { @@ -402,6 +439,8 @@ RV_attr_open(void *obj, const H5VL_loc_params_t *loc_params, const char *attr_na RV_object_t *attribute = NULL; size_t attr_name_len = 0; size_t host_header_len = 0; + size_t path_size = 0; + size_t path_len = 0; char *host_header = NULL; char *found_attr_name = NULL; char request_url[URL_MAX_LENGTH]; @@ -456,6 +495,41 @@ RV_attr_open(void *obj, const H5VL_loc_params_t *loc_params, const char *attr_na attribute->domain = parent->domain; parent->domain->u.file.ref_count++; + attribute->handle_path = NULL; + + if (attr_name) { + /* Parent name is included if it is not the root */ + hbool_t include_parent_name = strcmp(parent->handle_path, "/"); + + path_size = (include_parent_name ? strlen(parent->handle_path) + 1 + strlen(attr_name) + 1 : 1 + strlen(attr_name) + 1); + + if ((attribute->handle_path = RV_malloc(path_size)) == NULL) + FUNC_GOTO_ERROR(H5E_SYM, H5E_CANTALLOC, NULL, "can't allocate space for handle path"); + + if (include_parent_name) { + strncpy(attribute->handle_path, parent->handle_path, strlen(parent->handle_path)); + path_len += strlen(parent->handle_path); + } + + /* Add leading slash if not in attribute name */ + if (attr_name[0] != '/') { + attribute->handle_path[path_len] = '/'; + path_len += 1; + } + + strncpy(attribute->handle_path + path_len, attr_name, strlen(attr_name) + 1); + path_len += (strlen(attr_name) + 1); + } + + attribute->u.attribute.parent_name = NULL; + + if (parent->handle_path) { + if ((attribute->u.attribute.parent_name = RV_malloc(strlen(parent->handle_path) + 1)) == NULL) + FUNC_GOTO_ERROR(H5E_ATTR, H5E_CANTALLOC, NULL, "can't allocate space for attribute parent name"); + + strncpy(attribute->u.attribute.parent_name, parent->handle_path, strlen(parent->handle_path) + 1); + } + /* Set the parent object's type and URI in the attribute's appropriate fields */ switch (loc_params->type) { /* H5Aopen */ @@ -2170,10 +2244,17 @@ RV_attr_specific(void *obj, const H5VL_loc_params_t *loc_params, H5VL_attr_speci } /* Increment refs for specific type */ + + RV_object_t *attr_iter_obj = (RV_object_t *)attr_iter_object; + + if ((attr_iter_obj->handle_path = RV_malloc(strlen(loc_obj->handle_path) +1)) == NULL) + FUNC_GOTO_ERROR(H5E_ATTR, H5E_CANTALLOC, FAIL, "can't allocate space for copy of object path"); + + strncpy(attr_iter_obj->handle_path, loc_obj->handle_path, strlen(loc_obj->handle_path) + 1); + switch (parent_obj_type) { case H5I_FILE: /* Copy fapl, fcpl, and filepath name to new object */ - RV_object_t *attr_iter_obj = (RV_object_t *)attr_iter_object; if (H5I_INVALID_HID == (attr_iter_obj->u.file.fapl_id = H5Pcopy(loc_obj->u.file.fapl_id))) @@ -2602,6 +2683,8 @@ RV_attr_close(void *attr, hid_t dxpl_id, void **req) if (RV_file_close(_attr->domain, H5P_DEFAULT, NULL) < 0) FUNC_GOTO_ERROR(H5E_FILE, H5E_CANTCLOSEOBJ, FAIL, "couldn't close attr domain"); + RV_free(_attr->u.attribute.parent_name); + RV_free(_attr->handle_path); RV_free(_attr); _attr = NULL; diff --git a/src/rest_vol_dataset.c b/src/rest_vol_dataset.c index ce17d67b..40551bfe 100644 --- a/src/rest_vol_dataset.c +++ b/src/rest_vol_dataset.c @@ -105,6 +105,8 @@ RV_dataset_create(void *obj, const H5VL_loc_params_t *loc_params, const char *na RV_object_t *new_dataset = NULL; curl_off_t create_request_body_len = 0; size_t host_header_len = 0; + size_t path_size = 0; + size_t path_len = 0; char *host_header = NULL; char *create_request_body = NULL; char request_url[URL_MAX_LENGTH]; @@ -144,6 +146,32 @@ RV_dataset_create(void *obj, const H5VL_loc_params_t *loc_params, const char *na new_dataset->domain = parent->domain; parent->domain->u.file.ref_count++; + new_dataset->handle_path = NULL; + + if (name) { + /* Parent name is included if it is not the root and the dataset is opened by relative path */ + hbool_t include_parent_name = strcmp(parent->handle_path, "/") && (name[0] != '/'); + + path_size = (include_parent_name ? strlen(parent->handle_path) + 1 + strlen(name) + 1 : 1 + strlen(name) + 1); + + if ((new_dataset->handle_path = RV_malloc(path_size)) == NULL) + FUNC_GOTO_ERROR(H5E_SYM, H5E_CANTALLOC, NULL, "can't allocate space for handle path"); + + if (include_parent_name) { + strncpy(new_dataset->handle_path, parent->handle_path, strlen(parent->handle_path)); + path_len += strlen(parent->handle_path); + } + + /* Add leading slash if not in dataset path */ + if (name[0] != '/') { + new_dataset->handle_path[path_len] = '/'; + path_len += 1; + } + + strncpy(new_dataset->handle_path + path_len, name, strlen(name) + 1); + path_len += (strlen(name) + 1); + } + /* Copy the DAPL if it wasn't H5P_DEFAULT, else set up a default one so that * H5Dget_access_plist() will function correctly */ @@ -303,6 +331,8 @@ RV_dataset_open(void *obj, const H5VL_loc_params_t *loc_params, const char *name htri_t search_ret; void *ret_value = NULL; loc_info loc_info_out; + size_t path_size = 0; + size_t path_len = 0; #ifdef RV_CONNECTOR_DEBUG printf("-> Received dataset open call with following parameters:\n"); @@ -331,6 +361,32 @@ RV_dataset_open(void *obj, const H5VL_loc_params_t *loc_params, const char *name dataset->domain = parent->domain; parent->domain->u.file.ref_count++; + dataset->handle_path = NULL; + + if (name) { + /* Parent name is included if it is not the root and the dataset is opened by relative path */ + hbool_t include_parent_name = strcmp(parent->handle_path, "/") && (name[0] != '/'); + + path_size = (include_parent_name ? strlen(parent->handle_path) + 1 + strlen(name) + 1 : 1 + strlen(name) + 1); + + if ((dataset->handle_path = RV_malloc(path_size)) == NULL) + FUNC_GOTO_ERROR(H5E_SYM, H5E_CANTALLOC, NULL, "can't allocate space for handle path"); + + if (include_parent_name) { + strncpy(dataset->handle_path, parent->handle_path, strlen(parent->handle_path)); + path_len += strlen(parent->handle_path); + } + + /* Add leading slash if not in dataset path */ + if (name[0] != '/') { + dataset->handle_path[path_len] = '/'; + path_len += 1; + } + + strncpy(dataset->handle_path + path_len, name, strlen(name) + 1); + path_len += (strlen(name) + 1); + } + loc_info_out.URI = dataset->URI; loc_info_out.domain = dataset->domain; loc_info_out.GCPL_base64 = NULL; @@ -1169,6 +1225,7 @@ RV_dataset_close(void *dset, hid_t dxpl_id, void **req) FUNC_DONE_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't close file"); } + RV_free(_dset->handle_path); RV_free(_dset); _dset = NULL; diff --git a/src/rest_vol_datatype.c b/src/rest_vol_datatype.c index e3adb8f1..71c14c19 100644 --- a/src/rest_vol_datatype.c +++ b/src/rest_vol_datatype.c @@ -72,6 +72,8 @@ RV_datatype_commit(void *obj, const H5VL_loc_params_t *loc_params, const char *n size_t link_body_nalloc = 0; size_t host_header_len = 0; size_t datatype_body_len = 0; + size_t path_size = 0; + size_t path_len = 0; char *host_header = NULL; char *commit_request_body = NULL; char *datatype_body = NULL; @@ -117,6 +119,32 @@ RV_datatype_commit(void *obj, const H5VL_loc_params_t *loc_params, const char *n new_datatype->domain = parent->domain; parent->domain->u.file.ref_count++; + new_datatype->handle_path = NULL; + + if (name) { + /* Parent name is included if it is not the root and the datatype is opened by relative path */ + hbool_t include_parent_name = strcmp(parent->handle_path, "/") && (name[0] != '/'); + + path_size = (include_parent_name ? strlen(parent->handle_path) + 1 + strlen(name) + 1 : 1 + strlen(name) + 1); + + if ((new_datatype->handle_path = RV_malloc(path_size)) == NULL) + FUNC_GOTO_ERROR(H5E_SYM, H5E_CANTALLOC, NULL, "can't allocate space for handle path"); + + if (include_parent_name) { + strncpy(new_datatype->handle_path, parent->handle_path, strlen(parent->handle_path)); + path_len += strlen(parent->handle_path); + } + + /* Add leading slash if not in datatype path */ + if (name[0] != '/') { + new_datatype->handle_path[path_len] = '/'; + path_len += 1; + } + + strncpy(new_datatype->handle_path + path_len, name, strlen(name) + 1); + path_len += (strlen(name) + 1); + } + /* Copy the TAPL if it wasn't H5P_DEFAULT, else set up a default one so that * datatype access property list functions will function correctly */ @@ -331,6 +359,8 @@ RV_datatype_open(void *obj, const H5VL_loc_params_t *loc_params, const char *nam H5I_type_t obj_type = H5I_UNINIT; loc_info loc_info_out; htri_t search_ret; + size_t path_size = 0; + size_t path_len = 0; void *ret_value = NULL; #ifdef RV_CONNECTOR_DEBUG @@ -358,6 +388,32 @@ RV_datatype_open(void *obj, const H5VL_loc_params_t *loc_params, const char *nam datatype->domain = parent->domain; parent->domain->u.file.ref_count++; + datatype->handle_path = NULL; + + if (name) { + /* Parent name is included if it is not the root and the datatype is opened by relative path */ + hbool_t include_parent_name = strcmp(parent->handle_path, "/") && (name[0] != '/'); + + path_size = (include_parent_name ? strlen(parent->handle_path) + 1 + strlen(name) + 1 : 1 + strlen(name) + 1); + + if ((datatype->handle_path = RV_malloc(path_size)) == NULL) + FUNC_GOTO_ERROR(H5E_SYM, H5E_CANTALLOC, NULL, "can't allocate space for handle path"); + + if (include_parent_name) { + strncpy(datatype->handle_path, parent->handle_path, strlen(parent->handle_path)); + path_len += strlen(parent->handle_path); + } + + /* Add leading slash if not in datatype path */ + if (name[0] != '/') { + datatype->handle_path[path_len] = '/'; + path_len += 1; + } + + strncpy(datatype->handle_path + path_len, name, strlen(name) + 1); + path_len += (strlen(name) + 1); + } + loc_info_out.URI = datatype->URI; loc_info_out.domain = datatype->domain; loc_info_out.GCPL_base64 = NULL; @@ -545,6 +601,7 @@ RV_datatype_close(void *dt, hid_t dxpl_id, void **req) if (RV_file_close(_dtype->domain, H5P_DEFAULT, NULL) < 0) FUNC_DONE_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't close file"); + RV_free(_dtype->handle_path); RV_free(_dtype); _dtype = NULL; diff --git a/src/rest_vol_file.c b/src/rest_vol_file.c index 9a164d27..07bab118 100644 --- a/src/rest_vol_file.c +++ b/src/rest_vol_file.c @@ -76,6 +76,7 @@ RV_file_create(const char *name, unsigned flags, hid_t fcpl_id, hid_t fapl_id, h new_file->u.file.fapl_id = FAIL; new_file->u.file.fcpl_id = FAIL; new_file->u.file.ref_count = 1; + new_file->handle_path = "/"; /* Copy the FAPL if it wasn't H5P_DEFAULT, else set up a default one so that * H5Fget_access_plist() will function correctly. Note that due to the nature @@ -343,7 +344,8 @@ RV_file_open(const char *name, unsigned flags, hid_t fapl_id, hid_t dxpl_id, voi file->u.file.fapl_id = FAIL; file->u.file.fcpl_id = FAIL; file->u.file.ref_count = 1; - + file->handle_path = "/"; + /* Store self-referential pointer in the domain field for this object * to simplify code for other types of objects */ diff --git a/src/rest_vol_group.c b/src/rest_vol_group.c index 49bd939a..0987662a 100644 --- a/src/rest_vol_group.c +++ b/src/rest_vol_group.c @@ -47,6 +47,8 @@ RV_group_create(void *obj, const H5VL_loc_params_t *loc_params, const char *name size_t host_header_len = 0; size_t base64_buf_size = 0; size_t plist_nalloc = 0; + size_t path_size = 0; + size_t path_len = 0; char *host_header = NULL; char *create_request_body = NULL; char *path_dirname = NULL; @@ -81,6 +83,9 @@ RV_group_create(void *obj, const H5VL_loc_params_t *loc_params, const char *name if (NULL == (new_group = (RV_object_t *)RV_malloc(sizeof(*new_group)))) FUNC_GOTO_ERROR(H5E_SYM, H5E_CANTALLOC, NULL, "can't allocate space for group object"); + if (!parent->handle_path) + FUNC_GOTO_ERROR(H5E_SYM, H5E_BADVALUE, NULL, "parent object has NULL path"); + new_group->URI[0] = '\0'; new_group->obj_type = H5I_GROUP; new_group->u.group.gapl_id = FAIL; @@ -89,6 +94,33 @@ RV_group_create(void *obj, const H5VL_loc_params_t *loc_params, const char *name new_group->domain = parent->domain; parent->domain->u.file.ref_count++; + new_group->handle_path = NULL; + + if (name) { + /* Parent name is included if it is not the root and the group is opened by relative path */ + hbool_t include_parent_name = strcmp(parent->handle_path, "/") && (name[0] != '/'); + + path_size = (include_parent_name ? strlen(parent->handle_path) + 1 + strlen(name) + 1 : 1 + strlen(name) + 1); + + if ((new_group->handle_path = RV_malloc(path_size)) == NULL) + FUNC_GOTO_ERROR(H5E_SYM, H5E_CANTALLOC, NULL, "can't allocate space for handle path"); + + if (include_parent_name) { + strncpy(new_group->handle_path, parent->handle_path, strlen(parent->handle_path)); + path_len += strlen(parent->handle_path); + } + + /* Add leading slash if not in group name */ + if (name[0] != '/') { + new_group->handle_path[path_len] = '/'; + path_len += 1; + } + + strncpy(new_group->handle_path + path_len, name, strlen(name) + 1); + path_len += (strlen(name) + 1); + } + + /* Copy the GAPL if it wasn't H5P_DEFAULT, else set up a default one so that * group access property list functions will function correctly */ @@ -336,7 +368,8 @@ RV_group_open(void *obj, const H5VL_loc_params_t *loc_params, const char *name, // char *base64_binary_gcpl = NULL; void *binary_gcpl = NULL; size_t *binary_gcpl_size = 0; - + size_t path_size = 0; + size_t path_len = 0; H5I_type_t obj_type = H5I_UNINIT; #ifdef RV_CONNECTOR_DEBUG @@ -351,6 +384,9 @@ RV_group_open(void *obj, const H5VL_loc_params_t *loc_params, const char *name, if (H5I_FILE != parent->obj_type && H5I_GROUP != parent->obj_type) FUNC_GOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "parent object not a file or group"); + if (!parent->handle_path) + FUNC_GOTO_ERROR(H5E_SYM, H5E_BADVALUE, NULL, "parent object has NULL path"); + /* Allocate and setup internal Group struct */ if (NULL == (group = (RV_object_t *)RV_malloc(sizeof(*group)))) FUNC_GOTO_ERROR(H5E_SYM, H5E_CANTALLOC, NULL, "can't allocate space for group object"); @@ -364,6 +400,32 @@ RV_group_open(void *obj, const H5VL_loc_params_t *loc_params, const char *name, group->domain = parent->domain; parent->domain->u.file.ref_count++; + group->handle_path = NULL; + + if (name) { + /* Parent name is included if it is not the root and the group is opened by relative path */ + hbool_t include_parent_name = strcmp(parent->handle_path, "/") && (name[0] != '/'); + + path_size = (include_parent_name ? strlen(parent->handle_path) + 1 + strlen(name) + 1 : 1 + strlen(name) + 1); + + if ((group->handle_path = RV_malloc(path_size)) == NULL) + FUNC_GOTO_ERROR(H5E_SYM, H5E_CANTALLOC, NULL, "can't allocate space for handle path"); + + if (include_parent_name) { + strncpy(group->handle_path, parent->handle_path, strlen(parent->handle_path)); + path_len += strlen(parent->handle_path); + } + + /* Add leading slash if not in group name */ + if (name[0] != '/') { + group->handle_path[path_len] = '/'; + path_len += 1; + } + + strncpy(group->handle_path + path_len, name, strlen(name) + 1); + path_len += (strlen(name) + 1); + } + /* Locate group and set domain */ loc_info_out.URI = group->URI; @@ -692,6 +754,8 @@ RV_group_close(void *grp, hid_t dxpl_id, void **req) FUNC_DONE_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't close file"); } + RV_free(_grp->handle_path); + RV_free(_grp); _grp = NULL; diff --git a/src/rest_vol_object.c b/src/rest_vol_object.c index bb008f9d..5a7ea3e1 100644 --- a/src/rest_vol_object.c +++ b/src/rest_vol_object.c @@ -275,8 +275,35 @@ RV_object_get(void *obj, const H5VL_loc_params_t *loc_params, H5VL_object_get_ar FUNC_GOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a file, group, dataset or committed datatype"); switch (args->op_type) { + case H5VL_OBJECT_GET_NAME: { + size_t copy_size = 0; + char *name = loc_obj->handle_path; + + if (!name) + FUNC_GOTO_ERROR(H5E_OBJECT, H5E_PATH, FAIL, "object has NULL name"); + + /* Only return the name if the user provided an allocate buffer */ + if (args->args.get_name.buf) { + /* Initialize entire buffer regardless of path size */ + memset(args->args.get_name.buf, 0, args->args.get_name.buf_size); + + /* If given an attribute, H5Iget_name returns the name of the object an attribute is attached to */ + if (loc_obj->obj_type == H5I_ATTR) + if ((name = loc_obj->u.attribute.parent_name) == NULL) + FUNC_GOTO_ERROR(H5E_OBJECT, H5E_BADVALUE, FAIL, "attribute parent has NULL name"); + + copy_size = (strlen(name) < args->args.get_name.buf_size - 1) ? strlen(name) : args->args.get_name.buf_size - 1; + strncpy(args->args.get_name.buf, name, copy_size); + args->args.get_name.buf[copy_size + 1] = '\0'; + } + + if (args->args.get_name.name_len) { + *args->args.get_name.name_len = strlen(name); + } + + } + break; case H5VL_OBJECT_GET_FILE: - case H5VL_OBJECT_GET_NAME: case H5VL_OBJECT_GET_TYPE: FUNC_GOTO_ERROR(H5E_OBJECT, H5E_UNSUPPORTED, FAIL, "unsupported object operation"); break;