summaryrefslogtreecommitdiffstats
path: root/examples/h5_elink_unix2win.c
blob: a22dc97b47b605b8a522e7b66ee08d37c7f1ad65 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 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.                                                        *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/* 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, const void *udata, size_t udata_size,
                    hid_t lapl_id)
{
    hid_t       fid;
    const char *file_name;
    const char *obj_name;
    char       *new_fname = NULL; /* Buffer allocated to hold Unix file path */
    ssize_t     prefix_len;       /* External link prefix length */
    size_t      fname_len;
    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, udata_size, NULL, &file_name, &obj_name) < 0)
        goto error;
    fname_len = strlen(file_name);

    /* See if the external link prefix property is set */
    if ((prefix_len = H5Pget_elink_prefix(lapl_id, NULL, 0)) < 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 (prefix_len > 0) {
        /* Allocate a buffer to hold the filename plus prefix */
        new_fname = malloc(prefix_len + fname_len + 1);

        /* Copy the prefix into the buffer */
        if (H5Pget_elink_prefix(lapl_id, new_fname, (size_t)(prefix_len + 1)) < 0)
            goto error;

        start_pos = prefix_len;
    }
    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 (new_fname)
        free(new_fname);

    return ret_value;

error:
    /* Free file name if it's been allocated */
    if (new_fname)
        free(new_fname);
    return -1;
}

const H5L_class_t elink_unix2win_class[1] = {{
    H5L_LINK_CLASS_T_VERS,    /* H5L_class_t version       */
    H5L_TYPE_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(void)
{
    hid_t fid = (-1); /* File ID */
    hid_t gid = (-1); /* Group ID */

    /* Create the target file. */
#ifdef H5_HAVE_WIN32_API
    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 H5_HAVE_WIN32_API
    /* 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 = H5Gopen2(fid, "ext_link", H5P_DEFAULT)) < 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;
}