summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--MANIFEST1
-rw-r--r--README2
-rw-r--r--src/H5.c2
-rw-r--r--src/H5D.c77
-rw-r--r--src/H5F.c25
-rw-r--r--src/H5Fprivate.h2
-rw-r--r--src/H5G.c149
-rw-r--r--src/H5Gpkg.h9
-rw-r--r--src/H5Gprivate.h3
-rw-r--r--src/H5I.c4
-rw-r--r--src/H5O.c16
-rw-r--r--src/H5R.c4
-rw-r--r--src/H5T.c9
-rw-r--r--test/Makefile.in9
-rw-r--r--test/mount.c1072
15 files changed, 1295 insertions, 89 deletions
diff --git a/MANIFEST b/MANIFEST
index b949c42..8112a82 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -298,6 +298,7 @@
./test/iopipe.c
./test/istore.c
./test/links.c
+./test/mount.c
./test/mtime.c
./test/overhead.c
./test/ragged.c
diff --git a/README b/README
index c05ccdf..806c481 100644
--- a/README
+++ b/README
@@ -1,4 +1,4 @@
-This is hdf5-1.1.11 released on Wed Oct 14 04:19:52 CDT 1998
+This is hdf5-1.1.12 released on Wed Oct 14 14:33:41 CDT 1998
Please refer to the INSTALL file for installation instructions.
------------------------------------------------------------------------------
diff --git a/src/H5.c b/src/H5.c
index fa6eba3..3fc25d7 100644
--- a/src/H5.c
+++ b/src/H5.c
@@ -1172,7 +1172,7 @@ H5_trace (hbool_t returning, const char *func, const char *type, ...)
}
/* Clear array sizes */
- for (i=0; i<NELMTS(asize); i++) asize[i] = -1;
+ for (i=0; i<(hssize_t)NELMTS(asize); i++) asize[i] = -1;
/* Parse the argument types */
for (argno=0; *type; argno++, type+=HDisupper(*type)?2:1) {
diff --git a/src/H5D.c b/src/H5D.c
index 27b46ca..6f5ca00 100644
--- a/src/H5D.c
+++ b/src/H5D.c
@@ -832,10 +832,12 @@ H5D_new(const H5D_create_t *create_parms)
HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, NULL,
"memory allocation failed");
}
- if(create_parms!=NULL)
+ if(create_parms!=NULL) {
ret_value->create_parms = H5P_copy (H5P_DATASET_CREATE, create_parms);
- else
- ret_value->create_parms = H5P_copy (H5P_DATASET_CREATE, &H5D_create_dflt);
+ } else {
+ ret_value->create_parms = H5P_copy (H5P_DATASET_CREATE,
+ &H5D_create_dflt);
+ }
H5F_addr_undef(&(ret_value->ent.header));
/* Success */
@@ -887,17 +889,28 @@ H5D_create(H5G_entry_t *loc, const char *name, const H5T_t *type,
intn i, ndims;
hsize_t max_dim[H5O_LAYOUT_NDIMS];
H5O_efl_t *efl = NULL;
- H5F_t *f = loc->file;
+ H5F_t *f = NULL;
FUNC_ENTER(H5D_create, NULL);
/* check args */
- assert (f);
assert (loc);
assert (name && *name);
assert (type);
assert (space);
assert (create_parms);
+ if (create_parms->pline.nfilters>0 &&
+ H5D_CHUNKED!=create_parms->layout) {
+ HGOTO_ERROR (H5E_DATASET, H5E_BADVALUE, NULL,
+ "filters can only be used with chunked layout");
+ }
+
+ /* What file is the dataset being added to? */
+ if (NULL==(f=H5G_insertion_file(loc, name))) {
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, NULL,
+ "unable to locate insertion point");
+ }
+
#ifdef HAVE_PARALLEL
/* If MPIO is used, no filter support yet. */
if (f->shared->access_parms->driver == H5F_LOW_MPIO &&
@@ -906,12 +919,7 @@ H5D_create(H5G_entry_t *loc, const char *name, const H5T_t *type,
"Parallel IO does not support filters yet");
}
#endif
- if (create_parms->pline.nfilters>0 &&
- H5D_CHUNKED!=create_parms->layout) {
- HGOTO_ERROR (H5E_DATASET, H5E_BADVALUE, NULL,
- "filters can only be used with chunked layout");
- }
-
+
/* Initialize the dataset object */
if (NULL==(new_dset = H5D_new(create_parms))) {
HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, NULL,
@@ -1118,8 +1126,9 @@ H5D_create(H5G_entry_t *loc, const char *name, const H5T_t *type,
* Modifications:
* Robb Matzke, 9 Jun 1998
* The data space message is no longer cached in the dataset struct.
- * Quincey Koziol, 12 Oct 1998
- * Moved guts of function into H5D_open_oid
+ *
+ * Quincey Koziol, 12 Oct 1998
+ * Moved guts of function into H5D_open_oid
*
*-------------------------------------------------------------------------
*/
@@ -1204,14 +1213,16 @@ H5D_open_oid(H5D_t *dataset, H5G_entry_t *ent)
}
/* Get the optional fill value message */
- if (NULL==H5O_read(&(dataset->ent), H5O_FILL, 0, &(dataset->create_parms->fill))) {
+ if (NULL==H5O_read(&(dataset->ent), H5O_FILL, 0,
+ &(dataset->create_parms->fill))) {
H5E_clear();
HDmemset(&(dataset->create_parms->fill), 0,
sizeof(dataset->create_parms->fill));
}
/* Get the optional filters message */
- if (NULL==H5O_read (&(dataset->ent), H5O_PLINE, 0, &(dataset->create_parms->pline))) {
+ if (NULL==H5O_read (&(dataset->ent), H5O_PLINE, 0,
+ &(dataset->create_parms->pline))) {
H5E_clear ();
HDmemset (&(dataset->create_parms->pline), 0,
sizeof(dataset->create_parms->pline));
@@ -1219,7 +1230,7 @@ H5D_open_oid(H5D_t *dataset, H5G_entry_t *ent)
#ifdef HAVE_PARALLEL
/* If MPIO is used, no filter support yet. */
- if (dataset.ent.file->shared->access_parms->driver == H5F_LOW_MPIO &&
+ if (dataset->ent.file->shared->access_parms->driver == H5F_LOW_MPIO &&
dataset->create_parms->pline.nfilters>0){
HGOTO_ERROR (H5E_DATASET, H5E_UNSUPPORTED, FAIL,
"Parallel IO does not support filters yet");
@@ -1255,12 +1266,14 @@ H5D_open_oid(H5D_t *dataset, H5G_entry_t *ent)
break;
default:
- HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "not implemented yet");
+ HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL,
+ "not implemented yet");
}
/* Get the external file list message, which might not exist */
- if (NULL==H5O_read (&(dataset->ent), H5O_EFL, 0, &(dataset->create_parms->efl)) &&
- !H5F_addr_defined (&(dataset->layout.addr))) {
+ if (NULL==H5O_read (&(dataset->ent), H5O_EFL, 0,
+ &(dataset->create_parms->efl)) &&
+ !H5F_addr_defined (&(dataset->layout.addr))) {
HGOTO_ERROR (H5E_DATASET, H5E_CANTINIT, FAIL,
"storage address is undefined an no external file list");
}
@@ -1270,7 +1283,8 @@ H5D_open_oid(H5D_t *dataset, H5G_entry_t *ent)
* This is especially important for parallel I/O where the B-tree must
* be fully populated before I/O can happen.
*/
- if ((dataset->ent.file->intent & H5F_ACC_RDWR) && H5D_CHUNKED==dataset->layout.type) {
+ if ((dataset->ent.file->intent & H5F_ACC_RDWR) &&
+ H5D_CHUNKED==dataset->layout.type) {
if (H5D_init_storage(dataset, space)<0) {
HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL,
"unable to initialize file storage");
@@ -1831,7 +1845,8 @@ H5D_write(H5D_t *dataset, const H5T_t *mem_type, const H5S_t *mem_space,
* turns off background preservation.
*/
#ifdef QAK
- printf("%s: check 0.5, nelmts=%d, mem_space->rank=%d\n",FUNC,(int)nelmts,mem_space->extent.u.simple.rank);
+ printf("%s: check 0.5, nelmts=%d, mem_space->rank=%d\n", FUNC,
+ (int)nelmts, mem_space->extent.u.simple.rank);
#endif /* QAK */
if (nelmts!=H5S_get_select_npoints (file_space)) {
HGOTO_ERROR (H5E_ARGS, H5E_BADVALUE, FAIL,
@@ -2266,8 +2281,7 @@ H5D_init_storage(H5D_t *dset, const H5S_t *space)
intn ndims;
hsize_t dim[H5O_LAYOUT_NDIMS];
hsize_t npoints, ptsperbuf;
- size_t i, size, bufsize=8*1024;
- hbool_t all_zero;
+ size_t size, bufsize=8*1024;
hid_t buf_id = -1;
haddr_t addr;
herr_t ret_value = FAIL;
@@ -2280,18 +2294,13 @@ H5D_init_storage(H5D_t *dset, const H5S_t *space)
switch (dset->layout.type) {
case H5D_CONTIGUOUS:
/*
- * If the fill value is non-zero then write the fill value to the
- * specified selection.
+ * If the fill value is set then write it to the specified selection
+ * even if it is all zero. This allows the application to force
+ * filling when the underlying storage isn't initialized to zero.
*/
- for (i=0, all_zero=TRUE; i<dset->create_parms->fill.size; i++) {
- if (((uint8*)(dset->create_parms->fill.buf))[i]) {
- all_zero = FALSE;
- break;
- }
- }
npoints = H5S_get_simple_extent_npoints(space);
-
- if (!all_zero && npoints==H5S_get_select_npoints(space)) {
+ if (dset->create_parms->fill.buf &&
+ npoints==H5S_get_select_npoints(space)) {
/*
* Fill the entire current extent with the fill value. We can do
* this quite efficiently by making sure we copy the fill value
@@ -2330,7 +2339,7 @@ H5D_init_storage(H5D_t *dset, const H5S_t *space)
npoints -= MIN(ptsperbuf, npoints);
H5F_addr_inc(&addr, size);
}
- } else if (!all_zero) {
+ } else if (dset->create_parms->fill.buf) {
/*
* Fill the specified selection with the fill value.
*/
diff --git a/src/H5F.c b/src/H5F.c
index 9436104..ac5d2fd 100644
--- a/src/H5F.c
+++ b/src/H5F.c
@@ -289,7 +289,7 @@ H5Fget_create_plist(hid_t file_id)
H5TRACE1("i","i",file_id);
/* check args */
- if (H5I_FILE != H5I_get_type(file_id) || NULL==(file=H5I_object(file_id))) {
+ if (H5I_FILE!=H5I_get_type(file_id) || NULL==(file=H5I_object(file_id))) {
HRETURN_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file");
}
@@ -1535,15 +1535,29 @@ H5F_flush(H5F_t *f, hbool_t invalidate)
herr_t
H5F_close(H5F_t *f)
{
+ uintn i;
+
FUNC_ENTER(H5F_close, FAIL);
/*
+ * Find the root of the virtual file. Then unmount and close each child
+ * before closing the current file.
+ */
+ while (f->mtab.parent) f = f->mtab.parent;
+ for (i=0; i<f->mtab.nmounts; i++) {
+ H5G_close(f->mtab.child[i].group);
+ f->mtab.child[i].file->mtab.parent = NULL;
+ H5F_close(f->mtab.child[i].file);
+ }
+ f->mtab.nmounts = 0;
+
+ /*
* If object headers are still open then delay deletion of resources until
* they have all been closed. Flush all caches and update the object
* header anyway so that failing to close all objects isn't a major
* problem.
*/
- if (f->nopen>0) {
+ if (f->nopen_objs>0) {
if (H5F_flush(f, FALSE)<0) {
HRETURN_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL,
"unable to flush cache");
@@ -1553,9 +1567,9 @@ H5F_close(H5F_t *f)
fprintf(H5DEBUG(F), "H5F: H5F_close(%s): %u object header%s still "
"open (file close will complete when %s closed)\n",
f->name,
- f->nopen,
- 1 == f->nopen ? " is" : "s are",
- 1 == f->nopen ? "that header is" : "those headers are");
+ f->nopen_objs,
+ 1 == f->nopen_objs?" is":"s are",
+ 1 == f->nopen_objs?"that header is":"those headers are");
}
#endif
f->close_pending = TRUE;
@@ -1942,6 +1956,7 @@ H5F_mountpoint(H5G_entry_t *find/*in,out*/)
if (0==cmp) {
ent = H5G_entof(parent->mtab.child[md].file->shared->root_grp);
*find = *ent;
+ parent = ent->file;
}
} while (!cmp);
diff --git a/src/H5Fprivate.h b/src/H5Fprivate.h
index 8ba9613..004c411 100644
--- a/src/H5Fprivate.h
+++ b/src/H5Fprivate.h
@@ -479,7 +479,7 @@ typedef struct H5F_t {
uintn intent; /* The flags passed to H5F_open()*/
char *name; /* Name used to open file */
H5F_file_t *shared; /* The shared file info */
- uintn nopen; /* Number of open object headers*/
+ uintn nopen_objs; /* Number of open object headers*/
hbool_t close_pending; /* File close is pending */
H5F_mtab_t mtab; /* File mount table */
} H5F_t;
diff --git a/src/H5G.c b/src/H5G.c
index e2d0e39..90dd1a9 100644
--- a/src/H5G.c
+++ b/src/H5G.c
@@ -427,7 +427,7 @@ H5Glink(hid_t loc_id, H5G_link_t type, const char *cur_name,
HRETURN_ERROR (H5E_ARGS, H5E_BADVALUE, FAIL,
"no new name specified");
}
- if (H5G_link (loc, type, cur_name, new_name)<0) {
+ if (H5G_link (loc, type, cur_name, new_name, H5G_TARGET_NORMAL)<0) {
HRETURN_ERROR (H5E_SYM, H5E_LINK, FAIL, "unable to create link");
}
@@ -839,15 +839,21 @@ H5G_basename(const char *name, size_t *size_p)
* understood by this function (unless it appears as an entry in
* the symbol table).
*
- * Symbolic links are followed automatically, but if
- * FOLLOW_SLINK is false and the last component of the name is a
- * symbolic link then that link is not followed. At most NLINKS
- * are followed and the next link generates an error.
+ * Symbolic links are followed automatically, but if TARGET
+ * includes the H5G_TARGET_SLINK bit and the last component of
+ * the name is a symbolic link then that link is not followed.
+ * The *NLINKS value is decremented each time a link is followed
+ * and link traversal fails if the value would become negative.
+ * If NLINKS is the null pointer then a default value is used.
*
* Mounted files are handled by calling H5F_mountpoint() after
* each step of the translation. If the input argument to that
* function is a mount point then the argument shall be replaced
* with information about the root group of the mounted file.
+ * But if TARGET includes the H5G_TARGET_MOUNT bit and the last
+ * component of the name is a mount point then H5F_mountpoint()
+ * is not called and information about the mount point itself is
+ * returned.
*
* Errors:
*
@@ -871,7 +877,7 @@ H5G_basename(const char *name, size_t *size_p)
static herr_t
H5G_namei(H5G_entry_t *loc_ent, const char *name, const char **rest/*out*/,
H5G_entry_t *grp_ent/*out*/, H5G_entry_t *obj_ent/*out*/,
- hbool_t follow_slink, intn *nlinks)
+ uintn target, intn *nlinks)
{
H5G_entry_t _grp_ent; /*entry for current group */
H5G_entry_t _obj_ent; /*entry found */
@@ -944,11 +950,12 @@ H5G_namei(H5G_entry_t *loc_ent, const char *name, const char **rest/*out*/,
/*
* If we found a symbolic link then we should follow it. But if this
- * is the last component of the name and FOLLOW_SLINK is zero then we
- * don't follow it.
+ * is the last component of the name and the H5G_TARGET_SLINK bit of
+ * TARGET is set then we don't follow it.
*/
if (H5G_CACHED_SLINK==obj_ent->type &&
- (follow_slink || ((s=H5G_component(name+nchars, NULL)) && *s))) {
+ (0==(target & H5G_TARGET_SLINK) ||
+ ((s=H5G_component(name+nchars, NULL)) && *s))) {
if ((*nlinks)-- <= 0) {
HRETURN_ERROR (H5E_SYM, H5E_SLINK, FAIL,
"too many symbolic links");
@@ -959,8 +966,17 @@ H5G_namei(H5G_entry_t *loc_ent, const char *name, const char **rest/*out*/,
}
}
+ /*
+ * Resolve mount points to the mounted group. Do not do this step if
+ * the H5G_TARGET_MOUNT bit of TARGET is set and this is the last
+ * component of the name.
+ */
+ if (0==(target & H5G_TARGET_MOUNT) ||
+ ((s=H5G_component(name+nchars, NULL)) && *s)) {
+ H5F_mountpoint(obj_ent/*in,out*/);
+ }
+
/* next component */
- H5F_mountpoint(obj_ent/*in,out*/);
name += nchars;
}
if (rest) *rest = name; /*final null */
@@ -1014,7 +1030,8 @@ H5G_traverse_slink (H5G_entry_t *grp_ent/*in,out*/,
linkval = H5MM_xstrdup (clv);
/* Traverse the link */
- if (H5G_namei (grp_ent, linkval, NULL, grp_ent, obj_ent, TRUE, nlinks)) {
+ if (H5G_namei (grp_ent, linkval, NULL, grp_ent, obj_ent, H5G_TARGET_NORMAL,
+ nlinks)) {
HGOTO_ERROR (H5E_SYM, H5E_NOTFOUND, FAIL,
"unable to follow symbolic link");
}
@@ -1101,8 +1118,8 @@ H5G_mkroot (H5F_t *f, H5G_entry_t *ent)
}
f->shared->root_grp->ent = *ent;
f->shared->root_grp->nref = 1;
- assert (1==f->nopen);
- f->nopen = 0;
+ assert (1==f->nopen_objs);
+ f->nopen_objs = 0;
FUNC_LEAVE(SUCCEED);
}
@@ -1146,7 +1163,8 @@ H5G_create(H5G_entry_t *loc, const char *name, size_t size_hint)
assert(name && *name);
/* lookup name */
- if (0 == H5G_namei(loc, name, &rest, &grp_ent, NULL, TRUE, NULL)) {
+ if (0 == H5G_namei(loc, name, &rest, &grp_ent, NULL, H5G_TARGET_NORMAL,
+ NULL)) {
HRETURN_ERROR(H5E_SYM, H5E_EXISTS, NULL, "already exists");
}
H5E_clear(); /*it's OK that we didn't find it */
@@ -1320,11 +1338,15 @@ H5G_close(H5G_t *grp)
/*-------------------------------------------------------------------------
* Function: H5G_rootof
*
- * Purpose: Return a pointer to the root group of the file.
+ * Purpose: Return a pointer to the root group of the file. If the file
+ * is part of a virtual file then the root group of the virtual
+ * file is returned.
*
- * Return: Success:
+ * Return: Success: Ptr to the root group of the file. Do not
+ * free the pointer -- it points directly into
+ * the file struct.
*
- * Failure:
+ * Failure: NULL
*
* Programmer: Robb Matzke
* Tuesday, October 13, 1998
@@ -1336,8 +1358,8 @@ H5G_close(H5G_t *grp)
H5G_t *
H5G_rootof(H5F_t *f)
{
-
FUNC_ENTER(H5G_rootof, NULL);
+ while (f->mtab.parent) f = f->mtab.parent;
FUNC_LEAVE(f->shared->root_grp);
}
@@ -1378,7 +1400,7 @@ H5G_insert(H5G_entry_t *loc, const char *name, H5G_entry_t *ent)
/*
* Look up the name -- it shouldn't exist yet.
*/
- if (H5G_namei(loc, name, &rest, &grp, NULL, TRUE, NULL) >= 0) {
+ if (H5G_namei(loc, name, &rest, &grp, NULL, H5G_TARGET_NORMAL, NULL)>=0) {
HRETURN_ERROR(H5E_SYM, H5E_EXISTS, FAIL, "already exists");
}
H5E_clear(); /*it's OK that we didn't find it */
@@ -1409,6 +1431,7 @@ H5G_insert(H5G_entry_t *loc, const char *name, H5G_entry_t *ent)
"unable to increment hard link count");
}
if (H5G_stab_insert(&grp, rest, ent) < 0) {
+ H5O_link(ent, -1);
HRETURN_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to insert name");
}
FUNC_LEAVE(SUCCEED);
@@ -1452,7 +1475,8 @@ H5G_find(H5G_entry_t *loc, const char *name,
assert (loc);
assert (name && *name);
- if (H5G_namei(loc, name, NULL, grp_ent, obj_ent, TRUE, NULL)<0) {
+ if (H5G_namei(loc, name, NULL, grp_ent, obj_ent, H5G_TARGET_NORMAL,
+ NULL)<0) {
HRETURN_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "object not found");
}
FUNC_LEAVE(SUCCEED);
@@ -1650,7 +1674,7 @@ H5G_loc (hid_t loc_id)
*/
herr_t
H5G_link (H5G_entry_t *loc, H5G_link_t type, const char *cur_name,
- const char *new_name)
+ const char *new_name, uintn namei_flags)
{
H5G_entry_t cur_obj; /*entry for the link tail */
H5G_entry_t grp_ent; /*ent for grp containing link hd*/
@@ -1673,7 +1697,8 @@ H5G_link (H5G_entry_t *loc, H5G_link_t type, const char *cur_name,
* Lookup the the new_name so we can get the group which will contain
* the new entry. The entry shouldn't exist yet.
*/
- if (H5G_namei (loc, new_name, &rest, &grp_ent, NULL, TRUE, NULL)>=0) {
+ if (H5G_namei (loc, new_name, &rest, &grp_ent, NULL, H5G_TARGET_NORMAL,
+ NULL)>=0) {
HRETURN_ERROR (H5E_SYM, H5E_EXISTS, FAIL, "already exists");
}
H5E_clear (); /*it's okay that we didn't find it*/
@@ -1738,9 +1763,10 @@ H5G_link (H5G_entry_t *loc, H5G_link_t type, const char *cur_name,
break;
case H5G_LINK_HARD:
- if (H5G_find (loc, cur_name, NULL, &cur_obj)<0) {
- HRETURN_ERROR (H5E_SYM, H5E_NOTFOUND, FAIL,
- "source object not found");
+ if (H5G_namei(loc, cur_name, NULL, NULL, &cur_obj, namei_flags,
+ NULL)<0) {
+ HRETURN_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL,
+ "source object not found");
}
if (H5G_insert (loc, new_name, &cur_obj)<0) {
HRETURN_ERROR (H5E_SYM, H5E_CANTINIT, FAIL,
@@ -1793,7 +1819,7 @@ H5G_get_objinfo (H5G_entry_t *loc, const char *name, hbool_t follow_link,
/* Find the object's symbol table entry */
if (H5G_namei (loc, name, NULL, &grp_ent/*out*/, &obj_ent/*out*/,
- follow_link, NULL)<0) {
+ follow_link?H5G_TARGET_NORMAL:H5G_TARGET_SLINK, NULL)<0) {
HRETURN_ERROR (H5E_SYM, H5E_NOTFOUND, FAIL, "unable to stat object");
}
@@ -1889,8 +1915,8 @@ H5G_linkval (H5G_entry_t *loc, const char *name, size_t size, char *buf/*out*/)
* Get the symbol table entry for the link head and the symbol table
* entry for the group in which the link head appears.
*/
- if (H5G_namei (loc, name, NULL, &grp_ent/*out*/, &obj_ent/*out*/, FALSE,
- NULL)<0) {
+ if (H5G_namei (loc, name, NULL, &grp_ent/*out*/, &obj_ent/*out*/,
+ H5G_TARGET_SLINK, NULL)<0) {
HRETURN_ERROR (H5E_SYM, H5E_NOTFOUND, FAIL,
"symbolic link was not found");
}
@@ -1947,7 +1973,8 @@ H5G_set_comment(H5G_entry_t *loc, const char *name, const char *buf)
FUNC_ENTER(H5G_set_comment, FAIL);
/* Get the symbol table entry for the object */
- if (H5G_namei(loc, name, NULL, NULL, &obj_ent/*out*/, TRUE, NULL)<0) {
+ if (H5G_namei(loc, name, NULL, NULL, &obj_ent/*out*/, H5G_TARGET_NORMAL,
+ NULL)<0) {
HRETURN_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "object not found");
}
@@ -1996,7 +2023,8 @@ H5G_get_comment(H5G_entry_t *loc, const char *name, size_t bufsize, char *buf)
FUNC_ENTER(H5G_get_comment, FAIL);
/* Get the symbol table entry for the object */
- if (H5G_namei(loc, name, NULL, NULL, &obj_ent/*out*/, TRUE, NULL)<0) {
+ if (H5G_namei(loc, name, NULL, NULL, &obj_ent/*out*/, H5G_TARGET_NORMAL,
+ NULL)<0) {
HRETURN_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "object not found");
}
@@ -2043,7 +2071,8 @@ H5G_unlink(H5G_entry_t *loc, const char *name)
assert(name && *name);
/* Get the entry for the group that contains the object to be unlinked */
- if (H5G_namei(loc, name, NULL, &grp_ent, &obj_ent, FALSE, NULL)<0) {
+ if (H5G_namei(loc, name, NULL, &grp_ent, &obj_ent,
+ H5G_TARGET_SLINK|H5G_TARGET_MOUNT, NULL)<0) {
HRETURN_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "object not found");
}
if (!H5F_addr_defined(&(grp_ent.header))) {
@@ -2113,7 +2142,8 @@ H5G_move(H5G_entry_t *loc, const char *src_name, const char *dst_name)
"unable to read symbolic link value");
}
} while (linkval[lv_size-1]);
- if (H5G_link(loc, H5G_LINK_SOFT, linkval, dst_name)<0) {
+ if (H5G_link(loc, H5G_LINK_SOFT, linkval, dst_name,
+ H5G_TARGET_NORMAL)<0) {
HRETURN_ERROR(H5E_SYM, H5E_CANTINIT, FAIL,
"unable to rename symbolic link");
}
@@ -2123,7 +2153,8 @@ H5G_move(H5G_entry_t *loc, const char *src_name, const char *dst_name)
/*
* Rename the object.
*/
- if (H5G_link(loc, H5G_LINK_HARD, src_name, dst_name)<0) {
+ if (H5G_link(loc, H5G_LINK_HARD, src_name, dst_name,
+ H5G_TARGET_MOUNT)<0) {
HRETURN_ERROR(H5E_SYM, H5E_CANTINIT, FAIL,
"unable to register new name for object");
}
@@ -2137,3 +2168,55 @@ H5G_move(H5G_entry_t *loc, const char *src_name, const char *dst_name)
FUNC_LEAVE(SUCCEED);
}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_insertion_file
+ *
+ * Purpose: Given a location and name that specifies a not-yet-existing
+ * object return the file into which the object is about to be
+ * inserted.
+ *
+ * Return: Success: File pointer
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, October 14, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+H5F_t *
+H5G_insertion_file(H5G_entry_t *loc, const char *name)
+{
+ const char *rest;
+ H5G_entry_t grp_ent;
+ size_t size;
+
+ FUNC_ENTER(H5G_insertion_file, NULL);
+ assert(loc);
+ assert(name && *name);
+
+ /*
+ * Look up the name to get the containing group and to make sure the name
+ * doesn't already exist.
+ */
+ if (H5G_namei(loc, name, &rest, &grp_ent, NULL, H5G_TARGET_NORMAL,
+ NULL)>=0) {
+ HRETURN_ERROR(H5E_SYM, H5E_EXISTS, NULL, "name already exists");
+ }
+ H5E_clear();
+
+ /* Make sure only the last component wasn't resolved */
+ rest = H5G_component(rest, &size);
+ assert(*rest && size>0);
+ rest = H5G_component(rest+size, NULL);
+ if (*rest) {
+ HRETURN_ERROR(H5E_SYM, H5E_NOTFOUND, NULL,
+ "insertion point not found");
+ }
+
+ FUNC_LEAVE(grp_ent.file);
+}
diff --git a/src/H5Gpkg.h b/src/H5Gpkg.h
index 74573f3..03a2629 100644
--- a/src/H5Gpkg.h
+++ b/src/H5Gpkg.h
@@ -56,6 +56,15 @@ struct H5G_t {
};
/*
+ * During name lookups (see H5G_namei()) we sometimes want information about
+ * a symbolic link or a mount point. The normal operation is to follow the
+ * symbolic link or mount point and return information about its target.
+ */
+#define H5G_TARGET_NORMAL 0x0000
+#define H5G_TARGET_SLINK 0x0001
+#define H5G_TARGET_MOUNT 0x0002
+
+/*
* These operations can be passed down from the H5G_stab layer to the
* H5G_node layer through the B-tree layer.
*/
diff --git a/src/H5Gprivate.h b/src/H5Gprivate.h
index 417f011..1cf448f 100644
--- a/src/H5Gprivate.h
+++ b/src/H5Gprivate.h
@@ -109,7 +109,7 @@ H5G_t *H5G_reopen (H5G_t *grp);
herr_t H5G_close (H5G_t *grp);
H5G_t *H5G_rootof(H5F_t *f);
herr_t H5G_link (H5G_entry_t *loc, H5G_link_t type, const char *cur_name,
- const char *new_name);
+ const char *new_name, uintn namei_flags);
herr_t H5G_get_objinfo (H5G_entry_t *loc, const char *name,
hbool_t follow_link, H5G_stat_t *statbuf/*out*/);
herr_t H5G_linkval (H5G_entry_t *loc, const char *name, size_t size,
@@ -122,6 +122,7 @@ herr_t H5G_move(H5G_entry_t *loc, const char *src_name, const char *dst_name);
herr_t H5G_unlink(H5G_entry_t *loc, const char *name);
herr_t H5G_find (H5G_entry_t *loc, const char *name,
H5G_entry_t *grp_ent/*out*/, H5G_entry_t *ent/*out*/);
+H5F_t *H5G_insertion_file(H5G_entry_t *loc, const char *name);
herr_t H5G_traverse_slink (H5G_entry_t *grp_ent/*in,out*/,
H5G_entry_t *obj_ent/*in,out*/,
intn *nlinks/*in,out*/);
diff --git a/src/H5I.c b/src/H5I.c
index 91c8b1a..6dc7ef3 100644
--- a/src/H5I.c
+++ b/src/H5I.c
@@ -564,8 +564,8 @@ H5I_get_type(hid_t id)
FUNC_ENTER(H5I_get_type, H5I_BADID);
- ret_value = H5I_GROUP(id);
- assert(ret_value>H5I_BADID && ret_value<H5I_MAXID);
+ if (id>0) ret_value = H5I_GROUP(id);
+ assert(ret_value>=H5I_BADID && ret_value<H5I_MAXID);
FUNC_LEAVE(ret_value);
}
diff --git a/src/H5O.c b/src/H5O.c
index 233d7f5..4386962 100644
--- a/src/H5O.c
+++ b/src/H5O.c
@@ -244,7 +244,7 @@ H5O_open(H5G_entry_t *obj_ent)
#endif
/* Increment open-lock counters */
- obj_ent->file->nopen++;
+ obj_ent->file->nopen_objs++;
FUNC_LEAVE(SUCCEED);
}
@@ -273,16 +273,16 @@ H5O_close(H5G_entry_t *obj_ent)
/* Check args */
assert(obj_ent);
assert(obj_ent->file);
- assert(obj_ent->file->nopen > 0);
+ assert(obj_ent->file->nopen_objs > 0);
/* Decrement open-lock counters */
- --obj_ent->file->nopen;
+ --obj_ent->file->nopen_objs;
/*
* If the file open-lock count has reached zero and the file has a close
* pending then close the file.
*/
- if (0 == obj_ent->file->nopen && obj_ent->file->close_pending) {
+ if (0 == obj_ent->file->nopen_objs && obj_ent->file->close_pending) {
H5F_close(obj_ent->file);
}
#ifdef H5O_DEBUG
@@ -1203,8 +1203,14 @@ H5O_modify(H5G_entry_t *ent, const H5O_class_t *type, intn overwrite,
} else {
/*
* The shared message is stored in some other object header.
- * Increment the reference count on that object header.
+ * The other object header must be in the same file as the
+ * new object header. Increment the reference count on that
+ * object header.
*/
+ if (sh_mesg->u.ent.file->shared != ent->file->shared) {
+ HGOTO_ERROR(H5E_OHDR, H5E_LINK, FAIL,
+ "interfile hard links are not allowed");
+ }
if (H5O_link (&(sh_mesg->u.ent), 1)<0) {
HGOTO_ERROR (H5E_OHDR, H5E_LINK, FAIL,
"unable to adjust shared object link count");
diff --git a/src/H5R.c b/src/H5R.c
index 88ab707..48051de 100644
--- a/src/H5R.c
+++ b/src/H5R.c
@@ -246,7 +246,7 @@ H5R_dereference(href_t *ref)
*/
/* Allocate the dataset structure */
if (NULL==(dataset = H5D_new(NULL))) {
- HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, NULL,
+ HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL,
"memory allocation failed");
}
@@ -258,7 +258,7 @@ H5R_dereference(href_t *ref)
/* Open the dataset object */
if (H5D_open_oid(dataset, &ent) < 0) {
- HGOTO_ERROR(H5E_DATASET, H5E_NOTFOUND, NULL, "not found");
+ HGOTO_ERROR(H5E_DATASET, H5E_NOTFOUND, FAIL, "not found");
}
/* Create an atom for the dataset */
diff --git a/src/H5T.c b/src/H5T.c
index 0231a0e..cb72c8c 100644
--- a/src/H5T.c
+++ b/src/H5T.c
@@ -3679,6 +3679,7 @@ herr_t
H5T_commit (H5G_entry_t *loc, const char *name, H5T_t *type)
{
herr_t ret_value = FAIL;
+ H5F_t *file = NULL;
FUNC_ENTER (H5T_commit, FAIL);
@@ -3699,11 +3700,17 @@ H5T_commit (H5G_entry_t *loc, const char *name, H5T_t *type)
"data type is immutable");
}
+ /* Find the insertion file */
+ if (NULL==(file=H5G_insertion_file(loc, name))) {
+ HRETURN_ERROR(H5E_SYM, H5E_CANTINIT, FAIL,
+ "unable to find insertion point");
+ }
+
/*
* Create the object header and open it for write access. Insert the data
* type message and then give the object header a name.
*/
- if (H5O_create (loc->file, 64, &(type->ent))<0) {
+ if (H5O_create (file, 64, &(type->ent))<0) {
HGOTO_ERROR (H5E_DATATYPE, H5E_CANTINIT, FAIL,
"unable to create data type object header");
}
diff --git a/test/Makefile.in b/test/Makefile.in
index a51f899..3b43e76 100644
--- a/test/Makefile.in
+++ b/test/Makefile.in
@@ -12,7 +12,7 @@ CPPFLAGS=-I. -I../src @CPPFLAGS@
# These are our main targets. They should be listed in the order to be
# executed, generally most specific tests to least specific tests.
TESTS=testhdf5 gheap hyperslab istore bittests dtypes dsets cmpd_dset extend \
- external shtype links unlink big mtime fillval
+ external shtype links unlink big mtime fillval mount
TIMINGS=iopipe chunk ragged overhead
# Temporary files
@@ -25,7 +25,7 @@ MOSTLYCLEAN=cmpd_dset.h5 dataset.h5 extend.h5 istore.h5 tfile1.h5 tfile2.h5 \
shtype2a.h5 shtype2b.h5 shtype3.h5 links.h5 chunk.h5 big.data \
big[0-9][0-9][0-9][0-9][0-9].h5 dtypes1.h5 dtypes2.h5 tattr.h5 \
tselect.h5 mtime.h5 ragged.h5 grptime.h5 unlink.h5 overhead.h5 \
- fillval_[0-9].h5 trefer.h5
+ fillval_[0-9].h5 mount_[0-9].h5 trefer.h5
CLEAN=$(TIMINGS)
# Source and object files for programs... The TEST_SRC list contains all the
@@ -35,7 +35,7 @@ CLEAN=$(TIMINGS)
TEST_SRC=testhdf5.c tattr.c tfile.c theap.c tmeta.c tohdr.c trefer.c tselect.c \
tstab.c th5s.c dtypes.c hyperslab.c istore.c dsets.c cmpd_dset.c extend.c \
external.c iopipe.c gheap.c shtype.c big.c links.c chunk.c bittests.c \
- mtime.c ragged.c unlink.c overhead.c fillval.c
+ mtime.c ragged.c unlink.c overhead.c fillval.c mount.c
TEST_OBJ=$(TEST_SRC:.c=.o)
# Private header files (not to be installed)...
@@ -116,4 +116,7 @@ overhead: overhead.o ../src/libhdf5.a
fillval: fillval.o ../src/libhdf5.a
$(CC) $(CFLAGS) -o $@ fillval.o ../src/libhdf5.a $(LIBS)
+mount: mount.o ../src/libhdf5.a
+ $(CC) $(CFLAGS) -o $@ mount.o ../src/libhdf5.a $(LIBS)
+
@CONCLUDE@
diff --git a/test/mount.c b/test/mount.c
new file mode 100644
index 0000000..516eba8
--- /dev/null
+++ b/test/mount.c
@@ -0,0 +1,1072 @@
+/*
+ * Copyright (C) 1998 NCSA
+ * All rights reserved.
+ *
+ * Programmer: Robb Matzke <matzke@llnl.gov>
+ * Wednesday, October 7, 1998
+ *
+ * Purpose: Tests file mounting.
+ */
+#include <hdf5.h>
+#include <stdlib.h>
+
+#define FALSE 0
+#define TRUE 1
+
+#define FILE_NAME_1 "mount_1.h5"
+#define FILE_NAME_2 "mount_2.h5"
+#define FILE_NAME_3 "mount_3.h5"
+
+#include <H5config.h>
+#ifndef HAVE_ATTRIBUTE
+# undef __attribute__
+# define __attribute__(X) /*void*/
+# define __unused__ /*void*/
+#else
+# define __unused__ __attribute__((unused))
+#endif
+
+
+/*-------------------------------------------------------------------------
+ * Function: cleanup
+ *
+ * Purpose: Removes test files
+ *
+ * Return: void
+ *
+ * Programmer: Robb Matzke
+ * Thursday, June 4, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+cleanup(void)
+{
+ if (!getenv("HDF5_NOCLEANUP")) {
+ remove(FILE_NAME_1);
+ remove(FILE_NAME_2);
+ remove(FILE_NAME_3);
+ }
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: display_error_cb
+ *
+ * Purpose: Displays the error stack after printing "*FAILED*".
+ *
+ * Return: Success: 0
+ *
+ * Failure: -1
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, March 4, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+display_error_cb(void __unused__ *client_data)
+{
+ puts("*FAILED*");
+ H5Eprint(stdout);
+ return 0;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: setup
+ *
+ * Purpose: Create some files and populate them with a few groups.
+ *
+ * Return: Success: 0
+ *
+ * Failure: -1
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, October 7, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+setup(void)
+{
+ hid_t file=-1;
+
+ /* file 1 */
+ if ((file=H5Fcreate(FILE_NAME_1, H5F_ACC_TRUNC, H5P_DEFAULT,
+ H5P_DEFAULT))<0) goto error;
+ if (H5Gclose(H5Gcreate(file, "/mnt1", 0))<0) goto error;
+ if (H5Gclose(H5Gcreate(file, "/mnt1/file1", 0))<0) goto error;
+ if (H5Gclose(H5Gcreate(file, "/mnt_unlink", 0))<0) goto error;
+ if (H5Gclose(H5Gcreate(file, "/mnt_move_a", 0))<0) goto error;
+ if (H5Glink(file, H5G_LINK_HARD, "/mnt1/file1", "/file1")<0) goto error;
+ if (H5Glink(file, H5G_LINK_HARD, "/mnt1", "/mnt1_link")<0) goto error;
+ if (H5Fclose(file)<0) goto error;
+
+ /* file 2 */
+ if ((file=H5Fcreate(FILE_NAME_2, H5F_ACC_TRUNC, H5P_DEFAULT,
+ H5P_DEFAULT))<0) goto error;
+ if (H5Gclose(H5Gcreate(file, "/file2", 0))<0) goto error;
+ if (H5Gclose(H5Gcreate(file, "/rename_a", 0))<0) goto error;
+ if (H5Gclose(H5Gcreate(file, "/rename_b", 0))<0) goto error;
+ if (H5Gclose(H5Gcreate(file, "/rename_a/x", 0))<0) goto error;
+ if (H5Fclose(file)<0) goto error;
+
+ /* file 3 */
+ if ((file=H5Fcreate(FILE_NAME_3, H5F_ACC_TRUNC, H5P_DEFAULT,
+ H5P_DEFAULT))<0) goto error;
+ if (H5Fclose(file)<0) goto error;
+
+ return 0;
+
+ error:
+ H5E_BEGIN_TRY {
+ H5Fclose(file);
+ } H5E_END_TRY;
+ return -1;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: test_basic
+ *
+ * Purpose: Mount file1 at file2:/mnt1 and try accessing an object in
+ * file2. Then unmount.
+ *
+ * Return: Success: 0
+ *
+ * Failure: number of errors
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, October 7, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+test_basic(void)
+{
+ hid_t file1=-1, file2=-1, grp=-1;
+
+ printf("%-70s", "Testing basic functionality");
+ fflush(stdout);
+
+ if ((file1=H5Fopen(FILE_NAME_1, H5F_ACC_RDONLY, H5P_DEFAULT))<0 ||
+ (file2=H5Fopen(FILE_NAME_2, H5F_ACC_RDONLY, H5P_DEFAULT))<0)
+ goto error;
+ if (H5Fmount(file1, "/mnt1", file2, H5P_DEFAULT)<0) goto error;
+ if ((grp=H5Gopen(file1, "/mnt1/file2"))<0) goto error;
+ if (H5Gclose(grp)<0) goto error;
+ if (H5Funmount(file1, "/mnt1")<0) goto error;
+ if (H5Fclose(file1)<0) goto error;
+ if (H5Fclose(file2)<0) goto error;
+
+ puts(" PASSED");
+ return 0;
+
+ error:
+ H5E_BEGIN_TRY {
+ H5Fclose(file1);
+ H5Fclose(file2);
+ } H5E_END_TRY;
+ return 1;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: test_illegal
+ *
+ * Purpose: Test things that are illegal to do. We should get a failure
+ * from the library for each of them.
+ *
+ * Return: Success: 0
+ *
+ * Failure: number of errors
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, October 7, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+test_illegal(void)
+{
+ hid_t file1=-1, file2=-1, file3=-1, mnt=-1;
+ herr_t status;
+
+ printf("%-70s", "Testing illegal mount operations");
+ fflush(stdout);
+
+ /* Open the files */
+ if ((file1=H5Fopen(FILE_NAME_1, H5F_ACC_RDONLY, H5P_DEFAULT))<0 ||
+ (file2=H5Fopen(FILE_NAME_2, H5F_ACC_RDONLY, H5P_DEFAULT))<0 ||
+ (file3=H5Fopen(FILE_NAME_3, H5F_ACC_RDONLY, H5P_DEFAULT))<0)
+ goto error;
+
+ /* Try mounting a file on itself */
+ H5E_BEGIN_TRY {
+ status = H5Fmount(file1, "/mnt1", file1, H5P_DEFAULT);
+ } H5E_END_TRY;
+ if (status>=0) {
+ puts("*FAILED*");
+ puts(" Mounting a file on itself should have failed.");
+ goto error;
+ }
+
+ /*
+ * Try mounting two files at the same place. We have to open the mount
+ * point before we mount the first file or we'll end up mounting file3 at
+ * the root of file2 and the mount will succeed.
+ */
+ if ((mnt=H5Gopen(file1, "/mnt1"))<0) goto error;
+ if (H5Fmount(mnt, ".", file2, H5P_DEFAULT)<0) goto error;
+ H5E_BEGIN_TRY {
+ status = H5Fmount(mnt, ".", file3, H5P_DEFAULT);
+ } H5E_END_TRY;
+ if (status>=0) {
+ puts("*FAILED*");
+ puts(" Mounting two files at one mount point should have failed.");
+ goto error;
+ }
+ if (H5Funmount(mnt, ".")<0) goto error;
+ if (H5Gclose(mnt)<0) goto error;
+
+
+ /* Close everything and return */
+ if (H5Fclose(file1)<0) goto error;
+ if (H5Fclose(file2)<0) goto error;
+ if (H5Fclose(file3)<0) goto error;
+ puts(" PASSED");
+ return 0;
+
+ error:
+ H5E_BEGIN_TRY {
+ H5Gclose(mnt);
+ H5Fclose(file1);
+ H5Fclose(file2);
+ H5Fclose(file3);
+ } H5E_END_TRY;
+ return 1;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: test_hide
+ *
+ * Purpose: The previous contents of the mount point is temporarily
+ * hidden. If objects in that group had names from other groups
+ * then the objects will still be visible by those other names.
+ *
+ * Return: Success: 0
+ *
+ * Failure: number of errors
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, October 7, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+test_hide(void)
+{
+ hid_t file1=-1, file2=-1, grp=-1;
+ H5G_stat_t sb1, sb2;
+
+ printf("%-70s", "Testing name hiding under mount point");
+ fflush(stdout);
+
+ if ((file1=H5Fopen(FILE_NAME_1, H5F_ACC_RDONLY, H5P_DEFAULT))<0 ||
+ (file2=H5Fopen(FILE_NAME_2, H5F_ACC_RDONLY, H5P_DEFAULT))<0)
+ goto error;
+
+ /* Get information about file1:/mnt1/file1 for later */
+ if (H5Gget_objinfo(file1, "/mnt1/file1", TRUE, &sb1)<0) goto error;
+
+ /* Build the virtual file */
+ if (H5Fmount(file1, "/mnt1", file2, H5P_DEFAULT)<0) goto error;
+
+ /* Original names under file1:/mnt1 should not be accessible */
+ H5E_BEGIN_TRY {
+ grp = H5Gopen(file1, "/mnt1/file1");
+ } H5E_END_TRY;
+ if (grp>=0) {
+ puts("*FAILED*");
+ puts(" Name is still accessible under mount point.");
+ goto error;
+ }
+
+ /*
+ * The original objects under file1:/mnt1 are still accessible by their
+ * other names. This is a rather stupid test but demonstrates a point.
+ */
+ if (H5Gget_objinfo(file1, "/file1", TRUE, &sb2)<0) goto error;
+ if (sb1.fileno[0]!=sb2.fileno[0] || sb1.fileno[1]!=sb2.fileno[1] ||
+ sb1.objno[0]!=sb2.objno[0] || sb1.objno[1]!=sb2.objno[1]) {
+ puts("*FAILED*");
+ puts(" Hard link failed for hidden object.");
+ goto error;
+ }
+
+ /* Unmount and close objects */
+ if (H5Funmount(file1, "/mnt1")<0) goto error;
+ H5Fclose(file1);
+ H5Fclose(file2);
+ puts(" PASSED");
+ return 0;
+
+ error:
+ H5E_BEGIN_TRY {
+ H5Gclose(grp);
+ H5Fclose(file1);
+ H5Fclose(file2);
+ } H5E_END_TRY;
+ return 1;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: test_assoc
+ *
+ * Purpose: Opening the mount point is the same as opening the root group
+ * of the mounted file before the file was mounted.
+ *
+ * Return: Success: 0
+ *
+ * Failure: number of errors
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, October 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+test_assoc(void)
+{
+ hid_t file1=-1, file2=-1;
+ H5G_stat_t sb1, sb2;
+
+ printf("%-70s", "Testing mount point open");
+ fflush(stdout);
+
+ /* Open the files */
+ if ((file1=H5Fopen(FILE_NAME_1, H5F_ACC_RDONLY, H5P_DEFAULT))<0 ||
+ (file2=H5Fopen(FILE_NAME_2, H5F_ACC_RDONLY, H5P_DEFAULT))<0)
+ goto error;
+
+ /* Get information about the root of file2 */
+ if (H5Gget_objinfo(file2, "/", TRUE, &sb1)<0) goto error;
+
+ /* Create the virtual file */
+ if (H5Fmount(file1, "/mnt1", file2, H5P_DEFAULT)<0) goto error;
+
+ /*
+ * Get info about the mount point -- should be the same as the root group
+ * of file2.
+ */
+ if (H5Gget_objinfo(file1, "/mnt1", TRUE, &sb2)<0) goto error;
+ if (sb1.fileno[0]!=sb2.fileno[0] || sb1.fileno[1]!=sb2.fileno[1] ||
+ sb1.objno[0]!=sb2.objno[0] || sb1.objno[1]!=sb2.objno[1]) {
+ puts("*FAILED*");
+ puts(" Association failed.");
+ goto error;
+ }
+
+ /* Shut down */
+ if (H5Funmount(file1, "/mnt1_link")<0) goto error;
+ if (H5Fclose(file1)<0) goto error;
+ if (H5Fclose(file2)<0) goto error;
+ puts(" PASSED");
+ return 0;
+
+ error:
+ H5E_BEGIN_TRY {
+ H5Fclose(file2);
+ H5Fclose(file1);
+ } H5E_END_TRY;
+ return 1;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: test_mntlnk
+ *
+ * Purpose: The mount point is actually an OID (not a name) so if there
+ * are other names for that group then the root group of the
+ * child will be visible in all those names.
+ *
+ * Return: Success: 0
+ *
+ * Failure: number of errors
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, October 7, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+test_mntlnk(void)
+{
+ hid_t file1=-1, file2=-1, grp=-1;
+
+ printf("%-70s", "Testing multi-linked mount point");
+ fflush(stdout);
+
+ /* Build the virtual file */
+ if ((file1=H5Fopen(FILE_NAME_1, H5F_ACC_RDONLY, H5P_DEFAULT))<0 ||
+ (file2=H5Fopen(FILE_NAME_2, H5F_ACC_RDONLY, H5P_DEFAULT))<0)
+ goto error;
+ if (H5Fmount(file1, "/mnt1", file2, H5P_DEFAULT)<0) goto error;
+
+ /*
+ * Can we see file2:/file2 as both file1:/mnt1/file2 and
+ * file1:/mnt1_link/file2?
+ */
+ if ((grp=H5Gopen(file1, "/mnt1/file2"))<0) goto error;
+ if (H5Gclose(grp)<0) goto error;
+ if ((grp=H5Gopen(file1, "/mnt1_link/file2"))<0) goto error;
+ if (H5Gclose(grp)<0) goto error;
+
+ /* Unlink using second name */
+ if (H5Funmount(file1, "/mnt1_link")<0) goto error;
+ if (H5Fclose(file1)<0) goto error;
+ if (H5Fclose(file2)<0) goto error;
+ puts(" PASSED");
+ return 0;
+
+ error:
+ H5E_BEGIN_TRY {
+ H5Gclose(grp);
+ H5Fclose(file1);
+ H5Fclose(file2);
+ } H5E_END_TRY;
+ return 1;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: test_move
+ *
+ * Purpose: An object cannot be moved or renamed with H5Gmove() in such a
+ * way that the new location would be in a different file than
+ * the original location.
+ *
+ * Return: Success: 0
+ *
+ * Failure: number of errors
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, October 7, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+test_move(void)
+{
+ hid_t file1=-1, file2=-1;
+ herr_t status;
+
+ printf("%-70s", "Testing object renaming");
+ fflush(stdout);
+
+ /* Build the virtual file */
+ if ((file1=H5Fopen(FILE_NAME_1, H5F_ACC_RDWR, H5P_DEFAULT))<0 ||
+ (file2=H5Fopen(FILE_NAME_2, H5F_ACC_RDWR, H5P_DEFAULT))<0)
+ goto error;
+ if (H5Fmount(file1, "/mnt1", file2, H5P_DEFAULT)<0) goto error;
+
+ /* First rename an object in the mounted file, then try it across files */
+ if (H5Gmove(file1, "/mnt1/rename_a/x", "/mnt1/rename_b/y")<0) goto error;
+ H5E_BEGIN_TRY {
+ status = H5Gmove(file1, "/mnt1/rename_b/y", "/y");
+ } H5E_END_TRY;
+ if (status>=0) {
+ puts("*FAILED*");
+ puts(" Moving an object across files should not have been possible");
+ goto error;
+ }
+
+ /* Shut down */
+ if (H5Funmount(file1, "/mnt1")<0) goto error;
+ if (H5Fclose(file1)<0) goto error;
+ if (H5Fclose(file2)<0) goto error;
+ puts(" PASSED");
+ return 0;
+
+ error:
+ H5E_BEGIN_TRY {
+ H5Fclose(file1);
+ H5Fclose(file2);
+ } H5E_END_TRY;
+ return 1;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: test_preopen
+ *
+ * Purpose: Objects that are opened under the mount point before the
+ * child is mounted will remain accessible.
+ *
+ * Return: Success: 0
+ *
+ * Failure: number of errors
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, October 7, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+test_preopen(void)
+{
+ hid_t file1=-1, file2=-1, grp=-1;
+
+ printf("%-70s", "Testing preopening objects under the mount point");
+ fflush(stdout);
+
+ if ((file1=H5Fopen(FILE_NAME_1, H5F_ACC_RDONLY, H5P_DEFAULT))<0 ||
+ (file2=H5Fopen(FILE_NAME_2, H5F_ACC_RDONLY, H5P_DEFAULT))<0)
+ goto error;
+
+ /* Open something under the mount point */
+ if ((grp=H5Gopen(file1, "/mnt1/file1"))<0) goto error;
+
+ /* Build the virtual file */
+ if (H5Fmount(file1, "/mnt1", file2, H5P_DEFAULT)<0) goto error;
+
+ /* Now access the thing we previously opened */
+ if (H5Gget_objinfo(grp, ".", TRUE, NULL)<0) goto error;
+
+ /* Shut down */
+ if (H5Funmount(file1, "/mnt1")<0) goto error;
+ if (H5Gclose(grp)<0) goto error;
+ if (H5Fclose(file1)<0) goto error;
+ if (H5Fclose(file2)<0) goto error;
+ puts(" PASSED");
+ return 0;
+
+ error:
+ H5E_BEGIN_TRY {
+ H5Gclose(grp);
+ H5Fclose(file2);
+ H5Fclose(file1);
+ } H5E_END_TRY;
+ return 1;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: test_postopen
+ *
+ * Purpose: Objects that are open in a mounted file remain accessible
+ * after the file is unmounted. Unmounting the file doesn't
+ * close the file.
+ *
+ * Return: Success: 0
+ *
+ * Failure: number of errors
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, October 14, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+test_postopen(void)
+{
+
+ hid_t file1=-1, file2=-1, grp=-1;
+
+ printf("%-70s", "Testing open object access after unmount");
+ fflush(stdout);
+
+ /* Create the virtual file */
+ if ((file1=H5Fopen(FILE_NAME_1, H5F_ACC_RDONLY, H5P_DEFAULT))<0 ||
+ (file2=H5Fopen(FILE_NAME_2, H5F_ACC_RDONLY, H5P_DEFAULT))<0)
+ goto error;
+ if (H5Fmount(file1, "/mnt1", file2, H5P_DEFAULT)<0) goto error;
+
+ /* Open some object in the mounted file */
+ if ((grp=H5Gopen(file1, "/mnt1/file2"))<0) goto error;
+
+ /* Unmount the file */
+ if (H5Funmount(file1, "/mnt1")<0) goto error;
+
+ /* Now access the thing we previously opened */
+ if (H5Gget_objinfo(grp, ".", TRUE, NULL)<0) goto error;
+
+ /* Try accessing it from the file */
+ if (H5Gget_objinfo(file2, "/file2", TRUE, NULL)<0) goto error;
+
+ /* Shut down */
+ if (H5Gclose(grp)<0) goto error;
+ if (H5Fclose(file1)<0) goto error;
+ if (H5Fclose(file2)<0) goto error;
+ puts(" PASSED");
+ return 0;
+
+ error:
+ H5E_BEGIN_TRY {
+ H5Gclose(grp);
+ H5Fclose(file2);
+ H5Fclose(file1);
+ } H5E_END_TRY;
+ return 1;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: test_unlink
+ *
+ * Purpose: Unlinking the mount point from its name doesn't affect its
+ * existence or the fact that there is a file that is mounted
+ * there.
+ *
+ * Return: Success: 0
+ *
+ * Failure: number of errors
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, October 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+test_unlink(void)
+{
+ hid_t file1=-1, file2=-1, mnt=-1, root=-1;
+ herr_t status;
+
+ printf("%-70s", "Testing mount point unlinking");
+ fflush(stdout);
+
+ /* Open files */
+ if ((file1=H5Fopen(FILE_NAME_1, H5F_ACC_RDWR, H5P_DEFAULT))<0 ||
+ (file2=H5Fopen(FILE_NAME_2, H5F_ACC_RDWR, H5P_DEFAULT))<0)
+ goto error;
+
+ /*
+ * Opening the mount point before mounting opens the group in the parent
+ * file, but opening the mount point after mounting is the same as
+ * opening the root group of the child file.
+ */
+ if ((mnt=H5Gopen(file1, "/mnt_unlink"))<0) goto error;
+ if (H5Fmount(file1, "/mnt_unlink", file2, H5P_DEFAULT)<0) goto error;
+ if ((root=H5Gopen(file1, "/mnt_unlink"))<0) goto error;
+
+ /*
+ * "/file2" of file2 should be visible as an absolute name through either
+ * file handle but not from the `mnt' handle since that handle was opened
+ * before the H5Fmount() and thus refers to the mount point itself rather
+ * than the group mounted there.
+ */
+ if (H5Gget_objinfo(file1, "/mnt_unlink/file2", TRUE, NULL)<0) goto error;
+ if (H5Gget_objinfo(mnt, "/mnt_unlink/file2", TRUE, NULL)<0) goto error;
+ if (H5Gget_objinfo(root, "/mnt_unlink/file2", TRUE, NULL)<0) goto error;
+ if (H5Gget_objinfo(root, "file2", TRUE, NULL)<0) goto error;
+ H5E_BEGIN_TRY {
+ status = H5Gget_objinfo(mnt, "file2", TRUE, NULL);
+ } H5E_END_TRY;
+ if (status>=0) {
+ puts("*FAILED*");
+ puts(" Incorrect traversal from mount point!");
+ goto error;
+ }
+
+ /* Unlink the mount point */
+ if (H5Gunlink(file1, "/mnt_unlink")<0) goto error;
+
+ /*
+ * We should still be able to get to "/file2" of file2 by starting at
+ * `root' which is still open, but not by name.
+ */
+ if (H5Gget_objinfo(root, "file2", TRUE, NULL)<0) goto error;
+ H5E_BEGIN_TRY {
+ status = H5Gget_objinfo(mnt, "file2", TRUE, NULL);
+ } H5E_END_TRY;
+ if (status>=0) {
+ puts("*FAILED*");
+ puts(" Traversal through mount point should not have worked!");
+ goto error;
+ }
+ H5E_BEGIN_TRY {
+ status = H5Gget_objinfo(file2, "/mnt_unlink/file2", TRUE, NULL);
+ } H5E_END_TRY;
+ if (status>=0) {
+ puts("*FAILED*");
+ puts(" Traversal through mount point should not have worked!");
+ goto error;
+ }
+
+ /*
+ * It's no longer possible to unmount the child by supplying the name of
+ * the mount point because the name doesn't exist anymore. We must
+ * supply the mount point directly.
+ */
+ H5E_BEGIN_TRY {
+ status = H5Funmount(file1, "/mnt_unlink");
+ } H5E_END_TRY;
+ if (status>=0) {
+ puts("*FAILED*");
+ puts(" Unmount by name should not have been allowed!");
+ goto error;
+ }
+ H5E_BEGIN_TRY {
+ status = H5Funmount(file2, "/");
+ } H5E_END_TRY;
+ if (status>=0) {
+ puts("*FAILED*");
+ puts(" Unmount by name should not have been allowed!");
+ goto error;
+ }
+ if (H5Funmount(mnt, ".")<0) goto error;
+
+ /* Close files */
+ if (H5Gclose(mnt)<0) goto error;
+ if (H5Gclose(root)<0) goto error;
+ if (H5Fclose(file1)<0) goto error;
+ if (H5Fclose(file2)<0) goto error;
+ puts(" PASSED");
+ return 0;
+
+ error:
+ H5E_BEGIN_TRY {
+ H5Gclose(mnt);
+ H5Gclose(root);
+ H5Fclose(file2);
+ H5Fclose(file1);
+ } H5E_END_TRY;
+ return 1;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: test_mvmpt
+ *
+ * Purpose: Try renaming the mount point while a file is mounted there.
+ *
+ * Return: Success: 0
+ *
+ * Failure: number of errors
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, October 13, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+test_mvmpt(void)
+{
+ hid_t file1=-1, file2=-1;
+
+ printf("%-70s", "Testing mount point renaming");
+ fflush(stdout);
+
+ /* Build the virtual file */
+ if ((file1=H5Fopen(FILE_NAME_1, H5F_ACC_RDWR, H5P_DEFAULT))<0 ||
+ (file2=H5Fopen(FILE_NAME_2, H5F_ACC_RDWR, H5P_DEFAULT))<0)
+ goto error;
+ if (H5Fmount(file1, "/mnt_move_a", file2, H5P_DEFAULT)<0) goto error;
+
+ /* Rename the mount point */
+ if (H5Gmove(file1, "/mnt_move_a", "/mnt_move_b")<0) goto error;
+
+ /* Access something under the new name */
+ if (H5Gget_objinfo(file1, "/mnt_move_b/file2", TRUE, NULL)<0) goto error;
+
+ /* Shut down */
+ if (H5Funmount(file1, "/mnt_move_b")<0) goto error;
+ if (H5Fclose(file1)<0) goto error;
+ if (H5Fclose(file2)<0) goto error;
+ puts(" PASSED");
+ return 0;
+
+ error:
+ H5E_BEGIN_TRY {
+ H5Fclose(file1);
+ H5Fclose(file2);
+ } H5E_END_TRY;
+ return 1;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: test_interlink
+ *
+ * Purpose: Hard links cannot cross file boundaries.
+ *
+ * Return: Success: 0
+ *
+ * Failure: number of errors
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, October 14, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+test_interlink(void)
+{
+ hid_t file1=-1, file2=-1, type=-1, space=-1, dset=-1;
+ herr_t status;
+ hsize_t cur_dims[1] = {2};
+
+ printf("%-70s", "Testing interfile hard links");
+ fflush(stdout);
+
+ /* Build the virtual file */
+ if ((file1=H5Fopen(FILE_NAME_1, H5F_ACC_RDWR, H5P_DEFAULT))<0 ||
+ (file2=H5Fopen(FILE_NAME_2, H5F_ACC_RDWR, H5P_DEFAULT))<0)
+ goto error;
+ if (H5Fmount(file1, "/mnt1", file2, H5P_DEFAULT)<0) goto error;
+
+ /* Try an interfile hard link directly */
+ H5E_BEGIN_TRY {
+ status = H5Glink(file1, H5G_LINK_HARD, "/mnt1/file2", "/file2");
+ } H5E_END_TRY;
+ if (status>=0) {
+ puts("*FAILED*");
+ puts(" Interfile hard link should not have been allowed!");
+ goto error;
+ }
+
+ /* Try an interfile hard link by renaming something */
+ H5E_BEGIN_TRY {
+ status = H5Gmove(file1, "/mnt1/file2", "/file2");
+ } H5E_END_TRY;
+ if (status>=0) {
+ puts("*FAILED*");
+ puts(" Interfile renaming should not have been allowed!");
+ goto error;
+ }
+
+ /* Try an interfile hard link by sharing a data type */
+ if ((type=H5Tcopy(H5T_NATIVE_INT))<0) goto error;
+ if (H5Tcommit(file1, "/type1", type)<0) goto error;
+ if ((space=H5Screate_simple(1, cur_dims, NULL))<0) goto error;
+ H5E_BEGIN_TRY {
+ dset = H5Dcreate(file1, "/mnt1/file2/dset", type, space, H5P_DEFAULT);
+ } H5E_END_TRY;
+ if (dset>=0) {
+ puts("*FAILED*");
+ puts(" Dataset and shared type must be in the same file!");
+ goto error;
+ }
+
+ /* Shut down */
+ if (H5Sclose(space)<0) goto error;
+ if (H5Tclose(type)<0) goto error;
+ if (H5Funmount(file1, "/mnt1")<0) goto error;
+ if (H5Fclose(file1)<0) goto error;
+ if (H5Fclose(file2)<0) goto error;
+ puts(" PASSED");
+ return 0;
+
+ error:
+ H5E_BEGIN_TRY {
+ H5Dclose(dset);
+ H5Sclose(space);
+ H5Tclose(type);
+ H5Fclose(file1);
+ H5Fclose(file2);
+ } H5E_END_TRY;
+ return 1;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: test_uniformity
+ *
+ * Purpose: Any file handle is equivalent to any other file handle in the
+ * same virtual file.
+ *
+ * Return: Success: 0
+ *
+ * Failure: number of errors
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, October 14, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+test_uniformity(void)
+{
+ hid_t file1=-1, file2=-1;
+
+ printf("%-70s", "Testing file handle uniformity");
+ fflush(stdout);
+
+ /* Build the virtual file */
+ if ((file1=H5Fopen(FILE_NAME_1, H5F_ACC_RDWR, H5P_DEFAULT))<0 ||
+ (file2=H5Fopen(FILE_NAME_2, H5F_ACC_RDWR, H5P_DEFAULT))<0)
+ goto error;
+ if (H5Fmount(file1, "/mnt1", file2, H5P_DEFAULT)<0) goto error;
+
+ /* Access some things from the file1 handle */
+ if (H5Gget_objinfo(file1, "/", TRUE, NULL)<0) goto error;
+ if (H5Gget_objinfo(file1, "/mnt1", TRUE, NULL)<0) goto error;
+ if (H5Gget_objinfo(file1, "mnt1", TRUE, NULL)<0) goto error;
+ if (H5Gget_objinfo(file1, "/mnt1/file2", TRUE, NULL)<0) goto error;
+ if (H5Gget_objinfo(file1, "mnt1/file2", TRUE, NULL)<0) goto error;
+
+ /* Access the same things from the file2 handle */
+ if (H5Gget_objinfo(file2, "/", TRUE, NULL)<0) goto error;
+ if (H5Gget_objinfo(file2, "/mnt1", TRUE, NULL)<0) goto error;
+ if (H5Gget_objinfo(file2, "mnt1", TRUE, NULL)<0) goto error;
+ if (H5Gget_objinfo(file2, "/mnt1/file2", TRUE, NULL)<0) goto error;
+ if (H5Gget_objinfo(file2, "mnt1/file2", TRUE, NULL)<0) goto error;
+
+ /* Shut down */
+ if (H5Funmount(file1, "/mnt1")<0) goto error;
+ if (H5Fclose(file1)<0) goto error;
+ if (H5Fclose(file2)<0) goto error;
+ puts(" PASSED");
+ return 0;
+
+ error:
+ H5E_BEGIN_TRY {
+ H5Fclose(file1);
+ H5Fclose(file2);
+ } H5E_END_TRY;
+ return 1;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: test_close
+ *
+ * Purpose: Closing any file handle closes the entire virtual file.
+ *
+ * Return: Success: 0
+ *
+ * Failure: number of errors
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, October 14, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+test_close(void)
+{
+ hid_t file1=-1, file2=-1;
+ herr_t status;
+
+ printf("%-70s", "Testing file handle close");
+ fflush(stdout);
+#if 1
+ puts(" SKIP");
+ puts(" Skipped for now (until H5F_t refcounts are implemented)...");
+ return 0;
+#endif
+
+ /* Build the virtual file */
+ if ((file1=H5Fopen(FILE_NAME_1, H5F_ACC_RDWR, H5P_DEFAULT))<0 ||
+ (file2=H5Fopen(FILE_NAME_2, H5F_ACC_RDWR, H5P_DEFAULT))<0)
+ goto error;
+ if (H5Fmount(file1, "/mnt1", file2, H5P_DEFAULT)<0) goto error;
+
+ /* Close by file1 */
+ if (H5Fclose(file1)<0) goto error;
+ H5E_BEGIN_TRY {
+ status = H5Fclose(file2);
+ } H5E_END_TRY;
+ if (status>=0) {
+ puts("*FAILED*");
+ puts(" File close should have closed all virtual file members!");
+ goto error;
+ }
+
+ /* Shut down */
+ puts(" PASSED");
+ return 0;
+
+ error:
+ H5E_BEGIN_TRY {
+ H5Fclose(file1);
+ H5Fclose(file2);
+ } H5E_END_TRY;
+ return 1;
+}
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: main
+ *
+ * Purpose: Test file mounting
+ *
+ * Return: Success: zero
+ *
+ * Failure: non-zero
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, October 7, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+main(void)
+{
+ int nerrors = 0;
+
+ H5Eset_auto(display_error_cb, NULL);
+ if (setup()<0) goto error;
+
+ nerrors += test_basic();
+ nerrors += test_illegal();
+ nerrors += test_hide();
+ nerrors += test_assoc();
+ nerrors += test_mntlnk();
+ nerrors += test_unlink();
+ nerrors += test_move();
+ nerrors += test_mvmpt();
+ nerrors += test_preopen();
+ nerrors += test_postopen();
+ nerrors += test_interlink();
+ nerrors += test_uniformity();
+ nerrors += test_close();
+
+ if (nerrors) goto error;
+ puts("All mount tests passed.");
+ cleanup();
+ exit(0);
+
+ error:
+ puts("***** MOUNT ERRORS *****");
+ exit(1);
+}