1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2 * Copyright by The HDF Group. *
3 * Copyright by the Board of Trustees of the University of Illinois. *
4 * All rights reserved. *
5 * *
6 * This file is part of HDF5. The full HDF5 copyright notice, including *
7 * terms governing use, modification, and redistribution, is contained in *
8 * the COPYING file, which can be found at the root of the source code *
9 * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
10 * If you do not have access to either file, you may request a copy from *
11 * help@hdfgroup.org. *
12 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
13
14 /***********************************************************
15 *
16 * Test program: titerate
17 *
18 * Test the Group & Attribute functionality
19 *
20 *************************************************************/
21
22 #include "testhdf5.h"
23 #include "H5srcdir.h"
24
25 #define DATAFILE "titerate.h5"
26
27 /* Number of datasets for group iteration test */
28 #define NDATASETS 50
29
30 /* Number of attributes for attribute iteration test */
31 #define NATTR 50
32
33 /* Number of groups for second group iteration test */
34 #define ITER_NGROUPS 150
35
36 /* General maximum length of names used */
37 #define NAMELEN 80
38
39 /* 1-D dataset with fixed dimensions */
40 #define SPACE1_RANK 1
41 #define SPACE1_DIM1 4
42
43 typedef enum {
44 RET_ZERO,
45 RET_TWO,
46 RET_CHANGE,
47 RET_CHANGE2
48 } iter_enum;
49
50 /* Custom group iteration callback data */
51 typedef struct {
52 char name[NAMELEN]; /* The name of the object */
53 H5O_type_t type; /* The type of the object */
54 iter_enum command; /* The type of return value */
55 } iter_info;
56
57 /* Definition for test_corrupted_attnamelen */
58 #define CORRUPTED_ATNAMELEN_FILE "corrupted_name_len.h5"
59 #define DSET_NAME "image"
60 typedef struct searched_err_t {
61 char message[256];
62 bool found;
63 } searched_err_t;
64
65 /* Call back function for test_corrupted_attnamelen */
66 static int find_err_msg_cb(unsigned n, const H5E_error2_t *err_desc, void *_client_data);
67
68 /* Local functions */
69 int iter_strcmp(const void *s1, const void *s2);
70 int iter_strcmp2(const void *s1, const void *s2);
71 static herr_t liter_cb(hid_t group, const char *name, const H5L_info_t *info,
72 void *op_data);
73 static herr_t liter_cb2(hid_t group, const char *name, const H5L_info_t *info,
74 void *op_data);
75 herr_t aiter_cb(hid_t group, const char *name, const H5A_info_t *ainfo,
76 void *op_data);
77
78 /****************************************************************
79 **
80 ** iter_strcmp(): String comparison routine for qsort
81 **
82 ****************************************************************/
iter_strcmp(const void * s1,const void * s2)83 H5_ATTR_PURE int iter_strcmp(const void *s1, const void *s2)
84 {
85 return(HDstrcmp(*(const char * const *)s1,*(const char * const *)s2));
86 }
87
88 /****************************************************************
89 **
90 ** liter_cb(): Custom link iteration callback routine.
91 **
92 ****************************************************************/
93 static herr_t
liter_cb(hid_t H5_ATTR_UNUSED group,const char * name,const H5L_info_t H5_ATTR_UNUSED * link_info,void * op_data)94 liter_cb(hid_t H5_ATTR_UNUSED group, const char *name, const H5L_info_t H5_ATTR_UNUSED *link_info,
95 void *op_data)
96 {
97 iter_info *info = (iter_info *)op_data;
98 static int count = 0;
99 static int count2 = 0;
100
101 HDstrcpy(info->name, name);
102
103 switch(info->command) {
104 case RET_ZERO:
105 return(0);
106
107 case RET_TWO:
108 return(2);
109
110 case RET_CHANGE:
111 count++;
112 return(count > 10 ? 1 : 0);
113
114 case RET_CHANGE2:
115 count2++;
116 return(count2 > 10 ? 1 : 0);
117
118 default:
119 HDprintf("invalid iteration command");
120 return(-1);
121 } /* end switch */
122 } /* end liter_cb() */
123
124 /****************************************************************
125 **
126 ** test_iter_group(): Test group iteration functionality
127 **
128 ****************************************************************/
129 static void
test_iter_group(hid_t fapl,hbool_t new_format)130 test_iter_group(hid_t fapl, hbool_t new_format)
131 {
132 hid_t file; /* File ID */
133 hid_t dataset; /* Dataset ID */
134 hid_t datatype; /* Common datatype ID */
135 hid_t filespace; /* Common dataspace ID */
136 hid_t root_group,grp; /* Root group ID */
137 int i; /* counting variable */
138 hsize_t idx; /* Index in the group */
139 char name[NAMELEN]; /* temporary name buffer */
140 char *lnames[NDATASETS + 2];/* Names of the links created */
141 char dataset_name[NAMELEN]; /* dataset name */
142 iter_info info; /* Custom iteration information */
143 H5G_info_t ginfo; /* Buffer for querying object's info */
144 herr_t ret; /* Generic return value */
145
146 /* Output message about test being performed */
147 MESSAGE(5, ("Testing Group Iteration Functionality\n"));
148
149 /* Create the test file with the datasets */
150 file = H5Fcreate(DATAFILE, H5F_ACC_TRUNC, H5P_DEFAULT, fapl);
151 CHECK(file, FAIL, "H5Fcreate");
152
153 /* Test iterating over empty group */
154 info.command = RET_ZERO;
155 idx = 0;
156 ret = H5Literate(file, H5_INDEX_NAME, H5_ITER_INC, &idx, liter_cb, &info);
157 VERIFY(ret, SUCCEED, "H5Literate");
158
159 datatype = H5Tcopy(H5T_NATIVE_INT);
160 CHECK(datatype, FAIL, "H5Tcopy");
161
162 filespace=H5Screate(H5S_SCALAR);
163 CHECK(filespace, FAIL, "H5Screate");
164
165 for(i=0; i< NDATASETS; i++) {
166 HDsprintf(name,"Dataset %d",i);
167 dataset = H5Dcreate2(file, name, datatype, filespace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
168 CHECK(dataset, FAIL, "H5Dcreate2");
169
170 /* Keep a copy of the dataset names around for later */
171 lnames[i] = HDstrdup(name);
172 CHECK_PTR(lnames[i], "strdup");
173
174 ret = H5Dclose(dataset);
175 CHECK(ret, FAIL, "H5Dclose");
176 } /* end for */
177
178 /* Create a group and named datatype under root group for testing */
179 grp = H5Gcreate2(file, "grp", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
180 CHECK(ret, FAIL, "H5Gcreate2");
181
182 lnames[NDATASETS] = HDstrdup("grp");
183 CHECK_PTR(lnames[NDATASETS], "strdup");
184
185 ret = H5Tcommit2(file, "dtype", datatype, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
186 CHECK(ret, FAIL, "H5Tcommit2");
187
188 lnames[NDATASETS + 1] = HDstrdup("dtype");
189 CHECK_PTR(lnames[NDATASETS], "strdup");
190
191 /* Close everything up */
192 ret = H5Tclose(datatype);
193 CHECK(ret, FAIL, "H5Tclose");
194
195 ret = H5Gclose(grp);
196 CHECK(ret, FAIL, "H5Gclose");
197
198 ret = H5Sclose(filespace);
199 CHECK(ret, FAIL, "H5Sclose");
200
201 ret = H5Fclose(file);
202 CHECK(ret, FAIL, "H5Fclose");
203
204 /* Sort the dataset names */
205 HDqsort(lnames, (size_t)(NDATASETS + 2), sizeof(char *), iter_strcmp);
206
207
208 /* Iterate through the datasets in the root group in various ways */
209 file = H5Fopen(DATAFILE, H5F_ACC_RDONLY, fapl);
210 CHECK(file, FAIL, "H5Fopen");
211
212 /* These two functions, H5Oget_info_by_idx and H5Lget_name_by_idx, actually
213 * iterate through B-tree for group members in internal library design.
214 */
215 root_group = H5Gopen2(file, "/", H5P_DEFAULT);
216 CHECK(root_group, FAIL, "H5Gopen2");
217
218 ret = H5Gget_info(root_group, &ginfo);
219 CHECK(ret, FAIL, "H5Gget_info");
220 VERIFY(ginfo.nlinks, (NDATASETS + 2), "H5Gget_info");
221
222 for(i = 0; i< (int)ginfo.nlinks; i++) {
223 H5O_info_t oinfo; /* Object info */
224
225 ret = (herr_t)H5Lget_name_by_idx(root_group, ".", H5_INDEX_NAME, H5_ITER_INC, (hsize_t)i, dataset_name, (size_t)NAMELEN, H5P_DEFAULT);
226 CHECK(ret, FAIL, "H5Lget_name_by_idx");
227
228 ret = H5Oget_info_by_idx2(root_group, ".", H5_INDEX_NAME, H5_ITER_INC, (hsize_t)i, &oinfo, H5O_INFO_BASIC, H5P_DEFAULT);
229 CHECK(ret, FAIL, "H5Oget_info_by_idx");
230 } /* end for */
231
232 H5E_BEGIN_TRY {
233 ret = (herr_t)H5Lget_name_by_idx(root_group, ".", H5_INDEX_NAME, H5_ITER_INC, (hsize_t)(NDATASETS+3), dataset_name, (size_t)NAMELEN, H5P_DEFAULT);
234 } H5E_END_TRY;
235 VERIFY(ret, FAIL, "H5Lget_name_by_idx");
236
237 ret = H5Gclose(root_group);
238 CHECK(ret, FAIL, "H5Gclose");
239
240 /* These two functions, H5Oget_info_by_idx and H5Lget_name_by_idx, actually
241 * iterate through B-tree for group members in internal library design.
242 * (Same as test above, but with the file ID instead of opening the root group)
243 */
244 ret = H5Gget_info(file, &ginfo);
245 CHECK(ret, FAIL, "H5Gget_info");
246 VERIFY(ginfo.nlinks, NDATASETS + 2, "H5Gget_info");
247
248 for(i = 0; i< (int)ginfo.nlinks; i++) {
249 H5O_info_t oinfo; /* Object info */
250
251 ret = (herr_t)H5Lget_name_by_idx(file, ".", H5_INDEX_NAME, H5_ITER_INC, (hsize_t)i, dataset_name, (size_t)NAMELEN, H5P_DEFAULT);
252 CHECK(ret, FAIL, "H5Lget_name_by_idx");
253
254 ret = H5Oget_info_by_idx2(file, ".", H5_INDEX_NAME, H5_ITER_INC, (hsize_t)i, &oinfo, H5O_INFO_BASIC, H5P_DEFAULT);
255 CHECK(ret, FAIL, "H5Oget_info_by_idx");
256 } /* end for */
257
258 H5E_BEGIN_TRY {
259 ret = (herr_t)H5Lget_name_by_idx(file, ".", H5_INDEX_NAME, H5_ITER_INC, (hsize_t)(NDATASETS + 3), dataset_name, (size_t)NAMELEN, H5P_DEFAULT);
260 } H5E_END_TRY;
261 VERIFY(ret, FAIL, "H5Lget_name_by_idx");
262
263 /* Test invalid indices for starting iteration */
264 info.command = RET_ZERO;
265 idx = (hsize_t)-1;
266 H5E_BEGIN_TRY {
267 ret = H5Literate(file, H5_INDEX_NAME, H5_ITER_INC, &idx, liter_cb, &info);
268 } H5E_END_TRY;
269 VERIFY(ret, FAIL, "H5Literate");
270
271 /* Test skipping exactly as many entries as in the group */
272 idx = NDATASETS + 2;
273 H5E_BEGIN_TRY {
274 ret = H5Literate(file, H5_INDEX_NAME, H5_ITER_INC, &idx, liter_cb, &info);
275 } H5E_END_TRY;
276 VERIFY(ret, FAIL, "H5Literate");
277
278 /* Test skipping more entries than are in the group */
279 idx = NDATASETS + 3;
280 H5E_BEGIN_TRY {
281 ret = H5Literate(file, H5_INDEX_NAME, H5_ITER_INC, &idx, liter_cb, &info);
282 } H5E_END_TRY;
283 VERIFY(ret, FAIL, "H5Literate");
284
285 /* Test all objects in group, when callback always returns 0 */
286 info.command = RET_ZERO;
287 idx = 0;
288 if((ret = H5Literate(file, H5_INDEX_NAME, H5_ITER_INC, &idx, liter_cb, &info)) > 0)
289 TestErrPrintf("Group iteration function didn't return zero correctly!\n");
290
291 /* Test all objects in group, when callback always returns 1 */
292 /* This also tests the "restarting" ability, because the index changes */
293 info.command = RET_TWO;
294 i = 0;
295 idx = 0;
296 while((ret = H5Literate(file, H5_INDEX_NAME, H5_ITER_INC, &idx, liter_cb, &info)) > 0) {
297 /* Verify return value from iterator gets propagated correctly */
298 VERIFY(ret, 2, "H5Literate");
299
300 /* Increment the number of times "2" is returned */
301 i++;
302
303 /* Verify that the index is the correct value */
304 VERIFY(idx, (hsize_t)i, "H5Literate");
305 if(idx > (NDATASETS + 2))
306 TestErrPrintf("Group iteration function walked too far!\n");
307
308 /* Verify that the correct name is retrieved */
309 if(HDstrcmp(info.name, lnames[(size_t)(idx - 1)]) != 0)
310 TestErrPrintf("Group iteration function didn't return name correctly for link - lnames[%u] = '%s'!\n", (unsigned)(idx - 1), lnames[(size_t)(idx - 1)]);
311 } /* end while */
312 VERIFY(ret, -1, "H5Literate");
313
314 if(i != (NDATASETS + 2))
315 TestErrPrintf("%u: Group iteration function didn't perform multiple iterations correctly!\n", __LINE__);
316
317 /* Test all objects in group, when callback changes return value */
318 /* This also tests the "restarting" ability, because the index changes */
319 info.command = new_format ? RET_CHANGE2 : RET_CHANGE;
320 i = 0;
321 idx = 0;
322 while((ret = H5Literate(file, H5_INDEX_NAME, H5_ITER_INC, &idx, liter_cb, &info)) >= 0) {
323 /* Verify return value from iterator gets propagated correctly */
324 VERIFY(ret, 1, "H5Literate");
325
326 /* Increment the number of times "1" is returned */
327 i++;
328
329 /* Verify that the index is the correct value */
330 VERIFY(idx, (hsize_t)(i + 10), "H5Literate");
331 if(idx > (NDATASETS + 2))
332 TestErrPrintf("Group iteration function walked too far!\n");
333
334 /* Verify that the correct name is retrieved */
335 if(HDstrcmp(info.name, lnames[(size_t)(idx - 1)]) != 0)
336 TestErrPrintf("Group iteration function didn't return name correctly for link - lnames[%u] = '%s'!\n", (unsigned)(idx - 1), lnames[(size_t)(idx - 1)]);
337 } /* end while */
338 VERIFY(ret, -1, "H5Literate");
339
340 if(i != 42 || idx != 52)
341 TestErrPrintf("%u: Group iteration function didn't perform multiple iterations correctly!\n", __LINE__);
342
343 ret = H5Fclose(file);
344 CHECK(ret, FAIL, "H5Fclose");
345
346 /* Free the dataset names */
347 for(i = 0; i< (NDATASETS + 2); i++)
348 HDfree(lnames[i]);
349 } /* test_iter_group() */
350
351 /****************************************************************
352 **
353 ** aiter_cb(): Custom group iteration callback routine.
354 **
355 ****************************************************************/
356 herr_t
aiter_cb(hid_t H5_ATTR_UNUSED group,const char * name,const H5A_info_t H5_ATTR_UNUSED * ainfo,void * op_data)357 aiter_cb(hid_t H5_ATTR_UNUSED group, const char *name, const H5A_info_t H5_ATTR_UNUSED *ainfo,
358 void *op_data)
359 {
360 iter_info *info = (iter_info *)op_data;
361 static int count = 0;
362 static int count2 = 0;
363
364 HDstrcpy(info->name, name);
365
366 switch(info->command) {
367 case RET_ZERO:
368 return(0);
369
370 case RET_TWO:
371 return(2);
372
373 case RET_CHANGE:
374 count++;
375 return(count > 10 ? 1 : 0);
376
377 case RET_CHANGE2:
378 count2++;
379 return(count2 > 10 ? 1 : 0);
380
381 default:
382 HDprintf("invalid iteration command");
383 return(-1);
384 } /* end switch */
385 } /* end aiter_cb() */
386
387 /****************************************************************
388 **
389 ** test_iter_attr(): Test attribute iteration functionality
390 **
391 ****************************************************************/
test_iter_attr(hid_t fapl,hbool_t new_format)392 static void test_iter_attr(hid_t fapl, hbool_t new_format)
393 {
394 hid_t file; /* File ID */
395 hid_t dataset; /* Common Dataset ID */
396 hid_t filespace; /* Common dataspace ID */
397 hid_t attribute; /* Attribute ID */
398 int i; /* counting variable */
399 hsize_t idx; /* Index in the attribute list */
400 char name[NAMELEN]; /* temporary name buffer */
401 char *anames[NATTR]; /* Names of the attributes created */
402 iter_info info; /* Custom iteration information */
403 herr_t ret; /* Generic return value */
404
405 /* Output message about test being performed */
406 MESSAGE(5, ("Testing Attribute Iteration Functionality\n"));
407
408 /* Create the test file with the datasets */
409 file = H5Fcreate(DATAFILE, H5F_ACC_TRUNC, H5P_DEFAULT, fapl);
410 CHECK(file, FAIL, "H5Fcreate");
411
412 filespace = H5Screate(H5S_SCALAR);
413 CHECK(filespace, FAIL, "H5Screate");
414
415 dataset = H5Dcreate2(file, "Dataset", H5T_NATIVE_INT, filespace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
416 CHECK(dataset, FAIL, "H5Dcreate2");
417
418 for(i = 0; i < NATTR; i++) {
419 HDsprintf(name, "Attribute %02d", i);
420 attribute = H5Acreate2(dataset, name, H5T_NATIVE_INT, filespace, H5P_DEFAULT, H5P_DEFAULT);
421 CHECK(attribute, FAIL, "H5Acreate2");
422
423 /* Keep a copy of the attribute names around for later */
424 anames[i] = HDstrdup(name);
425 CHECK_PTR(anames[i], "strdup");
426
427 ret = H5Aclose(attribute);
428 CHECK(ret, FAIL, "H5Aclose");
429 } /* end for */
430
431 /* Close everything up */
432 ret = H5Dclose(dataset);
433 CHECK(ret, FAIL, "H5Dclose");
434
435 ret = H5Sclose(filespace);
436 CHECK(ret, FAIL, "H5Sclose");
437
438 ret = H5Fclose(file);
439 CHECK(ret, FAIL, "H5Fclose");
440
441
442 /* Iterate through the attributes on the dataset in various ways */
443 file = H5Fopen(DATAFILE, H5F_ACC_RDONLY, fapl);
444 CHECK(file, FAIL, "H5Fopen");
445
446 dataset = H5Dopen2(file, "Dataset", H5P_DEFAULT);
447 CHECK(dataset, FAIL, "H5Dopen2");
448
449 /* Test invalid indices for starting iteration */
450 info.command = RET_ZERO;
451
452 /* Test skipping exactly as many attributes as there are */
453 idx = NATTR;
454 H5E_BEGIN_TRY {
455 ret = H5Aiterate2(dataset, H5_INDEX_NAME, H5_ITER_INC, &idx, aiter_cb, &info);
456 } H5E_END_TRY;
457 VERIFY(ret, FAIL, "H5Aiterate2");
458
459 /* Test skipping more attributes than there are */
460 idx = NATTR + 1;
461 H5E_BEGIN_TRY {
462 ret = H5Aiterate2(dataset, H5_INDEX_NAME, H5_ITER_INC, &idx, aiter_cb, &info);
463 } H5E_END_TRY;
464 VERIFY(ret, FAIL, "H5Aiterate2");
465
466 /* Test all attributes on dataset, when callback always returns 0 */
467 info.command = RET_ZERO;
468 idx = 0;
469 if((ret = H5Aiterate2(dataset, H5_INDEX_NAME, H5_ITER_INC, &idx, aiter_cb, &info)) > 0)
470 TestErrPrintf("Attribute iteration function didn't return zero correctly!\n");
471
472 /* Test all attributes on dataset, when callback always returns 1 */
473 /* This also tests the "restarting" ability, because the index changes */
474 info.command = RET_TWO;
475 i = 0;
476 idx = 0;
477 while((ret = H5Aiterate2(dataset, H5_INDEX_NAME, H5_ITER_INC, &idx, aiter_cb, &info)) > 0) {
478 /* Verify return value from iterator gets propagated correctly */
479 VERIFY(ret, 2, "H5Aiterate2");
480
481 /* Increment the number of times "2" is returned */
482 i++;
483
484 /* Verify that the index is the correct value */
485 VERIFY(idx, (unsigned)i, "H5Aiterate2");
486
487 /* Don't check name when new format is used */
488 if(!new_format) {
489 /* Verify that the correct name is retrieved */
490 if(HDstrcmp(info.name, anames[(size_t)idx - 1]) != 0)
491 TestErrPrintf("%u: Attribute iteration function didn't set names correctly, info.name = '%s', anames[%u] = '%s'!\n", __LINE__, info.name, (unsigned)(idx - 1), anames[(size_t)idx - 1]);
492 } /* end if */
493 } /* end while */
494 VERIFY(ret, -1, "H5Aiterate2");
495 if(i != 50 || idx != 50)
496 TestErrPrintf("%u: Attribute iteration function didn't perform multiple iterations correctly!\n", __LINE__);
497
498
499 /* Test all attributes on dataset, when callback changes return value */
500 /* This also tests the "restarting" ability, because the index changes */
501 info.command = new_format ? RET_CHANGE2 : RET_CHANGE;
502 i = 0;
503 idx = 0;
504 while((ret = H5Aiterate2(dataset, H5_INDEX_NAME, H5_ITER_INC, &idx, aiter_cb, &info)) > 0) {
505 /* Verify return value from iterator gets propagated correctly */
506 VERIFY(ret, 1, "H5Aiterate2");
507
508 /* Increment the number of times "1" is returned */
509 i++;
510
511 /* Verify that the index is the correct value */
512 VERIFY(idx, (unsigned)i + 10, "H5Aiterate2");
513
514 /* Don't check name when new format is used */
515 if(!new_format) {
516 /* Verify that the correct name is retrieved */
517 if(HDstrcmp(info.name, anames[(size_t)idx - 1]) != 0)
518 TestErrPrintf("%u: Attribute iteration function didn't set names correctly, info.name = '%s', anames[%u] = '%s'!\n", __LINE__, info.name, (unsigned)(idx - 1), anames[(size_t)idx - 1]);
519 } /* end if */
520 } /* end while */
521 VERIFY(ret, -1, "H5Aiterate2");
522 if(i != 40 || idx != 50)
523 TestErrPrintf("%u: Attribute iteration function didn't perform multiple iterations correctly!\n", __LINE__);
524
525 ret=H5Fclose(file);
526 CHECK(ret, FAIL, "H5Fclose");
527
528 ret=H5Dclose(dataset);
529 CHECK(ret, FAIL, "H5Dclose");
530
531 /* Free the attribute names */
532 for(i=0; i< NATTR; i++)
533 HDfree(anames[i]);
534
535 } /* test_iter_attr() */
536
537 /****************************************************************
538 **
539 ** iter_strcmp2(): String comparison routine for qsort
540 **
541 ****************************************************************/
iter_strcmp2(const void * s1,const void * s2)542 H5_ATTR_PURE int iter_strcmp2(const void *s1, const void *s2)
543 {
544 return(HDstrcmp((const char *)s1, (const char *)s2));
545 } /* end iter_strcmp2() */
546
547 /****************************************************************
548 **
549 ** liter_cb2(): Custom link iteration callback routine.
550 **
551 ****************************************************************/
552 static herr_t
liter_cb2(hid_t loc_id,const char * name,const H5L_info_t H5_ATTR_UNUSED * link_info,void * opdata)553 liter_cb2(hid_t loc_id, const char *name, const H5L_info_t H5_ATTR_UNUSED *link_info,
554 void *opdata)
555 {
556 const iter_info *test_info = (const iter_info *)opdata;
557 H5O_info_t oinfo;
558 herr_t ret; /* Generic return value */
559
560 if(HDstrcmp(name, test_info->name)) {
561 TestErrPrintf("name = '%s', test_info = '%s'\n", name, test_info->name);
562 return(H5_ITER_ERROR);
563 } /* end if */
564
565 /*
566 * Get type of the object and check it.
567 */
568 ret = H5Oget_info_by_name2(loc_id, name, &oinfo, H5O_INFO_BASIC, H5P_DEFAULT);
569 CHECK(ret, FAIL, "H5Oget_info_by_name");
570
571 if(test_info->type != oinfo.type) {
572 TestErrPrintf("test_info->type = %d, oinfo.type = %d\n", test_info->type, (int)oinfo.type);
573 return(H5_ITER_ERROR);
574 } /* end if */
575
576 return(H5_ITER_STOP);
577 } /* liter_cb2() */
578
579 /****************************************************************
580 **
581 ** test_iter_group_large(): Test group iteration functionality
582 ** for groups with large #'s of objects
583 **
584 ****************************************************************/
585 static void
test_iter_group_large(hid_t fapl)586 test_iter_group_large(hid_t fapl)
587 {
588 hid_t file; /* HDF5 File IDs */
589 hid_t dataset; /* Dataset ID */
590 hid_t group; /* Group ID */
591 hid_t sid; /* Dataspace ID */
592 hid_t tid; /* Datatype ID */
593 hsize_t dims[] = {SPACE1_DIM1};
594 herr_t ret; /* Generic return value */
595 char gname[20]; /* Temporary group name */
596 iter_info *names; /* Names of objects in the root group */
597 iter_info *curr_name; /* Pointer to the current name in the root group */
598 int i;
599
600 /* Compound datatype */
601 typedef struct s1_t {
602 unsigned int a;
603 unsigned int b;
604 float c;
605 } s1_t;
606
607 /* Allocate & initialize array */
608 names = (iter_info *)HDcalloc(sizeof(iter_info), (ITER_NGROUPS + 2));
609 CHECK_PTR(names, "HDcalloc");
610
611 /* Output message about test being performed */
612 MESSAGE(5, ("Testing Large Group Iteration Functionality\n"));
613
614 /* Create file */
615 file = H5Fcreate(DATAFILE, H5F_ACC_TRUNC, H5P_DEFAULT, fapl);
616 CHECK(file, FAIL, "H5Fcreate");
617
618 /* Create dataspace for datasets */
619 sid = H5Screate_simple(SPACE1_RANK, dims, NULL);
620 CHECK(sid, FAIL, "H5Screate_simple");
621
622 /* Create a bunch of groups */
623 for(i = 0; i < ITER_NGROUPS; i++) {
624 HDsprintf(gname, "Group_%d", i);
625
626 /* Add the name to the list of objects in the root group */
627 HDstrcpy(names[i].name, gname);
628 names[i].type = H5O_TYPE_GROUP;
629
630 /* Create a group */
631 group = H5Gcreate2(file, gname, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
632 CHECK(group, FAIL, "H5Gcreate2");
633
634 /* Close a group */
635 ret = H5Gclose(group);
636 CHECK(ret, FAIL, "H5Gclose");
637 } /* end for */
638
639 /* Create a dataset */
640 dataset = H5Dcreate2(file, "Dataset1", H5T_STD_U32LE, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
641 CHECK(dataset, FAIL, "H5Dcreate2");
642
643 /* Add the name to the list of objects in the root group */
644 HDstrcpy(names[ITER_NGROUPS].name, "Dataset1");
645 names[ITER_NGROUPS].type = H5O_TYPE_DATASET;
646
647 /* Close Dataset */
648 ret = H5Dclose(dataset);
649 CHECK(ret, FAIL, "H5Dclose");
650
651 /* Close Dataspace */
652 ret = H5Sclose(sid);
653 CHECK(ret, FAIL, "H5Sclose");
654
655 /* Create a datatype */
656 tid = H5Tcreate(H5T_COMPOUND, sizeof(s1_t));
657 CHECK(tid, FAIL, "H5Tcreate");
658
659 /* Insert fields */
660 ret = H5Tinsert(tid, "a", HOFFSET(s1_t, a), H5T_NATIVE_INT);
661 CHECK(ret, FAIL, "H5Tinsert");
662
663 ret = H5Tinsert(tid, "b", HOFFSET(s1_t, b), H5T_NATIVE_INT);
664 CHECK(ret, FAIL, "H5Tinsert");
665
666 ret = H5Tinsert(tid, "c", HOFFSET(s1_t, c), H5T_NATIVE_FLOAT);
667 CHECK(ret, FAIL, "H5Tinsert");
668
669 /* Save datatype for later */
670 ret = H5Tcommit2(file, "Datatype1", tid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
671 CHECK(ret, FAIL, "H5Tcommit2");
672
673 /* Add the name to the list of objects in the root group */
674 HDstrcpy(names[ITER_NGROUPS + 1].name, "Datatype1");
675 names[ITER_NGROUPS + 1].type = H5O_TYPE_NAMED_DATATYPE;
676
677 /* Close datatype */
678 ret = H5Tclose(tid);
679 CHECK(ret, FAIL, "H5Tclose");
680
681 /* Need to sort the names in the root group, cause that's what the library does */
682 HDqsort(names, (size_t)(ITER_NGROUPS + 2), sizeof(iter_info), iter_strcmp2);
683
684 /* Iterate through the file to see members of the root group */
685 curr_name = &names[0];
686 ret = H5Literate(file, H5_INDEX_NAME, H5_ITER_INC, NULL, liter_cb2, curr_name);
687 CHECK(ret, FAIL, "H5Literate");
688 for(i = 1; i < 100; i++) {
689 hsize_t idx = (hsize_t)i;
690
691 curr_name = &names[i];
692 ret = H5Literate(file, H5_INDEX_NAME, H5_ITER_INC, &idx, liter_cb2, curr_name);
693 CHECK(ret, FAIL, "H5Literate");
694 } /* end for */
695
696 /* Close file */
697 ret = H5Fclose(file);
698 CHECK(ret, FAIL, "H5Fclose");
699
700 /* Release memory */
701 HDfree(names);
702 } /* test_iterate_group_large() */
703
704 /****************************************************************
705 **
706 ** test_grp_memb_funcs(): Test group member information
707 ** functionality
708 **
709 ****************************************************************/
test_grp_memb_funcs(hid_t fapl)710 static void test_grp_memb_funcs(hid_t fapl)
711 {
712 hid_t file; /* File ID */
713 hid_t dataset; /* Dataset ID */
714 hid_t datatype; /* Common datatype ID */
715 hid_t filespace; /* Common dataspace ID */
716 hid_t root_group,grp; /* Root group ID */
717 int i; /* counting variable */
718 char name[NAMELEN]; /* temporary name buffer */
719 char *dnames[NDATASETS+2];/* Names of the datasets created */
720 char *obj_names[NDATASETS+2];/* Names of the objects in group */
721 char dataset_name[NAMELEN]; /* dataset name */
722 ssize_t name_len; /* Length of object's name */
723 H5G_info_t ginfo; /* Buffer for querying object's info */
724 herr_t ret = SUCCEED; /* Generic return value */
725
726 /* Output message about test being performed */
727 MESSAGE(5, ("Testing Group Member Information Functionality\n"));
728
729 /* Create the test file with the datasets */
730 file = H5Fcreate(DATAFILE, H5F_ACC_TRUNC, H5P_DEFAULT, fapl);
731 CHECK(file, FAIL, "H5Fcreate");
732
733 datatype = H5Tcopy(H5T_NATIVE_INT);
734 CHECK(datatype, FAIL, "H5Tcopy");
735
736 filespace = H5Screate(H5S_SCALAR);
737 CHECK(filespace, FAIL, "H5Screate");
738
739 for(i = 0; i < NDATASETS; i++) {
740 HDsprintf(name, "Dataset %d", i);
741 dataset = H5Dcreate2(file, name, datatype, filespace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
742 CHECK(dataset, FAIL, "H5Dcreate2");
743
744 /* Keep a copy of the dataset names around for later */
745 dnames[i] = HDstrdup(name);
746 CHECK_PTR(dnames[i], "strdup");
747
748 ret = H5Dclose(dataset);
749 CHECK(ret, FAIL, "H5Dclose");
750 } /* end for */
751
752 /* Create a group and named datatype under root group for testing */
753 grp = H5Gcreate2(file, "grp", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
754 CHECK(ret, FAIL, "H5Gcreate2");
755
756 dnames[NDATASETS] = HDstrdup("grp");
757 CHECK_PTR(dnames[NDATASETS], "strdup");
758
759 ret = H5Tcommit2(file, "dtype", datatype, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
760 CHECK(ret, FAIL, "H5Tcommit2");
761
762 dnames[NDATASETS + 1] = HDstrdup("dtype");
763 CHECK_PTR(dnames[NDATASETS], "strdup");
764
765 /* Close everything up */
766 ret = H5Tclose(datatype);
767 CHECK(ret, FAIL, "H5Tclose");
768
769 ret = H5Gclose(grp);
770 CHECK(ret, FAIL, "H5Gclose");
771
772 ret = H5Sclose(filespace);
773 CHECK(ret, FAIL, "H5Sclose");
774
775 ret = H5Fclose(file);
776 CHECK(ret, FAIL, "H5Fclose");
777
778 /* Sort the dataset names */
779 HDqsort(dnames, (size_t)(NDATASETS + 2), sizeof(char *), iter_strcmp);
780
781 /* Iterate through the datasets in the root group in various ways */
782 file = H5Fopen(DATAFILE, H5F_ACC_RDONLY, fapl);
783 CHECK(file, FAIL, "H5Fopen");
784
785 /* These two functions, H5Oget_info_by_idx and H5Lget_name_by_idx, actually
786 * iterate through B-tree for group members in internal library design.
787 */
788 root_group = H5Gopen2(file, "/", H5P_DEFAULT);
789 CHECK(root_group, FAIL, "H5Gopen2");
790
791 ret = H5Gget_info(root_group, &ginfo);
792 CHECK(ret, FAIL, "H5Gget_info");
793 VERIFY(ginfo.nlinks, (NDATASETS + 2), "H5Gget_info");
794
795 for(i = 0; i < (int)ginfo.nlinks; i++) {
796 H5O_info_t oinfo; /* Object info */
797
798 /* Test with NULL for name, to query length */
799 name_len = H5Lget_name_by_idx(root_group, ".", H5_INDEX_NAME, H5_ITER_INC, (hsize_t)i, NULL, (size_t)NAMELEN, H5P_DEFAULT);
800 CHECK(name_len, FAIL, "H5Lget_name_by_idx");
801
802 ret = (herr_t)H5Lget_name_by_idx(root_group, ".", H5_INDEX_NAME, H5_ITER_INC, (hsize_t)i, dataset_name, (size_t)(name_len + 1), H5P_DEFAULT);
803 CHECK(ret, FAIL, "H5Lget_name_by_idx");
804
805 /* Double-check that the length is the same */
806 VERIFY(ret, name_len, "H5Lget_name_by_idx");
807
808 /* Keep a copy of the dataset names around for later */
809 obj_names[i] = HDstrdup(dataset_name);
810 CHECK_PTR(obj_names[i], "strdup");
811
812 ret = H5Oget_info_by_idx2(root_group, ".", H5_INDEX_NAME, H5_ITER_INC, (hsize_t)i, &oinfo, H5O_INFO_BASIC, H5P_DEFAULT);
813 CHECK(ret, FAIL, "H5Oget_info_by_idx");
814
815 if(!HDstrcmp(dataset_name, "grp"))
816 VERIFY(oinfo.type, H5O_TYPE_GROUP, "H5Lget_name_by_idx");
817 if(!HDstrcmp(dataset_name, "dtype"))
818 VERIFY(oinfo.type, H5O_TYPE_NAMED_DATATYPE, "H5Lget_name_by_idx");
819 if(!HDstrncmp(dataset_name, "Dataset", (size_t)7))
820 VERIFY(oinfo.type, H5O_TYPE_DATASET, "H5Lget_name_by_idx");
821 } /* end for */
822
823 H5E_BEGIN_TRY {
824 ret = (herr_t)H5Lget_name_by_idx(root_group, ".", H5_INDEX_NAME, H5_ITER_INC, (hsize_t)(NDATASETS+3), dataset_name, (size_t)NAMELEN, H5P_DEFAULT);
825 } H5E_END_TRY;
826 VERIFY(ret, FAIL, "H5Lget_name_by_idx");
827
828 /* Sort the dataset names */
829 HDqsort(obj_names, (size_t)(NDATASETS + 2), sizeof(char *), iter_strcmp);
830
831 /* Compare object names */
832 for(i = 0; i< (int)ginfo.nlinks; i++) {
833 ret = HDstrcmp(dnames[i], obj_names[i]);
834 VERIFY(ret, 0, "HDstrcmp");
835 } /* end for */
836
837 ret = H5Gclose(root_group);
838 CHECK(ret, FAIL, "H5Gclose");
839
840
841 ret = H5Fclose(file);
842 CHECK(ret, FAIL, "H5Fclose");
843
844 /* Free the dataset names */
845 for(i = 0; i< (NDATASETS + 2); i++) {
846 HDfree(dnames[i]);
847 HDfree(obj_names[i]);
848 } /* end for */
849 } /* test_grp_memb_funcs() */
850
851 /****************************************************************
852 **
853 ** test_links(): Test soft and hard link iteration
854 **
855 ****************************************************************/
test_links(hid_t fapl)856 static void test_links(hid_t fapl)
857 {
858 hid_t file; /* File ID */
859 char obj_name[NAMELEN]; /* Names of the object in group */
860 ssize_t name_len; /* Length of object's name */
861 hid_t gid, gid1;
862 H5G_info_t ginfo; /* Buffer for querying object's info */
863 hsize_t i;
864 herr_t ret; /* Generic return value */
865
866 /* Output message about test being performed */
867 MESSAGE(5, ("Testing Soft and Hard Link Iteration Functionality\n"));
868
869 /* Create the test file with the datasets */
870 file = H5Fcreate(DATAFILE, H5F_ACC_TRUNC, H5P_DEFAULT, fapl);
871 CHECK(file, FAIL, "H5Fcreate");
872
873 /* create groups */
874 gid = H5Gcreate2(file, "/g1", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
875 CHECK(gid, FAIL, "H5Gcreate2");
876
877 gid1 = H5Gcreate2(file, "/g1/g1.1", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
878 CHECK(gid1, FAIL, "H5Gcreate2");
879
880 /* create soft and hard links to the group "/g1". */
881 ret = H5Lcreate_soft("something", gid, "softlink", H5P_DEFAULT, H5P_DEFAULT);
882 CHECK(ret, FAIL, "H5Lcreate_soft");
883
884 ret = H5Lcreate_hard(gid, "/g1", H5L_SAME_LOC, "hardlink", H5P_DEFAULT, H5P_DEFAULT);
885 CHECK(ret, FAIL, "H5Lcreate_hard");
886
887 ret = H5Gget_info(gid, &ginfo);
888 CHECK(ret, FAIL, "H5Gget_info");
889 VERIFY(ginfo.nlinks, 3, "H5Gget_info");
890
891 /* Test these two functions, H5Oget_info_by_idx and H5Lget_name_by_idx */
892 for(i = 0; i < ginfo.nlinks; i++) {
893 H5O_info_t oinfo; /* Object info */
894 H5L_info_t linfo; /* Link info */
895
896 /* Get link name */
897 name_len = H5Lget_name_by_idx(gid, ".", H5_INDEX_NAME, H5_ITER_INC, i, obj_name, (size_t)NAMELEN, H5P_DEFAULT);
898 CHECK(name_len, FAIL, "H5Lget_name_by_idx");
899
900 /* Get link type */
901 ret = H5Lget_info_by_idx(gid, ".", H5_INDEX_NAME, H5_ITER_INC, (hsize_t)i, &linfo, H5P_DEFAULT);
902 CHECK(ret, FAIL, "H5Lget_info_by_idx");
903
904 /* Get object type */
905 if(linfo.type == H5L_TYPE_HARD) {
906 ret = H5Oget_info_by_idx2(gid, ".", H5_INDEX_NAME, H5_ITER_INC, (hsize_t)i, &oinfo, H5O_INFO_BASIC, H5P_DEFAULT);
907 CHECK(ret, FAIL, "H5Oget_info_by_idx");
908 } /* end if */
909
910 if(!HDstrcmp(obj_name, "g1.1"))
911 VERIFY(oinfo.type, H5O_TYPE_GROUP, "H5Lget_name_by_idx");
912 else if(!HDstrcmp(obj_name, "hardlink"))
913 VERIFY(oinfo.type, H5O_TYPE_GROUP, "H5Lget_name_by_idx");
914 else if(!HDstrcmp(obj_name, "softlink"))
915 VERIFY(linfo.type, H5L_TYPE_SOFT, "H5Lget_name_by_idx");
916 else
917 CHECK(0, 0, "unknown object name");
918 } /* end for */
919
920 ret = H5Gclose(gid);
921 CHECK(ret, FAIL, "H5Gclose");
922
923 ret = H5Gclose(gid1);
924 CHECK(ret, FAIL, "H5Gclose");
925
926 ret = H5Fclose(file);
927 CHECK(ret, FAIL, "H5Fclose");
928 } /* test_links() */
929
930 /*-------------------------------------------------------------------------
931 * Function: find_err_msg_cb
932 *
933 * Purpose: Callback function to find the given error message.
934 * Helper function for test_corrupted_attnamelen().
935 *
936 * Return: H5_ITER_STOP when the message is found
937 * H5_ITER_CONT, otherwise
938 *
939 *-------------------------------------------------------------------------
940 */
941 static int
find_err_msg_cb(unsigned n,const H5E_error2_t * err_desc,void * _client_data)942 find_err_msg_cb(unsigned n, const H5E_error2_t *err_desc, void *_client_data)
943 {
944 int status = H5_ITER_CONT;
945 searched_err_t *searched_err = (searched_err_t *)_client_data;
946
947 if (searched_err == NULL)
948 return H5_ITER_ERROR;
949
950 /* If the searched error message is found, stop the iteration */
951 if (err_desc->desc != NULL && strcmp(err_desc->desc, searched_err->message) == 0)
952 {
953 searched_err->found = true;
954 status = H5_ITER_STOP;
955 }
956
957 return status;
958 } /* end find_err_msg_cb() */
959
960 /**************************************************************************
961 **
962 ** test_corrupted_attnamelen(): Test the fix for the JIRA issue HDFFV-10588,
963 ** where corrupted attribute's name length can be
964 ** detected and invalid read can be avoided.
965 **
966 **************************************************************************/
test_corrupted_attnamelen(void)967 static void test_corrupted_attnamelen(void)
968 {
969 hid_t fid = -1; /* File ID */
970 hid_t did = -1; /* Dataset ID */
971 searched_err_t err_caught; /* Data to be passed to callback func */
972 int err_status; /* Status returned by H5Aiterate2 */
973 herr_t ret; /* Return value */
974 const char *testfile = H5_get_srcdir_filename(CORRUPTED_ATNAMELEN_FILE); /* Corrected test file name */
975
976 const char *err_message = "attribute name has different length than stored length";
977 /* the error message produced when the failure occurs */
978
979 /* Output message about test being performed */
980 MESSAGE(5, ("Testing the Handling of Corrupted Attribute's Name Length\n"));
981
982 fid = H5Fopen(testfile, H5F_ACC_RDONLY, H5P_DEFAULT);
983 CHECK(fid, FAIL, "H5Fopen");
984
985 /* Open the dataset */
986 did = H5Dopen2(fid, DSET_NAME, H5P_DEFAULT);
987 CHECK(did, FAIL, "H5Dopen2");
988
989 /* Call H5Aiterate2 to trigger the failure in HDFFV-10588. Failure should
990 occur in the decoding stage, so some arguments are not needed. */
991 err_status = H5Aiterate2(did, H5_INDEX_NAME, H5_ITER_INC, NULL, NULL, NULL);
992 VERIFY(err_status, FAIL, "H5Aiterate2");
993
994 /* Make sure the intended error was caught */
995 if(err_status == -1)
996 {
997 /* Initialize client data */
998 HDstrcpy(err_caught.message, err_message);
999 err_caught.found = false;
1000
1001 /* Look for the correct error message */
1002 ret = H5Ewalk2(H5E_DEFAULT, H5E_WALK_UPWARD, find_err_msg_cb, &err_caught);
1003 CHECK(ret, FAIL, "H5Ewalk2");
1004
1005 /* Fail if the indicated message is not found */
1006 CHECK(err_caught.found, false, "test_corrupted_attnamelen: Expected error not found");
1007 }
1008
1009 /* Close the dataset and file */
1010 ret = H5Dclose(did);
1011 CHECK(ret, FAIL, "H5Dclose");
1012
1013 ret = H5Fclose(fid);
1014 CHECK(ret, FAIL, "H5Fclose");
1015
1016 } /* test_corrupted_attnamelen() */
1017
1018 /****************************************************************
1019 **
1020 ** test_iterate(): Main iteration testing routine.
1021 **
1022 ****************************************************************/
1023 void
test_iterate(void)1024 test_iterate(void)
1025 {
1026 hid_t fapl, fapl2; /* File access property lists */
1027 unsigned new_format; /* Whether to use the new format or not */
1028 herr_t ret; /* Generic return value */
1029
1030 /* Output message about test being performed */
1031 MESSAGE(5, ("Testing Iteration Operations\n"));
1032
1033 /* Get the default FAPL */
1034 fapl = H5Pcreate(H5P_FILE_ACCESS);
1035 CHECK(fapl, FAIL, "H5Pcreate");
1036
1037 /* Copy the file access property list */
1038 fapl2 = H5Pcopy(fapl);
1039 CHECK(fapl2, FAIL, "H5Pcopy");
1040
1041 /* Set the "use the latest version of the format" bounds for creating objects in the file */
1042 ret = H5Pset_libver_bounds(fapl2, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST);
1043 CHECK(ret, FAIL, "H5Pset_libver_bounds");
1044
1045 /* These next tests use the same file */
1046 for(new_format = FALSE; new_format <= TRUE; new_format++) {
1047 test_iter_group(new_format ? fapl2 : fapl, new_format); /* Test group iteration */
1048 test_iter_group_large(new_format ? fapl2 : fapl); /* Test group iteration for large # of objects */
1049 test_iter_attr(new_format ? fapl2 : fapl, new_format); /* Test attribute iteration */
1050 test_grp_memb_funcs(new_format ? fapl2 : fapl); /* Test group member information functions */
1051 test_links(new_format ? fapl2 : fapl); /* Test soft and hard link iteration */
1052 } /* end for */
1053
1054 /* Test the fix for issue HDFFV-10588 */
1055 test_corrupted_attnamelen();
1056
1057 /* Close FAPLs */
1058 ret = H5Pclose(fapl);
1059 CHECK(ret, FAIL, "H5Pclose");
1060 ret = H5Pclose(fapl2);
1061 CHECK(ret, FAIL, "H5Pclose");
1062 } /* test_iterate() */
1063
1064
1065 /*-------------------------------------------------------------------------
1066 * Function: cleanup_iterate
1067 *
1068 * Purpose: Cleanup temporary test files
1069 *
1070 * Return: none
1071 *
1072 * Programmer: Quincey Koziol
1073 * April 5, 2000
1074 *
1075 * Modifications:
1076 *
1077 *-------------------------------------------------------------------------
1078 */
1079 void
cleanup_iterate(void)1080 cleanup_iterate(void)
1081 {
1082 HDremove(DATAFILE);
1083 }
1084
1085