Coverage Report

Created: 2024-06-18 06:29

/src/hdf5/src/H5Gname.c
Line
Count
Source (jump to first uncovered line)
1
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2
 * Copyright by The HDF Group.                                               *
3
 * All rights reserved.                                                      *
4
 *                                                                           *
5
 * This file is part of HDF5.  The full HDF5 copyright notice, including     *
6
 * terms governing use, modification, and redistribution, is contained in    *
7
 * the COPYING file, which can be found at the root of the source code       *
8
 * distribution tree, or in https://www.hdfgroup.org/licenses.               *
9
 * If you do not have access to either file, you may request a copy from     *
10
 * help@hdfgroup.org.                                                        *
11
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
12
13
/*-------------------------------------------------------------------------
14
 *
15
 * Created:   H5Gname.c
16
 *
17
 * Purpose:   Functions for handling group hierarchy paths.
18
 *
19
 *-------------------------------------------------------------------------
20
 */
21
22
/****************/
23
/* Module Setup */
24
/****************/
25
26
#include "H5Gmodule.h" /* This source code file is part of the H5G module */
27
28
/***********/
29
/* Headers */
30
/***********/
31
#include "H5private.h"   /* Generic Functions     */
32
#include "H5Dprivate.h"  /* Datasets        */
33
#include "H5Eprivate.h"  /* Error handling        */
34
#include "H5Fprivate.h"  /* File access       */
35
#include "H5Gpkg.h"      /* Groups          */
36
#include "H5Iprivate.h"  /* IDs           */
37
#include "H5Lprivate.h"  /* Links                                */
38
#include "H5MMprivate.h" /* Memory wrappers     */
39
40
#include "H5VLnative_private.h" /* Native VOL connector                     */
41
42
/****************/
43
/* Local Macros */
44
/****************/
45
46
/******************/
47
/* Local Typedefs */
48
/******************/
49
50
/* Struct used by change name callback function */
51
typedef struct H5G_names_t {
52
    H5G_names_op_t op;              /* Operation performed on file */
53
    H5F_t         *src_file;        /* Top file in src location's mounted file hier. */
54
    H5RS_str_t    *src_full_path_r; /* Source location's full path */
55
    H5F_t         *dst_file;        /* Destination location's file */
56
    H5RS_str_t    *dst_full_path_r; /* Destination location's full path */
57
} H5G_names_t;
58
59
/* Info to pass to the iteration function when building name */
60
typedef struct H5G_gnba_iter_t {
61
    /* In */
62
    const H5O_loc_t *loc; /* The location of the object we're looking for */
63
64
    /* Out */
65
    char *path; /* Name of the object */
66
} H5G_gnba_iter_t;
67
68
/********************/
69
/* Package Typedefs */
70
/********************/
71
72
/********************/
73
/* Local Prototypes */
74
/********************/
75
76
static htri_t      H5G__common_path(const H5RS_str_t *fullpath_r, const H5RS_str_t *prefix_r);
77
static H5RS_str_t *H5G__build_fullpath(const char *prefix, const char *name);
78
static herr_t      H5G__name_move_path(H5RS_str_t **path_r_ptr, const char *full_suffix, const char *src_path,
79
                                       const char *dst_path);
80
static int         H5G__name_replace_cb(void *obj_ptr, hid_t obj_id, void *key);
81
82
/*********************/
83
/* Package Variables */
84
/*********************/
85
86
/*****************************/
87
/* Library Private Variables */
88
/*****************************/
89
90
/*******************/
91
/* Local Variables */
92
/*******************/
93
94
/*-------------------------------------------------------------------------
95
 * Function:  H5G__component
96
 *
97
 * Purpose: Returns the pointer to the first component of the
98
 *    specified name by skipping leading slashes.  Returns
99
 *    the size in characters of the component through SIZE_P not
100
 *    counting leading slashes or the null terminator.
101
 *
102
 * Return:  Success:  Ptr into NAME.
103
 *
104
 *    Failure:  Ptr to the null terminator of NAME.
105
 *
106
 *-------------------------------------------------------------------------
107
 */
108
const char *
109
H5G__component(const char *name, size_t *size_p)
110
944
{
111
944
    FUNC_ENTER_PACKAGE_NOERR
112
113
944
    assert(name);
114
115
1.08k
    while ('/' == *name)
116
138
        name++;
117
944
    if (size_p)
118
802
        *size_p = strcspn(name, "/");
119
120
944
    FUNC_LEAVE_NOAPI(name)
121
944
} /* end H5G__component() */
122
123
/*-------------------------------------------------------------------------
124
 * Function:  H5G_normalize
125
 *
126
 * Purpose: Returns a pointer to a new string which has duplicate and
127
 *              trailing slashes removed from it.
128
 *
129
 * Return:  Success:  Ptr to normalized name.
130
 *    Failure:  NULL
131
 *
132
 *-------------------------------------------------------------------------
133
 */
134
char *
135
H5G_normalize(const char *name)
136
0
{
137
0
    char    *norm;             /* Pointer to the normalized string */
138
0
    size_t   s, d;             /* Positions within the strings */
139
0
    unsigned last_slash;       /* Flag to indicate last character was a slash */
140
0
    char    *ret_value = NULL; /* Return value */
141
142
0
    FUNC_ENTER_NOAPI_NOINIT
143
144
    /* Sanity check */
145
0
    assert(name);
146
147
    /* Duplicate the name, to return */
148
0
    if (NULL == (norm = H5MM_strdup(name)))
149
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for normalized string");
150
151
    /* Walk through the characters, omitting duplicated '/'s */
152
0
    s = d      = 0;
153
0
    last_slash = 0;
154
0
    while (name[s] != '\0') {
155
0
        if (name[s] == '/')
156
0
            if (last_slash)
157
0
                ;
158
0
            else {
159
0
                norm[d++]  = name[s];
160
0
                last_slash = 1;
161
0
            } /* end else */
162
0
        else {
163
0
            norm[d++]  = name[s];
164
0
            last_slash = 0;
165
0
        } /* end else */
166
0
        s++;
167
0
    } /* end while */
168
169
    /* Terminate normalized string */
170
0
    norm[d] = '\0';
171
172
    /* Check for final '/' on normalized name & eliminate it */
173
0
    if (d > 1 && last_slash)
174
0
        norm[d - 1] = '\0';
175
176
    /* Set return value */
177
0
    ret_value = norm;
178
179
0
done:
180
0
    FUNC_LEAVE_NOAPI(ret_value)
181
0
} /* end H5G_normalize() */
182
183
/*-------------------------------------------------------------------------
184
 * Function: H5G__common_path
185
 *
186
 * Purpose: Determine if one path is a valid prefix of another path
187
 *
188
 * Return: true for valid prefix, false for not a valid prefix, FAIL
189
 *              on error
190
 *
191
 *
192
 *-------------------------------------------------------------------------
193
 */
194
static htri_t
195
H5G__common_path(const H5RS_str_t *fullpath_r, const H5RS_str_t *prefix_r)
196
0
{
197
0
    const char *fullpath;          /* Pointer to actual fullpath string */
198
0
    const char *prefix;            /* Pointer to actual prefix string */
199
0
    size_t      nchars1, nchars2;  /* Number of characters in components */
200
0
    htri_t      ret_value = false; /* Return value */
201
202
0
    FUNC_ENTER_PACKAGE_NOERR
203
204
    /* Get component of each name */
205
0
    fullpath = H5RS_get_str(fullpath_r);
206
0
    assert(fullpath);
207
0
    fullpath = H5G__component(fullpath, &nchars1);
208
0
    assert(fullpath);
209
0
    prefix = H5RS_get_str(prefix_r);
210
0
    assert(prefix);
211
0
    prefix = H5G__component(prefix, &nchars2);
212
0
    assert(prefix);
213
214
    /* Check if we have a real string for each component */
215
0
    while (*fullpath && *prefix) {
216
        /* Check that the components we found are the same length */
217
0
        if (nchars1 == nchars2) {
218
            /* Check that the two components are equal */
219
0
            if (strncmp(fullpath, prefix, nchars1) == 0) {
220
                /* Advance the pointers in the names */
221
0
                fullpath += nchars1;
222
0
                prefix += nchars2;
223
224
                /* Get next component of each name */
225
0
                fullpath = H5G__component(fullpath, &nchars1);
226
0
                assert(fullpath);
227
0
                prefix = H5G__component(prefix, &nchars2);
228
0
                assert(prefix);
229
0
            } /* end if */
230
0
            else
231
0
                HGOTO_DONE(false);
232
0
        } /* end if */
233
0
        else
234
0
            HGOTO_DONE(false);
235
0
    } /* end while */
236
237
    /* If we reached the end of the prefix path to check, it must be a valid prefix */
238
0
    if (*prefix == '\0')
239
0
        ret_value = true;
240
241
0
done:
242
0
    FUNC_LEAVE_NOAPI(ret_value)
243
0
} /* end H5G__common_path() */
244
245
/*-------------------------------------------------------------------------
246
 * Function: H5G__build_fullpath
247
 *
248
 * Purpose: Build a full path from a prefix & base pair of strings
249
 *
250
 * Return: Pointer to reference counted string on success, NULL on error
251
 *
252
 *-------------------------------------------------------------------------
253
 */
254
static H5RS_str_t *
255
H5G__build_fullpath(const char *prefix, const char *name)
256
280
{
257
280
    H5RS_str_t *ret_value = NULL; /* Return value */
258
259
280
    FUNC_ENTER_PACKAGE
260
261
    /* Sanity check */
262
280
    assert(prefix);
263
280
    assert(name);
264
265
    /* Create full path */
266
280
    if (NULL == (ret_value = H5RS_create(prefix)))
267
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTCREATE, NULL, "can't create ref-counted string");
268
280
    if (prefix[strlen(prefix) - 1] != '/')
269
30
        H5RS_aputc(ret_value, '/'); /* Add separator, if the prefix doesn't end in one */
270
280
    H5RS_acat(ret_value, name);
271
272
280
done:
273
280
    FUNC_LEAVE_NOAPI(ret_value)
274
280
} /* end H5G__build_fullpath() */
275
276
/*-------------------------------------------------------------------------
277
 * Function:  H5G_build_fullpath_refstr_str
278
 *
279
 * Purpose:     Append an object path to an existing ref-counted path
280
 *
281
 * Return:  Success:  Non-NULL, combined path
282
 *    Failure:  NULL
283
 *
284
 *-------------------------------------------------------------------------
285
 */
286
H5RS_str_t *
287
H5G_build_fullpath_refstr_str(H5RS_str_t *prefix_r, const char *name)
288
280
{
289
280
    const char *prefix;           /* Pointer to raw string for path */
290
280
    H5RS_str_t *ret_value = NULL; /* Return value */
291
292
280
    FUNC_ENTER_NOAPI_NOINIT_NOERR
293
294
280
    assert(prefix_r);
295
280
    assert(name);
296
297
    /* Get the raw string for the user path */
298
280
    prefix = H5RS_get_str(prefix_r);
299
280
    assert(prefix);
300
301
    /* Create reference counted string for path */
302
280
    ret_value = H5G__build_fullpath(prefix, name);
303
304
280
    FUNC_LEAVE_NOAPI(ret_value)
305
280
} /* end H5G_build_fullpath_refstr_str() */
306
307
/*-------------------------------------------------------------------------
308
 * Function:    H5G__name_init
309
 *
310
 * Purpose:     Set the initial path for a group hierarchy name
311
 *
312
 * Return:  Success:  Non-negative
313
 *    Failure:  Negative
314
 *
315
 *-------------------------------------------------------------------------
316
 */
317
herr_t
318
H5G__name_init(H5G_name_t *name, const char *path)
319
7
{
320
7
    FUNC_ENTER_PACKAGE_NOERR
321
322
    /* Check arguments */
323
7
    assert(name);
324
325
    /* Set the initial paths for a name object */
326
7
    name->full_path_r = H5RS_create(path);
327
7
    assert(name->full_path_r);
328
7
    name->user_path_r = H5RS_create(path);
329
7
    assert(name->user_path_r);
330
7
    name->obj_hidden = 0;
331
332
7
    FUNC_LEAVE_NOAPI(SUCCEED)
333
7
} /* end H5G__name_init() */
334
335
/*-------------------------------------------------------------------------
336
 * Function:  H5G_name_set
337
 *
338
 * Purpose:     Set the name of a symbol entry OBJ, located at LOC
339
 *
340
 * Return:  Success:  Non-negative
341
 *    Failure:  Negative
342
 *
343
 *-------------------------------------------------------------------------
344
 */
345
herr_t
346
H5G_name_set(const H5G_name_t *loc, H5G_name_t *obj, const char *name)
347
140
{
348
140
    herr_t ret_value = SUCCEED;
349
350
140
    FUNC_ENTER_NOAPI(FAIL)
351
352
140
    assert(loc);
353
140
    assert(obj);
354
140
    assert(name);
355
356
    /* Free & reset the object's previous paths info (if they exist) */
357
140
    H5G_name_free(obj);
358
359
    /* Create the object's full path, if a full path exists in the location */
360
140
    if (loc->full_path_r) {
361
        /* Go build the new full path */
362
140
        if ((obj->full_path_r = H5G_build_fullpath_refstr_str(loc->full_path_r, name)) == NULL)
363
0
            HGOTO_ERROR(H5E_SYM, H5E_PATH, FAIL, "can't build user path name");
364
140
    } /* end if */
365
366
    /* Create the object's user path, if a user path exists in the location */
367
140
    if (loc->user_path_r) {
368
        /* Go build the new user path */
369
140
        if ((obj->user_path_r = H5G_build_fullpath_refstr_str(loc->user_path_r, name)) == NULL)
370
0
            HGOTO_ERROR(H5E_SYM, H5E_PATH, FAIL, "can't build user path name");
371
140
    } /* end if */
372
373
140
done:
374
140
    FUNC_LEAVE_NOAPI(ret_value)
375
140
} /* end H5G_name_set() */
376
377
/*-------------------------------------------------------------------------
378
 * Function:    H5G_name_copy
379
 *
380
 * Purpose:     Do a copy of group hier. names
381
 *
382
 * Return:  Success:  Non-negative
383
 *    Failure:  Negative
384
 *
385
 * Notes:       'depth' parameter determines how much of the group entry
386
 *              structure we want to copy.  The depths are:
387
 *                  H5_COPY_SHALLOW - Copy all the fields from the source
388
 *                      to the destination, including the user path and
389
 *                      canonical path. (Destination "takes ownership" of
390
 *                      user and canonical paths)
391
 *                  H5_COPY_DEEP - Copy all the fields from the source to
392
 *                      the destination, deep copying the user and canonical
393
 *                      paths.
394
 *
395
 *-------------------------------------------------------------------------
396
 */
397
herr_t
398
H5G_name_copy(H5G_name_t *dst, const H5G_name_t *src, H5_copy_depth_t depth)
399
1.13k
{
400
1.13k
    FUNC_ENTER_NOAPI_NOINIT_NOERR
401
402
    /* Check arguments */
403
1.13k
    assert(src);
404
1.13k
    assert(dst);
405
#if defined(H5_USING_MEMCHECKER) || !defined(NDEBUG)
406
    assert(dst->full_path_r == NULL);
407
    assert(dst->user_path_r == NULL);
408
#endif /* H5_USING_MEMCHECKER */
409
1.13k
    assert(depth == H5_COPY_SHALLOW || depth == H5_COPY_DEEP);
410
411
    /* Copy the top level information */
412
1.13k
    H5MM_memcpy(dst, src, sizeof(H5G_name_t));
413
414
    /* Deep copy the names */
415
1.13k
    if (depth == H5_COPY_DEEP) {
416
669
        dst->full_path_r = H5RS_dup(src->full_path_r);
417
669
        dst->user_path_r = H5RS_dup(src->user_path_r);
418
669
    }
419
467
    else {
420
467
        H5_GCC_CLANG_DIAG_OFF("cast-qual")
421
467
        H5G_name_reset((H5G_name_t *)src);
422
467
        H5_GCC_CLANG_DIAG_ON("cast-qual")
423
467
    }
424
425
1.13k
    FUNC_LEAVE_NOAPI(SUCCEED)
426
1.13k
} /* end H5G_name_copy() */
427
428
/*-------------------------------------------------------------------------
429
 * Function:    H5G_get_name
430
 *
431
 * Purpose:     Gets a name of an object from its ID.
432
 *
433
 * Notes: Internal routine for H5Iget_name().
434
435
 * Return:  Success:  Non-negative, length of name
436
 *    Failure:  Negative
437
 *
438
 *-------------------------------------------------------------------------
439
 */
440
herr_t
441
H5G_get_name(const H5G_loc_t *loc, char *name /*out*/, size_t size, size_t *name_len, bool *cached)
442
0
{
443
0
    herr_t ret_value = SUCCEED; /* Return value */
444
445
0
    FUNC_ENTER_NOAPI(FAIL)
446
447
    /* Sanity check */
448
0
    assert(loc);
449
450
    /* If the user path is available and it's not "hidden", use it */
451
0
    if (loc->path->user_path_r != NULL && loc->path->obj_hidden == 0) {
452
0
        size_t len; /* Length of object's name */
453
454
0
        len = H5RS_len(loc->path->user_path_r);
455
456
0
        if (name) {
457
0
            strncpy(name, H5RS_get_str(loc->path->user_path_r), MIN((len + 1), size));
458
0
            if (len >= size)
459
0
                name[size - 1] = '\0';
460
0
        } /* end if */
461
462
        /* Set name length, if requested */
463
0
        if (name_len)
464
0
            *name_len = len;
465
466
        /* Indicate that the name is cached, if requested */
467
        /* (Currently only used for testing - QAK, 2010/07/26) */
468
0
        if (cached)
469
0
            *cached = true;
470
0
    } /* end if */
471
0
    else if (!loc->path->obj_hidden) {
472
        /* Search for name of object */
473
0
        if (H5G_get_name_by_addr(loc->oloc->file, loc->oloc, name, size, name_len) < 0)
474
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't determine name");
475
476
        /* Indicate that the name is _not_ cached, if requested */
477
        /* (Currently only used for testing - QAK, 2010/07/26) */
478
0
        if (cached)
479
0
            *cached = false;
480
0
    } /* end else */
481
482
0
done:
483
0
    FUNC_LEAVE_NOAPI(ret_value)
484
0
} /* end H5G_get_name() */
485
486
/*-------------------------------------------------------------------------
487
 * Function:  H5G_name_reset
488
 *
489
 * Purpose: Reset a group hierarchy name to an empty state
490
 *
491
 * Return:  Success:  Non-negative
492
 *    Failure:  Negative
493
 *
494
 *-------------------------------------------------------------------------
495
 */
496
herr_t
497
H5G_name_reset(H5G_name_t *name)
498
2.00k
{
499
2.00k
    FUNC_ENTER_NOAPI_NOINIT_NOERR
500
501
    /* Check arguments */
502
2.00k
    assert(name);
503
504
    /* Clear the group hier. name to an empty state */
505
2.00k
    memset(name, 0, sizeof(H5G_name_t));
506
507
2.00k
    FUNC_LEAVE_NOAPI(SUCCEED)
508
2.00k
} /* end H5G_name_reset() */
509
510
/*-------------------------------------------------------------------------
511
 * Function:  H5G_name_free
512
 *
513
 * Purpose: Free the 'ID to name' buffers.
514
 *
515
 * Return:  Success
516
 *
517
 *-------------------------------------------------------------------------
518
 */
519
herr_t
520
H5G_name_free(H5G_name_t *name)
521
1.72k
{
522
1.72k
    FUNC_ENTER_NOAPI_NOINIT_NOERR
523
524
    /* Check args */
525
1.72k
    assert(name);
526
527
1.72k
    if (name->full_path_r) {
528
716
        H5RS_decr(name->full_path_r);
529
716
        name->full_path_r = NULL;
530
716
    } /* end if */
531
1.72k
    if (name->user_path_r) {
532
716
        H5RS_decr(name->user_path_r);
533
716
        name->user_path_r = NULL;
534
716
    } /* end if */
535
1.72k
    name->obj_hidden = 0;
536
537
1.72k
    FUNC_LEAVE_NOAPI(SUCCEED)
538
1.72k
} /* end H5G_name_free() */
539
540
/*-------------------------------------------------------------------------
541
 * Function:    H5G__name_move_path
542
 *
543
 * Purpose:     Update a user or canonical path after an object moves
544
 *
545
 * Return:  Success:  Non-negative
546
 *    Failure:  Negative
547
 *
548
 *-------------------------------------------------------------------------
549
 */
550
static herr_t
551
H5G__name_move_path(H5RS_str_t **path_r_ptr, const char *full_suffix, const char *src_path,
552
                    const char *dst_path)
553
0
{
554
0
    const char *path;                /* Path to update */
555
0
    size_t      path_len;            /* Length of path */
556
0
    size_t      full_suffix_len;     /* Length of full suffix */
557
0
    herr_t      ret_value = SUCCEED; /* Return value */
558
559
0
    FUNC_ENTER_PACKAGE
560
561
    /* Check arguments */
562
0
    assert(path_r_ptr && *path_r_ptr);
563
0
    assert(full_suffix);
564
0
    assert(src_path);
565
0
    assert(dst_path);
566
567
    /* Get pointer to path to update */
568
0
    path = H5RS_get_str(*path_r_ptr);
569
0
    assert(path);
570
571
    /* Check if path needs to be updated */
572
0
    full_suffix_len = strlen(full_suffix);
573
0
    path_len        = strlen(path);
574
0
    if (full_suffix_len < path_len) {
575
0
        const char *dst_suffix;        /* Destination suffix that changes */
576
0
        const char *src_suffix;        /* Source suffix that changes */
577
0
        size_t      path_prefix_len;   /* Length of path prefix */
578
0
        const char *path_prefix2;      /* 2nd prefix for path */
579
0
        size_t      path_prefix2_len;  /* Length of 2nd path prefix */
580
0
        size_t      common_prefix_len; /* Length of common prefix */
581
0
        H5RS_str_t *rs;                /* Ref-counted string for new path */
582
583
        /* Compute path prefix before full suffix */
584
0
        path_prefix_len = path_len - full_suffix_len;
585
586
        /* Determine the common prefix for src & dst paths */
587
0
        common_prefix_len = 0;
588
        /* Find first character that is different */
589
0
        while (*(src_path + common_prefix_len) == *(dst_path + common_prefix_len))
590
0
            common_prefix_len++;
591
        /* Back up to previous '/' */
592
0
        while (*(src_path + common_prefix_len) != '/')
593
0
            common_prefix_len--;
594
        /* Include '/' */
595
0
        common_prefix_len++;
596
597
        /* Determine source suffix */
598
0
        src_suffix = src_path + (common_prefix_len - 1);
599
600
        /* Determine destination suffix */
601
0
        dst_suffix = dst_path + (common_prefix_len - 1);
602
603
        /* Compute path prefix before src suffix */
604
0
        path_prefix2     = path;
605
0
        path_prefix2_len = path_prefix_len - strlen(src_suffix);
606
607
        /* Allocate new ref-counted string */
608
0
        if (NULL == (rs = H5RS_create(NULL)))
609
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTCREATE, FAIL, "can't create ref-counted string");
610
611
        /* Create the new path */
612
0
        if (path_prefix2_len > 0)
613
0
            H5RS_ancat(rs, path_prefix2, path_prefix2_len);
614
0
        H5RS_acat(rs, dst_suffix);
615
0
        if (full_suffix_len > 0)
616
0
            H5RS_acat(rs, full_suffix);
617
618
        /* Release previous path */
619
0
        H5RS_decr(*path_r_ptr);
620
621
        /* Take ownership of the new full path */
622
0
        *path_r_ptr = rs;
623
0
    } /* end if */
624
625
0
done:
626
0
    FUNC_LEAVE_NOAPI(ret_value)
627
0
} /* end H5G__name_move_path() */
628
629
/*-------------------------------------------------------------------------
630
 * Function: H5G__name_replace_cb
631
 *
632
 * Purpose: H5I_iterate callback function to replace group entry names
633
 *
634
 * Return: Success: 0, Failure: -1
635
 *
636
 *-------------------------------------------------------------------------
637
 */
638
static int
639
H5G__name_replace_cb(void *obj_ptr, hid_t obj_id, void *key)
640
0
{
641
0
    const H5G_names_t *names = (const H5G_names_t *)key; /* Get operation's information */
642
0
    H5O_loc_t         *oloc;         /* Object location for object that the ID refers to */
643
0
    H5G_name_t        *obj_path;     /* Pointer to group hier. path for obj */
644
0
    H5F_t             *top_obj_file; /* Top file in object's mounted file hier. */
645
0
    bool   obj_in_child = false;     /* Flag to indicate that the object is in the child mount hier. */
646
0
    herr_t ret_value    = SUCCEED;   /* Return value */
647
648
0
    FUNC_ENTER_PACKAGE
649
650
0
    assert(obj_ptr);
651
652
    /* Get the symbol table entry */
653
0
    switch (H5I_get_type(obj_id)) {
654
0
        case H5I_GROUP:
655
0
            oloc     = H5G_oloc((H5G_t *)obj_ptr);
656
0
            obj_path = H5G_nameof((H5G_t *)obj_ptr);
657
0
            break;
658
659
0
        case H5I_DATASET:
660
0
            oloc     = H5D_oloc((H5D_t *)obj_ptr);
661
0
            obj_path = H5D_nameof((H5D_t *)obj_ptr);
662
0
            break;
663
664
0
        case H5I_DATATYPE:
665
            /* Avoid non-named datatypes */
666
0
            if (!H5T_is_named((H5T_t *)obj_ptr))
667
0
                HGOTO_DONE(SUCCEED); /* Do not exit search over IDs */
668
669
0
            oloc     = H5T_oloc((H5T_t *)obj_ptr);
670
0
            obj_path = H5T_nameof((H5T_t *)obj_ptr);
671
0
            break;
672
673
0
        case H5I_MAP:
674
0
            HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "maps not supported in native VOL connector");
675
676
0
        case H5I_UNINIT:
677
0
        case H5I_BADID:
678
0
        case H5I_FILE:
679
0
        case H5I_DATASPACE:
680
0
        case H5I_ATTR:
681
0
        case H5I_VFL:
682
0
        case H5I_VOL:
683
0
        case H5I_GENPROP_CLS:
684
0
        case H5I_GENPROP_LST:
685
0
        case H5I_ERROR_CLASS:
686
0
        case H5I_ERROR_MSG:
687
0
        case H5I_ERROR_STACK:
688
0
        case H5I_SPACE_SEL_ITER:
689
0
        case H5I_EVENTSET:
690
0
        case H5I_NTYPES:
691
0
        default:
692
0
            HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "unknown data object");
693
0
    } /* end switch */
694
0
    assert(oloc);
695
0
    assert(obj_path);
696
697
    /* Check if the object has a full path still */
698
0
    if (!obj_path->full_path_r)
699
0
        HGOTO_DONE(SUCCEED); /* No need to look at object, it's path is already invalid */
700
701
    /* Find the top file in object's mount hier. */
702
0
    if (H5F_PARENT(oloc->file)) {
703
        /* Check if object is in child file (for mount & unmount operations) */
704
0
        if (names->dst_file && H5F_SAME_SHARED(oloc->file, names->dst_file))
705
0
            obj_in_child = true;
706
707
        /* Find the "top" file in the chain of mounted files */
708
0
        top_obj_file = H5F_PARENT(oloc->file);
709
0
        while (H5F_PARENT(top_obj_file) != NULL) {
710
            /* Check if object is in child mount hier. (for mount & unmount operations) */
711
0
            if (names->dst_file && H5F_SAME_SHARED(top_obj_file, names->dst_file))
712
0
                obj_in_child = true;
713
714
0
            top_obj_file = H5F_PARENT(top_obj_file);
715
0
        } /* end while */
716
0
    }     /* end if */
717
0
    else
718
0
        top_obj_file = oloc->file;
719
720
    /* Check if object is in top of child mount hier. (for mount & unmount operations) */
721
0
    if (names->dst_file && H5F_SAME_SHARED(top_obj_file, names->dst_file))
722
0
        obj_in_child = true;
723
724
    /* Check if the object is in same file mount hier. */
725
0
    if (!H5F_SAME_SHARED(top_obj_file, names->src_file))
726
0
        HGOTO_DONE(SUCCEED); /* No need to look at object, it's path is already invalid */
727
728
0
    switch (names->op) {
729
        /*-------------------------------------------------------------------------
730
         * H5G_NAME_MOUNT
731
         *-------------------------------------------------------------------------
732
         */
733
0
        case H5G_NAME_MOUNT:
734
            /* Check if object is in child mount hier. */
735
0
            if (obj_in_child) {
736
0
                const char *full_path; /* Full path of current object */
737
0
                const char *src_path;  /* Full path of source object */
738
0
                H5RS_str_t *rs;        /* Ref-counted string for new path */
739
740
                /* Get pointers to paths of interest */
741
0
                full_path = H5RS_get_str(obj_path->full_path_r);
742
0
                src_path  = H5RS_get_str(names->src_full_path_r);
743
744
                /* Create new full path */
745
0
                if (NULL == (rs = H5RS_create(src_path)))
746
0
                    HGOTO_ERROR(H5E_SYM, H5E_CANTCREATE, FAIL, "can't create ref-counted string");
747
0
                H5RS_acat(rs, full_path);
748
749
                /* Release previous full path */
750
0
                H5RS_decr(obj_path->full_path_r);
751
752
                /* Take ownership of the new full path */
753
0
                obj_path->full_path_r = rs;
754
0
            } /* end if */
755
            /* Object must be in parent mount file hier. */
756
0
            else {
757
                /* Check if the source is along the entry's path */
758
                /* (But not actually the entry itself) */
759
0
                if (H5G__common_path(obj_path->full_path_r, names->src_full_path_r) &&
760
0
                    H5RS_cmp(obj_path->full_path_r, names->src_full_path_r)) {
761
                    /* Hide the user path */
762
0
                    (obj_path->obj_hidden)++;
763
0
                } /* end if */
764
0
            }     /* end else */
765
0
            break;
766
767
        /*-------------------------------------------------------------------------
768
         * H5G_NAME_UNMOUNT
769
         *-------------------------------------------------------------------------
770
         */
771
0
        case H5G_NAME_UNMOUNT:
772
0
            if (obj_in_child) {
773
0
                const char *full_path;   /* Full path of current object */
774
0
                const char *full_suffix; /* Full path after source path */
775
0
                const char *src_path;    /* Full path of source object */
776
0
                H5RS_str_t *rs;          /* Ref-counted string for new path */
777
778
                /* Get pointers to paths of interest */
779
0
                full_path = H5RS_get_str(obj_path->full_path_r);
780
0
                src_path  = H5RS_get_str(names->src_full_path_r);
781
782
                /* Construct full path suffix */
783
0
                full_suffix = full_path + strlen(src_path);
784
785
                /* Create new full path suffix */
786
0
                if (NULL == (rs = H5RS_create(full_suffix)))
787
0
                    HGOTO_ERROR(H5E_SYM, H5E_CANTCREATE, FAIL, "can't create ref-counted string");
788
789
                /* Release previous full path */
790
0
                H5RS_decr(obj_path->full_path_r);
791
792
                /* Take ownership of the new full path */
793
0
                obj_path->full_path_r = rs;
794
795
                /* Check if the object's user path should be invalidated */
796
0
                if (obj_path->user_path_r && H5RS_len(rs) < H5RS_len(obj_path->user_path_r)) {
797
                    /* Free user path */
798
0
                    H5RS_decr(obj_path->user_path_r);
799
0
                    obj_path->user_path_r = NULL;
800
0
                } /* end if */
801
0
            }     /* end if */
802
0
            else {
803
                /* Check if file being unmounted was hiding the object */
804
0
                if (H5G__common_path(obj_path->full_path_r, names->src_full_path_r) &&
805
0
                    H5RS_cmp(obj_path->full_path_r, names->src_full_path_r)) {
806
                    /* Un-hide the user path */
807
0
                    (obj_path->obj_hidden)--;
808
0
                } /* end if */
809
0
            }     /* end else */
810
0
            break;
811
812
        /*-------------------------------------------------------------------------
813
         * H5G_NAME_DELETE
814
         *-------------------------------------------------------------------------
815
         */
816
0
        case H5G_NAME_DELETE:
817
            /* Check if the location being unlinked is in the path for the current object */
818
0
            if (H5G__common_path(obj_path->full_path_r, names->src_full_path_r)) {
819
                /* Free paths for object */
820
0
                H5G_name_free(obj_path);
821
0
            } /* end if */
822
0
            break;
823
824
        /*-------------------------------------------------------------------------
825
         * H5G_NAME_MOVE
826
         *-------------------------------------------------------------------------
827
         */
828
0
        case H5G_NAME_MOVE: /* Link move case, check for relative names case */
829
            /* Check if the src object moved is in the current object's path */
830
0
            if (H5G__common_path(obj_path->full_path_r, names->src_full_path_r)) {
831
0
                const char *full_path;   /* Full path of current object */
832
0
                const char *full_suffix; /* Suffix of full path, after src_path */
833
0
                const char *src_path;    /* Full path of source object */
834
0
                const char *dst_path;    /* Full path of destination object */
835
0
                H5RS_str_t *rs;          /* Ref-counted string for new path */
836
837
                /* Sanity check */
838
0
                assert(names->dst_full_path_r);
839
840
                /* Get pointers to paths of interest */
841
0
                full_path = H5RS_get_str(obj_path->full_path_r);
842
0
                src_path  = H5RS_get_str(names->src_full_path_r);
843
0
                dst_path  = H5RS_get_str(names->dst_full_path_r);
844
845
                /* Make certain that the source and destination names are full (not relative) paths */
846
0
                assert(*src_path == '/');
847
0
                assert(*dst_path == '/');
848
849
                /* Get pointer to "full suffix" */
850
0
                full_suffix = full_path + strlen(src_path);
851
852
                /* Update the user path, if one exists */
853
0
                if (obj_path->user_path_r)
854
0
                    if (H5G__name_move_path(&(obj_path->user_path_r), full_suffix, src_path, dst_path) < 0)
855
0
                        HGOTO_ERROR(H5E_SYM, H5E_PATH, FAIL, "can't build user path name");
856
857
                /* Create new full path */
858
0
                if (NULL == (rs = H5RS_create(dst_path)))
859
0
                    HGOTO_ERROR(H5E_SYM, H5E_CANTCREATE, FAIL, "can't create ref-counted string");
860
0
                H5RS_acat(rs, full_suffix);
861
862
                /* Release previous full path */
863
0
                H5RS_decr(obj_path->full_path_r);
864
865
                /* Take ownership of the new full path */
866
0
                obj_path->full_path_r = rs;
867
0
            } /* end if */
868
0
            break;
869
870
0
        default:
871
0
            HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid operation");
872
0
    } /* end switch */
873
874
0
done:
875
0
    FUNC_LEAVE_NOAPI(ret_value)
876
0
} /* end H5G__name_replace_cb() */
877
878
/*-------------------------------------------------------------------------
879
 * Function: H5G_name_replace
880
 *
881
 * Purpose: Search the list of open IDs and replace names according to a
882
 *              particular operation.  The operation occurred on the
883
 *              SRC_FILE/SRC_FULL_PATH_R object.  The new name (if there is
884
 *              one) is NEW_NAME_R.  Additional entry location information
885
 *              (currently only needed for the 'move' operation) is passed in
886
 *              DST_FILE/DST_FULL_PATH_R.
887
 *
888
 * Return: Success: 0, Failure: -1
889
 *
890
 *-------------------------------------------------------------------------
891
 */
892
herr_t
893
H5G_name_replace(const H5O_link_t *lnk, H5G_names_op_t op, H5F_t *src_file, H5RS_str_t *src_full_path_r,
894
                 H5F_t *dst_file, H5RS_str_t *dst_full_path_r)
895
0
{
896
0
    herr_t ret_value = SUCCEED;
897
898
0
    FUNC_ENTER_NOAPI(FAIL)
899
900
    /* Check arguments */
901
0
    assert(src_file);
902
903
    /* Check if the object we are manipulating has a path */
904
0
    if (src_full_path_r) {
905
0
        bool search_group    = false; /* Flag to indicate that groups are to be searched */
906
0
        bool search_dataset  = false; /* Flag to indicate that datasets are to be searched */
907
0
        bool search_datatype = false; /* Flag to indicate that datatypes are to be searched */
908
909
        /* Check for particular link to operate on */
910
0
        if (lnk) {
911
            /* Look up the object type for each type of link */
912
0
            switch (lnk->type) {
913
0
                case H5L_TYPE_HARD: {
914
0
                    H5O_loc_t  tmp_oloc; /* Temporary object location */
915
0
                    H5O_type_t obj_type; /* Type of object at location */
916
917
                    /* Build temporary object location */
918
0
                    tmp_oloc.file = src_file;
919
0
                    tmp_oloc.addr = lnk->u.hard.addr;
920
921
                    /* Get the type of the object */
922
0
                    if (H5O_obj_type(&tmp_oloc, &obj_type) < 0)
923
0
                        HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't get object type");
924
925
                    /* Determine which type of objects to operate on */
926
0
                    switch (obj_type) {
927
0
                        case H5O_TYPE_GROUP:
928
                            /* Search and replace names through group IDs */
929
0
                            search_group = true;
930
0
                            break;
931
932
0
                        case H5O_TYPE_DATASET:
933
                            /* Search and replace names through dataset IDs */
934
0
                            search_dataset = true;
935
0
                            break;
936
937
0
                        case H5O_TYPE_NAMED_DATATYPE:
938
                            /* Search and replace names through datatype IDs */
939
0
                            search_datatype = true;
940
0
                            break;
941
942
0
                        case H5O_TYPE_MAP:
943
0
                            HGOTO_ERROR(H5E_SYM, H5E_BADTYPE, FAIL,
944
0
                                        "maps not supported in native VOL connector");
945
946
0
                        case H5O_TYPE_UNKNOWN:
947
0
                        case H5O_TYPE_NTYPES:
948
                            /* Search and replace names through datatype IDs */
949
0
                        default:
950
0
                            HGOTO_ERROR(H5E_SYM, H5E_BADTYPE, FAIL, "not valid object type");
951
0
                    } /* end switch */
952
0
                }     /* end case */
953
0
                break;
954
955
0
                case H5L_TYPE_SOFT:
956
                    /* Symbolic links might resolve to any object, so we need to search all IDs */
957
0
                    search_group = search_dataset = search_datatype = true;
958
0
                    break;
959
960
0
                case H5L_TYPE_ERROR:
961
0
                case H5L_TYPE_EXTERNAL:
962
0
                case H5L_TYPE_MAX:
963
0
                default: /* User-defined link */
964
                    /* Check for unknown library-defined link type */
965
0
                    if (lnk->type < H5L_TYPE_UD_MIN)
966
0
                        HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "unknown link type");
967
968
                    /* User-defined & external links automatically wipe out
969
                     * names (because it would be too much work to track them),
970
                     * so there's no point in searching them.
971
                     */
972
0
                    break;
973
0
            } /* end switch */
974
0
        }     /* end if */
975
0
        else {
976
            /* We pass NULL as link pointer when we need to search all IDs */
977
0
            search_group = search_dataset = search_datatype = true;
978
0
        }
979
980
        /* Check if we need to operate on the objects affected */
981
0
        if (search_group || search_dataset || search_datatype) {
982
0
            H5G_names_t names; /* Structure to hold operation information for callback */
983
984
            /* Find top file in src location's mount hierarchy */
985
0
            while (H5F_PARENT(src_file))
986
0
                src_file = H5F_PARENT(src_file);
987
988
            /* Set up common information for callback */
989
0
            names.src_file        = src_file;
990
0
            names.src_full_path_r = src_full_path_r;
991
0
            names.dst_file        = dst_file;
992
0
            names.dst_full_path_r = dst_full_path_r;
993
0
            names.op              = op;
994
995
            /* Search through group IDs */
996
0
            if (search_group)
997
0
                if (H5I_iterate(H5I_GROUP, H5G__name_replace_cb, &names, false) < 0)
998
0
                    HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "can't iterate over groups");
999
1000
            /* Search through dataset IDs */
1001
0
            if (search_dataset)
1002
0
                if (H5I_iterate(H5I_DATASET, H5G__name_replace_cb, &names, false) < 0)
1003
0
                    HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "can't iterate over datasets");
1004
1005
            /* Search through datatype IDs */
1006
0
            if (search_datatype)
1007
0
                if (H5I_iterate(H5I_DATATYPE, H5G__name_replace_cb, &names, false) < 0)
1008
0
                    HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "can't iterate over datatypes");
1009
0
        } /* end if */
1010
0
    }     /* end if */
1011
1012
0
done:
1013
0
    FUNC_LEAVE_NOAPI(ret_value)
1014
0
} /* end H5G_name_replace() */
1015
1016
/*-------------------------------------------------------------------------
1017
 * Function:    H5G__get_name_by_addr_cb
1018
 *
1019
 * Purpose:     Callback for retrieving object's name by address
1020
 *
1021
 * Return:      Positive if path is for object desired
1022
 *              0 if not correct object
1023
 *              negative on failure.
1024
 *
1025
 *-------------------------------------------------------------------------
1026
 */
1027
static herr_t
1028
H5G__get_name_by_addr_cb(hid_t gid, const char *path, const H5L_info2_t *linfo, void *_udata)
1029
0
{
1030
0
    H5G_gnba_iter_t *udata = (H5G_gnba_iter_t *)_udata; /* User data for iteration */
1031
0
    H5G_loc_t        obj_loc;                           /* Location of object */
1032
0
    H5G_name_t       obj_path;                          /* Object's group hier. path */
1033
0
    H5O_loc_t        obj_oloc;                          /* Object's object location */
1034
0
    bool             obj_found = false;                 /* Object at 'path' found */
1035
0
    herr_t           ret_value = H5_ITER_CONT;          /* Return value */
1036
1037
0
    FUNC_ENTER_PACKAGE
1038
1039
    /* Sanity check */
1040
0
    assert(path);
1041
0
    assert(linfo);
1042
0
    assert(udata->loc);
1043
0
    assert(udata->path == NULL);
1044
1045
    /* Check for hard link with correct address */
1046
0
    if (linfo->type == H5L_TYPE_HARD) {
1047
0
        haddr_t link_addr;
1048
1049
        /* Retrieve hard link address from VOL token */
1050
0
        if (H5VL_native_token_to_addr(udata->loc->file, H5I_FILE, linfo->u.token, &link_addr) < 0)
1051
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTUNSERIALIZE, FAIL, "can't deserialize object token into address");
1052
1053
0
        if (udata->loc->addr == link_addr) {
1054
0
            H5G_loc_t grp_loc; /* Location of group */
1055
1056
            /* Get group's location */
1057
0
            if (H5G_loc(gid, &grp_loc) < 0)
1058
0
                HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5_ITER_ERROR, "bad group location");
1059
1060
            /* Set up opened object location to fill in */
1061
0
            obj_loc.oloc = &obj_oloc;
1062
0
            obj_loc.path = &obj_path;
1063
0
            H5G_loc_reset(&obj_loc);
1064
1065
            /* Find the object */
1066
0
            if (H5G_loc_find(&grp_loc, path, &obj_loc /*out*/) < 0)
1067
0
                HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, H5_ITER_ERROR, "object not found");
1068
0
            obj_found = true;
1069
1070
            /* Check for object in same file (handles mounted files) */
1071
            /* (re-verify address, in case we traversed a file mount) */
1072
0
            if (udata->loc->addr == obj_loc.oloc->addr && udata->loc->file == obj_loc.oloc->file) {
1073
0
                if (NULL == (udata->path = H5MM_strdup(path)))
1074
0
                    HGOTO_ERROR(H5E_SYM, H5E_CANTALLOC, H5_ITER_ERROR, "can't duplicate path string");
1075
1076
                /* We found a match so we return immediately */
1077
0
                HGOTO_DONE(H5_ITER_STOP);
1078
0
            } /* end if */
1079
0
        }     /* end if */
1080
0
    }         /* end if */
1081
1082
0
done:
1083
0
    if (obj_found && H5G_loc_free(&obj_loc) < 0)
1084
0
        HDONE_ERROR(H5E_SYM, H5E_CANTRELEASE, H5_ITER_ERROR, "can't free location");
1085
1086
0
    FUNC_LEAVE_NOAPI(ret_value)
1087
0
} /* end H5G__get_name_by_addr_cb() */
1088
1089
/*-------------------------------------------------------------------------
1090
 * Function:    H5G_get_name_by_addr
1091
 *
1092
 * Purpose:     Tries to figure out the path to an object from it's address
1093
 *
1094
 * Return:      Success:    Returns size of path name, and copies it into buffer
1095
 *                          pointed to by name if that buffer is big enough.
1096
 *                          0 if it cannot find the path
1097
 *
1098
 *              Failure:    -1
1099
 *
1100
 *-------------------------------------------------------------------------
1101
 */
1102
herr_t
1103
H5G_get_name_by_addr(H5F_t *f, const H5O_loc_t *loc, char *name, size_t size, size_t *name_len)
1104
0
{
1105
0
    H5G_gnba_iter_t udata;               /* User data for iteration  */
1106
0
    size_t          len;                 /* Length of path name */
1107
0
    H5G_loc_t       root_loc;            /* Root group's location    */
1108
0
    bool            found_obj = false;   /* If we found the object   */
1109
0
    herr_t          status;              /* Status from iteration    */
1110
0
    herr_t          ret_value = SUCCEED; /* Return value             */
1111
1112
    /* Portably clear udata struct (before FUNC_ENTER) */
1113
0
    memset(&udata, 0, sizeof(udata));
1114
1115
0
    FUNC_ENTER_NOAPI(FAIL)
1116
1117
    /* Construct a group location for root group of the file */
1118
0
    if (H5G_root_loc(f, &root_loc) < 0)
1119
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't get root group's location");
1120
1121
    /* Check for root group being the object looked for */
1122
0
    if (root_loc.oloc->addr == loc->addr && root_loc.oloc->file == loc->file) {
1123
0
        if (NULL == (udata.path = H5MM_strdup("")))
1124
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTALLOC, FAIL, "can't duplicate path string");
1125
0
        found_obj = true;
1126
0
    } /* end if */
1127
0
    else {
1128
        /* Set up user data for iterator */
1129
0
        udata.loc  = loc;
1130
0
        udata.path = NULL;
1131
1132
        /* Visit all the links in the file */
1133
0
        if ((status = H5G_visit(&root_loc, "/", H5_INDEX_NAME, H5_ITER_NATIVE, H5G__get_name_by_addr_cb,
1134
0
                                &udata)) < 0)
1135
0
            HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "group traversal failed while looking for object name");
1136
0
        else if (status > 0)
1137
0
            found_obj = true;
1138
0
    } /* end else */
1139
1140
    /* Check for finding the object */
1141
0
    if (found_obj) {
1142
        /* Set the length of the full path */
1143
0
        len = strlen(udata.path) + 1; /* Length of path + 1 (for "/") */
1144
1145
        /* If there's a buffer provided, copy into it, up to the limit of its size */
1146
0
        if (name) {
1147
            /* Copy the initial path separator */
1148
0
            strncpy(name, "/", (size_t)2);
1149
1150
            /* Append the rest of the path */
1151
            /* (less one character, for the initial path separator) */
1152
0
            strncat(name, udata.path, (size - 2));
1153
0
            if (len >= size)
1154
0
                name[size - 1] = '\0';
1155
0
        } /* end if */
1156
0
    }     /* end if */
1157
0
    else
1158
0
        len = 0;
1159
1160
    /* Set path name length, if given */
1161
0
    if (name_len)
1162
0
        *name_len = len;
1163
1164
0
done:
1165
    /* Release resources */
1166
0
    H5MM_xfree(udata.path);
1167
1168
0
    FUNC_LEAVE_NOAPI(ret_value)
1169
0
} /* end H5G_get_name_by_addr() */