mirror of
https://github.com/HDFGroup/hdf5.git
synced 2024-12-15 07:40:23 +08:00
2090a527c1
* Moves get_option from the tools library to the C library * Adds H5 prefix to get_option call and variables * Renames the H5_get_option long options struct and enum
1179 lines
39 KiB
C
1179 lines
39 KiB
C
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
* Copyright by The HDF Group. *
|
|
* Copyright by the Board of Trustees of the University of Illinois. *
|
|
* All rights reserved. *
|
|
* *
|
|
* This file is part of HDF5. The full HDF5 copyright notice, including *
|
|
* terms governing use, modification, and redistribution, is contained in *
|
|
* the COPYING file, which can be found at the root of the source code *
|
|
* distribution tree, or in https://www.hdfgroup.org/licenses. *
|
|
* If you do not have access to either file, you may request a copy from *
|
|
* help@hdfgroup.org. *
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
/*
|
|
* Portions of this work are derived from _Obfuscated C and Other Mysteries_,
|
|
* by Don Libes, copyright (c) 1993 by John Wiley & Sons, Inc.
|
|
*/
|
|
|
|
#include "h5tools.h"
|
|
#include "h5tools_utils.h"
|
|
#include "H5private.h"
|
|
#include "h5trav.h"
|
|
|
|
#ifdef H5_HAVE_ROS3_VFD
|
|
#include "H5FDros3.h"
|
|
#endif
|
|
|
|
/* Global variables */
|
|
unsigned h5tools_nCols = 80;
|
|
static int h5tools_d_status = 0;
|
|
static const char *h5tools_progname = "h5tools";
|
|
|
|
/*
|
|
* The output functions need a temporary buffer to hold a piece of the
|
|
* dataset while it's being printed. This constant sets the limit on the
|
|
* size of that temporary buffer in bytes. For efficiency's sake, choose the
|
|
* largest value suitable for your machine (for testing use a small value).
|
|
*/
|
|
/* Maximum size used in a call to malloc for a dataset */
|
|
hsize_t H5TOOLS_MALLOCSIZE = (256 * 1024 * 1024); /* 256 MB */
|
|
/* size of hyperslab buffer when a dataset is bigger than H5TOOLS_MALLOCSIZE */
|
|
hsize_t H5TOOLS_BUFSIZE = (32 * 1024 * 1024); /* 32 MB */
|
|
|
|
/* ``parallel_print'' variables */
|
|
unsigned char g_Parallel = 0; /*0 for serial, 1 for parallel */
|
|
char outBuff[OUTBUFF_SIZE];
|
|
unsigned outBuffOffset;
|
|
FILE * overflow_file = NULL;
|
|
|
|
/* local functions */
|
|
static void init_table(hid_t fid, table_t **tbl);
|
|
#ifdef H5DUMP_DEBUG
|
|
static void dump_table(hid_t fid, char *tablename, table_t *table);
|
|
#endif /* H5DUMP_DEBUG */
|
|
static void add_obj(table_t *table, const H5O_token_t *obj_token, const char *objname, hbool_t recorded);
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: parallel_print
|
|
*
|
|
* Purpose: wrapper for printf for use in parallel mode.
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
void
|
|
parallel_print(const char *format, ...)
|
|
{
|
|
int bytes_written;
|
|
va_list ap;
|
|
|
|
HDva_start(ap, format);
|
|
|
|
if (!g_Parallel)
|
|
HDvprintf(format, ap);
|
|
else {
|
|
if (overflow_file == NULL) /*no overflow has occurred yet */ {
|
|
bytes_written = HDvsnprintf(outBuff + outBuffOffset, OUTBUFF_SIZE - outBuffOffset, format, ap);
|
|
HDva_end(ap);
|
|
HDva_start(ap, format);
|
|
|
|
if ((bytes_written < 0) || ((unsigned)bytes_written >= (OUTBUFF_SIZE - outBuffOffset))) {
|
|
/* Terminate the outbuff at the end of the previous output */
|
|
outBuff[outBuffOffset] = '\0';
|
|
|
|
overflow_file = HDtmpfile();
|
|
if (overflow_file == NULL)
|
|
HDfprintf(rawerrorstream,
|
|
"warning: could not create overflow file. Output may be truncated.\n");
|
|
else
|
|
bytes_written = HDvfprintf(overflow_file, format, ap);
|
|
}
|
|
else
|
|
outBuffOffset += (unsigned)bytes_written;
|
|
}
|
|
else
|
|
bytes_written = HDvfprintf(overflow_file, format, ap);
|
|
}
|
|
HDva_end(ap);
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: error_msg
|
|
*
|
|
* Purpose: Print a nicely formatted error message to stderr flushing the
|
|
* stdout stream first.
|
|
*
|
|
* Return: Nothing
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
void
|
|
error_msg(const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
HDva_start(ap, fmt);
|
|
FLUSHSTREAM(rawattrstream);
|
|
FLUSHSTREAM(rawdatastream);
|
|
FLUSHSTREAM(rawoutstream);
|
|
HDfprintf(rawerrorstream, "%s error: ", h5tools_getprogname());
|
|
HDvfprintf(rawerrorstream, fmt, ap);
|
|
|
|
HDva_end(ap);
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: warn_msg
|
|
*
|
|
* Purpose: Print a nicely formatted warning message to stderr flushing
|
|
* the stdout stream first.
|
|
*
|
|
* Return: Nothing
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
void
|
|
warn_msg(const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
HDva_start(ap, fmt);
|
|
FLUSHSTREAM(rawattrstream);
|
|
FLUSHSTREAM(rawdatastream);
|
|
FLUSHSTREAM(rawoutstream);
|
|
HDfprintf(rawerrorstream, "%s warning: ", h5tools_getprogname());
|
|
HDvfprintf(rawerrorstream, fmt, ap);
|
|
HDva_end(ap);
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: help_ref_msg
|
|
*
|
|
* Purpose: Print a message to refer help page
|
|
*
|
|
* Return: Nothing
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
void
|
|
help_ref_msg(FILE *output)
|
|
{
|
|
HDfprintf(output, "Try '-h' or '--help' for more information or ");
|
|
HDfprintf(output, "see the <%s> entry in the 'HDF5 Reference Manual'.\n", h5tools_getprogname());
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Function: parse_tuple()
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Create array of pointers to strings, identified as elements in a tuple
|
|
* of arbitrary length separated by provided character.
|
|
* ("tuple" because "nple" looks strange)
|
|
*
|
|
* * Receives pointer to start of tuple sequence string, '('.
|
|
* * Attempts to separate elements by token-character `sep`.
|
|
* * If the separator character is preceded by a backslash '\',
|
|
* the backslash is deleted and the separator is included in the
|
|
* element string as any other character.
|
|
* * To end an element with a backslash, escape the backslash, e.g.
|
|
* "(myelem\\,otherelem) -> {"myelem\", "otherelem"}
|
|
* * In all other cases, a backslash appearing not as part of "\\" or
|
|
* "\<sep>" digraph will be included berbatim.
|
|
* * Last two characters in the string MUST be ")\0".
|
|
*
|
|
* * Generates a copy of the input string `start`, (src..")\0"), replacing
|
|
* separators and close-paren with null charaters.
|
|
* * This string is allocated at runtime and should be freed when done.
|
|
* * Generates array of char pointers, and directs start of each element
|
|
* (each pointer) into this copy.
|
|
* * Each tuple element points to the start of its string (substring)
|
|
* and ends with a null terminator.
|
|
* * This array is allocated at runtime and should be freed when done.
|
|
* * Reallocates and expands elements array during parsing.
|
|
* * Initially allocated for 2 (plus one null entry), and grows by
|
|
* powers of 2.
|
|
* * The final 'slot' in the element array (elements[nelements], e.g.)
|
|
* always points to NULL.
|
|
* * The number of elements found and stored are passed out through pointer
|
|
* to unsigned, `nelems`.
|
|
*
|
|
* Return:
|
|
*
|
|
* FAIL If malformed--does not look like a tuple "(...)"
|
|
* or major error was encountered while parsing.
|
|
* or
|
|
* SUCCEED String looks properly formed "(...)" and no major errors.
|
|
*
|
|
* Stores number of elements through pointer `nelems`.
|
|
* Stores list of pointers to char (first char in each element
|
|
* string) through pointer `ptrs_out`.
|
|
* NOTE: `ptrs_out[nelems] == NULL` should be true.
|
|
* NOTE: list is malloc'd by function, and should be freed
|
|
* when done.
|
|
* Stores "source string" for element pointers through `cpy_out`.
|
|
* NOTE: Each element substring is null-terminated.
|
|
* NOTE: There may be extra characters after the last element
|
|
* (past its null terminator), but is guaranteed to
|
|
* be null-terminated.
|
|
* NOTE: `cpy_out` string is malloc'd by function,
|
|
* and should be freed when done.
|
|
*
|
|
* Programmer: Jacob Smith
|
|
* 2017-11-10
|
|
*
|
|
*****************************************************************************
|
|
*/
|
|
herr_t
|
|
parse_tuple(const char *start, int sep, char **cpy_out, unsigned *nelems, char ***ptrs_out)
|
|
{
|
|
char * elem_ptr = NULL;
|
|
char * dest_ptr = NULL;
|
|
unsigned elems_count = 0;
|
|
char ** elems = NULL; /* more like *elems[], but complier... */
|
|
char ** elems_re = NULL; /* temporary pointer, for realloc */
|
|
char * cpy = NULL;
|
|
herr_t ret_value = SUCCEED;
|
|
unsigned init_slots = 2;
|
|
|
|
/*****************
|
|
* SANITY-CHECKS *
|
|
*****************/
|
|
|
|
/* must start with "("
|
|
*/
|
|
if (start[0] != '(') {
|
|
ret_value = FAIL;
|
|
goto done;
|
|
}
|
|
|
|
/* must end with ")"
|
|
*/
|
|
while (start[elems_count] != '\0') {
|
|
elems_count++;
|
|
}
|
|
if (start[elems_count - 1] != ')') {
|
|
ret_value = FAIL;
|
|
goto done;
|
|
}
|
|
|
|
elems_count = 0;
|
|
|
|
/***********
|
|
* PREPARE *
|
|
***********/
|
|
|
|
/* create list
|
|
*/
|
|
elems = (char **)HDmalloc(sizeof(char *) * (init_slots + 1));
|
|
if (elems == NULL) {
|
|
ret_value = FAIL;
|
|
goto done;
|
|
} /* CANTALLOC */
|
|
|
|
/* create destination string
|
|
*/
|
|
start++; /* advance past opening paren '(' */
|
|
cpy = (char *)HDmalloc(sizeof(char) * (HDstrlen(start))); /* no +1; less '(' */
|
|
if (cpy == NULL) {
|
|
ret_value = FAIL;
|
|
goto done;
|
|
} /* CANTALLOC */
|
|
|
|
/* set pointers
|
|
*/
|
|
dest_ptr = cpy; /* start writing copy here */
|
|
elem_ptr = cpy; /* first element starts here */
|
|
elems[elems_count++] = elem_ptr; /* set first element pointer into list */
|
|
|
|
/*********
|
|
* PARSE *
|
|
*********/
|
|
|
|
while (*start != '\0') {
|
|
/* For each character in the source string...
|
|
*/
|
|
if (*start == '\\') {
|
|
/* Possibly an escape digraph.
|
|
*/
|
|
if ((*(start + 1) == '\\') || (*(start + 1) == sep)) {
|
|
/* Valid escape digraph of "\\" or "\<sep>".
|
|
*/
|
|
start++; /* advance past escape char '\' */
|
|
*(dest_ptr++) = *(start++); /* Copy subsequent char */
|
|
/* and advance pointers. */
|
|
}
|
|
else {
|
|
/* Not an accepted escape digraph.
|
|
* Copy backslash character.
|
|
*/
|
|
*(dest_ptr++) = *(start++);
|
|
}
|
|
}
|
|
else if (*start == sep) {
|
|
/* Non-escaped separator.
|
|
* Terminate elements substring in copy, record element, advance.
|
|
* Expand elements list if appropriate.
|
|
*/
|
|
*(dest_ptr++) = 0; /* Null-terminate elem substring in copy */
|
|
/* and advance pointer. */
|
|
start++; /* Advance src pointer past separator. */
|
|
elem_ptr = dest_ptr; /* Element pointer points to start of first */
|
|
/* character after null sep in copy. */
|
|
elems[elems_count++] = elem_ptr; /* Set elem pointer in list */
|
|
/* and increment count. */
|
|
|
|
/* Expand elements list, if necessary.
|
|
*/
|
|
if (elems_count == init_slots) {
|
|
init_slots *= 2;
|
|
elems_re = (char **)realloc(elems, sizeof(char *) * (init_slots + 1));
|
|
if (elems_re == NULL) {
|
|
/* CANTREALLOC */
|
|
ret_value = FAIL;
|
|
goto done;
|
|
}
|
|
elems = elems_re;
|
|
}
|
|
}
|
|
else if (*start == ')' && *(start + 1) == '\0') {
|
|
/* Found terminal, non-escaped close-paren. Last element.
|
|
* Write null terminator to copy.
|
|
* Advance source pointer to gently break from loop.
|
|
* Requred to prevent ")" from always being added to last element.
|
|
*/
|
|
start++;
|
|
}
|
|
else {
|
|
/* Copy character into destination. Advance pointers.
|
|
*/
|
|
*(dest_ptr++) = *(start++);
|
|
}
|
|
}
|
|
*dest_ptr = '\0'; /* Null-terminate destination string. */
|
|
elems[elems_count] = NULL; /* Null-terminate elements list. */
|
|
|
|
/********************
|
|
* PASS BACK VALUES *
|
|
********************/
|
|
|
|
*ptrs_out = elems;
|
|
*nelems = elems_count;
|
|
*cpy_out = cpy;
|
|
|
|
done:
|
|
if (ret_value == FAIL) {
|
|
/* CLEANUP */
|
|
if (cpy)
|
|
free(cpy);
|
|
if (elems)
|
|
free(elems);
|
|
}
|
|
|
|
return ret_value;
|
|
|
|
} /* parse_tuple */
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: indentation
|
|
*
|
|
* Purpose: Print spaces for indentation
|
|
*
|
|
* Return: void
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
void
|
|
indentation(unsigned x)
|
|
{
|
|
if (x < h5tools_nCols) {
|
|
while (x-- > 0)
|
|
PRINTVALSTREAM(rawoutstream, " ");
|
|
}
|
|
else {
|
|
HDfprintf(rawerrorstream, "error: the indentation exceeds the number of cols.\n");
|
|
HDexit(1);
|
|
}
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: print_version
|
|
*
|
|
* Purpose: Print the program name and the version information which is
|
|
* defined the same as the HDF5 library version.
|
|
*
|
|
* Return: void
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
void
|
|
print_version(const char *progname)
|
|
{
|
|
PRINTSTREAM(rawoutstream, "%s: Version %u.%u.%u%s%s\n", progname, H5_VERS_MAJOR, H5_VERS_MINOR,
|
|
H5_VERS_RELEASE, ((const char *)H5_VERS_SUBRELEASE)[0] ? "-" : "", H5_VERS_SUBRELEASE);
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: init_table
|
|
*
|
|
* Purpose: allocate and initialize tables for shared groups, datasets,
|
|
* and committed types
|
|
*
|
|
* Return: void
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
static void
|
|
init_table(hid_t fid, table_t **tbl)
|
|
{
|
|
table_t *table = (table_t *)HDmalloc(sizeof(table_t));
|
|
|
|
table->fid = fid;
|
|
table->size = 20;
|
|
table->nobjs = 0;
|
|
table->objs = (obj_t *)HDmalloc(table->size * sizeof(obj_t));
|
|
|
|
*tbl = table;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: free_table
|
|
*
|
|
* Purpose: free tables for shared groups, datasets,
|
|
* and committed types
|
|
*
|
|
* Return: void
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
void
|
|
free_table(table_t *table)
|
|
{
|
|
unsigned u; /* Local index value */
|
|
|
|
/* Free the names for the objects in the table */
|
|
for (u = 0; u < table->nobjs; u++)
|
|
if (table->objs[u].objname)
|
|
HDfree(table->objs[u].objname);
|
|
|
|
HDfree(table->objs);
|
|
}
|
|
|
|
#ifdef H5DUMP_DEBUG
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: dump_table
|
|
*
|
|
* Purpose: display the contents of tables for debugging purposes
|
|
*
|
|
* Return: void
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
static void
|
|
dump_table(hid_t fid, char *tablename, table_t *table)
|
|
{
|
|
unsigned u;
|
|
char * obj_tok_str = NULL;
|
|
|
|
PRINTSTREAM(rawoutstream, "%s: # of entries = %d\n", tablename, table->nobjs);
|
|
for (u = 0; u < table->nobjs; u++) {
|
|
H5VLconnector_token_to_str(fid, table->objs[u].obj_token, &obj_tok_str);
|
|
|
|
PRINTSTREAM(rawoutstream, "%s %s %d %d\n", obj_tok_str, table->objs[u].objname,
|
|
table->objs[u].displayed, table->objs[u].recorded);
|
|
|
|
H5VLfree_token_str(fid, obj_tok_str);
|
|
}
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: dump_tables
|
|
*
|
|
* Purpose: display the contents of tables for debugging purposes
|
|
*
|
|
* Return: void
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
void
|
|
dump_tables(find_objs_t *info)
|
|
{
|
|
dump_table(info->fid, "group_table", info->group_table);
|
|
dump_table(info->fid, "dset_table", info->dset_table);
|
|
dump_table(info->fid, "type_table", info->type_table);
|
|
}
|
|
#endif /* H5DUMP_DEBUG */
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: search_obj
|
|
*
|
|
* Purpose: search the object specified by objno in the table
|
|
*
|
|
* Return: Success: an integer, the location of the object
|
|
*
|
|
* Failure: FAIL if object is not found
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
H5_ATTR_PURE obj_t *
|
|
search_obj(table_t *table, const H5O_token_t *obj_token)
|
|
{
|
|
unsigned u;
|
|
int token_cmp;
|
|
|
|
for (u = 0; u < table->nobjs; u++) {
|
|
if (H5Otoken_cmp(table->fid, &table->objs[u].obj_token, obj_token, &token_cmp) < 0)
|
|
return NULL;
|
|
if (!token_cmp)
|
|
return &(table->objs[u]);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: find_objs_cb
|
|
*
|
|
* Purpose: Callback to find objects, committed types and store them in tables
|
|
*
|
|
* Return: Success: SUCCEED
|
|
*
|
|
* Failure: FAIL
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
static herr_t
|
|
find_objs_cb(const char *name, const H5O_info2_t *oinfo, const char *already_seen, void *op_data)
|
|
{
|
|
find_objs_t *info = (find_objs_t *)op_data;
|
|
herr_t ret_value = 0;
|
|
|
|
switch (oinfo->type) {
|
|
case H5O_TYPE_GROUP:
|
|
if (NULL == already_seen)
|
|
add_obj(info->group_table, &oinfo->token, name, TRUE);
|
|
break;
|
|
|
|
case H5O_TYPE_DATASET:
|
|
if (NULL == already_seen) {
|
|
hid_t dset = H5I_INVALID_HID;
|
|
|
|
/* Add the dataset to the list of objects */
|
|
add_obj(info->dset_table, &oinfo->token, name, TRUE);
|
|
|
|
/* Check for a dataset that uses a named datatype */
|
|
if ((dset = H5Dopen2(info->fid, name, H5P_DEFAULT)) >= 0) {
|
|
hid_t type = H5Dget_type(dset);
|
|
|
|
if (H5Tcommitted(type) > 0) {
|
|
H5O_info2_t type_oinfo;
|
|
|
|
H5Oget_info3(type, &type_oinfo, H5O_INFO_BASIC);
|
|
if (search_obj(info->type_table, &type_oinfo.token) == NULL)
|
|
add_obj(info->type_table, &type_oinfo.token, name, FALSE);
|
|
} /* end if */
|
|
|
|
H5Tclose(type);
|
|
H5Dclose(dset);
|
|
} /* end if */
|
|
else
|
|
ret_value = FAIL;
|
|
} /* end if */
|
|
break;
|
|
|
|
case H5O_TYPE_NAMED_DATATYPE:
|
|
if (NULL == already_seen) {
|
|
obj_t *found_obj;
|
|
|
|
if ((found_obj = search_obj(info->type_table, &oinfo->token)) == NULL)
|
|
add_obj(info->type_table, &oinfo->token, name, TRUE);
|
|
else {
|
|
/* Use latest version of name */
|
|
HDfree(found_obj->objname);
|
|
found_obj->objname = HDstrdup(name);
|
|
|
|
/* Mark named datatype as having valid name */
|
|
found_obj->recorded = TRUE;
|
|
} /* end else */
|
|
} /* end if */
|
|
break;
|
|
|
|
case H5O_TYPE_MAP:
|
|
case H5O_TYPE_UNKNOWN:
|
|
case H5O_TYPE_NTYPES:
|
|
default:
|
|
break;
|
|
} /* end switch */
|
|
|
|
return ret_value;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: init_objs
|
|
*
|
|
* Purpose: Initialize tables for groups, datasets & named datatypes
|
|
*
|
|
* Return: Success: SUCCEED
|
|
*
|
|
* Failure: FAIL
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
herr_t
|
|
init_objs(hid_t fid, find_objs_t *info, table_t **group_table, table_t **dset_table, table_t **type_table)
|
|
{
|
|
herr_t ret_value = SUCCEED;
|
|
|
|
/* Initialize the tables */
|
|
init_table(fid, group_table);
|
|
init_table(fid, dset_table);
|
|
init_table(fid, type_table);
|
|
|
|
/* Init the find_objs_t */
|
|
info->fid = fid;
|
|
info->group_table = *group_table;
|
|
info->type_table = *type_table;
|
|
info->dset_table = *dset_table;
|
|
|
|
/* Find all shared objects */
|
|
if ((ret_value = h5trav_visit(fid, "/", TRUE, TRUE, find_objs_cb, NULL, info, H5O_INFO_BASIC)) < 0)
|
|
H5TOOLS_GOTO_ERROR(FAIL, "finding shared objects failed");
|
|
|
|
done:
|
|
/* Release resources */
|
|
if (ret_value < 0) {
|
|
free_table(*group_table);
|
|
info->group_table = NULL;
|
|
free_table(*type_table);
|
|
info->type_table = NULL;
|
|
free_table(*dset_table);
|
|
info->dset_table = NULL;
|
|
}
|
|
return ret_value;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: add_obj
|
|
*
|
|
* Purpose: add a shared object to the table
|
|
* realloc the table if necessary
|
|
*
|
|
* Return: void
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
static void
|
|
add_obj(table_t *table, const H5O_token_t *obj_token, const char *objname, hbool_t record)
|
|
{
|
|
size_t u;
|
|
|
|
/* See if we need to make table larger */
|
|
if (table->nobjs == table->size) {
|
|
table->size *= 2;
|
|
table->objs = (struct obj_t *)HDrealloc(table->objs, table->size * sizeof(table->objs[0]));
|
|
} /* end if */
|
|
|
|
/* Increment number of objects in table */
|
|
u = table->nobjs++;
|
|
|
|
/* Set information about object */
|
|
HDmemcpy(&table->objs[u].obj_token, obj_token, sizeof(H5O_token_t));
|
|
table->objs[u].objname = HDstrdup(objname);
|
|
table->objs[u].recorded = record;
|
|
table->objs[u].displayed = 0;
|
|
}
|
|
|
|
#ifndef H5_HAVE_TMPFILE
|
|
/*-------------------------------------------------------------------------
|
|
* Function: tmpfile
|
|
*
|
|
* Purpose: provide tmpfile() function when it is not supported by the
|
|
* system. Always return NULL for now.
|
|
*
|
|
* Return: a stream description when succeeds.
|
|
* NULL if fails.
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
FILE *
|
|
tmpfile(void)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
#endif
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: H5tools_get_symlink_info
|
|
*
|
|
* Purpose: Get symbolic link (soft, external) info and its target object type
|
|
(dataset, group, named datatype) and path, if exist
|
|
*
|
|
* Patameters:
|
|
* - [IN] fileid : link file id
|
|
* - [IN] linkpath : link path
|
|
* - [OUT] link_info: returning target object info (h5tool_link_info_t)
|
|
*
|
|
* Return:
|
|
* 2 : given pathname is object
|
|
* 1 : Succeed to get link info.
|
|
* 0 : Detected as a dangling link
|
|
* -1 : H5 API failed.
|
|
*
|
|
* NOTE:
|
|
* link_info->trg_path must be freed out of this function
|
|
*-------------------------------------------------------------------------*/
|
|
int
|
|
H5tools_get_symlink_info(hid_t file_id, const char *linkpath, h5tool_link_info_t *link_info,
|
|
hbool_t get_obj_type)
|
|
{
|
|
htri_t l_ret;
|
|
H5O_info2_t trg_oinfo;
|
|
hid_t fapl = H5P_DEFAULT;
|
|
hid_t lapl = H5P_DEFAULT;
|
|
int ret_value = -1; /* init to fail */
|
|
|
|
/* init */
|
|
link_info->trg_type = H5O_TYPE_UNKNOWN;
|
|
|
|
/* if path is root, return group type */
|
|
if (!HDstrcmp(linkpath, "/")) {
|
|
link_info->trg_type = H5O_TYPE_GROUP;
|
|
H5TOOLS_GOTO_DONE(2);
|
|
}
|
|
|
|
/* check if link itself exist */
|
|
if (H5Lexists(file_id, linkpath, H5P_DEFAULT) <= 0) {
|
|
if (link_info->opt.msg_mode == 1)
|
|
parallel_print("Warning: link <%s> doesn't exist \n", linkpath);
|
|
H5TOOLS_GOTO_DONE(FAIL);
|
|
} /* end if */
|
|
|
|
/* get info from link */
|
|
if (H5Lget_info2(file_id, linkpath, &(link_info->linfo), H5P_DEFAULT) < 0) {
|
|
if (link_info->opt.msg_mode == 1)
|
|
parallel_print("Warning: unable to get link info from <%s>\n", linkpath);
|
|
H5TOOLS_GOTO_DONE(FAIL);
|
|
} /* end if */
|
|
|
|
/* given path is hard link (object) */
|
|
if (link_info->linfo.type == H5L_TYPE_HARD)
|
|
H5TOOLS_GOTO_DONE(2);
|
|
|
|
/* trg_path must be freed out of this function when finished using */
|
|
if ((link_info->trg_path = (char *)HDcalloc(link_info->linfo.u.val_size, sizeof(char))) == NULL) {
|
|
if (link_info->opt.msg_mode == 1)
|
|
parallel_print("Warning: unable to allocate buffer for <%s>\n", linkpath);
|
|
H5TOOLS_GOTO_DONE(FAIL);
|
|
} /* end if */
|
|
|
|
/* get link value */
|
|
if (H5Lget_val(file_id, linkpath, (void *)link_info->trg_path, link_info->linfo.u.val_size, H5P_DEFAULT) <
|
|
0) {
|
|
if (link_info->opt.msg_mode == 1)
|
|
parallel_print("Warning: unable to get link value from <%s>\n", linkpath);
|
|
H5TOOLS_GOTO_DONE(FAIL);
|
|
} /* end if */
|
|
|
|
/*-----------------------------------------------------
|
|
* if link type is external link use different lapl to
|
|
* follow object in other file
|
|
*/
|
|
if (link_info->linfo.type == H5L_TYPE_EXTERNAL) {
|
|
if ((fapl = H5Pcreate(H5P_FILE_ACCESS)) < 0)
|
|
H5TOOLS_GOTO_DONE(FAIL);
|
|
if (H5Pset_fapl_sec2(fapl) < 0)
|
|
H5TOOLS_GOTO_DONE(FAIL);
|
|
if ((lapl = H5Pcreate(H5P_LINK_ACCESS)) < 0)
|
|
H5TOOLS_GOTO_DONE(FAIL);
|
|
if (H5Pset_elink_fapl(lapl, fapl) < 0)
|
|
H5TOOLS_GOTO_DONE(FAIL);
|
|
} /* end if */
|
|
|
|
/* Check for retrieving object info */
|
|
if (get_obj_type) {
|
|
/*--------------------------------------------------------------
|
|
* if link's target object exist, get type
|
|
*/
|
|
/* check if target object exist */
|
|
l_ret = H5Oexists_by_name(file_id, linkpath, lapl);
|
|
|
|
/* detect dangling link */
|
|
if (l_ret == FALSE) {
|
|
H5TOOLS_GOTO_DONE(0);
|
|
}
|
|
else if (l_ret < 0) { /* function failed */
|
|
H5TOOLS_GOTO_DONE(FAIL);
|
|
}
|
|
|
|
/* get target object info */
|
|
if (H5Oget_info_by_name3(file_id, linkpath, &trg_oinfo, H5O_INFO_BASIC, lapl) < 0) {
|
|
if (link_info->opt.msg_mode == 1)
|
|
parallel_print("Warning: unable to get object information for <%s>\n", linkpath);
|
|
H5TOOLS_GOTO_DONE(FAIL);
|
|
} /* end if */
|
|
|
|
/* check unknown type */
|
|
if (trg_oinfo.type < H5O_TYPE_GROUP || trg_oinfo.type >= H5O_TYPE_NTYPES) {
|
|
if (link_info->opt.msg_mode == 1)
|
|
parallel_print("Warning: target object of <%s> is unknown type\n", linkpath);
|
|
H5TOOLS_GOTO_DONE(FAIL);
|
|
} /* end if */
|
|
|
|
/* set target obj type to return */
|
|
HDmemcpy(&link_info->obj_token, &trg_oinfo.token, sizeof(H5O_token_t));
|
|
link_info->trg_type = trg_oinfo.type;
|
|
link_info->fileno = trg_oinfo.fileno;
|
|
} /* end if */
|
|
else
|
|
link_info->trg_type = H5O_TYPE_UNKNOWN;
|
|
|
|
/* succeed */
|
|
ret_value = 1;
|
|
|
|
done:
|
|
if (fapl != H5P_DEFAULT)
|
|
H5Pclose(fapl);
|
|
if (lapl != H5P_DEFAULT)
|
|
H5Pclose(lapl);
|
|
|
|
return ret_value;
|
|
} /* end H5tools_get_symlink_info() */
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Audience: Public
|
|
*
|
|
* Purpose: Initialize the name and operation status of the H5 Tools library
|
|
*
|
|
* Description:
|
|
* These are utility functions to set/get the program name and operation status.
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
void
|
|
h5tools_setprogname(const char *Progname)
|
|
{
|
|
h5tools_progname = Progname;
|
|
}
|
|
|
|
void
|
|
h5tools_setstatus(int D_status)
|
|
{
|
|
h5tools_d_status = D_status;
|
|
}
|
|
|
|
H5_ATTR_PURE const char *
|
|
h5tools_getprogname(void)
|
|
{
|
|
return h5tools_progname;
|
|
}
|
|
|
|
H5_ATTR_PURE int
|
|
h5tools_getstatus(void)
|
|
{
|
|
return h5tools_d_status;
|
|
}
|
|
|
|
/*-----------------------------------------------------------
|
|
* PURPOSE :
|
|
* if environment variable H5TOOLS_BUFSIZE is set,
|
|
* update H5TOOLS_BUFSIZE and H5TOOLS_MALLOCSIZE from the env
|
|
* This can be called from each tools main() as part of initial act.
|
|
* Note: this is more of debugging purpose for now.
|
|
*/
|
|
int
|
|
h5tools_getenv_update_hyperslab_bufsize(void)
|
|
{
|
|
const char *env_str = NULL;
|
|
long hyperslab_bufsize_mb;
|
|
int ret_value = 1;
|
|
|
|
/* check if environment variable is set for the hyperslab buffer size */
|
|
if (NULL != (env_str = HDgetenv("H5TOOLS_BUFSIZE"))) {
|
|
errno = 0;
|
|
hyperslab_bufsize_mb = HDstrtol(env_str, (char **)NULL, 10);
|
|
if (errno != 0 || hyperslab_bufsize_mb <= 0)
|
|
H5TOOLS_GOTO_ERROR(FAIL, "hyperslab buffer size failed");
|
|
|
|
/* convert MB to byte */
|
|
H5TOOLS_BUFSIZE = (hsize_t)hyperslab_bufsize_mb * 1024 * 1024;
|
|
|
|
H5TOOLS_MALLOCSIZE = MAX(H5TOOLS_BUFSIZE, H5TOOLS_MALLOCSIZE);
|
|
}
|
|
|
|
done:
|
|
return ret_value;
|
|
}
|
|
|
|
#ifdef H5_HAVE_ROS3_VFD
|
|
/*----------------------------------------------------------------------------
|
|
*
|
|
* Function: h5tools_parse_ros3_fapl_tuple
|
|
*
|
|
* Purpose: A convenience function that parses a string containing a tuple
|
|
* of S3 VFD credential information and then passes the result to
|
|
* `h5tools_populate_ros3_fapl()` in order to setup a valid
|
|
* configuration for the S3 VFD.
|
|
*
|
|
* Return: SUCCEED/FAIL
|
|
*
|
|
*----------------------------------------------------------------------------
|
|
*/
|
|
herr_t
|
|
h5tools_parse_ros3_fapl_tuple(const char *tuple_str, int delim, H5FD_ros3_fapl_t *fapl_config_out)
|
|
{
|
|
const char *ccred[3];
|
|
unsigned nelems = 0;
|
|
char * s3cred_src = NULL;
|
|
char ** s3cred = NULL;
|
|
herr_t ret_value = SUCCEED;
|
|
|
|
/* Attempt to parse S3 credentials tuple */
|
|
if (parse_tuple(tuple_str, delim, &s3cred_src, &nelems, &s3cred) < 0)
|
|
H5TOOLS_GOTO_ERROR(FAIL, "failed to parse S3 VFD info tuple");
|
|
|
|
/* Sanity-check tuple count */
|
|
if (nelems != 3)
|
|
H5TOOLS_GOTO_ERROR(FAIL, "invalid S3 VFD credentials");
|
|
|
|
ccred[0] = (const char *)s3cred[0];
|
|
ccred[1] = (const char *)s3cred[1];
|
|
ccred[2] = (const char *)s3cred[2];
|
|
|
|
if (0 == h5tools_populate_ros3_fapl(fapl_config_out, ccred))
|
|
H5TOOLS_GOTO_ERROR(FAIL, "failed to populate S3 VFD FAPL config");
|
|
|
|
done:
|
|
if (s3cred)
|
|
HDfree(s3cred);
|
|
if (s3cred_src)
|
|
HDfree(s3cred_src);
|
|
|
|
return ret_value;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
*
|
|
* Function: h5tools_populate_ros3_fapl()
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Set the values of a ROS3 fapl configuration object.
|
|
*
|
|
* If the values pointer is NULL, sets fapl target `fa` to a default
|
|
* (valid, current-version, non-authenticating) fapl config.
|
|
*
|
|
* If `values` pointer is _not_ NULL, expects `values` to contain at least
|
|
* three non-null pointers to null-terminated strings, corresponding to:
|
|
* { aws_region,
|
|
* secret_id,
|
|
* secret_key,
|
|
* }
|
|
* If all three strings are empty (""), the default fapl will be default.
|
|
* Both aws_region and secret_id values must be both empty or both
|
|
* populated. If
|
|
* Only secret_key is allowed to be empty (the empty string, "").
|
|
* All values are checked against overflow as defined in the ros3 vfd
|
|
* header file; if a value overruns the permitted space, FAIL is returned
|
|
* and the function aborts without resetting the fapl to values initially
|
|
* present.
|
|
*
|
|
* Return:
|
|
*
|
|
* 0 (failure) if...
|
|
* * Read-Only S3 VFD is not enabled.
|
|
* * NULL fapl pointer: (NULL, {...} )
|
|
* * Warning: In all cases below, fapl will be set as "default"
|
|
* before error occurs.
|
|
* * NULL value strings: (&fa, {NULL?, NULL? NULL?, ...})
|
|
* * Incomplete fapl info:
|
|
* * empty region, non-empty id, key either way
|
|
* * (&fa, {"", "...", "?"})
|
|
* * empty id, non-empty region, key either way
|
|
* * (&fa, {"...", "", "?"})
|
|
* * "non-empty key and either id or region empty
|
|
* * (&fa, {"", "", "...")
|
|
* * (&fa, {"", "...", "...")
|
|
* * (&fa, {"...", "", "...")
|
|
* * Any string would overflow allowed space in fapl definition.
|
|
* or
|
|
* 1 (success)
|
|
* * Sets components in fapl_t pointer, copying strings as appropriate.
|
|
* * "Default" fapl (valid version, authenticate->False, empty strings)
|
|
* * `values` pointer is NULL
|
|
* * (&fa, NULL)
|
|
* * first three strings in `values` are empty ("")
|
|
* * (&fa, {"", "", "", ...}
|
|
* * Authenticating fapl
|
|
* * region, id, and optional key provided
|
|
* * (&fa, {"...", "...", ""})
|
|
* * (&fa, {"...", "...", "..."})
|
|
*
|
|
* Programmer: Jacob Smith
|
|
* 2017-11-13
|
|
*
|
|
*----------------------------------------------------------------------------
|
|
*/
|
|
int
|
|
h5tools_populate_ros3_fapl(H5FD_ros3_fapl_t *fa, const char **values)
|
|
{
|
|
int show_progress = 0; /* set to 1 for debugging */
|
|
int ret_value = 1; /* 1 for success, 0 for failure */
|
|
/* e.g.? if (!populate()) { then failed } */
|
|
|
|
if (show_progress) {
|
|
HDprintf("called h5tools_populate_ros3_fapl\n");
|
|
}
|
|
|
|
if (fa == NULL) {
|
|
if (show_progress) {
|
|
HDprintf(" ERROR: null pointer to fapl_t\n");
|
|
}
|
|
ret_value = 0;
|
|
goto done;
|
|
}
|
|
|
|
if (show_progress) {
|
|
HDprintf(" preset fapl with default values\n");
|
|
}
|
|
fa->version = H5FD_CURR_ROS3_FAPL_T_VERSION;
|
|
fa->authenticate = FALSE;
|
|
*(fa->aws_region) = '\0';
|
|
*(fa->secret_id) = '\0';
|
|
*(fa->secret_key) = '\0';
|
|
|
|
/* sanity-check supplied values
|
|
*/
|
|
if (values != NULL) {
|
|
if (values[0] == NULL) {
|
|
if (show_progress) {
|
|
HDprintf(" ERROR: aws_region value cannot be NULL\n");
|
|
}
|
|
ret_value = 0;
|
|
goto done;
|
|
}
|
|
if (values[1] == NULL) {
|
|
if (show_progress) {
|
|
HDprintf(" ERROR: secret_id value cannot be NULL\n");
|
|
}
|
|
ret_value = 0;
|
|
goto done;
|
|
}
|
|
if (values[2] == NULL) {
|
|
if (show_progress) {
|
|
HDprintf(" ERROR: secret_key value cannot be NULL\n");
|
|
}
|
|
ret_value = 0;
|
|
goto done;
|
|
}
|
|
|
|
/* if region and ID are supplied (key optional), write to fapl...
|
|
* fail if value would overflow
|
|
*/
|
|
if (*values[0] != '\0' && *values[1] != '\0') {
|
|
if (HDstrlen(values[0]) > H5FD_ROS3_MAX_REGION_LEN) {
|
|
if (show_progress) {
|
|
HDprintf(" ERROR: aws_region value too long\n");
|
|
}
|
|
ret_value = 0;
|
|
goto done;
|
|
}
|
|
HDmemcpy(fa->aws_region, values[0], (HDstrlen(values[0]) + 1));
|
|
if (show_progress) {
|
|
HDprintf(" aws_region set\n");
|
|
}
|
|
|
|
if (HDstrlen(values[1]) > H5FD_ROS3_MAX_SECRET_ID_LEN) {
|
|
if (show_progress) {
|
|
HDprintf(" ERROR: secret_id value too long\n");
|
|
}
|
|
ret_value = 0;
|
|
goto done;
|
|
}
|
|
HDmemcpy(fa->secret_id, values[1], (HDstrlen(values[1]) + 1));
|
|
if (show_progress) {
|
|
HDprintf(" secret_id set\n");
|
|
}
|
|
|
|
if (HDstrlen(values[2]) > H5FD_ROS3_MAX_SECRET_KEY_LEN) {
|
|
if (show_progress) {
|
|
HDprintf(" ERROR: secret_key value too long\n");
|
|
}
|
|
ret_value = 0;
|
|
goto done;
|
|
}
|
|
HDmemcpy(fa->secret_key, values[2], (HDstrlen(values[2]) + 1));
|
|
if (show_progress) {
|
|
HDprintf(" secret_key set\n");
|
|
}
|
|
|
|
fa->authenticate = TRUE;
|
|
if (show_progress) {
|
|
HDprintf(" set to authenticate\n");
|
|
}
|
|
}
|
|
else if (*values[0] != '\0' || *values[1] != '\0' || *values[2] != '\0') {
|
|
if (show_progress) {
|
|
HDprintf(" ERROR: invalid assortment of empty/non-empty values\n");
|
|
}
|
|
ret_value = 0;
|
|
goto done;
|
|
}
|
|
} /* values != NULL */
|
|
|
|
done:
|
|
return ret_value;
|
|
} /* h5tools_populate_ros3_fapl */
|
|
#endif /* H5_HAVE_ROS3_VFD */
|
|
|
|
#ifdef H5_HAVE_LIBHDFS
|
|
/*----------------------------------------------------------------------------
|
|
*
|
|
* Function: h5tools_parse_hdfs_fapl_tuple
|
|
*
|
|
* Purpose: A convenience function that parses a string containing a tuple
|
|
* of HDFS VFD configuration information.
|
|
*
|
|
* Return: SUCCEED/FAIL
|
|
*
|
|
*----------------------------------------------------------------------------
|
|
*/
|
|
herr_t
|
|
h5tools_parse_hdfs_fapl_tuple(const char *tuple_str, int delim, H5FD_hdfs_fapl_t *fapl_config_out)
|
|
{
|
|
unsigned long k = 0;
|
|
unsigned nelems = 0;
|
|
char * props_src = NULL;
|
|
char ** props = NULL;
|
|
herr_t ret_value = SUCCEED;
|
|
|
|
/* Attempt to parse HDFS configuration tuple */
|
|
if (parse_tuple(tuple_str, delim, &props_src, &nelems, &props) < 0)
|
|
H5TOOLS_GOTO_ERROR(FAIL, "failed to parse HDFS VFD configuration tuple");
|
|
|
|
/* Sanity-check tuple count */
|
|
if (nelems != 5)
|
|
H5TOOLS_GOTO_ERROR(FAIL, "invalid HDFS VFD configuration");
|
|
|
|
/* Populate fapl configuration structure with given properties.
|
|
* WARNING: No error-checking is done on length of input strings...
|
|
* Silent overflow is possible, albeit unlikely.
|
|
*/
|
|
if (HDstrncmp(props[0], "", 1)) {
|
|
HDstrncpy(fapl_config_out->namenode_name, (const char *)props[0], HDstrlen(props[0]));
|
|
}
|
|
if (HDstrncmp(props[1], "", 1)) {
|
|
k = strtoul((const char *)props[1], NULL, 0);
|
|
if (errno == ERANGE)
|
|
H5TOOLS_GOTO_ERROR(FAIL, "supposed port number wasn't");
|
|
fapl_config_out->namenode_port = (int32_t)k;
|
|
}
|
|
if (HDstrncmp(props[2], "", 1)) {
|
|
HDstrncpy(fapl_config_out->kerberos_ticket_cache, (const char *)props[2], HDstrlen(props[2]));
|
|
}
|
|
if (HDstrncmp(props[3], "", 1)) {
|
|
HDstrncpy(fapl_config_out->user_name, (const char *)props[3], HDstrlen(props[3]));
|
|
}
|
|
if (HDstrncmp(props[4], "", 1)) {
|
|
k = HDstrtoul((const char *)props[4], NULL, 0);
|
|
if (errno == ERANGE)
|
|
H5TOOLS_GOTO_ERROR(FAIL, "supposed buffersize number wasn't");
|
|
fapl_config_out->stream_buffer_size = (int32_t)k;
|
|
}
|
|
|
|
done:
|
|
if (props)
|
|
HDfree(props);
|
|
if (props_src)
|
|
HDfree(props_src);
|
|
|
|
return ret_value;
|
|
}
|
|
#endif /* H5_HAVE_LIBHDFS */
|