From cfb2a264f1a441c4267c9d6095a4f11744a602f2 Mon Sep 17 00:00:00 2001 From: Robb Matzke Date: Wed, 14 Oct 1998 14:35:08 -0500 Subject: [svn-r761] Changes since 19981013 ---------------------- ./src/H5.c Fixed a signed vs. unsigned comparison. ./src/H5D.c Setting a fill value of all zeros will cause the fill value to be written to the dataset instead of relying on the low-level file driver initializing unwritten areas with zero. ./src/H5D.c ./src/H5F.c ./src/H5Fprivate.h ./src/H5G.c ./src/H5Gpkg.h ./src/H5Gprivate.h ./src/H5O.c ./src/H5T.c More file mounting stuff. ./src/H5I.c Fixed a bug where trying to close an invalid object id caused a core dump. For instance, H5Gclose(-1). ./MANIFEST ./test/Makefile.in ./test/mount.c [NEW] Mounting tests. ./src/H5R.c Fixed a couple (herr_t)NULL casts. --- MANIFEST | 1 + README | 2 +- src/H5.c | 2 +- src/H5D.c | 77 ++-- src/H5F.c | 25 +- src/H5Fprivate.h | 2 +- src/H5G.c | 149 ++++++-- src/H5Gpkg.h | 9 + src/H5Gprivate.h | 3 +- src/H5I.c | 4 +- src/H5O.c | 16 +- src/H5R.c | 4 +- src/H5T.c | 9 +- test/Makefile.in | 9 +- test/mount.c | 1072 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 15 files changed, 1295 insertions(+), 89 deletions(-) create mode 100644 test/mount.c 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; icreate_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; icreate_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; imtab.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_value0) ret_value = H5I_GROUP(id); + assert(ret_value>=H5I_BADID && ret_valuefile->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 + * Wednesday, October 7, 1998 + * + * Purpose: Tests file mounting. + */ +#include +#include + +#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 +#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); +} -- cgit v0.12