Symbolic links with relative path


I know that it is possible to set relative path to the target when creating soft link for example.
But what if the target is one level above in the hierarchy?
For example the target dataset is located /dset.
And the soft link are going to be placed to /group/dset_link.
What will be the relative path in that case? I ve tried to set it as ../dset but it seem not to work…

Also is there any restricted symbols for link names? Or is there some rules like the link name must not start with space…

In HDF5 path names, .. does not have the meaning it does in a shell. .. is a legitimate link name. In the example below, two groups are created. The first is linked as .. under the root group, the second is linked as ... in the first group.

In HDF5, .. cannot have the meaning of “one level above in the hierarchy”, because we are dealing with multi-graphs. A node can have multiple (direct) parents, and the concept of level is meaningful only for tree-like structures.

Only the path separator / and the combination ./ and /./ are special. A single space or multiple spaces are legitimate link names.



#include "hdf5.h"
#include <stdlib.h>

int main()
  __label__ fail_group, fail_prop, fail_lcpl, fail_file;
  int ret_val = EXIT_SUCCESS;
  hid_t file, lcpl, group;
  char  fname[] = "g2.h5";
  char  path[]  = "./../...";

  if ((file = H5Fcreate(fname, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) ==
      H5I_INVALID_HID) {
    ret_val = EXIT_FAILURE;
    goto fail_file;

  if ((lcpl = H5Pcreate(H5P_LINK_CREATE)) == H5I_INVALID_HID) {
    ret_val = EXIT_FAILURE;
    goto fail_lcpl;
  // ensure that intermediate groups are created automatically
  if (H5Pset_create_intermediate_group(lcpl, 1) < 0) {
    ret_val = EXIT_FAILURE;
    goto fail_prop;
  // create two groups
  if ((group = H5Gcreate(file, path, lcpl, H5P_DEFAULT, H5P_DEFAULT)) ==
      H5I_INVALID_HID) {
    ret_val = EXIT_FAILURE;
    goto fail_group;
  return ret_val;
$ h5dump g2.h5 
HDF5 "g2.h5" {
GROUP "/" {
   GROUP ".." {
      GROUP "..." {
1 Like

I forgot to mention that in HDF5 the ‘relative’ in ‘relative path’ always means relative to the accompanying handle loc_id, e.g., file handle, group handle, etc.


1 Like

Thank you very much for such comprehensive answer.

Very interesting, good to know

While a node can have multiple parents, if it is retrieved by name the names are in a tree structure, so one could construct a function that takes a in input path and resolves a soft link stored in that node relative to that input path. It seems like that might have value.

1 Like

When you say ‘node,’ you mean ‘group,’ right? (Because that’s the only type of place where we store links…) So you are asking for a function that retrieves the soft link’s value and, if it’s a relative path, normalizes it w.r.t. to the given input path and returns that path?


Yes - I mean like doing like what POSIX filesystems do, where you can make soft links and hard links, and relative soft links are supported there. You can make a soft relative link and then make a hard link to that soft link somewhere else in the tree, and the filesystem will try to resolve it relative to the path through which it is accessed.

You mean a hard link to the group that contains that soft link? (There is no such thing as a hard link to a soft link in HDF5…)


Ah - I see. So it would necessarily be different from a POSIX system

Just to recap:

mkdir -p test/test1
echo "Hello, World!" > test/foo
ln -s ../foo test/test1/foo

This references three inodes, as can be seen by

ls -Ri test

The relative symbolic link resolves correctly.

:~ cat test/test1/foo
Hello, World!

I think what you are suggesting is to mimic this behavior. Correct?

Like hard links/inode numbers in POSIX, HDF5 hard links have object header addresses (haddr_t) as their values/destinations. The difference is that if we use the analogy inode “=” object header, only two inodes (HDF5 object headers) exist in the HDF5 case.

  1. The object header of the group test/test1
  2. The object header of the “file” test/foo

There is no object header for test/test1/foo, because that is stored as a (soft) link in the group test/test1 with destination ../foo. Nevertheless, the function you are suggesting could be implemented.

Can you give us a use case?


Sometimes soft links are very useful for pre-templating a file for us (we have a schema that is known ahead of time for links, e.g. NeXus, and it is convenient to make the links before the data is written)

But then we also would like to be able to embed those groups into another file, and if we use soft links they will no longer be valid if the group is moved to a new base path (we can walk the tree and rewrite all the soft links of course, but it would be nice if we didn’t have to).


The relative path for linking to a target dataset one level above the soft link would be “…/…/dset”.

I see the use case, but .. is a legitimate link name and the proposed convention deviates from that interpretation, which makes it more problematic and inherently ambiguous. The symbolic resolver function can be implemented using a simple combination of H5Lget_val, strncat, and realpath (or Win32 _fullpath). Taking this beyond the symbolic level, and with an expectation of robustness, will easily balloon into a real monster: Most of the code will just be dealing w/ corner cases, and a maintenance nightmare.But maybe I’m too pessimistic…