summaryrefslogtreecommitdiffstats
path: root/test/objcopy_ref.c
blob: 33d1f648160a722e945767a3a1ecd70da79041a1 (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
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 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://support.hdfgroup.org/ftp/HDF5/releases.  *
 * If you do not have access to either file, you may request a copy from     *
 * help@hdfgroup.org.                                                        *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/*
 * Programmer:     Peter X. Cao
 *                 May 01, 2005
 *
 * Purpose:    Test H5Ocopy() for references.
 */

#include "testhdf5.h"

#define H5F_FRIEND      /*suppress error about including H5Fpkg */
#define H5F_TESTING
#include "H5Fpkg.h"     /* File access                          */

const char *FILENAME[] = {
    "objcopy_ref_src",
    "objcopy_ref_dst",
    "objcopy_ref_ext",
    "objcopy_ref_src2",
    "verbound_ref_src",
    "verbound_ref_dst",
    NULL
};

/* Configuration, really a series of bit flags.  Maximum value is all three
 * bit flags enabled.
 */
#define CONFIG_SHARE_SRC 1
#define CONFIG_SHARE_DST 2
#define CONFIG_SRC_NEW_FORMAT 4
#define CONFIG_DST_NEW_FORMAT 8
#define CONFIG_DENSE 16
#define MAX_CONFIGURATION 31

#define NAME_DATASET_SIMPLE     "dataset_simple"
#define NAME_DATASET_SUB_SUB     "/g0/g00/g000/dataset_simple"
#define NAME_GROUP_UNCOPIED     "/uncopied"
#define NAME_GROUP_TOP         "/g0"
#define NAME_GROUP_SUB         "/g0/g00"
#define NAME_GROUP_SUB_SUB2     "g000"
#define NAME_GROUP_LINK        "/g_links"
#define NAME_GROUP_LINK2    "/g_links2"
#define NAME_GROUP_REF            "ref_grp"
#define NAME_LINK_SOFT        "/g_links/soft_link_to_dataset_simple"
#define NAME_LINK_SOFT2        "/g_links2/soft_link_to_dataset_simple"
#define NAME_LINK_EXTERN    "/g_links/external_link_to_dataset_simple"
#define NAME_LINK_EXTERN2       "/g_links2/external_link_to_dataset_simple"
#define NAME_LINK_SOFT_DANGLE    "/g_links/soft_link_to_nowhere"
#define NAME_LINK_SOFT_DANGLE2    "/g_links2/soft_link_to_nowhere"
#define NAME_LINK_EXTERN_DANGLE "/g_links/external_link_to_nowhere"
#define NAME_LINK_EXTERN_DANGLE2        "/g_links2/external_link_to_nowhere"

#define NAME_BUF_SIZE   1024
#define ATTR_NAME_LEN 80
#define DIM_SIZE_1 12
#define DIM_SIZE_2  6

unsigned num_attributes_g;         /* Number of attributes created */

/* Table containing object id and object name */
/* (Used for detecting duplicate objects when comparing groups */
static struct {
    size_t  nalloc;             /* number of slots allocated */
    size_t  nobjs;              /* number of objects */
    haddr_t *obj;               /* Addresses of objects seen */
} idtab_g;

/* Local function prototypes */
static int
compare_data(hid_t parent1, hid_t parent2, hid_t pid, hid_t tid, size_t nelmts,
            const void *buf1, const void *buf2, hid_t obj_owner);
static int
compare_datasets(hid_t did, hid_t did2, hid_t pid, const void *wbuf);
static int
compare_groups(hid_t gid, hid_t gid2, hid_t pid, int depth, unsigned copy_flags);

/*-------------------------------------------------------------------------
 * Function: addr_insert
 *
 * Purpose: Add an address to the table.
 *
 * Return: void
 *
 * Programmer: Quincey Koziol
 *              Saturday, November  5, 2005
 *
 *-------------------------------------------------------------------------
 */
static void
addr_insert(H5O_info_t *oi)
{
    size_t  n;

    /* Don't add it if the link count is 1 because such an object can only
     * be encountered once. */
    if(oi->rc < 2)
        return;

    /* Extend the table */
    if(idtab_g.nobjs >= idtab_g.nalloc) {
        idtab_g.nalloc = MAX(256, 2*idtab_g.nalloc);
        idtab_g.obj = (haddr_t *)HDrealloc(idtab_g.obj, idtab_g.nalloc * sizeof(idtab_g.obj[0]));
    } /* end if */

    /* Insert the entry */
    n = idtab_g.nobjs++;
    idtab_g.obj[n] = oi->addr;
} /* end addr_insert() */


/*-------------------------------------------------------------------------
 * Function: addr_lookup
 *
 * Purpose: Check if address has already been encountered
 *
 * Return: Success: TRUE/FALSE
 *
 * Failure: (can't fail)
 *
 * Programmer: Quincey Koziol
 *              Saturday, November  5, 2005
 *
 *-------------------------------------------------------------------------
 */
static H5_ATTR_PURE hbool_t
addr_lookup(H5O_info_t *oi)
{
    size_t  n;

    if(oi->rc < 2) return FALSE; /*only one link possible*/

    for(n = 0; n < idtab_g.nobjs; n++)
        if(H5F_addr_eq(idtab_g.obj[n], oi->addr))
            return TRUE;

    return FALSE;
} /* end addr_lookup() */


/*-------------------------------------------------------------------------
 * Function: addr_reset
 *
 * Purpose: Reset the address tracking data structures
 *
 * Return: void
 *
 * Programmer: Quincey Koziol
 *              Saturday, November  5, 2005
 *
 *-------------------------------------------------------------------------
 */
static void
addr_reset(void)
{
    if(idtab_g.obj)
        HDfree(idtab_g.obj);
    idtab_g.obj = NULL;
    idtab_g.nalloc = idtab_g.nobjs = 0;
} /* end addr_reset() */


/*-------------------------------------------------------------------------
 * Function:    attach_ref_attr
 *
 * Purpose:     Create an attribute with object references
 *
 * Return:      Non-negative on success/Negative on failure
 *
 *-------------------------------------------------------------------------
 */
static herr_t
attach_ref_attr(hid_t file_id, hid_t loc_id)
{
    char dsetname1[] = "dataset1_pointed_by_ref_attr";
    char dsetname2[] = "dataset2_pointed_by_ref_attr";
    hid_t did1 = (-1), did2 = (-1), aid = (-1), sid = (-1), sid_ref = (-1);
    hsize_t dims[2] =  {2,9};
    hsize_t dims_ref[1] = {2};
    H5R_ref_t ref[2];
    int data1[2][9] = {{1,1,1,1,1,1,1,1,1},{1,1,1,1,1,1,1,1,18}};
    int data2[2][9] = {{2,2,2,2,2,2,2,2,2},{2,2,2,2,2,2,2,2,18}};

    /* creates two simple datasets */
    if((sid = H5Screate_simple(2, dims, NULL)) < 0) TEST_ERROR
    if((sid_ref = H5Screate_simple(1, dims_ref, NULL)) < 0) TEST_ERROR
    if((did1 = H5Dcreate2(file_id, dsetname1, H5T_NATIVE_INT, sid,  H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR
    if(H5Dwrite(did1, H5T_NATIVE_INT, H5S_ALL , H5S_ALL, H5P_DEFAULT,data1) < 0) TEST_ERROR
    if((did2 = H5Dcreate2(file_id, dsetname2, H5T_NATIVE_INT, sid,  H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR
    if(H5Dwrite(did2, H5T_NATIVE_INT, H5S_ALL , H5S_ALL, H5P_DEFAULT,data2) < 0) TEST_ERROR

    /* create an attribute with two object references */
    if(H5Rcreate_object(file_id, dsetname1, H5P_DEFAULT, &ref[0]) < 0) TEST_ERROR
    if(H5Rcreate_object(file_id, dsetname2, H5P_DEFAULT, &ref[1]) < 0) TEST_ERROR
    if((aid = H5Acreate2(loc_id, "obj_ref_attr", H5T_STD_REF, sid_ref, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR
    if(H5Awrite(aid, H5T_STD_REF, ref) < 0) TEST_ERROR

    if(H5Sclose(sid) < 0) TEST_ERROR
    if(H5Sclose(sid_ref) < 0) TEST_ERROR
    if(H5Dclose(did1) < 0) TEST_ERROR
    if(H5Dclose(did2) < 0) TEST_ERROR
    if(H5Aclose(aid) < 0) TEST_ERROR
    if(H5Rdestroy(&ref[0]) < 0) TEST_ERROR
    if(H5Rdestroy(&ref[1]) < 0) TEST_ERROR

    return 0;

error:
    H5E_BEGIN_TRY {
        H5Sclose(sid);
        H5Sclose(sid_ref);
        H5Dclose(did1);
        H5Dclose(did2);
        H5Aclose(aid);
        H5Rdestroy(&ref[0]);
        H5Rdestroy(&ref[1]);
    } H5E_END_TRY;

    return(-1);
}

/*-------------------------------------------------------------------------
 * Function:    attach_reg_ref_attr
 *
 * Purpose:     Create an attribute with object references
 *
 * Return:      Non-negative on success/Negative on failure
 *
 * Programmer:  Peter Cao
 *              Monday, March 5, 2006
 *
 *-------------------------------------------------------------------------
 */
static herr_t
attach_reg_ref_attr(hid_t file_id, hid_t loc_id)
{
    const char dsetnamev[] = "dataset_pointed_by_reg_ref_attr";
    hid_t aid = (-1);
    hid_t space_id = (-1);       /* dataspace identifiers */
    hid_t spacer_id = (-1);       /* dataspace identifiers */
    hid_t dsetv_id = (-1);       /*dataset identifiers*/
    hsize_t dims[2] =  {2,9};
    hsize_t dimsr[1] =  {2};
    int rank = 2;
    int rankr =1;
    H5R_ref_t ref[2];
    int data[2][9] = {{1,1,2,3,3,4,5,5,999},{1,2,2,3,4,4,5,6,999}};
    hsize_t start[2] = {0, 3};
    hsize_t count[2] = {2, 3};
    hsize_t coord[3][2] = {{0, 0}, {1, 6}, {0, 8}};
    size_t num_points = 3;

    /* create a 2D dataset */
    if((space_id = H5Screate_simple(rank, dims, NULL)) < 0) TEST_ERROR
    if((spacer_id = H5Screate_simple(rankr, dimsr, NULL)) < 0) TEST_ERROR
    if((dsetv_id = H5Dcreate2(file_id, dsetnamev, H5T_NATIVE_INT, space_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR
    if(H5Dwrite(dsetv_id, H5T_NATIVE_INT, H5S_ALL , H5S_ALL, H5P_DEFAULT,data) < 0) TEST_ERROR

    /* create reg_ref of block selection */
    if(H5Sselect_hyperslab(space_id,H5S_SELECT_SET,start,NULL,count,NULL) < 0) TEST_ERROR
    if(H5Rcreate_region(file_id, dsetnamev, space_id, H5P_DEFAULT, &ref[0]) < 0) TEST_ERROR

    /* create reg_ref of point selection */
    if(H5Sselect_none(space_id) < 0) TEST_ERROR
    if(H5Sselect_elements(space_id, H5S_SELECT_SET, num_points, (const hsize_t *)coord) < 0) TEST_ERROR
    if(H5Rcreate_region(file_id, dsetnamev, space_id, H5P_DEFAULT, &ref[1]) < 0) TEST_ERROR

    /* create reg_ref attribute */
    if((aid = H5Acreate2(loc_id, "reg_ref_attr", H5T_STD_REF, spacer_id, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR
    if(H5Awrite(aid, H5T_STD_REF, ref) < 0) TEST_ERROR

    /* attach the reg_ref attribute to the dataset itself */
    if(H5Aclose(aid) < 0) TEST_ERROR
    if((aid = H5Acreate2(dsetv_id, "reg_ref_attr", H5T_STD_REF, spacer_id, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR
    if(H5Awrite(aid, H5T_STD_REF, ref) < 0) TEST_ERROR

    if(H5Sclose(spacer_id) < 0) TEST_ERROR
    if(H5Sclose(space_id) < 0) TEST_ERROR
    if(H5Dclose(dsetv_id) < 0) TEST_ERROR
    if(H5Aclose(aid) < 0) TEST_ERROR
    if(H5Rdestroy(&ref[0]) < 0) TEST_ERROR
    if(H5Rdestroy(&ref[1]) < 0) TEST_ERROR


    return 0;

error:
    H5E_BEGIN_TRY {
        H5Sclose(spacer_id);
        H5Sclose(space_id);
        H5Dclose(dsetv_id);
        H5Aclose(aid);
        H5Rdestroy(&ref[0]);
        H5Rdestroy(&ref[1]);
    } H5E_END_TRY;

    return(-1);
}


/*-------------------------------------------------------------------------
 * Function:    create_reg_ref_dataset
 *
 * Purpose:     Create a dataset with region references
 *
 * Return:      Non-negative on success/Negative on failure
 *
 * Programmer:  Peter Cao
 *              Friday, August 4, 2006
 *
 *-------------------------------------------------------------------------
 */
static herr_t
create_reg_ref_dataset(hid_t file_id, hid_t loc_id)
{
    const char dsetnamev[] = "dataset_pointed_by_ref_dset";
    const char dsetnamer[] = "dataset_with_reg_ref";
    const char dsetnamer1[] = "compact_dataset_with_reg_ref";
    const char dsetnamer2[] = "compressed_dataset_with_reg_ref";
    hid_t space_id = (-1);       /* dataspace identifiers */
    hid_t spacer_id = (-1);
    hid_t dsetv_id = (-1);       /*dataset identifiers*/
    hid_t dsetr_id = (-1);
    hsize_t dims[2] =  {2,9};
    hsize_t dimsr[1] =  {2};
    int rank = 2;
    int rankr =1;
    hsize_t chunk_size=1;
    H5R_ref_t ref[2];
    int data[2][9] = {{1,1,2,3,3,4,5,5,6},{1,2,2,3,4,4,5,6,6}};
    hsize_t start[2];
    hsize_t count[2];
    hsize_t coord[3][2] = {{0, 0}, {1, 6}, {0, 8}};
    size_t num_points = 3;
    hid_t pid = (-1);

    if((space_id = H5Screate_simple(rank, dims, NULL)) < 0) TEST_ERROR
    if((spacer_id = H5Screate_simple(rankr, dimsr, NULL)) < 0) TEST_ERROR
    if((dsetv_id = H5Dcreate2(file_id, dsetnamev, H5T_NATIVE_INT, space_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR
    if(H5Dwrite(dsetv_id, H5T_NATIVE_INT, H5S_ALL , H5S_ALL, H5P_DEFAULT,data) < 0) TEST_ERROR
    if((dsetr_id = H5Dcreate2(loc_id, dsetnamer, H5T_STD_REF, spacer_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR

    start[0] = 0;
    start[1] = 3;
    count[0] = 2;
    count[1] = 3;
    if(H5Sselect_hyperslab(space_id,H5S_SELECT_SET,start,NULL,count,NULL) < 0) TEST_ERROR
    if(H5Rcreate_region(file_id, dsetnamev, space_id, H5P_DEFAULT, &ref[0]) < 0) TEST_ERROR
    if(H5Sselect_none(space_id) < 0) TEST_ERROR
    if(H5Sselect_elements(space_id, H5S_SELECT_SET, num_points, (const hsize_t *)coord) < 0) TEST_ERROR
    if(H5Rcreate_region(file_id, dsetnamev, space_id, H5P_DEFAULT, &ref[1]) < 0) TEST_ERROR
    if(H5Dwrite(dsetr_id, H5T_STD_REF, H5S_ALL, H5S_ALL, H5P_DEFAULT,ref) < 0) TEST_ERROR
    if(H5Dclose(dsetr_id) < 0) TEST_ERROR

    /* create and set compact plist */
    if((pid = H5Pcreate(H5P_DATASET_CREATE)) < 0) TEST_ERROR
    if(H5Pset_layout(pid, H5D_COMPACT) < 0) TEST_ERROR

    if((dsetr_id = H5Dcreate2(loc_id, dsetnamer1, H5T_STD_REF, spacer_id, H5P_DEFAULT, pid, H5P_DEFAULT)) < 0) TEST_ERROR
    if(H5Pclose(pid) < 0) TEST_ERROR
    if(H5Dwrite(dsetr_id, H5T_STD_REF, H5S_ALL, H5S_ALL, H5P_DEFAULT, ref) < 0) TEST_ERROR
    if(H5Dclose(dsetr_id) < 0) TEST_ERROR

    /* create and set comp & chunk plist */
    if((pid = H5Pcreate(H5P_DATASET_CREATE)) < 0) TEST_ERROR
    if(H5Pset_chunk(pid, 1, &chunk_size) < 0) TEST_ERROR
    if(H5Pset_deflate(pid, 9) < 0) TEST_ERROR

    if((dsetr_id = H5Dcreate2(loc_id, dsetnamer2, H5T_STD_REF, spacer_id, H5P_DEFAULT, pid, H5P_DEFAULT)) < 0) TEST_ERROR
    if(H5Pclose(pid) < 0) TEST_ERROR
    if(H5Dwrite(dsetr_id, H5T_STD_REF, H5S_ALL, H5S_ALL, H5P_DEFAULT,ref) < 0) TEST_ERROR
    if(H5Dclose(dsetr_id) < 0) TEST_ERROR

    if(H5Sclose(space_id) < 0) TEST_ERROR
    if(H5Sclose(spacer_id) < 0) TEST_ERROR
    if(H5Dclose(dsetv_id) < 0) TEST_ERROR
    if(H5Rdestroy(&ref[0]) < 0) TEST_ERROR
    if(H5Rdestroy(&ref[1]) < 0) TEST_ERROR

    return 0;


error:
    H5E_BEGIN_TRY {
        H5Sclose(space_id);
        H5Sclose(spacer_id);
        H5Dclose(dsetr_id);
        H5Dclose(dsetv_id);
        H5Pclose(pid);
        H5Rdestroy(&ref[0]);
        H5Rdestroy(&ref[1]);
    } H5E_END_TRY;

    return(-1);
}

/*-------------------------------------------------------------------------
 * Function:    test_copy_attach_attributes
 *
 * Purpose:     Attach NUM_ATTRIBUTES attributes to the object to be copied
 *
 * Return:    Non-negative on success/Negative on failure
 *
 * Programmer:  Peter Cao
 *              Friday, September 30, 2005
 *
 *-------------------------------------------------------------------------
 */
static int
test_copy_attach_attributes(hid_t loc_id, hid_t type_id)
{
    hid_t aid = -1, sid = -1;
    char attr_name[ATTR_NAME_LEN];
    int  attr_data[2];
    hsize_t dim1 = 2;
    hid_t acpl = -1;
    unsigned  u;
    int ret_value = -1;

    if((sid = H5Screate_simple(1, &dim1, NULL)) < 0 )
        goto done;

    /* Create attribute creation plist */
    if((acpl = H5Pcreate(H5P_ATTRIBUTE_CREATE)) < 0)
        goto done;

    for(u = 0; u < num_attributes_g; u++) {
        HDsprintf(attr_name, "%u attr", u);

        /* Set attribute data */
        attr_data[0] = (int)(100 * u);
        attr_data[1] = (int)(200 * u);

        /* Set attribute character set (alternate) */
        if(u % 2) {
            if(H5Pset_char_encoding(acpl, H5T_CSET_ASCII) < 0)
                goto done;
        } /* end if */
        else
            if(H5Pset_char_encoding(acpl, H5T_CSET_UTF8) < 0)
                goto done;

        if((aid = H5Acreate2(loc_id, attr_name, type_id, sid, acpl, H5P_DEFAULT)) < 0)
            goto done;

        if(H5Awrite(aid, H5T_NATIVE_INT, attr_data) < 0)
            goto done;

        if(aid > 0)
            H5Aclose(aid);

         aid = -1;
    }

    ret_value = 0;

done:
    if(sid > 0)
        H5Sclose(sid);
    if(aid > 0)
        H5Aclose(aid);
    if(acpl > 0)
        H5Pclose(acpl);

    return ret_value;
}

/*-------------------------------------------------------------------------
 * Function:    compare_attribute
 *
 * Purpose:     Compare two attributes to check that they are equal
 *
 * Return:      TRUE if attributes are equal/FALSE if they are different
 *
 * Programmer:  Peter Cao
 *              Saturday, December 17, 2005
 *
 *-------------------------------------------------------------------------
 */
static int
compare_attribute(hid_t aid, hid_t aid2, hid_t pid, const void *wbuf, hid_t obj_owner)
{
    hid_t sid = -1, sid2 = -1;                  /* Dataspace IDs */
    hid_t tid = -1, tid2 = -1;                  /* Datatype IDs */
    size_t elmt_size;                           /* Size of datatype */
    htri_t is_committed;                        /* If the datatype is committed */
    htri_t is_committed2;                       /* If the datatype is committed */
    H5A_info_t ainfo;                           /* Attribute info */
    H5A_info_t ainfo2;                          /* Attribute info */
    hssize_t nelmts;                            /* # of elements in dataspace */
    void *rbuf = NULL;                          /* Buffer for reading raw data */
    void *rbuf2 = NULL;                         /* Buffer for reading raw data */

    /* Check the character sets are equal */
    if(H5Aget_info(aid, &ainfo) < 0) TEST_ERROR
    if(H5Aget_info(aid2, &ainfo2) < 0) TEST_ERROR
    if(ainfo.cset != ainfo2.cset) TEST_ERROR

    /* Check the creation orders are equal (if appropriate) */
    if(ainfo.corder_valid != ainfo2.corder_valid) TEST_ERROR
    if(ainfo.corder_valid)
        if(ainfo.corder != ainfo2.corder) TEST_ERROR

    /* Check the datatypes are equal */

    /* Open the datatype for the source attribute */
    if((tid = H5Aget_type(aid)) < 0) TEST_ERROR

    /* Open the datatype for the destination attribute */
    if((tid2 = H5Aget_type(aid2)) < 0) TEST_ERROR

    /* Check that both datatypes are committed/not committed */
    if((is_committed = H5Tcommitted(tid)) < 0) TEST_ERROR
    if((is_committed2 = H5Tcommitted(tid2)) < 0) TEST_ERROR
    if(is_committed != is_committed2) TEST_ERROR

    /* Compare the datatypes */
    if(H5Tequal(tid, tid2) != TRUE) TEST_ERROR

    /* Determine the size of datatype (for later) */
    if((elmt_size = H5Tget_size(tid)) == 0) TEST_ERROR

    /* Check the dataspaces are equal */

    /* Open the dataspace for the source attribute */
    if((sid = H5Aget_space(aid)) < 0) TEST_ERROR

    /* Open the dataspace for the destination attribute */
    if((sid2 = H5Aget_space(aid2)) < 0) TEST_ERROR

    /* Compare the dataspaces */
    if(H5Sextent_equal(sid, sid2) != TRUE) TEST_ERROR

    /* Determine the number of elements in dataspace (for later) */
    if((nelmts = H5Sget_simple_extent_npoints(sid2)) < 0) TEST_ERROR

    /* Check the raw data is equal */

    /* Allocate & initialize space for the raw data buffers */
    if((rbuf = HDcalloc( elmt_size, (size_t)nelmts)) == NULL) TEST_ERROR
    if((rbuf2 = HDcalloc( elmt_size, (size_t)nelmts)) == NULL) TEST_ERROR

    /* Read data from the source attribute */
    if(H5Aread(aid, tid, rbuf) < 0) TEST_ERROR

    /* Read data from the destination attribute */
    if(H5Aread(aid2, tid2, rbuf2) < 0) TEST_ERROR

    /* Check raw data read in against data written out */
    if(wbuf) {
        if(!compare_data(aid, (hid_t)0, pid, tid, (size_t)nelmts, wbuf, rbuf, obj_owner)) TEST_ERROR
        if(!compare_data(aid2, (hid_t)0, pid, tid2, (size_t)nelmts, wbuf, rbuf2, obj_owner)) TEST_ERROR
    } /* end if */
    /* Don't have written data, just compare data between the two attributes */
    else
        if(!compare_data(aid, aid2, pid, tid, (size_t)nelmts, rbuf, rbuf2, obj_owner)) TEST_ERROR

    /* Reclaim vlen data, if necessary */
    if(H5Tdetect_class(tid, H5T_VLEN) == TRUE || H5Tdetect_class(tid, H5T_REFERENCE) == TRUE)
        if(H5Treclaim(tid, sid, H5P_DEFAULT, rbuf) < 0) TEST_ERROR
    if(H5Tdetect_class(tid2, H5T_VLEN) == TRUE || H5Tdetect_class(tid2, H5T_REFERENCE) == TRUE)
        if(H5Treclaim(tid2, sid2, H5P_DEFAULT, rbuf2) < 0) TEST_ERROR

    /* Release raw data buffers */
    HDfree(rbuf);
    rbuf = NULL;
    HDfree(rbuf2);
    rbuf2 = NULL;

    /* close the source dataspace */
    if(H5Sclose(sid) < 0) TEST_ERROR

    /* close the destination dataspace */
    if(H5Sclose(sid2) < 0) TEST_ERROR

    /* close the source datatype */
    if(H5Tclose(tid) < 0) TEST_ERROR

    /* close the destination datatype */
    if(H5Tclose(tid2) < 0) TEST_ERROR

    return TRUE;

error:
    if(rbuf)
        HDfree(rbuf);
    if(rbuf2)
        HDfree(rbuf2);
    H5E_BEGIN_TRY {
        H5Sclose(sid2);
        H5Sclose(sid);
        H5Tclose(tid2);
        H5Tclose(tid);
    } H5E_END_TRY;
    return FALSE;
} /* end compare_attribute() */


/*-------------------------------------------------------------------------
 * Function:    compare_std_attributes
 *
 * Purpose:     Compare "standard" attributes on two objects to check that they are equal
 *
 * Return:    TRUE if objects have same attributes/FALSE if they are different
 *
 * Programmer:  Quincey Koziol
 *              Monday, October 31, 2005
 *
 * Note:    This isn't very general, the attributes are assumed to be
 *              those written in test_copy_attach_attributes().
 *
 *-------------------------------------------------------------------------
 */
static int
compare_std_attributes(hid_t oid, hid_t oid2, hid_t pid)
{
    hid_t aid = -1, aid2 = -1;                  /* Attribute IDs */
    H5O_info_t oinfo1, oinfo2;                  /* Object info */
    unsigned cpy_flags;                         /* Object copy flags */

    /* Retrieve the object copy flags from the property list, if it's non-DEFAULT */
    if(pid != H5P_DEFAULT) {
        if(H5Pget_copy_object(pid, &cpy_flags) < 0) TEST_ERROR
    } /* end if */
    else
        cpy_flags = 0;

    /* Check the number of attributes on source dataset */
    if(H5Oget_info2(oid, &oinfo1, H5O_INFO_NUM_ATTRS) < 0) TEST_ERROR

    /* Check the number of attributes on destination dataset */
    if(H5Oget_info2(oid2, &oinfo2, H5O_INFO_NUM_ATTRS) < 0) TEST_ERROR

    if(cpy_flags & H5O_COPY_WITHOUT_ATTR_FLAG) {
        /* Check that the destination has no attributes */
        if(oinfo2.num_attrs != 0) TEST_ERROR
    } /* end if */
    else {
        char attr_name[ATTR_NAME_LEN];  /* Attribute name */
        unsigned i;             /* Local index variable */

        /* Compare the number of attributes */
        if(oinfo1.num_attrs != oinfo2.num_attrs) TEST_ERROR

        /* Check the attributes are equal */
        for(i = 0; i < (unsigned)oinfo1.num_attrs; i++) {
            if((aid = H5Aopen_by_idx(oid, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, (hsize_t)i, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR
            if(H5Aget_name(aid, (size_t)ATTR_NAME_LEN, attr_name) < 0) TEST_ERROR

            if((aid2 = H5Aopen(oid2, attr_name, H5P_DEFAULT)) < 0) TEST_ERROR

            /* Check the attributes are equal */
            if(!compare_attribute(aid, aid2, pid, NULL, oid)) TEST_ERROR

            /* Close the attributes */
            if(H5Aclose(aid) < 0) TEST_ERROR
            if(H5Aclose(aid2) < 0) TEST_ERROR
        } /* end for */
    } /* end if */

    /* Objects should be the same. :-) */
    return TRUE;

error:
    H5E_BEGIN_TRY {
        H5Aclose(aid2);
        H5Aclose(aid);
    } H5E_END_TRY;
    return FALSE;
} /* end compare_std_attributes() */


/*-------------------------------------------------------------------------
 * Function:    compare_data
 *
 * Purpose:     Compare two buffers of data to check that they are equal
 *
 * Return:    TRUE if buffer are equal/FALSE if they are different
 *
 * Programmer:  Quincey Koziol
 *              Monday, November 21, 2005
 *
 *-------------------------------------------------------------------------
 */
static int
compare_data(hid_t parent1, hid_t parent2, hid_t pid, hid_t tid, size_t nelmts,
        const void *buf1, const void *buf2, hid_t obj_owner)
{
    size_t elmt_size;           /* Size of an element */

    /* Check size of each element */
    if((elmt_size = H5Tget_size(tid)) == 0) TEST_ERROR

    /* If the type is a compound containing a vlen, loop over all elements for
     * each compound member.  Compounds containing reference  are not supported
     * yet. */
    if((H5Tget_class(tid) == H5T_COMPOUND)
            && (H5Tdetect_class(tid, H5T_VLEN) == TRUE)) {
        hid_t           memb_id;    /* Member id */
        const uint8_t   *memb1;     /* Pointer to current member */
        const uint8_t   *memb2;     /* Pointer to current member */
        int             nmembs;     /* Number of members */
        size_t          memb_off;   /* Member offset */
        size_t          memb_size;  /* Member size */
        unsigned        memb_idx;   /* Member index */
        size_t          elmt;       /* Current element */

        /* Get number of members in compound */
        if((nmembs = H5Tget_nmembers(tid)) < 0) TEST_ERROR

        /* Loop over members */
        for(memb_idx=0; memb_idx<(unsigned)nmembs; memb_idx++) {
            /* Get member offset.  Note that we cannot check for an error here.
             */
            memb_off = H5Tget_member_offset(tid, memb_idx);

            /* Get member id */
            if((memb_id = H5Tget_member_type(tid, memb_idx)) < 0) TEST_ERROR

            /* Get member size */
            if((memb_size = H5Tget_size(memb_id)) == 0) TEST_ERROR

            /* Set up pointers to member in the first element */
            memb1 = (const uint8_t *)buf1 + memb_off;
            memb2 = (const uint8_t *)buf2 + memb_off;

            /* Check if this member contains (or is) a vlen */
            if(H5Tget_class(memb_id) == H5T_VLEN) {
                hid_t base_id;  /* vlen base type id */

                /* Get base type of vlen datatype */
                if((base_id = H5Tget_super(memb_id)) < 0) TEST_ERROR

                /* Iterate over all elements, recursively calling this function
                 * for each */
                for(elmt=0; elmt<nelmts; elmt++) {
                    /* Check vlen lengths */
                    if(((const hvl_t *)((const void *)memb1))->len
                            != ((const hvl_t *)((const void *)memb2))->len)
                        TEST_ERROR

                    /* Check vlen data */
                    if(!compare_data(parent1, parent2, pid, base_id,
                            ((const hvl_t *)((const void *)memb1))->len,
                            ((const hvl_t *)((const void *)memb1))->p,
                            ((const hvl_t *)((const void *)memb2))->p, obj_owner))
                        TEST_ERROR

                    /* Update member pointers */
                    memb1 += elmt_size;
                    memb2 += elmt_size;
                } /* end for */
            } else {
                /* vlens cannot currently be nested below the top layer of a
                 * compound */
                HDassert(H5Tdetect_class(memb_id, H5T_VLEN) == FALSE);

                /* Iterate over all elements, calling memcmp() for each */
                for(elmt=0; elmt<nelmts; elmt++) {
                    if(HDmemcmp(memb1, memb2, memb_size))
                        TEST_ERROR

                    /* Update member pointers */
                    memb1 += elmt_size;
                    memb2 += elmt_size;
                } /* end for */
            } /* end else */
        } /* end for */
    } else if(H5Tdetect_class(tid, H5T_VLEN) == TRUE) {
        const hvl_t *vl_buf1, *vl_buf2; /* Aliases for buffers to compare */
        hid_t base_tid;                 /* Base type of vlen datatype */
        size_t u;                       /* Local index variable */

        /* Check for "simple" vlen datatype */
        if(H5Tget_class(tid) != H5T_VLEN) TEST_ERROR

        /* Get base type of vlen datatype */
        if((base_tid = H5Tget_super(tid)) < 0) TEST_ERROR

        /* Loop over elements in buffers */
        vl_buf1 = (const hvl_t *)buf1;
        vl_buf2 = (const hvl_t *)buf2;
        for(u = 0; u < nelmts; u++, vl_buf1++, vl_buf2++) {
            /* Check vlen lengths */
            if(vl_buf1->len != vl_buf2->len) TEST_ERROR

            /* Check vlen data */
            if(!compare_data(parent1, parent2, pid, base_tid, vl_buf1->len, vl_buf1->p, vl_buf2->p, obj_owner)) TEST_ERROR
        } /* end for */

        if(H5Tclose(base_tid) < 0) TEST_ERROR
    } /* end if */
    else if(H5Tdetect_class(tid, H5T_REFERENCE) == TRUE) {
        size_t u;                       /* Local index variable */

        /* Check for "simple" reference datatype */
        if(H5Tget_class(tid) != H5T_REFERENCE) TEST_ERROR

        /* Check for object or region reference */
        if(H5Tequal(tid, H5T_STD_REF) > 0) {
            const H5R_ref_t *ref_buf1, *ref_buf2;      /* Aliases for buffers to compare */

            /* Loop over elements in buffers */
            ref_buf1 = (const H5R_ref_t *)buf1;
            ref_buf2 = (const H5R_ref_t *)buf2;
            for(u = 0; u < nelmts; u++, ref_buf1++, ref_buf2++) {
                hid_t obj1_id, obj2_id;         /* IDs for objects referenced */
                H5O_type_t obj1_type, obj2_type; /* Types of objects referenced */

                /* Check for types of objects handled */
                if(H5Rget_obj_type3(ref_buf1, H5P_DEFAULT, &obj1_type) < 0) TEST_ERROR
                if(H5Rget_obj_type3(ref_buf2, H5P_DEFAULT, &obj2_type) < 0) TEST_ERROR
                if(obj1_type != obj2_type) TEST_ERROR

                /* Open referenced objects */
                if((obj1_id = H5Ropen_object(ref_buf1, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR
                if((obj2_id = H5Ropen_object(ref_buf2, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR

                /* break the infinite loop when the ref_object points to itself */
                if(obj_owner > 0) {
                    H5O_info_t oinfo1, oinfo2;

                    if(H5Oget_info2(obj_owner, &oinfo1, H5O_INFO_BASIC) < 0) TEST_ERROR
                    if(H5Oget_info2(obj1_id, &oinfo2, H5O_INFO_BASIC) < 0) TEST_ERROR
                    if(H5F_addr_eq(oinfo1.addr, oinfo2.addr)) {
                        if(H5Oclose(obj1_id) < 0) TEST_ERROR
                        if(H5Oclose(obj2_id) < 0) TEST_ERROR
                        return TRUE;
                    }
                }

                /* Check for types of objects handled */
                switch(obj1_type) {
                    case H5O_TYPE_DATASET:
                        if(compare_datasets(obj1_id, obj2_id, pid, NULL) != TRUE) TEST_ERROR
                        break;

                    case H5O_TYPE_GROUP:
                        if(compare_groups(obj1_id, obj2_id, pid, -1, 0) != TRUE) TEST_ERROR
                        break;

                    case H5O_TYPE_NAMED_DATATYPE:
                        if(H5Tequal(obj1_id, obj2_id) != TRUE) TEST_ERROR
                        break;

                    case H5O_TYPE_MAP:
                        /* Maps not supported in native VOL connector */

                    case H5O_TYPE_UNKNOWN:
                    case H5O_TYPE_NTYPES:
                    default:
                        TEST_ERROR
                } /* end switch */

                /* Close objects */
                if(H5Oclose(obj1_id) < 0) TEST_ERROR
                if(H5Oclose(obj2_id) < 0) TEST_ERROR

                if(H5Rget_type(ref_buf1) == H5R_DATASET_REGION2) {
                    hid_t obj1_sid, obj2_sid;       /* Dataspace IDs for objects referenced */

                    /* Get regions for referenced datasets */
                    if((obj1_sid = H5Ropen_region(ref_buf1, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR
                    if((obj2_sid = H5Ropen_region(ref_buf2, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR

                    /* Check if dataspaces are the same shape */
                    if(H5Sselect_shape_same(obj1_sid, obj2_sid) < 0) TEST_ERROR

                    /* Close dataspaces */
                    if(H5Sclose(obj1_sid) < 0) TEST_ERROR
                    if(H5Sclose(obj2_sid) < 0) TEST_ERROR
                } /* end if */
            } /* end for */
        } /* end if */
        else
            TEST_ERROR
    } /* end else */
    else
        if(HDmemcmp(buf1, buf2, (elmt_size * nelmts))) TEST_ERROR

    /* Data should be the same. :-) */
    return TRUE;

error:
    return FALSE;
} /* end compare_data() */


/*-------------------------------------------------------------------------
 * Function:    compare_datasets
 *
 * Purpose:     Compare two datasets to check that they are equal
 *
 * Return:    TRUE if datasets are equal/FALSE if they are different
 *
 * Programmer:  Quincey Koziol
 *              Tuesday, October 25, 2005
 *
 *-------------------------------------------------------------------------
 */
static int
compare_datasets(hid_t did, hid_t did2, hid_t pid, const void *wbuf)
{
    hid_t sid = -1, sid2 = -1;                  /* Dataspace IDs */
    hid_t tid = -1, tid2 = -1;                  /* Datatype IDs */
    hid_t dcpl = -1, dcpl2 = -1;                /* Dataset creation property list IDs */
    size_t elmt_size;                           /* Size of datatype */
    htri_t is_committed;                        /* If the datatype is committed */
    htri_t is_committed2;                       /* If the datatype is committed */
    int nfilters;                               /* Number of filters applied to dataset */
    hssize_t nelmts;                            /* # of elements in dataspace */
    void *rbuf = NULL;                          /* Buffer for reading raw data */
    void *rbuf2 = NULL;                         /* Buffer for reading raw data */
    H5D_space_status_t space_status;            /* Dataset's raw dataspace status */
    H5D_space_status_t space_status2;           /* Dataset's raw dataspace status */

    /* Check the datatypes are equal */

    /* Open the datatype for the source dataset */
    if((tid = H5Dget_type(did)) < 0) TEST_ERROR

    /* Open the datatype for the destination dataset */
    if((tid2 = H5Dget_type(did2)) < 0) TEST_ERROR

    /* Check that both datatypes are committed/not committed */
    if((is_committed = H5Tcommitted(tid)) < 0) TEST_ERROR
    if((is_committed2 = H5Tcommitted(tid2)) < 0) TEST_ERROR
    if(is_committed != is_committed2) TEST_ERROR

    /* Compare the datatypes */
    if(H5Tequal(tid, tid2) != TRUE) TEST_ERROR

    /* Determine the size of datatype (for later) */
    if((elmt_size = H5Tget_size(tid)) == 0) TEST_ERROR


    /* Check the dataspaces are equal */

    /* Open the dataspace for the source dataset */
    if((sid = H5Dget_space(did)) < 0) TEST_ERROR

    /* Open the dataspace for the destination dataset */
    if((sid2 = H5Dget_space(did2)) < 0) TEST_ERROR

    /* Compare the dataspaces */
    if(H5Sextent_equal(sid, sid2) != TRUE) TEST_ERROR

    /* Determine the number of elements in dataspace (for later) */
    if((nelmts = H5Sget_simple_extent_npoints(sid)) < 0) TEST_ERROR


    /* Check the dataset creation property lists are equal */

    /* Open the dataset creation property list for the source dataset */
    if((dcpl = H5Dget_create_plist(did)) < 0) TEST_ERROR

    /* Open the dataset creation property list for the destination dataset */
    if((dcpl2 = H5Dget_create_plist(did2)) < 0) TEST_ERROR

    /* Compare the rest of the dataset creation property lists */
    if(H5Pequal(dcpl, dcpl2) != TRUE) TEST_ERROR

    /* Get the number of filters on dataset (for later) */
    if((nfilters = H5Pget_nfilters(dcpl)) < 0) TEST_ERROR

    /* close the source dataset creation property list */
    if(H5Pclose(dcpl) < 0) TEST_ERROR

    /* close the destination dataset creation property list */
    if(H5Pclose(dcpl2) < 0) TEST_ERROR


    /* Check the allocated storage is the same */

    /* Check that the space allocation status is the same */
    if(H5Dget_space_status(did, &space_status) < 0) TEST_ERROR
    if(H5Dget_space_status(did2, &space_status2) < 0) TEST_ERROR
    if(space_status != space_status2) TEST_ERROR

    /* Check that the space used is the same */
    /* (Don't check if the dataset is filtered (i.e. compressed, etc.) and
     *  the datatype is VLEN, since the addresses for the vlen
     *  data in each dataset will (probably) be different and the storage
     *  size will thus vary)
     */
    if(!(nfilters > 0 && (H5Tdetect_class(tid, H5T_VLEN) ||
            (H5Tdetect_class(tid, H5T_REFERENCE) && H5Tequal(tid, H5T_STD_REF))))) {
        hsize_t storage_size = H5Dget_storage_size(did);        /* Dataset's raw data storage size */
        hsize_t storage_size2 = H5Dget_storage_size(did2);      /* 2nd Dataset's raw data storage size */

        if(storage_size != storage_size2) TEST_ERROR
    } /* end if */

    /* Check the raw data is equal */

    /* Allocate & initialize space for the raw data buffers */
    if((rbuf = HDcalloc( elmt_size, (size_t)nelmts)) == NULL) TEST_ERROR
    if((rbuf2 = HDcalloc( elmt_size, (size_t)nelmts)) == NULL) TEST_ERROR

    /* Read data from datasets */
    if(H5Dread(did, tid, H5S_ALL, H5S_ALL, H5P_DEFAULT, rbuf) < 0) TEST_ERROR
    if(H5Dread(did2, tid2, H5S_ALL, H5S_ALL, H5P_DEFAULT, rbuf2) < 0) TEST_ERROR

    /* Check raw data read in against data written out */
    if(wbuf) {
        if(!compare_data(did, (hid_t)0, pid, tid, (size_t)nelmts, wbuf, rbuf, did)) TEST_ERROR
        if(!compare_data(did2, (hid_t)0, pid, tid2, (size_t)nelmts, wbuf, rbuf2, did2)) TEST_ERROR
    } /* end if */
    /* Don't have written data, just compare data between the two datasets */
    else
        if(!compare_data(did, did2, pid, tid, (size_t)nelmts, rbuf, rbuf2, did)) TEST_ERROR

    /* Reclaim vlen data, if necessary */
    if(H5Tdetect_class(tid, H5T_VLEN) == TRUE || H5Tdetect_class(tid, H5T_REFERENCE) == TRUE)
        if(H5Treclaim(tid, sid, H5P_DEFAULT, rbuf) < 0) TEST_ERROR
    if(H5Tdetect_class(tid2, H5T_VLEN) == TRUE || H5Tdetect_class(tid2, H5T_REFERENCE) == TRUE)
        if(H5Treclaim(tid2, sid2, H5P_DEFAULT, rbuf2) < 0) TEST_ERROR

    /* Release raw data buffers */
    HDfree(rbuf);
    rbuf = NULL;
    HDfree(rbuf2);
    rbuf2 = NULL;

    /* close the source dataspace */
    if(H5Sclose(sid) < 0) TEST_ERROR

    /* close the destination dataspace */
    if(H5Sclose(sid2) < 0) TEST_ERROR

    /* close the source datatype */
    if(H5Tclose(tid) < 0) TEST_ERROR

    /* close the destination datatype */
    if(H5Tclose(tid2) < 0) TEST_ERROR


    /* Check if the attributes are equal */
    if(compare_std_attributes(did, did2, pid) != TRUE) TEST_ERROR


    /* Datasets should be the same. :-) */
    return TRUE;

error:
    H5E_BEGIN_TRY {
        if(rbuf)
            HDfree(rbuf);
        if(rbuf2)
            HDfree(rbuf2);
        H5Pclose(dcpl2);
        H5Pclose(dcpl);
        H5Sclose(sid2);
        H5Sclose(sid);
        H5Tclose(tid2);
        H5Tclose(tid);
    } H5E_END_TRY;
    return FALSE;
} /* end compare_datasets() */


/*-------------------------------------------------------------------------
 * Function:    compare_groups
 *
 * Purpose:     Compare two groups to check that they are "equal"
 *
 * Return:    TRUE if group are equal/FALSE if they are different
 *
 * Programmer:  Quincey Koziol
 *              Monday, October 31, 2005
 *
 *-------------------------------------------------------------------------
 */
static int
compare_groups(hid_t gid, hid_t gid2, hid_t pid, int depth, unsigned copy_flags)
{
    H5G_info_t ginfo;           /* Group info struct */
    H5G_info_t ginfo2;          /* Group info struct */
    hsize_t idx;                /* Index over the objects in group */
    unsigned cpy_flags;         /* Object copy flags */

    /* Retrieve the object copy flags from the property list, if it's non-DEFAULT */
    if(pid != H5P_DEFAULT) {
        if(H5Pget_copy_object(pid, &cpy_flags) < 0) TEST_ERROR
    } /* end if */
    else
        cpy_flags = 0;

    /* Check if both groups have the same # of objects */
    if(H5Gget_info(gid, &ginfo) < 0) TEST_ERROR
    if(H5Gget_info(gid2, &ginfo2) < 0) TEST_ERROR
    if((cpy_flags & H5O_COPY_SHALLOW_HIERARCHY_FLAG) && depth == 0) {
        if(ginfo2.nlinks != 0) TEST_ERROR
    } /* end if */
    else {
        if(ginfo.nlinks != ginfo2.nlinks) TEST_ERROR
    } /* end if */

    /* Check contents of groups */
    if(ginfo2.nlinks > 0) {
        char objname[NAME_BUF_SIZE];            /* Name of object in group */
        char objname2[NAME_BUF_SIZE];           /* Name of object in group */
        H5L_info_t linfo;                       /* Link information */
        H5L_info_t linfo2;                      /* Link information */

        /* Loop over contents of groups */
        for(idx = 0; idx < ginfo.nlinks; idx++) {
            /* Check name of objects */
            if(H5Lget_name_by_idx(gid, ".", H5_INDEX_NAME, H5_ITER_INC, idx, objname, (size_t)NAME_BUF_SIZE, H5P_DEFAULT) < 0) TEST_ERROR
            if(H5Lget_name_by_idx(gid2, ".", H5_INDEX_NAME, H5_ITER_INC, idx, objname2, (size_t)NAME_BUF_SIZE, H5P_DEFAULT) < 0) TEST_ERROR
            if(HDstrcmp(objname, objname2)) TEST_ERROR

            /* Get link info */
            if(H5Lget_info(gid, objname, &linfo, H5P_DEFAULT) < 0) TEST_ERROR
            if(H5Lget_info(gid2, objname2, &linfo2, H5P_DEFAULT) < 0) TEST_ERROR
            if(linfo.type != linfo2.type) TEST_ERROR

            /* Extra checks for "real" objects */
            if(linfo.type == H5L_TYPE_HARD) {
                hid_t oid, oid2;                /* IDs of objects within group */
                H5O_info_t oinfo, oinfo2;       /* Object info */

                /* Compare some pieces of the object info */
                if(H5Oget_info_by_name2(gid, objname, &oinfo, H5O_INFO_BASIC|H5O_INFO_HDR, H5P_DEFAULT) < 0) TEST_ERROR
                if(H5Oget_info_by_name2(gid2, objname2, &oinfo2, H5O_INFO_BASIC|H5O_INFO_HDR, H5P_DEFAULT) < 0) TEST_ERROR

                if(oinfo.type != oinfo2.type) TEST_ERROR
                if(oinfo.rc != oinfo2.rc) TEST_ERROR

                /* If NULL messages are preserved, the number of messages
                 * should be the same in the destination.
                 * Otherwise, it should simply be true that the number
                 * of messages hasn't increased.
                 */
                 if(H5O_COPY_PRESERVE_NULL_FLAG & copy_flags) {
                    if(oinfo.hdr.nmesgs != oinfo2.hdr.nmesgs)
                        ;
                    else
                        if(oinfo.hdr.nmesgs < oinfo2.hdr.nmesgs) TEST_ERROR
                 }

                /* Check for object already having been compared */
                if(addr_lookup(&oinfo))
                    continue;
                else
                    addr_insert(&oinfo);

                /* Open objects */
                if((oid = H5Oopen(gid, objname, H5P_DEFAULT)) < 0) FAIL_STACK_ERROR
                if((oid2 = H5Oopen(gid2, objname2, H5P_DEFAULT)) < 0) FAIL_STACK_ERROR

                /* Compare objects within group */
                switch(oinfo.type) {
                    case H5O_TYPE_GROUP:
                        /* Compare groups */
                        if(compare_groups(oid, oid2, pid, depth - 1, copy_flags) != TRUE) TEST_ERROR
                        break;

                    case H5O_TYPE_DATASET:
                        /* Compare datasets */
                        if(compare_datasets(oid, oid2, pid, NULL) != TRUE) TEST_ERROR
                        break;

                    case H5O_TYPE_NAMED_DATATYPE:
                        /* Compare datatypes */
                        if(H5Tequal(oid, oid2) != TRUE) TEST_ERROR
                        break;

                    case H5O_TYPE_MAP:
                        HDassert(0 && "maps not supported in native VOL connector");

                    case H5O_TYPE_UNKNOWN:
                    case H5O_TYPE_NTYPES:
                    default:
                        HDassert(0 && "Unknown type of object");
                        break;
                } /* end switch */

                /* Close objects */
                if(H5Oclose(oid) < 0) TEST_ERROR
                if(H5Oclose(oid2) < 0) TEST_ERROR
            } /* end if */
            else {
                /* Check that both links are the same size */
                if(linfo.u.val_size != linfo2.u.val_size) TEST_ERROR

                /* Compare link values */
                if(linfo.type == H5L_TYPE_SOFT ||
                        (linfo.type >= H5L_TYPE_UD_MIN && linfo.type <= H5L_TYPE_MAX)) {
                    char linkval[NAME_BUF_SIZE];            /* Link value */
                    char linkval2[NAME_BUF_SIZE];           /* Link value */

                    /* Get link values */
                    HDassert(linfo.u.val_size <= NAME_BUF_SIZE);
                    if(H5Lget_val(gid, objname, linkval, (size_t)NAME_BUF_SIZE, H5P_DEFAULT) < 0) TEST_ERROR
                    if(H5Lget_val(gid2, objname2, linkval2, (size_t)NAME_BUF_SIZE, H5P_DEFAULT) < 0) TEST_ERROR

                    /* Compare link data */
                    if(HDmemcmp(linkval, linkval2, linfo.u.val_size)) TEST_ERROR
                } /* end else-if */
                else {
HDassert(0 && "Unknown type of link");
                } /* end else */
            } /* end else */
        } /* end for */
    } /* end if */

    /* Check if the attributes are equal */
    if(compare_std_attributes(gid, gid2, pid) != TRUE) TEST_ERROR

    /* Groups should be the same. :-) */
    return TRUE;

error:
    H5E_BEGIN_TRY {
    } H5E_END_TRY;
    return FALSE;
} /* end compare_groups() */

/*-------------------------------------------------------------------------
 * Function:    test_copy_option
 *
 * Purpose:     Create a group in SRC file and copy it to DST file
 *
 * Return:      Success:        0
 *              Failure:        number of errors
 *
 * Programmer:  Peter Cao
 *               March 11, 2006
 *
 *-------------------------------------------------------------------------
 */
static int
test_copy_option(hid_t fcpl_src, hid_t fcpl_dst, hid_t src_fapl, hid_t dst_fapl,
    unsigned flag, hbool_t crt_intermediate_grp, const char* test_desciption)
{
    hid_t fid_src = -1, fid_dst = -1, fid_ext = -1; /* File IDs */
    hid_t sid = -1;                             /* Dataspace ID */
    hid_t did = -1;                             /* Dataset ID */
    hid_t gid=-1, gid2=-1, gid_ref=-1;          /* Group IDs */
    hid_t gid_sub=-1, gid_sub_sub=-1;           /* Sub-group ID */
    hid_t pid=-1, lcpl_id=-1;            /* Property IDs */
    unsigned cpy_flags;                         /* Object copy flags */
    int depth = -1;                             /* Copy depth */
    hsize_t dim2d[2];
    int buf[DIM_SIZE_1][DIM_SIZE_2];
    int i, j;
    char src_filename[NAME_BUF_SIZE];
    char dst_filename[NAME_BUF_SIZE];

    TESTING(test_desciption);

    /* set initial data values */
    for (i=0; i<DIM_SIZE_1; i++)
        for (j=0; j<DIM_SIZE_2; j++)
            buf[i][j] = 10000 + 100*i+j;

    /* Initialize the filenames */
    h5_fixname(FILENAME[0], src_fapl, src_filename, sizeof src_filename);
    h5_fixname(FILENAME[1], dst_fapl, dst_filename, sizeof dst_filename);

    /* Reset file address checking info */
    addr_reset();

    /* create source file */
    if((fid_src = H5Fcreate(src_filename, H5F_ACC_TRUNC, fcpl_src, src_fapl)) < 0) TEST_ERROR

    /* create group at the SRC file */
    if((gid = H5Gcreate2(fid_src, NAME_GROUP_TOP, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR

    /* attach attributes to the group */
    if(test_copy_attach_attributes(gid, H5T_NATIVE_INT) < 0) TEST_ERROR

    /* Set dataspace dimensions */
    dim2d[0]=DIM_SIZE_1;
    dim2d[1]=DIM_SIZE_2;

    /* create dataspace */
    if((sid = H5Screate_simple(2, dim2d, NULL)) < 0) TEST_ERROR

    /* add a dataset to the top group */
    if((did = H5Dcreate2(gid, NAME_DATASET_SIMPLE, H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR
    if(H5Dwrite(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, buf) < 0) TEST_ERROR
    if(H5Dclose(did) < 0) TEST_ERROR

    /* create a sub-group */
    if((gid_sub = H5Gcreate2(fid_src, NAME_GROUP_SUB, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR

    /* add a dataset to the sub group */
    if((did = H5Dcreate2(gid_sub, NAME_DATASET_SIMPLE, H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR
    if(H5Dwrite(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, buf) < 0) TEST_ERROR
    if(H5Dclose(did) < 0) TEST_ERROR

    /* create sub-sub-group */
    if((gid_sub_sub = H5Gcreate2(gid_sub, NAME_GROUP_SUB_SUB2, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR

    /* add a dataset to the sub sub group */
    if((did = H5Dcreate2(gid_sub_sub, NAME_DATASET_SIMPLE, H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR
    if(H5Dwrite(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, buf) < 0) TEST_ERROR

    /* close dataset */
    if(H5Dclose(did) < 0) TEST_ERROR

    /* close dataspace */
    if(H5Sclose(sid) < 0) TEST_ERROR

    if(H5Gclose(gid_sub_sub) < 0) TEST_ERROR

    if(H5Gclose(gid_sub) < 0) TEST_ERROR

    /* close the group */
    if(H5Gclose(gid) < 0) FAIL_STACK_ERROR

    if((flag & H5O_COPY_EXPAND_SOFT_LINK_FLAG) > 0) {
        /* Create group to copy */
        if((gid = H5Gcreate2(fid_src, NAME_GROUP_LINK, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) FAIL_STACK_ERROR
        if(H5Lcreate_soft(NAME_DATASET_SUB_SUB, fid_src, NAME_LINK_SOFT, H5P_DEFAULT, H5P_DEFAULT) < 0) FAIL_STACK_ERROR
        if(H5Lcreate_soft("nowhere", fid_src, NAME_LINK_SOFT_DANGLE, H5P_DEFAULT, H5P_DEFAULT) < 0) FAIL_STACK_ERROR
        if(H5Gclose(gid) < 0) FAIL_STACK_ERROR

        /* Create group to compare with */
        if((gid = H5Gcreate2(fid_src, NAME_GROUP_LINK2, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) FAIL_STACK_ERROR
        if(H5Lcreate_hard(fid_src, NAME_DATASET_SUB_SUB, H5L_SAME_LOC, NAME_LINK_SOFT2, H5P_DEFAULT, H5P_DEFAULT) < 0) FAIL_STACK_ERROR
        if(H5Lcreate_soft("nowhere", fid_src, NAME_LINK_SOFT_DANGLE2, H5P_DEFAULT, H5P_DEFAULT) < 0) FAIL_STACK_ERROR
        if(H5Gclose(gid) < 0) FAIL_STACK_ERROR
    } /* end if */

    if((flag & H5O_COPY_EXPAND_EXT_LINK_FLAG) > 0) {
        char    ext_filename[NAME_BUF_SIZE];

        h5_fixname(FILENAME[2], src_fapl, ext_filename, sizeof ext_filename);

        /* Create the external file and dataset */
        if((fid_ext = H5Fcreate(ext_filename, H5F_ACC_TRUNC, fcpl_src, src_fapl)) < 0) TEST_ERROR
        if((sid = H5Screate_simple(2, dim2d, NULL)) < 0) TEST_ERROR
        if((did = H5Dcreate2(fid_ext, NAME_DATASET_SIMPLE, H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR
        if(H5Dwrite(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, buf) < 0) TEST_ERROR
        if(H5Dclose(did) < 0) TEST_ERROR
        if(H5Fclose(fid_ext) < 0) TEST_ERROR

        /* Create group to copy */
        if(!(flag & H5O_COPY_EXPAND_SOFT_LINK_FLAG)) {
            if((gid = H5Gcreate2(fid_src, NAME_GROUP_LINK, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR
        } /* end if */
        else
            if((gid = H5Gopen2(fid_src, NAME_GROUP_LINK, H5P_DEFAULT)) < 0) TEST_ERROR
        if(H5Lcreate_external(ext_filename, NAME_DATASET_SIMPLE, fid_src, NAME_LINK_EXTERN, H5P_DEFAULT, H5P_DEFAULT) < 0) TEST_ERROR
        if(H5Lcreate_external("no_file", "no_object", fid_src, NAME_LINK_EXTERN_DANGLE, H5P_DEFAULT, H5P_DEFAULT) < 0) TEST_ERROR
        if(H5Gclose(gid) < 0) TEST_ERROR

        /* Create group to compare with */
        if(!(flag & H5O_COPY_EXPAND_SOFT_LINK_FLAG)) {
            if((gid = H5Gcreate2(fid_src, NAME_GROUP_LINK2, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR
        } /* end if */
        else
            if((gid = H5Gopen2(fid_src, NAME_GROUP_LINK2, H5P_DEFAULT)) < 0) TEST_ERROR
        if((did = H5Dcreate2(fid_src, NAME_LINK_EXTERN2, H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR
        if(H5Dwrite(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, buf) < 0) TEST_ERROR
        if(H5Lcreate_external("no_file", "no_object", fid_src, NAME_LINK_EXTERN_DANGLE2, H5P_DEFAULT, H5P_DEFAULT) < 0) TEST_ERROR
        if(H5Dclose(did) < 0) TEST_ERROR
        if(H5Gclose(gid) < 0) TEST_ERROR

        /* Close dataspace */
        if(H5Sclose(sid) < 0) TEST_ERROR
    } /* end if */

    if((flag & H5O_COPY_EXPAND_REFERENCE_FLAG) > 0) {
        if((gid_ref = H5Gcreate2(fid_src, NAME_GROUP_REF, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR

        /* create an attribute of new object references */
        if(attach_ref_attr(fid_src, gid_ref) < 0) TEST_ERROR

        /* create an attribute of region references */
        if(attach_reg_ref_attr(fid_src, gid_ref) < 0) TEST_ERROR

        /* create a dataset of region references */
        if(create_reg_ref_dataset(fid_src, gid_ref) < 0) TEST_ERROR

        /* Close group holding reference objects */
        if(H5Gclose(gid_ref) < 0) TEST_ERROR
    } /* end if */

    /* close the SRC file */
    if(H5Fclose(fid_src) < 0) TEST_ERROR

    /* open the source file with read-only */
    /* (except when expanding soft links */
    if((flag & H5O_COPY_EXPAND_SOFT_LINK_FLAG) > 0) {
        if((fid_src = H5Fopen(src_filename, H5F_ACC_RDWR, src_fapl)) < 0) TEST_ERROR
    } /* end if */
    else
        if((fid_src = H5Fopen(src_filename, H5F_ACC_RDONLY, src_fapl)) < 0) TEST_ERROR

    /* create destination file */
    if((fid_dst = H5Fcreate(dst_filename, H5F_ACC_TRUNC, fcpl_dst, dst_fapl)) < 0) TEST_ERROR

    /* Create an uncopied object in destination file so that addresses in source and destination
       files aren't the same */
    if(H5Gclose(H5Gcreate2(fid_dst, NAME_GROUP_UNCOPIED, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR

    /* create property to pass copy options */
    if((pid = H5Pcreate(H5P_OBJECT_COPY)) < 0) TEST_ERROR

    /* set options for object copy */
    if(H5Pset_copy_object(pid, flag) < 0) TEST_ERROR

    /* Verify object copy flags */
    if(H5Pget_copy_object(pid, &cpy_flags) < 0) TEST_ERROR
    if(cpy_flags != flag) TEST_ERROR

    /* copy the group from SRC to DST */
    if(crt_intermediate_grp) {
        /* Create link creation plist to pass in intermediate group creation */
        if((lcpl_id = H5Pcreate(H5P_LINK_CREATE)) < 0) TEST_ERROR
        if(H5Pset_create_intermediate_group(lcpl_id, TRUE) < 0) TEST_ERROR

        if(H5Ocopy(fid_src, NAME_GROUP_TOP, fid_dst, "/new_g0/new_g00", pid, lcpl_id) < 0) TEST_ERROR

        if(H5Pclose(lcpl_id) < 0) TEST_ERROR

        /* open the group for copy */
        if((gid = H5Gopen2(fid_src, NAME_GROUP_TOP, H5P_DEFAULT)) < 0) FAIL_STACK_ERROR

        /* open the destination group */
        if((gid2 = H5Gopen2(fid_dst, "/new_g0/new_g00", H5P_DEFAULT)) < 0) FAIL_STACK_ERROR

    } else if(((flag & H5O_COPY_EXPAND_SOFT_LINK_FLAG) > 0)
            || ((flag & H5O_COPY_EXPAND_EXT_LINK_FLAG) > 0)) {
        if(H5Ocopy(fid_src, NAME_GROUP_LINK, fid_dst, NAME_GROUP_LINK, pid, H5P_DEFAULT) < 0) TEST_ERROR

        if((flag & H5O_COPY_EXPAND_SOFT_LINK_FLAG) > 0)
            /* Unlink dataset to copy from original location */
            /* (So group comparison works properly) */
            if(H5Ldelete(fid_src, NAME_DATASET_SUB_SUB, H5P_DEFAULT) < 0) FAIL_STACK_ERROR

        /* open the group for copy */
        if((gid = H5Gopen2(fid_src, NAME_GROUP_LINK2, H5P_DEFAULT)) < 0) FAIL_STACK_ERROR

        /* open the destination group */
        if((gid2 = H5Gopen2(fid_dst, NAME_GROUP_LINK, H5P_DEFAULT)) < 0) FAIL_STACK_ERROR

    } else if(flag & (H5O_COPY_WITHOUT_ATTR_FLAG | H5O_COPY_PRESERVE_NULL_FLAG)) {
        if(H5Ocopy(fid_src, NAME_GROUP_TOP, fid_dst, NAME_GROUP_TOP, pid, H5P_DEFAULT) < 0) TEST_ERROR

        /* open the group for copy */
        if((gid = H5Gopen2(fid_src, NAME_GROUP_TOP, H5P_DEFAULT)) < 0) FAIL_STACK_ERROR

        /* open the destination group */
        if((gid2 = H5Gopen2(fid_dst, NAME_GROUP_TOP, H5P_DEFAULT)) < 0) FAIL_STACK_ERROR
    } else if(flag & H5O_COPY_SHALLOW_HIERARCHY_FLAG) {
        if(H5Ocopy(fid_src, NAME_GROUP_TOP, fid_dst, NAME_GROUP_TOP, pid, H5P_DEFAULT) < 0) TEST_ERROR

        /* open the group for copy */
        if((gid = H5Gopen2(fid_src, NAME_GROUP_TOP, H5P_DEFAULT)) < 0) FAIL_STACK_ERROR

        /* open the destination group */
        if((gid2 = H5Gopen2(fid_dst, NAME_GROUP_TOP, H5P_DEFAULT)) < 0) FAIL_STACK_ERROR

        /* Set the copy depth */
        depth = 1;
    } else if((flag & H5O_COPY_EXPAND_REFERENCE_FLAG) > 0) {
        if(H5Ocopy(fid_src, NAME_GROUP_REF, fid_dst, NAME_GROUP_REF, pid, H5P_DEFAULT) < 0) TEST_ERROR

        /* open the group for copy */
        if((gid = H5Gopen2(fid_src, NAME_GROUP_REF, H5P_DEFAULT)) < 0) FAIL_STACK_ERROR

        /* open the destination group */
        if((gid2 = H5Gopen2(fid_dst, NAME_GROUP_REF, H5P_DEFAULT)) < 0) FAIL_STACK_ERROR
    } else {
        /* Unknown flag */
        TEST_ERROR
    } /* end else */

    /* Check if the groups are equal */
    if(compare_groups(gid, gid2, pid, depth, flag) != TRUE) TEST_ERROR
    if(H5Gclose(gid2) < 0) TEST_ERROR
    if(H5Gclose(gid) < 0) TEST_ERROR

    /* close the SRC file */
    if(H5Fclose(fid_src) < 0) TEST_ERROR

    /* close the DST file */
    if(H5Fclose(fid_dst) < 0) TEST_ERROR

    /* close properties */
    if(H5Pclose(pid) < 0) TEST_ERROR

    PASSED();
    return 0;

error:
    H5E_BEGIN_TRY {
        H5Pclose(lcpl_id);
        H5Pclose(pid);
        H5Sclose(sid);
        H5Dclose(did);
        H5Gclose(gid_ref);
        H5Gclose(gid_sub);
        H5Gclose(gid2);
        H5Gclose(gid);
        H5Fclose(fid_dst);
        H5Fclose(fid_src);
        H5Fclose(fid_ext);
    } H5E_END_TRY;
    return 1;
} /* end test_copy_option */

/*-------------------------------------------------------------------------
 * Function:    main
 *
 * Purpose:     Test H5Ocopy()
 *
 *              Tests a number of cases: messages can be stored in the
 *              new or old format, messages can be shared in either,
 *              both, or neither of the source and destination files.
 *
 * Return:      EXIT_SUCCESS/EXIT_FAILURE
 *
 * Programmer:  Peter Cao
 *              Friday, September 30, 2005
 *
 *-------------------------------------------------------------------------
 */
int
main(void)
{
    int     nerrors = 0;
    hid_t    fapl, fapl2;
    hid_t   fcpl_shared, ocpl;
    unsigned    max_compact, min_dense;
    int     configuration;  /* Configuration of tests. */
    int    ExpressMode;

    /* Setup */
    h5_reset();
    fapl = h5_fileaccess();

    ExpressMode = GetTestExpress();
    if (ExpressMode > 1)
        HDprintf("***Express test mode on.  Some tests may be skipped\n");

    /* Copy the file access property list */
    if((fapl2 = H5Pcopy(fapl)) < 0) TEST_ERROR

    /* Set the "use the latest version of the format" bounds for creating objects in the file */
    if(H5Pset_libver_bounds(fapl2, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0) TEST_ERROR

    /* Create an FCPL with sharing enabled */
    if((fcpl_shared = H5Pcreate(H5P_FILE_CREATE)) < 0) TEST_ERROR
    if(H5Pset_shared_mesg_nindexes(fcpl_shared, 1) < 0) TEST_ERROR
    if(H5Pset_shared_mesg_index(fcpl_shared, 0, H5O_SHMESG_ALL_FLAG, 10) < 0) TEST_ERROR

    /* Obtain the default attribute storage phase change values */
    if((ocpl = H5Pcreate(H5P_OBJECT_CREATE)) < 0) TEST_ERROR
    if(H5Pget_attr_phase_change(ocpl, &max_compact, &min_dense) < 0) TEST_ERROR
    if(H5Pclose(ocpl) < 0) TEST_ERROR

    /* Test in all configurations */
    for(configuration = 0; configuration <= MAX_CONFIGURATION; configuration++) {
        hid_t src_fapl;
        hid_t dst_fapl;
        hid_t fcpl_src;
        hid_t fcpl_dst;

        /* No need to test dense attributes with old format */
        if(!(configuration & CONFIG_SRC_NEW_FORMAT) && (configuration & CONFIG_DENSE))
            continue;

        /* TODO Region references currently do not support copy from new format to old format
         * (this may be fixed once H5Sencode/decode and H5CXis fixed) */
        if((configuration & CONFIG_SRC_NEW_FORMAT) && !(configuration & CONFIG_DST_NEW_FORMAT))
            continue;

        /* Test with and without shared messages */
        if(configuration & CONFIG_SHARE_SRC) {
            HDputs("\nTesting with shared src messages:");
            fcpl_src = fcpl_shared;
        }
        else {
            HDputs("\nTesting without shared src messages:");
            fcpl_src = H5P_DEFAULT;
        }
        if(configuration & CONFIG_SHARE_DST) {
            HDputs("Testing with shared dst messages:");
            fcpl_dst = fcpl_shared;
        }
        else {
            HDputs("Testing without shared dst messages:");
            fcpl_dst = H5P_DEFAULT;
        }

        /* Set the FAPL for the source file's type of format */
        if(configuration & CONFIG_SRC_NEW_FORMAT) {
            HDputs("Testing with latest format for source file:");
            src_fapl = fapl2;

            /* Test with and without dense attributes */
            if(configuration & CONFIG_DENSE) {
                HDputs("Testing with dense attributes:");
                num_attributes_g = max_compact + 1;
            }
            else {
                HDputs("Testing without dense attributes:");
                num_attributes_g = MAX(min_dense, 2) - 2;
            }
        } /* end if */
        else {
            HDputs("Testing with oldest file format for source file:");
            src_fapl = fapl;
            num_attributes_g = 4;
        } /* end else */

        /* Set the FAPL for the destination file's type of format */
        if(configuration & CONFIG_DST_NEW_FORMAT) {
            HDputs("Testing with latest format for destination file:");
            dst_fapl = fapl2;
        } /* end if */
        else {
            HDputs("Testing with oldest file format for destination file:");
            dst_fapl = fapl;
        } /* end else */

        /* The tests... */
        nerrors += test_copy_option(fcpl_src, fcpl_dst, src_fapl, dst_fapl,
                    H5O_COPY_EXPAND_REFERENCE_FLAG,
                    FALSE, "H5Ocopy(): expand object reference");
    } /* end for */

    /* Reset file address checking info */
    addr_reset();

    /* Verify symbol table messages are cached */
    nerrors += (h5_verify_cached_stabs(FILENAME, fapl) < 0 ? 1 : 0);

    /* Results */
    if(nerrors) {
        HDprintf("***** %d OBJECT COPY TEST%s FAILED! *****\n",
                nerrors, (1 == nerrors ? "" : "S"));
        HDexit(EXIT_FAILURE);
    } /* end if */

    HDputs ("All object copying tests passed.");

    /* close property list.
     * NOTE: if this property list is not closed and the test is
     *          run with the split or multi driver, an interesting
     *          problem is exposed in the property list shutdown code.
     *
     *          Namely, since the split/multi driver copies property
     *          lists for internal use, there's a (high) chance that
     *          leaving the FAPL open and having the library's shutdown
     *          code close it will cause the underlying property lists
     *          to be cleaned up first, causing the actual property list
     *          close operation to fail (since it won't be able to close
     *          the already closed underlying property list).
     *
     *          The could be addressed by converting the split/multi to
     *          use non-public API routines, or putting some way into the
     *          public H5I routines to indicate ordering at shutdown.
     *
     *          For now, we just make certain to close the property list.
     *          (QAK - 2016/04/06)
     *
     */
    H5Pclose(fapl2);

    h5_cleanup(FILENAME, fapl);

    HDexit(EXIT_SUCCESS);

error:
    HDexit(EXIT_FAILURE);
} /* main */