diff options
Diffstat (limited to 'examples')
-rw-r--r-- | examples/Makefile.am | 18 | ||||
-rw-r--r-- | examples/Makefile.in | 20 | ||||
-rw-r--r-- | examples/h5_elink_unix2win.c | 209 | ||||
-rw-r--r-- | examples/h5_extlink.c | 662 |
4 files changed, 903 insertions, 6 deletions
diff --git a/examples/Makefile.am b/examples/Makefile.am index e6991d9..701dd70 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -29,13 +29,15 @@ endif # it would try to compile them instead of using the h5cc script. # Use the boilerplate in config/examples.am instead. TEST_PROG = h5_write h5_read h5_extend_write h5_chunk_read h5_compound \ - h5_group h5_select h5_attribute h5_mount h5_reference h5_drivers + h5_group h5_select h5_attribute h5_mount h5_reference h5_drivers \ + h5_extlink h5_elink_unix2win # Install files # List all file that should be installed in examples directory INSTALL_FILES = h5_write.c h5_read.c h5_extend_write.c h5_chunk_read.c \ h5_compound.c h5_group.c h5_select.c h5_attribute.c h5_mount.c \ - h5_reference.c h5_drivers.c ph5example.c + h5_reference.c h5_drivers.c h5_extlink.c h5_elink_unix2win.c \ + ph5example.c # Additional dependencies for each program are listed below. $(EXTRA_PROG): $(LIBHDF5) @@ -49,6 +51,16 @@ endif h5_read.chkexe_: h5_write.chkexe_ h5_chunk_read.chkexe_: h5_extend_write.chkexe_ +# The external link examples demonstrate how to use paths; they need +# directories to be created to do this. +EXTLINK_DIRS=red blue u2w + +$(EXTLINK_DIRS): + echo $(mkdir_p) $@ + $(mkdir_p) $@ + +CHECK_CLEANFILES+=$(EXTLINK_DIRS) + # Example directory EXAMPLEDIR=$(docdir)/hdf5/examples/c @@ -71,6 +83,8 @@ h5_reference: $(srcdir)/h5_reference.c h5_drivers: $(srcdir)/h5_drivers.c ph5example: $(srcdir)/ph5example.c h5_dtransform: $(srcdir)/h5_dtransform.c +h5_extlink: $(srcdir)/h5_extlink.c $(EXTLINK_DIRS) +h5_elink_unix2win: $(srcdir)/h5_elink_unix2win.c $(EXTLINK_DIRS) include $(top_srcdir)/config/examples.am include $(top_srcdir)/config/conclude.am diff --git a/examples/Makefile.in b/examples/Makefile.in index db42db5..cfb64d7 100644 --- a/examples/Makefile.in +++ b/examples/Makefile.in @@ -299,7 +299,7 @@ TRACE = perl $(top_srcdir)/bin/trace # .chkexe files are used to mark tests that have run successfully. # .chklog files are output from those tests. # *.clog are from the MPE option. -CHECK_CLEANFILES = *.chkexe *.chklog *.clog *.h5 +CHECK_CLEANFILES = *.chkexe *.chklog *.clog $(EXTLINK_DIRS) *.h5 @BUILD_PARALLEL_CONDITIONAL_TRUE@TEST_PROG_PARA = ph5example # Example programs. @@ -307,16 +307,22 @@ CHECK_CLEANFILES = *.chkexe *.chklog *.clog *.h5 # it would try to compile them instead of using the h5cc script. # Use the boilerplate in config/examples.am instead. TEST_PROG = h5_write h5_read h5_extend_write h5_chunk_read h5_compound \ - h5_group h5_select h5_attribute h5_mount h5_reference h5_drivers + h5_group h5_select h5_attribute h5_mount h5_reference h5_drivers \ + h5_extlink h5_elink_unix2win # Install files # List all file that should be installed in examples directory INSTALL_FILES = h5_write.c h5_read.c h5_extend_write.c h5_chunk_read.c \ h5_compound.c h5_group.c h5_select.c h5_attribute.c h5_mount.c \ - h5_reference.c h5_drivers.c ph5example.c + h5_reference.c h5_drivers.c h5_extlink.c h5_elink_unix2win.c \ + ph5example.c +# The external link examples demonstrate how to use paths; they need +# directories to be created to do this. +EXTLINK_DIRS = red blue u2w + # Example directory EXAMPLEDIR = $(docdir)/hdf5/examples/c @@ -530,6 +536,10 @@ $(EXTRA_PROG): $(LIBHDF5) h5_read.chkexe_: h5_write.chkexe_ h5_chunk_read.chkexe_: h5_extend_write.chkexe_ +$(EXTLINK_DIRS): + echo $(mkdir_p) $@ + $(mkdir_p) $@ + # List dependencies for each program. Normally, automake would take # care of this for us, but if we tell automake about the programs it # will try to build them with the normal C compiler, not h5cc. This is @@ -549,6 +559,8 @@ h5_reference: $(srcdir)/h5_reference.c h5_drivers: $(srcdir)/h5_drivers.c ph5example: $(srcdir)/ph5example.c h5_dtransform: $(srcdir)/h5_dtransform.c +h5_extlink: $(srcdir)/h5_extlink.c $(EXTLINK_DIRS) +h5_elink_unix2win: $(srcdir)/h5_elink_unix2win.c $(EXTLINK_DIRS) # How to create EXAMPLEDIR if it doesn't already exist $(EXAMPLEDIR): @@ -625,7 +637,7 @@ install-doc uninstall-doc: # clean up files generated by tests so they can be re-run. build-check-clean: - $(RM) $(CHECK_CLEANFILES) + $(RM) -rf $(CHECK_CLEANFILES) # run check-clean whenever mostlyclean is run mostlyclean-local: build-check-clean diff --git a/examples/h5_elink_unix2win.c b/examples/h5_elink_unix2win.c new file mode 100644 index 0000000..35ab271 --- /dev/null +++ b/examples/h5_elink_unix2win.c @@ -0,0 +1,209 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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 files COPYING and Copyright.html. COPYING can be found at the root * + * of the source code distribution tree; Copyright.html can be found at the * + * root level of an installed copy of the electronic HDF5 document set and * + * is linked from the top-level documents page. It can also be found at * + * http://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html. If you do not have * + * access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* This program demonstrates how to translate an external link created on + * a Windows machine into a format that a *nix machine can read. + * This is done by registering a new traversal function for external links. + * + * This example is designed to be run on Unix and will create an external + * link with a Windows-style path. Using the traversal function below, + * the example then successfully follows the external link. + * + * The external link will create a file called "u2w/u2w_target.h5". + * The example will fail if the directory u2w does not exist. + */ + +#include "hdf5.h" +#include <stdlib.h> +#include <string.h> + + +/* "Windows to Unix" traversal function for external links + * + * Translates a filename stored in Unix format to Windows format by replacing + * forward slashes with backslashes. + * Makes no attempt to handle Windows drive names (e.g., "C:\"), spaces within + * file names, quotes, etc. These are left as an exercise for the user. :) + * Note that this may not be necessary on your system; many Windows systems can + * understand Unix paths. + */ +static hid_t elink_unix2win_trav(const char *link_name, hid_t cur_group, void * udata, size_t udata_size, hid_t lapl_id) +{ + hid_t fid; + char *file_name; + hbool_t fname_alloc = 0; /* Whether file_name has been allocated */ + char *obj_name; + char *new_fname = NULL; /* Buffer allocated to hold Unix file path */ + size_t fname_len; + htri_t result; + size_t buf_size; /* Size prefix buffer */ + size_t start_pos; /* Initial position in new_fname buffer */ + size_t x; /* Counter variable */ + hid_t ret_value = -1; + + printf("Converting Unix path to Windows path.\n"); + + if(H5Lunpack_elink_val(udata, &file_name, &obj_name) < 0) + goto error; + fname_len = strlen(file_name); + + /* See if the external link prefix property is set */ + if((result = H5Pexist(lapl_id, H5L_ELINK_PREFIX_PROP)) < 0) + goto error; + + /* If so, prepend it to the filename. We assume that the prefix + * is in the correct format for the current file system. + */ + if(result > 0) + { + if(H5Pget_size(lapl_id, H5L_ELINK_PREFIX_PROP, &buf_size) < 0) + goto error; + + /* Allocate a buffer to hold the filename plus prefix */ + new_fname = malloc(buf_size + fname_len + 1); + + /* Copy the prefix into the buffer */ + if(H5Pget(lapl_id, H5L_ELINK_PREFIX_PROP, new_fname) < 0) + goto error; + + start_pos = buf_size - 1; + } + else + { + /* Allocate a buffer to hold just the filename */ + new_fname = malloc(fname_len + 1); + start_pos = 0; + } + + /* We should now copy file_name into new_fname starting at position pos. + * We'll convert '/' characters into '\' characters as we go. + */ + for(x=0; file_name[x] != '\0'; x++) + { + if(file_name[x] == '/') + new_fname[x + start_pos] = '\\'; + else + new_fname[x + start_pos] = file_name[x]; + } + new_fname[x + start_pos] = '\0'; + + /* Now open the file and object within it */ + if((fid = H5Fopen(new_fname, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) + goto error; + ret_value = H5Oopen(fid, obj_name, lapl_id); /* If this fails, our return value will be negative. */ + if(H5Fclose(fid) < 0) + goto error; + + /* Free file_name if it's been allocated */ + if(fname_alloc) + free(file_name); + + return ret_value; + +error: + /* Free file_name if it's been allocated */ + if(new_fname) + free(new_fname); + return -1; +} + +const H5L_link_class_t elink_unix2win_class[1] = {{ + H5L_LINK_CLASS_T_VERS, /* H5L_link_class_t version */ + H5L_LINK_EXTERNAL, /* Link type id number */ + "unix2win external link", /* Link class name for debugging */ + NULL, /* Creation callback */ + NULL, /* Move callback */ + NULL, /* Copy callback */ + elink_unix2win_trav, /* The actual traversal function */ + NULL, /* Deletion callback */ + NULL /* Query callback */ +}}; + + +/* The example function. + * Creates a file named "unix2win.h5" with an external link pointing to + * the file "u2w/u2w_target.h5". + * + * Registers a new traversal function for external links and then + * follows the external link to open the target file. + */ +static int +unix2win_example() +{ + hid_t fid = (-1); /* File ID */ + hid_t gid = (-1); /* Group ID */ + + /* Create the target file. */ +#ifdef WIN32 + if((fid=H5Fcreate("u2w\u2w_target.h5", H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT))<0) goto error; +#else + if((fid=H5Fcreate("u2w/u2w_target.h5", H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT))<0) goto error; +#endif + if(H5Fclose(fid) < 0) goto error; + + /* Create the source file with an external link in Windows format */ + if((fid=H5Fcreate("unix2win.h5", H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT))<0) goto error; + + /* Create the external link */ + if(H5Lcreate_external("u2w/../u2w/u2w_target.h5", "/", fid, "ext_link", H5P_DEFAULT, H5P_DEFAULT) < 0) goto error; + + /* If we are not on Windows, assume we are on a Unix-y filesystem and + * follow the external link normally. + * If we are on Windows, register the unix2win traversal function so + * that external links can be traversed. + */ + +#ifdef WIN32 + /* Register the elink_unix2win class defined above to replace default + * external links + */ + if(H5Lregister(elink_unix2win_class) < 0) goto error; +#endif + + /* Now follow the link */ + if((gid = H5Gopen(fid, "ext_link")) < 0) goto error; + printf("Successfully followed external link.\n"); + + /* Close the group and the file */ + if(H5Gclose(gid) <0) goto error; + if(H5Fclose(fid) <0) goto error; + + return 0; + + error: + printf("Error!\n"); + H5E_BEGIN_TRY { + H5Gclose (gid); + H5Fclose (fid); + } H5E_END_TRY; + return -1; +} + + +/* Main function + * + * Invokes the example function. + */ +int +main(void) +{ + int ret; + + printf("Testing unix2win external links.\n"); + ret = unix2win_example(); + + return ret; +} + + diff --git a/examples/h5_extlink.c b/examples/h5_extlink.c new file mode 100644 index 0000000..92ac398 --- /dev/null +++ b/examples/h5_extlink.c @@ -0,0 +1,662 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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 files COPYING and Copyright.html. COPYING can be found at the root * + * of the source code distribution tree; Copyright.html can be found at the * + * root level of an installed copy of the electronic HDF5 document set and * + * is linked from the top-level documents page. It can also be found at * + * http://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html. If you do not have * + * access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* This program demonstrates how to create and use "external links" in + * HDF5. + * + * External links point from one HDF5 file to an object (Group, Dataset, or + * committed Datatype) in another file. + */ + +#include "hdf5.h" +#include <string.h> + +#define SOURCE_FILE "extlink_source.h5" +#define TARGET_FILE "extlink_target.h5" + +#define PREFIX_SOURCE_FILE "extlink_prefix_source.h5" + +#define SOFT_LINK_FILE "soft_link.h5" +#define SOFT_LINK_NAME "soft_link_to_group" +#define UD_SOFT_LINK_NAME "ud_soft_link" +#define TARGET_GROUP "target_group" + +#define UD_SOFT_CLASS 65 + +#define HARD_LINK_FILE "hard_link.h5" +#define HARD_LINK_NAME "hard_link_to_group" +#define UD_HARD_LINK_NAME "ud_hard_link" + +#define UD_HARD_CLASS 66 + +#define PLIST_LINK_PROP "plist_link_prop" +#define UD_PLIST_CLASS 66 + + + +/* Basic external link example + * + * Creates two files and uses an external link to access an object in the + * second file from the first file. + */ +void extlink_example() +{ + hid_t source_file_id, targ_file_id; + hid_t group_id, group2_id; + + /* Create two files, a source and a target */ + source_file_id = H5Fcreate(SOURCE_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + targ_file_id = H5Fcreate(TARGET_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + + /* Create a group in the target file for the external link to point to. */ + group_id = H5Gcreate(targ_file_id, "target_group", (size_t) 0); + + /* Close the group and the target file */ + H5Gclose(group_id); + + /* Create an external link in the source file pointing to the target group. + * We could instead have created the external link first, then created the + * group it points to; the order doesn't matter. + */ + H5Lcreate_external(TARGET_FILE, "target_group", source_file_id, "ext_link", H5P_DEFAULT, H5P_DEFAULT); + + /* Now we can use the external link to create a new group inside the + * target group (even though the target file is closed!). The external + * link works just like a soft link. + */ + group_id = H5Gcreate(source_file_id, "ext_link/new_group", (size_t) 0); + + /* The group is inside the target file and we can access it normally. + * Here, group_id and group2_id point to the same group inside the + * target file. + */ + group2_id = H5Gopen(targ_file_id, "target_group/new_group"); + + /* Don't forget to close the IDs we opened. */ + H5Gclose(group2_id); + H5Gclose(group_id); + + H5Fclose(targ_file_id); + H5Fclose(source_file_id); + + /* The link from the source file to the target file will work as long as + * the target file can be found. If the target file is moved, renamed, + * or deleted in the filesystem, HDF5 won't be able to find it and the + * external link will "dangle." + */ +} + + +/* External link prefix example + * + * Uses a group access property list to set a "prefix" for the filenames + * accessed through an external link. + * + * Group access property lists inherit from link access property lists; + * the external link prefix property is actually a property of LAPLs. + * + * This example requires a "red" directory and a "blue" directory to exist + * where it is run (so to run this example on Unix, first mkdir red and mkdir + * blue). + */ +void extlink_prefix_example() +{ + hid_t source_file_id, red_file_id, blue_file_id; + hid_t group_id, group2_id; + hid_t gapl_id; + + /* Create three files, a source and two targets. The targets will have + * the same name, but one will be located in the red directory and one will + * be located in the blue directory */ + source_file_id = H5Fcreate(PREFIX_SOURCE_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + red_file_id = H5Fcreate("red/prefix_target.h5", H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + blue_file_id = H5Fcreate("blue/prefix_target.h5", H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + + /* This test needs a red and a blue directory in the filesystem. If they're not present, + * trying to create the files above will fail. + */ + if(red_file_id < 0 || blue_file_id < 0) + printf("This test requires directories named 'red' and 'blue' to exist. Did you forget to create them?\n"); + + /* Create an external link in the source file pointing to the root group of + * a file named prefix_target.h5. This file doesn't exist in the current + * directory, but the files in the red and blue directories both have this + * name. + */ + H5Lcreate_external("prefix_target.h5", "/", source_file_id, "ext_link", H5P_DEFAULT, H5P_DEFAULT); + + /* If we tried to traverse the external link now, we would fail (since the + * file it points to doesn't exist). Instead, we'll create a group access + * property list that will provide a prefix path to the external link. + * Group access property lists inherit the properties of link access + * property lists. + */ + gapl_id = H5Pcreate(H5P_GROUP_ACCESS); + H5Pset_elink_prefix(gapl_id, "red/"); + + /* Now if we traverse the external link, HDF5 will look for an external + * file named red/prefix_target.h5, which exists. + * To pass the group access property list, we need to use H5Gopen_expand. + */ + group_id = H5Gopen_expand(source_file_id, "ext_link", gapl_id); + + /* Now we can use the open group ID to create a new group inside the + * "red" file. + */ + group2_id = H5Gcreate(group_id, "pink", (size_t) 0); + + /* Close both groups. */ + H5Gclose(group2_id); + H5Gclose(group_id); + + /* If we change the prefix, the same external link can find a file in the blue + * directory. + */ + H5Pset_elink_prefix(gapl_id, "blue/"); + group_id = H5Gopen_expand(source_file_id, "ext_link", gapl_id); + group2_id = H5Gcreate(group_id, "sky blue", (size_t) 0); + + /* Close both groups. */ + H5Gclose(group2_id); + H5Gclose(group_id); + + /* Each file has had a group created inside it using the same external link. */ + group_id = H5Gopen(red_file_id, "pink"); + group2_id = H5Gopen(blue_file_id, "sky blue"); + + /* Clean up our open IDs */ + H5Gclose(group2_id); + H5Gclose(group_id); + H5Pclose(gapl_id); + H5Fclose(blue_file_id); + H5Fclose(red_file_id); + H5Fclose(source_file_id); + + /* User-defined links can expand on the ability to pass in parameters + * using an access property list; for instance, a user-defined link + * might function like an external link but allow the full filename to be + * passed in through the access property list. + */ +} + + +/* Soft Link example + * + * Create a new class of user-defined links that behave like HDF5's built-in + * soft links. + * + * This isn't very useful by itself (HDF5's soft links already do the same + * thing), but it can serve as an example for how to reference objects by + * name. + */ + +/* We need to define the callback function that the soft link will use. + * It is defined after the example below. + * To keep the example simple, these links don't have a query callback. + * In general, link classes should always be query-able. + * We might also have wanted to supply a creation callback that checks + * that a path was supplied in the udata. + */ +static hid_t UD_soft_traverse(const char *link_name, hid_t cur_group, void *udata, size_t udata_size, hid_t lapl_id); + +void soft_link_example() +{ + hid_t file_id; + hid_t group_id; + /* Define the link class that we'll use to register "user-defined hard + * links" using the callbacks we defined above. + * A link class can have NULL for any callback except its traverse + * callback. + */ + const H5L_link_class_t UD_soft_class[1] = {{ + H5L_LINK_CLASS_T_VERS, /* Version number for this struct. + * This field is always H5L_LINK_CLASS_T_VERS */ + UD_SOFT_CLASS, /* Link class id number. This can be any + * value between H5L_LINK_UD_MIN (64) and + * H5L_LINK_MAX (255). It should be a + * value that isn't already being used by + * another kind of link. We'll use 65. */ + "UD_soft_link", /* Link class name for debugging */ + NULL, /* Creation callback */ + NULL, /* Move callback */ + NULL, /* Copy callback */ + UD_soft_traverse, /* The actual traversal function */ + NULL, /* Deletion callback */ + NULL /* Query callback */ + }}; + + + /* First, create a file and an object within the file for the link to + * point to. + */ + file_id = H5Fcreate(SOFT_LINK_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + group_id = H5Gcreate(file_id, TARGET_GROUP, (size_t) 0); + H5Gclose(group_id); + + /* This is how we create a normal soft link to the group. + */ + H5Lcreate_soft(TARGET_GROUP, file_id, SOFT_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT); + + /* To do the same thing using a user-defined link, we first have to + * register the link class we defined. + */ + H5Lregister(UD_soft_class); + + /* Now create a user-defined link. We give it the path to the group + * as its udata.1 + */ + H5Lcreate_ud(file_id, UD_SOFT_LINK_NAME, UD_SOFT_CLASS, TARGET_GROUP, + strlen(TARGET_GROUP) + 1, H5P_DEFAULT, H5P_DEFAULT); + + /* We can access the group through the UD soft link like we would through + * a normal soft link. This link will still dangle if the object's + * original name is changed or unlinked. + */ + group_id = H5Gopen(file_id, UD_SOFT_LINK_NAME); + + /* The group is now open normally. Don't forget to close it! */ + H5Gclose(group_id); + + H5Fclose(file_id); +} + +/* UD_soft_traverse + * The actual traversal function simply needs to open the correct object by + * name and return its ID. + */ +static hid_t UD_soft_traverse(const char *link_name, hid_t cur_group, void *udata, size_t udata_size, hid_t lapl_id) +{ + const char *target = (char *) udata; + hid_t ret_value; + + /* Pass the udata straight through to HDF5. If it's invalid, let HDF5 + * return an error. + */ + ret_value = H5Oopen(cur_group, target, lapl_id); + return ret_value; +} + + + +/* Hard Link example + * + * Create a new class of user-defined links that behave like HDF5's built-in + * hard links. + * + * This isn't very useful by itself (HDF5's hard links already do the same + * thing), but it can serve as an example for how to reference objects by + * address. + */ + +/* We need to define the callback functions that the hard link will use. + * These are defined after the example below. + * To keep the example simple, these links don't have a query callback. + * Generally, real link classes should always be query-able. + */ +static herr_t UD_hard_create(const char *link_name, hid_t loc_group, void *udata, size_t udata_size, hid_t lcpl_id); +static herr_t UD_hard_delete(const char *link_name, hid_t loc_group, void *udata, size_t udata_size); +static hid_t UD_hard_traverse(const char *link_name, hid_t cur_group, void *udata, size_t udata_size, hid_t lapl_id); + +void hard_link_example() +{ + hid_t file_id; + hid_t group_id; + H5L_linkinfo_t li; + /* Define the link class that we'll use to register "user-defined hard + * links" using the callbacks we defined above. + * A link class can have NULL for any callback except its traverse + * callback. + */ + const H5L_link_class_t UD_hard_class[1] = {{ + H5L_LINK_CLASS_T_VERS, /* Version number for this struct. + * This field is always H5L_LINK_CLASS_T_VERS */ + UD_HARD_CLASS, /* Link class id number. This can be any + * value between H5L_LINK_UD_MIN (64) and + * H5L_LINK_MAX (255). It should be a + * value that isn't already being used by + * another kind of link. We'll use 66. */ + "UD_hard_link", /* Link class name for debugging */ + UD_hard_create, /* Creation callback */ + NULL, /* Move callback */ + NULL, /* Copy callback */ + UD_hard_traverse, /* The actual traversal function */ + UD_hard_delete, /* Deletion callback */ + NULL /* Query callback */ + }}; + + + /* First, create a file and an object within the file for the link to + * point to. + */ + file_id = H5Fcreate(HARD_LINK_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + group_id = H5Gcreate(file_id, TARGET_GROUP, (size_t) 0); + H5Gclose(group_id); + + /* This is how we create a normal hard link to the group. This + * creates a second "name" for the group. + */ + H5Lcreate_hard(file_id, TARGET_GROUP, file_id, HARD_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT); + + /* To do the same thing using a user-defined link, we first have to + * register the link class we defined. + */ + H5Lregister(UD_hard_class); + + /* Since hard links link by object address, we'll need to retrieve + * the target group's address. We do this by calling H5Lget_linkinfo + * on a hard link to the object. + */ + H5Lget_linkinfo(file_id, TARGET_GROUP, &li, H5P_DEFAULT); + + /* Now create a user-defined link. We give it the group's address + * as its udata. + */ + H5Lcreate_ud(file_id, UD_HARD_LINK_NAME, UD_HARD_CLASS, &(li.u.address), + sizeof(li.u.address), H5P_DEFAULT, H5P_DEFAULT); + + /* The UD hard link has now incremented the group's reference count + * like a normal hard link would. This means that we can unlink the + * other two links to that group and it won't be deleted until the + * UD hard link is deleted. + */ + H5Lunlink(file_id, TARGET_GROUP, H5P_DEFAULT); + H5Lunlink(file_id, HARD_LINK_NAME, H5P_DEFAULT); + + /* The group is still accessible through the UD hard link. If this were + * a soft link instead, the object would have been deleted when the last + * hard link to it was unlinked. */ + group_id = H5Gopen(file_id, UD_HARD_LINK_NAME); + + /* The group is now open normally. Don't forget to close it! */ + H5Gclose(group_id); + + /* Removing the user-defined hard link will delete the group. */ + H5Lunlink(file_id, UD_HARD_LINK_NAME, H5P_DEFAULT); + + H5Fclose(file_id); +} + +/* Callbacks for User-defined hard links. */ +/* UD_hard_create + * The most important thing this callback does is to increment the reference + * count on the target object. Without this step, the object could be + * deleted while this link still pointed to it, resulting in possible data + * corruption! + * The create callback also checks the arguments used to create this link. + * If this function returns a negative value, the call to H5Lcreate_ud() + * will also return failure and the link will not be created. + */ +static herr_t UD_hard_create(const char *link_name, hid_t loc_group, void *udata, size_t udata_size, hid_t lcpl_id) +{ + haddr_t addr; + hid_t target_obj = -1; + herr_t ret_value = 0; + + /* Make sure that the address passed in looks valid */ + if(udata_size != sizeof(haddr_t)) + { + ret_value = -1; + goto done; + } + + addr = *((haddr_t *) udata); + + /* Open the object this link points to so that we can increment + * its reference count. This also ensures that the address passed + * in points to a real object (although this check is not perfect!) */ + target_obj= H5Oopen_by_addr(loc_group, addr); + if(target_obj < 0) + { + ret_value = -1; + goto done; + } + + /* Increment the reference count of the target object */ + if(H5Oincr_refcount(target_obj) < 0) + { + ret_value = -1; + goto done; + } + +done: + /* Close the target object if we opened it */ + if(target_obj >= 0) + H5Oclose(target_obj); + return ret_value; +} + +/* UD_hard_delete + * Since the creation function increments the object's reference count, it's + * important to decrement it again when the link is deleted. + */ +static herr_t UD_hard_delete(const char *link_name, hid_t loc_group, void *udata, size_t udata_size) +{ + haddr_t addr; + hid_t target_obj = -1; + herr_t ret_value = 0; + + /* Sanity check; we have already verified the udata's size in the creation + * callback. + */ + if(udata_size != sizeof(haddr_t)) + { + ret_value = -1; + goto done; + } + + addr = *((haddr_t *) udata); + + /* Open the object this link points to */ + target_obj= H5Oopen_by_addr(loc_group, addr); + if(target_obj < 0) + { + ret_value = -1; + goto done; + } + + /* Decrement the reference count of the target object */ + if(H5Odecr_refcount(target_obj) < 0) + { + ret_value = -1; + goto done; + } + +done: + /* Close the target object if we opened it */ + if(target_obj >= 0) + H5Oclose(target_obj); + return ret_value; +} + +/* UD_hard_traverse + * The actual traversal function simply needs to open the correct object and + * return its ID. + */ +static hid_t UD_hard_traverse(const char *link_name, hid_t cur_group, void * udata, size_t udata_size, hid_t lapl_id) +{ + haddr_t addr; + hid_t ret_value = -1; + + /* Sanity check; we have already verified the udata's size in the creation + * callback. + */ + if(udata_size != sizeof(haddr_t)) + return -1; + + addr = *((haddr_t *) udata); + + /* Open the object by address. If H5Oopen_by_addr fails, ret_value will + * be negative to indicate that the traversal function failed. + */ + ret_value = H5Oopen_by_addr(cur_group, addr); + + return ret_value; +} + + + +/* Plist example + * + * Create a new class of user-defined links that open objects within a file + * based on a value passed in through a link access property list. + * + * Group, dataset, and datatype access property lists all inherit from link + * access property lists, so they can be used instead of LAPLs. + */ + +/* We need to define the callback functions that this link type will use. + * These are defined after the example below. + * These links have no udata, so they don't need a query function. + */ +static hid_t UD_plist_traverse(const char *link_name, hid_t cur_group, void *udata, size_t udata_size, hid_t lapl_id); + +void plist_link_example() +{ + hid_t file_id; + hid_t group_id, group2_id; + hid_t gapl_id; + char *path = NULL; + + /* Define the link class that we'll use to register "plist + * links" using the callback we defined above. + * A link class can have NULL for any callback except its traverse + * callback. + */ + const H5L_link_class_t UD_plist_class[1] = {{ + H5L_LINK_CLASS_T_VERS, /* Version number for this struct. + * This field is always H5L_LINK_CLASS_T_VERS */ + UD_PLIST_CLASS, /* Link class id number. This can be any + * value between H5L_LINK_UD_MIN (64) and + * H5L_LINK_MAX (255). It should be a + * value that isn't already being used by + * another kind of link. We'll use 67. */ + "UD_plist_link", /* Link class name for debugging */ + NULL, /* Creation callback */ + NULL, /* Move callback */ + NULL, /* Copy callback */ + UD_plist_traverse, /* The actual traversal function */ + NULL, /* Deletion callback */ + NULL /* Query callback */ + }}; + + + /* First, create a file and two objects within the file for the link to + * point to. + */ + file_id = H5Fcreate(HARD_LINK_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + group_id = H5Gcreate(file_id, "group_1", (size_t) 0); + H5Gclose(group_id); + group_id = H5Gcreate(file_id, "group_1/group_2", (size_t) 0); + H5Gclose(group_id); + + /* Register "plist links" and create one. It has no udata at all. */ + H5Lregister(UD_plist_class); + H5Lcreate_ud(file_id, "plist_link", UD_PLIST_CLASS, NULL, 0, + H5P_DEFAULT, H5P_DEFAULT); + + /* Create a group access property list to pass in the target for the + * plist link. + */ + gapl_id = H5Pcreate(H5P_GROUP_ACCESS); + + /* There is no HDF5 API for setting the property that controls these + * links, so we have to add the property manually + */ + H5Pinsert(gapl_id, PLIST_LINK_PROP, sizeof(const char *), &(path), NULL, NULL, NULL, NULL, NULL, NULL); + + /* Set the property to point to the first group. */ + path = "group_1"; + H5Pset(gapl_id, PLIST_LINK_PROP, &path); + + /* Open the first group through the plist link using the GAPL we just + * created */ + group_id = H5Gopen_expand(file_id, "plist_link", gapl_id); + + /* If we change the value set on the property list, it will change where + * the plist link points. + */ + path = "group_1/group_2"; + H5Pset(gapl_id, PLIST_LINK_PROP, &path); + group2_id = H5Gopen_expand(file_id, "plist_link", gapl_id); + + /* group_id points to group_1 and group2_id points to group_2, both opened + * through the same link. + * Using more than one of this type of link could quickly become confusing, + * since they will all use the same property list; however, there is + * nothing to prevent the links from changing the property list in their + * traverse callbacks. + */ + + /* Clean up */ + H5Pclose(gapl_id); + H5Gclose(group_id); + H5Gclose(group2_id); + H5Fclose(file_id); +} + +/* Traversal callback for User-defined plist links. */ +/* UD_plist_traverse + * Open a path passed in through the property list. + */ +static hid_t UD_plist_traverse(const char *link_name, hid_t cur_group, void * udata, size_t udata_size, hid_t lapl_id) +{ + char * path; + hid_t ret_value = -1; + + /* If the link property isn't set or can't be found, traversal fails. */ + if(H5Pexist(lapl_id, PLIST_LINK_PROP) < 0) + goto error; + + if(H5Pget(lapl_id, PLIST_LINK_PROP, &path) < 0) + goto error; + + /* Open the object by address. If H5Oopen_by_addr fails, ret_value will + * be negative to indicate that the traversal function failed. + */ + ret_value = H5Oopen(cur_group, path, lapl_id); + + return ret_value; + +error: + return -1; +} + + + +/* Main function + * + * Invokes the example functions. + */ + int +main(void) +{ + printf("Testing basic external links.\n"); + extlink_example(); + + printf("Testing external link prefixes.\n"); + extlink_prefix_example(); + + printf("Testing user-defined soft links.\n"); + soft_link_example(); + + printf("Testing user-defined hard links.\n"); + hard_link_example(); + + printf("Testing user-defined property list links.\n"); + plist_link_example(); + + return 0; +} + + |