summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--configure.in3
-rw-r--r--release_docs/RELEASE.txt4
-rw-r--r--src/H5AC.c2
-rw-r--r--src/H5F.c198
-rw-r--r--src/H5FD.c6
-rw-r--r--src/H5FDlog.c20
-rw-r--r--src/H5FDpublic.h6
-rw-r--r--src/H5FDsec2.c44
-rw-r--r--src/H5FDsec2.h1
-rw-r--r--src/H5Fdbg.c4
-rw-r--r--src/H5Fpkg.h10
-rw-r--r--src/H5Fprivate.h13
-rw-r--r--src/H5Fquery.c130
-rw-r--r--src/H5Gloc.c4
-rw-r--r--src/H5Lexternal.c205
-rw-r--r--src/H5config.h.in3
-rw-r--r--src/H5private.h12
-rw-r--r--src/H5system.c89
-rw-r--r--test/links.c372
19 files changed, 752 insertions, 374 deletions
diff --git a/configure.in b/configure.in
index 53531af..6884ca4 100644
--- a/configure.in
+++ b/configure.in
@@ -1989,7 +1989,8 @@ dnl
AC_CHECK_FUNCS(alarm BSDgettimeofday fork frexpf frexpl)
AC_CHECK_FUNCS(gethostname getpwuid getrusage longjmp lstat)
AC_CHECK_FUNCS(rand_r random setsysinfo siglongjmp signal)
-AC_CHECK_FUNCS(snprintf srandom strdup system tmpfile vasprintf waitpid)
+AC_CHECK_FUNCS(snprintf srandom strdup symlink system)
+AC_CHECK_FUNCS(tmpfile vasprintf waitpid)
dnl Check for vsnprintf() separately, so we can detect situations where it
dnl doesn't return the correct size for formatted strings that are too large
diff --git a/release_docs/RELEASE.txt b/release_docs/RELEASE.txt
index 54f81d7..37250d4 100644
--- a/release_docs/RELEASE.txt
+++ b/release_docs/RELEASE.txt
@@ -106,7 +106,9 @@ Bug Fixes since HDF5-1.8.4
Library
-------
- - None EIP - 2009/10/21
+ - Allow "child" files from external links to be correctly located when
+ relative to a "parent" file that is opened through a symbolic link.
+ (QAK - 2009/12/01)
Parallel Library
----------------
diff --git a/src/H5AC.c b/src/H5AC.c
index f24f7b1..079eb17 100644
--- a/src/H5AC.c
+++ b/src/H5AC.c
@@ -2370,7 +2370,7 @@ H5AC_stats(const H5F_t *f)
HDassert(f->shared->cache);
/* at present, this can't fail */
- (void)H5C_stats(f->shared->cache, f->name, FALSE);
+ (void)H5C_stats(f->shared->cache, H5F_OPEN_NAME(f), FALSE);
done:
FUNC_LEAVE_NOAPI(ret_value)
diff --git a/src/H5F.c b/src/H5F.c
index d259db4..dcb5fab 100644
--- a/src/H5F.c
+++ b/src/H5F.c
@@ -67,7 +67,6 @@ typedef struct H5F_olist_t {
/* PRIVATE PROTOTYPES */
static size_t H5F_get_objects(const H5F_t *f, unsigned types, size_t max_objs, hid_t *obj_id_list, hbool_t app_ref);
static int H5F_get_objects_cb(void *obj_ptr, hid_t obj_id, void *key);
-static herr_t H5F_get_vfd_handle(const H5F_t *file, hid_t fapl, void** file_handle);
static H5F_t *H5F_new(H5F_file_t *shared, hid_t fcpl_id, hid_t fapl_id,
H5FD_t *lf);
static herr_t H5F_dest(H5F_t *f, hid_t dxpl_id);
@@ -705,21 +704,18 @@ done:
* driver.
*
* Return: Success: non-negative value.
- *
- * Failture: negative.
+ * Failure: negative.
*
* Programmer: Raymond Lu
* Sep. 16, 2002
*
- * Modification:
- *
*-------------------------------------------------------------------------
*/
herr_t
H5Fget_vfd_handle(hid_t file_id, hid_t fapl, void **file_handle)
{
H5F_t *file; /* File to query */
- herr_t ret_value; /* Return value */
+ herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_API(H5Fget_vfd_handle, FAIL)
H5TRACE3("e", "ii**x", file_id, fapl, file_handle);
@@ -732,7 +728,9 @@ H5Fget_vfd_handle(hid_t file_id, hid_t fapl, void **file_handle)
if(NULL == (file = (H5F_t *)H5I_object_verify(file_id, H5I_FILE)))
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a file id")
- ret_value = H5F_get_vfd_handle(file, fapl, file_handle);
+ /* Retrieve the VFD handle for the file */
+ if(H5F_get_vfd_handle(file, fapl, file_handle) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't retrieve VFD handle")
done:
FUNC_LEAVE_API(ret_value)
@@ -740,39 +738,6 @@ done:
/*-------------------------------------------------------------------------
- * Function: H5F_get_vfd_handle
- *
- * Purpose: Returns a pointer to the file handle of the low-level file
- * driver. This is the private function for H5Fget_vfd_handle.
- *
- * Return: Success: Non-negative.
- *
- * Failture: negative.
- *
- * Programmer: Raymond Lu
- * Sep. 16, 2002
- *
- * Modification:
- *
- *-------------------------------------------------------------------------
- */
-static herr_t
-H5F_get_vfd_handle(const H5F_t *file, hid_t fapl, void**file_handle)
-{
- herr_t ret_value;
-
- FUNC_ENTER_NOAPI_NOINIT(H5F_get_vfd_handle)
-
- assert(file_handle);
- if((ret_value=H5FD_get_vfd_handle(file->shared->lf, fapl, file_handle)) < 0)
- HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't get file handle for file driver")
-
-done:
- FUNC_LEAVE_NOAPI(ret_value)
-}
-
-
-/*-------------------------------------------------------------------------
* Function: H5Fis_hdf5
*
* Purpose: Check the file signature to detect an HDF5 file.
@@ -1112,7 +1077,8 @@ H5F_dest(H5F_t *f, hid_t dxpl_id)
}
/* Free the non-shared part of the file */
- f->name = (char *)H5MM_xfree(f->name);
+ f->open_name = (char *)H5MM_xfree(f->open_name);
+ f->actual_name = (char *)H5MM_xfree(f->actual_name);
f->extpath = (char *)H5MM_xfree(f->extpath);
if(H5FO_top_dest(f) < 0)
HDONE_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "problems closing file")
@@ -1162,7 +1128,6 @@ H5F_dest(H5F_t *f, hid_t dxpl_id)
* cause the default file access parameters to be used.
*
* Return: Success: A new file pointer.
- *
* Failure: NULL
*
* Programmer: Robb Matzke
@@ -1192,7 +1157,7 @@ H5F_open(const char *name, unsigned flags, hid_t fcpl_id, hid_t fapl_id, hid_t d
* Otherwise it is the application's responsibility to never open the
* same file more than once at a time.
*/
- if((drvr = H5FD_get_class(fapl_id)) == NULL)
+ if(NULL == (drvr = H5FD_get_class(fapl_id)))
HGOTO_ERROR(H5E_FILE, H5E_CANTGET, NULL, "unable to retrieve VFL class")
/*
@@ -1278,7 +1243,7 @@ H5F_open(const char *name, unsigned flags, hid_t fcpl_id, hid_t fapl_id, hid_t d
* file can be accessed through the C library.
*/
file->intent = flags;
- file->name = H5MM_xstrdup(name);
+ file->open_name = H5MM_xstrdup(name);
/*
* Read or write the file superblock, depending on whether the file is
@@ -1336,10 +1301,14 @@ H5F_open(const char *name, unsigned flags, hid_t fcpl_id, hid_t fapl_id, hid_t d
HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "file close degree doesn't match")
} /* end if */
- /* formulate the absolute path for later search of target file for external link */
- if (H5_build_extpath(name, &file->extpath) < 0)
+ /* Formulate the absolute path for later search of target file for external links */
+ if(H5_build_extpath(name, &file->extpath) < 0)
HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "unable to build extpath")
+ /* Formulate the actual file name, after following symlinks, etc. */
+ if(H5F_build_actual_name(file, name, &file->actual_name) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "unable to build actual name")
+
/* Success */
ret_value = file;
@@ -2001,8 +1970,9 @@ H5Freopen(hid_t file_id)
/* Keep old file's read/write intent in new file */
new_file->intent = old_file->intent;
- /* Duplicate old file's name */
- new_file->name = H5MM_xstrdup(old_file->name);
+ /* Duplicate old file's names */
+ new_file->open_name = H5MM_xstrdup(old_file->open_name);
+ new_file->actual_name = H5MM_xstrdup(old_file->actual_name);
if((ret_value = H5I_register(H5I_FILE, new_file, TRUE)) < 0)
HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to atomize file handle")
@@ -2103,37 +2073,6 @@ done:
/*-------------------------------------------------------------------------
- * Function: H5F_get_eoa
- *
- * Purpose: Quick and dirty routine to retrieve the file's 'eoa' value
- *
- * Return: Non-negative on success/Negative on failure
- *
- * Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu>
- * June 1, 2004
- *
- *-------------------------------------------------------------------------
- */
-haddr_t
-H5F_get_eoa(const H5F_t *f, H5FD_mem_t type)
-{
- haddr_t ret_value;
-
- FUNC_ENTER_NOAPI(H5F_get_eoa, HADDR_UNDEF)
-
- HDassert(f);
- HDassert(f->shared);
-
- /* Dispatch to driver */
- if(HADDR_UNDEF == (ret_value = H5FD_get_eoa(f->shared->lf, type)))
- HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, HADDR_UNDEF, "driver get_eoa request failed")
-
-done:
- FUNC_LEAVE_NOAPI(ret_value)
-} /* end H5F_get_eoa() */
-
-
-/*-------------------------------------------------------------------------
* Function: H5F_incr_nopen_objs
*
* Purpose: Increment the number of open objects for a file.
@@ -2188,6 +2127,100 @@ H5F_decr_nopen_objs(H5F_t *f)
/*-------------------------------------------------------------------------
+ * Function: H5F_build_actual_name
+ *
+ * Purpose: Retrieve the name of a file, after following symlinks, etc.
+ *
+ * Note: Currently only working for "POSIX I/O compatible" VFDs
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Programmer: Quincey Koziol
+ * November 25, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_build_actual_name(const H5F_t *f, const char *name, char **actual_name/*out*/)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT(H5F_build_actual_name)
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(name);
+ HDassert(actual_name);
+
+ /* Clear actual name pointer to begin with */
+ *actual_name = NULL;
+
+/* Assume that if the OS can't create symlinks, that we don't need to worry
+ * about resolving them either. -QAK
+ */
+#ifdef H5_HAVE_SYMLINK
+ /* Check for POSIX I/O compatible file handle */
+ if(H5F_HAS_FEATURE(f, H5FD_FEAT_POSIX_COMPAT_HANDLE)) {
+ h5_stat_t lst; /* Stat info from lstat() call */
+
+ /* Call lstat() on the file's name */
+ if(HDlstat(name, &lst) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't retrieve stat info for file")
+
+ /* Check for symbolic link */
+ if(S_IFLNK == (lst.st_mode & S_IFMT)) {
+ int *fd; /* POSIX I/O file descriptor */
+ h5_stat_t st; /* Stat info from stat() call */
+ h5_stat_t fst; /* Stat info from fstat() call */
+ char realname[PATH_MAX]; /* Fully resolved path name of file */
+
+ /* Perform a sanity check that the file or link wasn't switched
+ * between when we opened it and when we called lstat(). This is
+ * according to the security best practices for lstat() documented
+ * here: https://www.securecoding.cert.org/confluence/display/seccode/POS35-C.+Avoid+race+conditions+while+checking+for+the+existence+of+a+symbolic+link
+ */
+
+ /* Retrieve the file handle */
+ if(H5F_get_vfd_handle(f, H5P_DEFAULT, (void **)&fd) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't retrieve POSIX file descriptor")
+
+ /* Stat the filename we're resolving */
+ if(HDstat(name, &st) < 0)
+ HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, FAIL, "unable to stat file")
+
+ /* Stat the file we opened */
+ if(HDfstat(*fd, &fst) < 0)
+ HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, FAIL, "unable to fstat file")
+
+ /* Verify that the files are really the same */
+ if(st.st_mode != fst.st_mode || st.st_ino != fst.st_ino || st.st_dev != fst.st_dev)
+ HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "files' st_ino or st_dev fields changed!")
+
+ /* Get the resolved path for the file name */
+ if(NULL == HDrealpath(name, realname))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't retrieve real path for file")
+
+ /* Duplicate the resolved path for the file name */
+ if(NULL == (*actual_name = (char *)H5MM_strdup(realname)))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, FAIL, "can't duplicate real path")
+ } /* end if */
+ } /* end if */
+#endif /* H5_HAVE_SYMLINK */
+
+ /* Check if we've resolved the file's name */
+ if(NULL == *actual_name) {
+ /* Just duplicate the name used to open the file */
+ if(NULL == (*actual_name = (char *)H5MM_strdup(name)))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, FAIL, "can't duplicate open name")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5F_build_actual_name() */
+
+
+/*-------------------------------------------------------------------------
* Function: H5F_addr_encode_len
*
* Purpose: Encodes an address into the buffer pointed to by *PP and
@@ -2723,6 +2756,9 @@ done:
* If an error occurs then the buffer pointed to by `name' (NULL or non-NULL)
* is unchanged and the function returns a negative value.
*
+ * Note: This routine returns the name that was used to open the file,
+ * not the actual name after resolving symlinks, etc.
+ *
* Return: Success: The length of the file name
* Failure: Negative
*
@@ -2758,10 +2794,10 @@ H5Fget_name(hid_t obj_id, char *name/*out*/, size_t size)
f = loc.oloc->file;
} /* end else */
- len = HDstrlen(f->name);
+ len = HDstrlen(H5F_OPEN_NAME(f));
if(name) {
- HDstrncpy(name, f->name, MIN(len+1,size));
+ HDstrncpy(name, H5F_OPEN_NAME(f), MIN(len + 1,size));
if(len >= size)
name[size-1]='\0';
} /* end if */
diff --git a/src/H5FD.c b/src/H5FD.c
index 8a0e230..4c0da40 100644
--- a/src/H5FD.c
+++ b/src/H5FD.c
@@ -2036,8 +2036,6 @@ done:
* Programmer: Raymond Lu
* Sep. 16, 2002
*
- * Modifications:
- *
*--------------------------------------------------------------------------
*/
herr_t
@@ -2047,11 +2045,13 @@ H5FD_get_vfd_handle(H5FD_t *file, hid_t fapl, void **file_handle)
FUNC_ENTER_NOAPI(H5FD_get_vfd_handle, FAIL)
+ /* Sanity check */
+ HDassert(file);
HDassert(file_handle);
if(NULL == file->cls->get_handle)
HGOTO_ERROR(H5E_VFL, H5E_UNSUPPORTED, FAIL, "file driver has no `get_vfd_handle' method")
- if((ret_value = file->cls->get_handle(file, fapl, file_handle)) < 0)
+ if((file->cls->get_handle)(file, fapl, file_handle) < 0)
HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't get file handle for file driver")
done:
diff --git a/src/H5FDlog.c b/src/H5FDlog.c
index f7eb349..051195e 100644
--- a/src/H5FDlog.c
+++ b/src/H5FDlog.c
@@ -801,22 +801,20 @@ done:
static herr_t
H5FD_log_query(const H5FD_t UNUSED * _f, unsigned long *flags /* out */)
{
- herr_t ret_value=SUCCEED;
-
- FUNC_ENTER_NOAPI(H5FD_log_query, FAIL)
+ FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5FD_log_query)
/* Set the VFL feature flags that this driver supports */
if(flags) {
*flags = 0;
- *flags|=H5FD_FEAT_AGGREGATE_METADATA; /* OK to aggregate metadata allocations */
- *flags|=H5FD_FEAT_ACCUMULATE_METADATA; /* OK to accumulate metadata for faster writes */
- *flags|=H5FD_FEAT_DATA_SIEVE; /* OK to perform data sieving for faster raw data reads & writes */
- *flags|=H5FD_FEAT_AGGREGATE_SMALLDATA; /* OK to aggregate "small" raw data allocations */
- }
+ *flags |= H5FD_FEAT_AGGREGATE_METADATA; /* OK to aggregate metadata allocations */
+ *flags |= H5FD_FEAT_ACCUMULATE_METADATA; /* OK to accumulate metadata for faster writes */
+ *flags |= H5FD_FEAT_DATA_SIEVE; /* OK to perform data sieving for faster raw data reads & writes */
+ *flags |= H5FD_FEAT_AGGREGATE_SMALLDATA; /* OK to aggregate "small" raw data allocations */
+ *flags |= H5FD_FEAT_POSIX_COMPAT_HANDLE; /* VFD handle is POSIX I/O call compatible */
+ } /* end if */
-done:
- FUNC_LEAVE_NOAPI(ret_value)
-}
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5FD_log_query() */
/*-------------------------------------------------------------------------
diff --git a/src/H5FDpublic.h b/src/H5FDpublic.h
index bef7ee5..cd6c964 100644
--- a/src/H5FDpublic.h
+++ b/src/H5FDpublic.h
@@ -171,6 +171,12 @@ typedef enum H5F_mem_t H5FD_mem_t;
* is flushed/closed.
*/
#define H5FD_FEAT_DIRTY_SBLK_LOAD 0x00000040
+ /*
+ * Defining the H5FD_FEAT_POSIX_COMPAT_HANDLE for a VFL driver means that
+ * the handle for the VFD (returned with the 'get_handle' callback) is
+ * of type 'int' and is compatible with POSIX I/O calls.
+ */
+#define H5FD_FEAT_POSIX_COMPAT_HANDLE 0x00000080
/* Forward declaration */
diff --git a/src/H5FDsec2.c b/src/H5FDsec2.c
index 398435a..b3f2739 100644
--- a/src/H5FDsec2.c
+++ b/src/H5FDsec2.c
@@ -263,8 +263,6 @@ done:
* Programmer: Quincey Koziol
* Friday, Jan 30, 2004
*
- * Modification:
- *
*---------------------------------------------------------------------------
*/
void
@@ -273,7 +271,7 @@ H5FD_sec2_term(void)
FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5FD_sec2_term)
/* Reset VFL ID */
- H5FD_SEC2_g=0;
+ H5FD_SEC2_g = 0;
FUNC_LEAVE_NOAPI_VOID
} /* end H5FD_sec2_term() */
@@ -291,8 +289,6 @@ H5FD_sec2_term(void)
* Programmer: Robb Matzke
* Thursday, February 19, 1998
*
- * Modifications:
- *
*-------------------------------------------------------------------------
*/
herr_t
@@ -349,34 +345,41 @@ H5FD_sec2_open(const char *name, unsigned flags, hid_t fapl_id, haddr_t maxaddr)
FUNC_ENTER_NOAPI(H5FD_sec2_open, NULL)
/* Sanity check on file offsets */
- assert(sizeof(file_offset_t)>=sizeof(size_t));
+ HDassert(sizeof(file_offset_t) >= sizeof(size_t));
/* Check arguments */
- if (!name || !*name)
+ if(!name || !*name)
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "invalid file name")
- if (0==maxaddr || HADDR_UNDEF==maxaddr)
+ if(0 == maxaddr || HADDR_UNDEF == maxaddr)
HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, NULL, "bogus maxaddr")
- if (ADDR_OVERFLOW(maxaddr))
+ if(ADDR_OVERFLOW(maxaddr))
HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, NULL, "bogus maxaddr")
/* Build the open flags */
o_flags = (H5F_ACC_RDWR & flags) ? O_RDWR : O_RDONLY;
- if (H5F_ACC_TRUNC & flags) o_flags |= O_TRUNC;
- if (H5F_ACC_CREAT & flags) o_flags |= O_CREAT;
- if (H5F_ACC_EXCL & flags) o_flags |= O_EXCL;
+ if(H5F_ACC_TRUNC & flags)
+ o_flags |= O_TRUNC;
+ if(H5F_ACC_CREAT & flags)
+ o_flags |= O_CREAT;
+ if(H5F_ACC_EXCL & flags)
+ o_flags |= O_EXCL;
/* Open the file */
- if ((fd=HDopen(name, o_flags, 0666))<0)
- HSYS_GOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to open file")
- if (HDfstat(fd, &sb)<0)
+ if((fd = HDopen(name, o_flags, 0666)) < 0) {
+ int myerrno = errno;
+ time_t mytime = HDtime(NULL);
+
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to open file: time = %s, name = '%s', errno = %d, error message = '%s', flags = %x, o_flags = %x", HDctime(&mytime), name, myerrno, HDstrerror(myerrno), flags, (unsigned)o_flags);
+ } /* end if */
+ if(HDfstat(fd, &sb) < 0)
HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, NULL, "unable to fstat file")
/* Create the new file struct */
- if (NULL==(file=H5FL_CALLOC(H5FD_sec2_t)))
+ if(NULL == (file = H5FL_CALLOC(H5FD_sec2_t)))
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "unable to allocate file struct")
file->fd = fd;
- H5_ASSIGN_OVERFLOW(file->eof,sb.st_size,h5_stat_size_t,haddr_t);
+ H5_ASSIGN_OVERFLOW(file->eof, sb.st_size, h5_stat_size_t, haddr_t);
file->pos = HADDR_UNDEF;
file->op = OP_UNKNOWN;
#ifdef _WIN32
@@ -558,6 +561,7 @@ H5FD_sec2_query(const H5FD_t *_file, unsigned long *flags /* out */)
*flags |= H5FD_FEAT_ACCUMULATE_METADATA; /* OK to accumulate metadata for faster writes */
*flags |= H5FD_FEAT_DATA_SIEVE; /* OK to perform data sieving for faster raw data reads & writes */
*flags |= H5FD_FEAT_AGGREGATE_SMALLDATA; /* OK to aggregate "small" raw data allocations */
+ *flags |= H5FD_FEAT_POSIX_COMPAT_HANDLE; /* VFD handle is POSIX I/O call compatible */
/* Check for flags that are set by h5repart */
if(file->fam_to_sec2)
@@ -687,13 +691,11 @@ done:
* Programmer: Raymond Lu
* Sept. 16, 2002
*
- * Modifications:
- *
*-------------------------------------------------------------------------
*/
/* ARGSUSED */
static herr_t
-H5FD_sec2_get_handle(H5FD_t *_file, hid_t UNUSED fapl, void** file_handle)
+H5FD_sec2_get_handle(H5FD_t *_file, hid_t UNUSED fapl, void **file_handle)
{
H5FD_sec2_t *file = (H5FD_sec2_t *)_file;
herr_t ret_value = SUCCEED;
@@ -706,7 +708,7 @@ H5FD_sec2_get_handle(H5FD_t *_file, hid_t UNUSED fapl, void** file_handle)
done:
FUNC_LEAVE_NOAPI(ret_value)
-}
+} /* end H5FD_sec2_get_handle() */
/*-------------------------------------------------------------------------
diff --git a/src/H5FDsec2.h b/src/H5FDsec2.h
index 9c3f59d..b7db0d5 100644
--- a/src/H5FDsec2.h
+++ b/src/H5FDsec2.h
@@ -39,3 +39,4 @@ H5_DLL herr_t H5Pset_fapl_sec2(hid_t fapl_id);
#endif
#endif
+
diff --git a/src/H5Fdbg.c b/src/H5Fdbg.c
index 2b13f11..723005e 100644
--- a/src/H5Fdbg.c
+++ b/src/H5Fdbg.c
@@ -73,7 +73,9 @@ H5F_debug(H5F_t *f, FILE *stream, int indent, int fwidth)
HDfprintf(stream, "%*sFile Super Block...\n", indent, "");
HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
- "File name:", f->name);
+ "File name (as opened):", H5F_OPEN_NAME(f));
+ HDfprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
+ "File name (after resolving symlinks):", H5F_ACTUAL_NAME(f));
HDfprintf(stream, "%*s%-*s 0x%08x\n", indent, "", fwidth,
"File access flags", f->shared->flags);
HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
diff --git a/src/H5Fpkg.h b/src/H5Fpkg.h
index 9dd73b5..f0da958 100644
--- a/src/H5Fpkg.h
+++ b/src/H5Fpkg.h
@@ -222,7 +222,7 @@ typedef struct H5F_file_t {
unsigned gc_ref; /* Garbage-collect references? */
hbool_t latest_format; /* Always use the latest format? */
hbool_t store_msg_crt_idx; /* Store creation index for object header messages? */
- int ncwfs; /* Num entries on cwfs list */
+ int ncwfs; /* Num entries on cwfs list */
struct H5HG_heap_t **cwfs; /* Global heap cache */
struct H5G_t *root_grp; /* Open root group */
H5FO_t *open_objs; /* Open objects in file */
@@ -248,14 +248,12 @@ typedef struct H5F_file_t {
/*
* This is the top-level file descriptor. One of these structures is
* allocated every time H5Fopen() is called although they may contain pointers
- * to shared H5F_file_t structs. The reference count (nrefs) indicates the
- * number of times the file has been opened (the application can only open a
- * file once explicitly, but the library can open the file a second time to
- * indicate that the file is mounted on some other file).
+ * to shared H5F_file_t structs.
*/
struct H5F_t {
unsigned intent; /* The flags passed to H5F_open()*/
- char *name; /* Name used to open file */
+ char *open_name; /* Name used to open file */
+ char *actual_name; /* Actual name of the file, after resolving symlinks, etc. */
char *extpath; /* Path for searching target external link file */
H5F_file_t *shared; /* The shared file info */
unsigned nopen_objs; /* Number of open object headers*/
diff --git a/src/H5Fprivate.h b/src/H5Fprivate.h
index ebb7088..6b086f3 100644
--- a/src/H5Fprivate.h
+++ b/src/H5Fprivate.h
@@ -249,8 +249,9 @@ typedef struct H5F_blk_aggr_t H5F_blk_aggr_t;
#define H5F_SIEVE_BUF_SIZE(F) ((F)->shared->sieve_buf_size)
#define H5F_GC_REF(F) ((F)->shared->gc_ref)
#define H5F_USE_LATEST_FORMAT(F) ((F)->shared->latest_format)
+#define H5F_OPEN_NAME(F) ((F)->open_name)
+#define H5F_ACTUAL_NAME(F) ((F)->actual_name)
#define H5F_EXTPATH(F) ((F)->extpath)
-#define H5F_NAME(F) ((F)->name)
#define H5F_GET_FC_DEGREE(F) ((F)->shared->fc_degree)
#define H5F_STORE_MSG_CRT_IDX(F) ((F)->shared->store_msg_crt_idx)
#define H5F_HAS_FEATURE(F,FL) ((F)->shared->lf->feature_flags & (FL))
@@ -273,8 +274,9 @@ typedef struct H5F_blk_aggr_t H5F_blk_aggr_t;
#define H5F_SIEVE_BUF_SIZE(F) (H5F_sieve_buf_size(F))
#define H5F_GC_REF(F) (H5F_gc_ref(F))
#define H5F_USE_LATEST_FORMAT(F) (H5F_use_latest_format(F))
+#define H5F_OPEN_NAME(F) (H5F_get_open_name(F))
+#define H5F_ACTUAL_NAME(F) (H5F_get_actual_name(F))
#define H5F_EXTPATH(F) (H5F_get_extpath(F))
-#define H5F_NAME(F) (H5F_get_name(F))
#define H5F_GET_FC_DEGREE(F) (H5F_get_fc_degree(F))
#define H5F_STORE_MSG_CRT_IDX(F) (H5F_store_msg_crt_idx(F))
#define H5F_HAS_FEATURE(F,FL) (H5F_has_feature(F,FL))
@@ -457,12 +459,15 @@ H5_DLL H5F_t *H5F_open(const char *name, unsigned flags, hid_t fcpl_id,
H5_DLL herr_t H5F_try_close(H5F_t *f);
H5_DLL unsigned H5F_incr_nopen_objs(H5F_t *f);
H5_DLL unsigned H5F_decr_nopen_objs(H5F_t *f);
+H5_DLL herr_t H5F_build_actual_name(const H5F_t *f, const char *,
+ char ** /*out*/ );
/* Functions than retrieve values from the file struct */
H5_DLL unsigned H5F_get_intent(const H5F_t *f);
H5_DLL hid_t H5F_get_access_plist(H5F_t *f, hbool_t app_ref);
H5_DLL char *H5F_get_extpath(const H5F_t *f);
-H5_DLL char *H5F_get_name(const H5F_t *f);
+H5_DLL char *H5F_get_open_name(const H5F_t *f);
+H5_DLL char *H5F_get_actual_name(const H5F_t *f);
H5_DLL hid_t H5F_get_id(H5F_t *file, hbool_t app_ref);
H5_DLL size_t H5F_get_obj_count(const H5F_t *f, unsigned types, hbool_t app_ref);
H5_DLL size_t H5F_get_obj_ids(const H5F_t *f, unsigned types, size_t max_objs, hid_t *obj_id_list, hbool_t app_ref);
@@ -491,6 +496,8 @@ H5_DLL hbool_t H5F_has_feature(const H5F_t *f, unsigned feature);
H5_DLL hid_t H5F_get_driver_id(const H5F_t *f);
H5_DLL herr_t H5F_get_fileno(const H5F_t *f, unsigned long *filenum);
H5_DLL haddr_t H5F_get_eoa(const H5F_t *f, H5FD_mem_t type);
+H5_DLL herr_t H5F_get_vfd_handle(const H5F_t *file, hid_t fapl,
+ void **file_handle);
/* Functions than check file mounting information */
H5_DLL hbool_t H5F_is_mount(const H5F_t *file);
diff --git a/src/H5Fquery.c b/src/H5Fquery.c
index 70c5ff1..c5ecf6b 100644
--- a/src/H5Fquery.c
+++ b/src/H5Fquery.c
@@ -103,54 +103,81 @@ H5F_get_intent(const H5F_t *f)
/*-------------------------------------------------------------------------
- * Function: H5F_get_extpath
+ * Function: H5F_get_open_name
*
- * Purpose: Retrieve the file's 'extpath' flags
- * This is used by H5L_extern_traverse() to retrieve the main file's location
- * when searching the target file.
+ * Purpose: Retrieve the name used to open a file.
*
- * Return: 'extpath' on success/abort on failure (shouldn't fail)
+ * Return: Success: The name of the file.
+ * Failure: ? (should not happen)
*
- * Programmer: Vailin Choi, April 2, 2008
+ * Programmer: Neil Fortner
+ * December 15 2008
*
*-------------------------------------------------------------------------
*/
char *
-H5F_get_extpath(const H5F_t *f)
+H5F_get_open_name(const H5F_t *f)
{
/* Use FUNC_ENTER_NOAPI_NOINIT_NOFUNC here to avoid performance issues */
- FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5F_get_extpath)
+ FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5F_get_open_name)
HDassert(f);
+ HDassert(f->open_name);
- FUNC_LEAVE_NOAPI(f->extpath)
-} /* end H5F_get_extpath() */
+ FUNC_LEAVE_NOAPI(f->open_name)
+} /* end H5F_get_open_name() */
/*-------------------------------------------------------------------------
- * Function: H5F_get_name
+ * Function: H5F_get_actual_name
*
- * Purpose: Retrieve the name of a file.
+ * Purpose: Retrieve the actual name of a file, after resolving symlinks, etc.
*
* Return: Success: The name of the file.
- *
* Failure: ? (should not happen)
*
- * Programmer: Neil Fortner
- * December 15 2008
+ * Programmer: Quincey Koziol
+ * November 25 2009
*
*-------------------------------------------------------------------------
*/
char *
-H5F_get_name(const H5F_t *f)
+H5F_get_actual_name(const H5F_t *f)
{
/* Use FUNC_ENTER_NOAPI_NOINIT_NOFUNC here to avoid performance issues */
- FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5F_get_name)
+ FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5F_get_actual_name)
HDassert(f);
+ HDassert(f->actual_name);
- FUNC_LEAVE_NOAPI(f->name)
-} /* end H5F_get_name() */
+ FUNC_LEAVE_NOAPI(f->actual_name)
+} /* end H5F_get_actual_name() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_get_extpath
+ *
+ * Purpose: Retrieve the file's 'extpath' flags
+ * This is used by H5L_extern_traverse() to retrieve the main file's location
+ * when searching the target file.
+ *
+ * Return: 'extpath' on success/abort on failure (shouldn't fail)
+ *
+ * Programmer: Vailin Choi, April 2, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+char *
+H5F_get_extpath(const H5F_t *f)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOFUNC here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5F_get_extpath)
+
+ HDassert(f);
+ HDassert(f->extpath);
+
+ FUNC_LEAVE_NOAPI(f->extpath)
+} /* end H5F_get_extpath() */
/*-------------------------------------------------------------------------
@@ -690,6 +717,71 @@ done:
/*-------------------------------------------------------------------------
+ * Function: H5F_get_eoa
+ *
+ * Purpose: Quick and dirty routine to retrieve the file's 'eoa' value
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu>
+ * June 1, 2004
+ *
+ *-------------------------------------------------------------------------
+ */
+haddr_t
+H5F_get_eoa(const H5F_t *f, H5FD_mem_t type)
+{
+ haddr_t ret_value;
+
+ FUNC_ENTER_NOAPI(H5F_get_eoa, HADDR_UNDEF)
+
+ HDassert(f);
+ HDassert(f->shared);
+
+ /* Dispatch to driver */
+ if(HADDR_UNDEF == (ret_value = H5FD_get_eoa(f->shared->lf, type)))
+ HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, HADDR_UNDEF, "driver get_eoa request failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_get_eoa() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_get_vfd_handle
+ *
+ * Purpose: Returns a pointer to the file handle of the low-level file
+ * driver. This is the private function for H5Fget_vfd_handle.
+ *
+ * Return: Success: Non-negative.
+ * Failure: negative.
+ *
+ * Programmer: Raymond Lu
+ * Sep. 16, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_get_vfd_handle(const H5F_t *file, hid_t fapl, void **file_handle)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(H5F_get_vfd_handle, FAIL)
+
+ /* Sanity check */
+ HDassert(file);
+ HDassert(file_handle);
+
+ /* Get the VFD handle */
+ if(H5FD_get_vfd_handle(file->shared->lf, fapl, file_handle) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't get file handle for file driver")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5F_get_vfd_handle() */
+
+
+/*-------------------------------------------------------------------------
* Function: H5F_is_tmp_addr
*
* Purpose: Quick and dirty routine to determine if an address is in
diff --git a/src/H5Gloc.c b/src/H5Gloc.c
index b6a3a17..47214a4 100644
--- a/src/H5Gloc.c
+++ b/src/H5Gloc.c
@@ -409,7 +409,7 @@ done:
*-------------------------------------------------------------------------
*/
static herr_t
-H5G_loc_find_cb(H5G_loc_t UNUSED *grp_loc/*in*/, const char UNUSED *name,
+H5G_loc_find_cb(H5G_loc_t UNUSED *grp_loc/*in*/, const char *name,
const H5O_link_t UNUSED *lnk, H5G_loc_t *obj_loc, void *_udata/*in,out*/,
H5G_own_loc_t *own_loc/*out*/)
{
@@ -420,7 +420,7 @@ H5G_loc_find_cb(H5G_loc_t UNUSED *grp_loc/*in*/, const char UNUSED *name,
/* Check if the name in this group resolved to a valid object */
if(obj_loc == NULL)
- HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "object doesn't exist")
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "object '%s' doesn't exist", name)
/* Take ownership of the object's group location */
/* (Group traversal callbacks are responsible for either taking ownership
diff --git a/src/H5Lexternal.c b/src/H5Lexternal.c
index 640ac07..b99012c 100644
--- a/src/H5Lexternal.c
+++ b/src/H5Lexternal.c
@@ -202,18 +202,14 @@ H5L_extern_traverse(const char UNUSED *link_name, hid_t cur_group,
size_t fname_len; /* Length of external link file name */
unsigned intent; /* File access permissions */
H5L_elink_cb_t cb_info; /* Callback info struct */
- const char *parent_file_name = NULL; /* Parent file name */
- const char *parent_group_name = NULL; /* Parent group name */
hid_t fapl_id = -1; /* File access property list for external link's file */
hid_t ext_obj = -1; /* ID for external link's object */
- hid_t ret_value; /* Return value */
-
- char *tempname=NULL, *ptr=NULL, *extpath=NULL;
- char *env_prefix=NULL, *tmp_env_prefix=NULL;
- char *out_prefix_name=NULL, *pp=NULL;
-
- H5P_genplist_t *fa_plist; /* File access property list pointer */
+ char *temp_group_name = NULL;/* Temporary pointer to group name */
+ char *temp_file_name = NULL; /* Temporary pointer to file name */
+ char *actual_file_name = NULL; /* Parent file's actual name */
+ H5P_genplist_t *fa_plist; /* File access property list pointer */
H5F_close_degree_t fc_degree = H5F_CLOSE_WEAK; /* File close degree for target file */
+ hid_t ret_value; /* Return value */
FUNC_ENTER_NOAPI(H5L_extern_traverse, FAIL)
@@ -236,7 +232,7 @@ H5L_extern_traverse(const char UNUSED *link_name, hid_t cur_group,
if(NULL == (plist = H5P_object_verify(lapl_id, H5P_LINK_ACCESS)))
HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
- /* get the fapl_id set for lapl_id if any */
+ /* Get the fapl_id set for lapl_id if any */
if(H5P_get(plist, H5L_ACS_ELINK_FAPL_NAME, &fapl_id) < 0)
HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get fapl for links")
@@ -266,8 +262,11 @@ H5L_extern_traverse(const char UNUSED *link_name, hid_t cur_group,
/* Make callback if it exists */
if(cb_info.func) {
+ const char *parent_file_name; /* Parent file name */
+ const char *parent_group_name; /* Parent group name */
+
/* Get parent file name */
- parent_file_name = H5F_NAME(loc.oloc->file);
+ parent_file_name = H5F_OPEN_NAME(loc.oloc->file);
/* Get parent group name */
if(loc.path->user_path_r != NULL && loc.path->obj_hidden == 0)
@@ -285,20 +284,19 @@ H5L_extern_traverse(const char UNUSED *link_name, hid_t cur_group,
group_name_len++;
/* Copy parent group name */
- if(NULL == (tempname = (char *) H5MM_malloc((size_t) group_name_len)))
- HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
- if(H5G_get_name(cur_group, tempname, (size_t) group_name_len, lapl_id, H5AC_ind_dxpl_id) < 0)
+ if(NULL == (temp_group_name = (char *)H5MM_malloc((size_t)group_name_len)))
+ HGOTO_ERROR(H5E_LINK, H5E_NOSPACE, FAIL, "memory allocation failed")
+ if(H5G_get_name(cur_group, temp_group_name, (size_t) group_name_len, lapl_id, H5AC_ind_dxpl_id) < 0)
HGOTO_ERROR(H5E_LINK, H5E_CANTGET, FAIL, "unable to retrieve group name")
- parent_group_name = tempname;
+ parent_group_name = temp_group_name;
} /* end else */
/* Make callback */
- if((cb_info.func)(parent_file_name, parent_group_name, file_name, obj_name,
- &intent, fapl_id, cb_info.user_data) < 0)
+ if((cb_info.func)(parent_file_name, parent_group_name, file_name, obj_name, &intent, fapl_id, cb_info.user_data) < 0)
HGOTO_ERROR(H5E_LINK, H5E_CALLBACK, FAIL, "traversal operator failed")
- /* Free tempname */
- tempname = (char *)H5MM_xfree(tempname);
+ /* Free temp_group_name */
+ temp_group_name = (char *)H5MM_xfree(temp_group_name);
/* Check access flags */
if((intent & H5F_ACC_TRUNC) || (intent & H5F_ACC_EXCL))
@@ -312,88 +310,128 @@ H5L_extern_traverse(const char UNUSED *link_name, hid_t cur_group,
/*
* Start searching for the target file
*/
- if ((tempname=H5MM_strdup(file_name)) == NULL)
+
+ /* Simplify intent flags for open calls */
+ intent = ((intent & H5F_ACC_RDWR) ? H5F_ACC_RDWR : H5F_ACC_RDONLY);
+
+ /* Copy the file name to use */
+ if(NULL == (temp_file_name = H5MM_strdup(file_name)))
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
/* target file_name is an absolute pathname: see RM for detailed description */
- if (CHECK_ABSOLUTE(file_name) || CHECK_ABS_PATH(file_name)) {
- if(NULL == (ext_file = H5F_open(file_name, ((intent & H5F_ACC_RDWR) ? H5F_ACC_RDWR : H5F_ACC_RDONLY),
- H5P_FILE_CREATE_DEFAULT, fapl_id, H5AC_dxpl_id))) {
+ if(CHECK_ABSOLUTE(file_name) || CHECK_ABS_PATH(file_name)) {
+ /* Try opening file */
+ if(NULL == (ext_file = H5F_open(file_name, intent, H5P_FILE_CREATE_DEFAULT, fapl_id, H5AC_dxpl_id))) {
+ char *ptr = NULL;
+
H5E_clear_stack(NULL);
+
/* get last component of file_name */
GET_LAST_DELIMITER(file_name, ptr)
HDassert(ptr);
- HDstrcpy(tempname, ++ptr);
- }
- } else if (CHECK_ABS_DRIVE(file_name)) {
- if(NULL == (ext_file = H5F_open(file_name, ((intent & H5F_ACC_RDWR) ? H5F_ACC_RDWR : H5F_ACC_RDONLY),
- H5P_FILE_CREATE_DEFAULT, fapl_id, H5AC_dxpl_id))) {
+ HDstrcpy(temp_file_name, ++ptr);
+ } /* end if */
+ } /* end if */
+ else if(CHECK_ABS_DRIVE(file_name)) {
+ if(NULL == (ext_file = H5F_open(file_name, intent, H5P_FILE_CREATE_DEFAULT, fapl_id, H5AC_dxpl_id))) {
H5E_clear_stack(NULL);
/* strip "<drive-letter>:" */
- HDstrcpy(tempname, &file_name[2]);
- }
- }
+ HDstrcpy(temp_file_name, &file_name[2]);
+ } /* end if */
+ } /* end if */
/* try searching from paths set in the environment variable */
- if ((ext_file == NULL) && (env_prefix=HDgetenv("HDF5_EXT_PREFIX"))) {
-
- if ((tmp_env_prefix = H5MM_strdup(env_prefix)) == NULL)
- HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
- pp = tmp_env_prefix;
-
- while ((tmp_env_prefix) && (*tmp_env_prefix)) {
- out_prefix_name = H5L_getenv_prefix_name(&tmp_env_prefix/*in,out*/);
- if ((out_prefix_name) && (*out_prefix_name)) {
-
- if (H5L_build_name(out_prefix_name, tempname, &full_name/*out*/) < 0)
- HGOTO_ERROR(H5E_LINK, H5E_CANTGET, FAIL, "can't prepend prefix to filename")
-
- ext_file = H5F_open(full_name, ((intent & H5F_ACC_RDWR) ? H5F_ACC_RDWR : H5F_ACC_RDONLY),
- H5P_FILE_CREATE_DEFAULT, fapl_id, H5AC_dxpl_id);
- if (full_name)
- H5MM_free(full_name);
- if (ext_file != NULL)
- break;
- H5E_clear_stack(NULL);
- }
- } /* end while */
- pp = (char *)H5MM_xfree(pp);
- }
+ if(ext_file == NULL) {
+ char *env_prefix;
+
+ if(NULL != (env_prefix = HDgetenv("HDF5_EXT_PREFIX"))) {
+ char *tmp_env_prefix;
+
+ if(NULL == (tmp_env_prefix = H5MM_strdup(env_prefix)))
+ HGOTO_ERROR(H5E_LINK, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ while((tmp_env_prefix) && (*tmp_env_prefix)) {
+ char *out_prefix_name;
+
+ out_prefix_name = H5L_getenv_prefix_name(&tmp_env_prefix/*in,out*/);
+ if(out_prefix_name && (*out_prefix_name)) {
+ if(H5L_build_name(out_prefix_name, temp_file_name, &full_name/*out*/) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTGET, FAIL, "can't prepend prefix to filename")
+
+ ext_file = H5F_open(full_name, intent, H5P_FILE_CREATE_DEFAULT, fapl_id, H5AC_dxpl_id);
+ full_name = (char *)H5MM_xfree(full_name);
+ if(ext_file != NULL)
+ break;
+ H5E_clear_stack(NULL);
+ } /* end if */
+ } /* end while */
+ } /* end if */
+ } /* end if */
/* try searching from property list */
- if (ext_file == NULL) {
+ if(ext_file == NULL) {
if(H5P_get(plist, H5L_ACS_ELINK_PREFIX_NAME, &my_prefix) < 0)
HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get external link prefix")
- if (my_prefix) {
- if (H5L_build_name(my_prefix, tempname, &full_name/*out*/) < 0)
+ if(my_prefix) {
+ if(H5L_build_name(my_prefix, temp_file_name, &full_name/*out*/) < 0)
HGOTO_ERROR(H5E_LINK, H5E_CANTGET, FAIL, "can't prepend prefix to filename")
- if ((ext_file=H5F_open(full_name, ((intent & H5F_ACC_RDWR) ? H5F_ACC_RDWR : H5F_ACC_RDONLY),
- H5P_FILE_CREATE_DEFAULT, fapl_id, H5AC_dxpl_id)) == NULL)
+ if(NULL == (ext_file = H5F_open(full_name, intent, H5P_FILE_CREATE_DEFAULT, fapl_id, H5AC_dxpl_id)))
H5E_clear_stack(NULL);
- if (full_name)
- H5MM_free(full_name);
- }
- }
+ full_name = (char *)H5MM_xfree(full_name);
+ } /* end if */
+ } /* end if */
+
+ /* try searching from main file's "extpath": see description in H5F_open() & H5_build_extpath() */
+ if(ext_file == NULL) {
+ char *extpath;
+
+ if(NULL != (extpath = H5F_EXTPATH(loc.oloc->file))) {
+ if(H5L_build_name(extpath, temp_file_name, &full_name/*out*/) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTGET, FAIL, "can't prepend prefix to filename")
+ if(NULL == (ext_file = H5F_open(full_name, intent, H5P_FILE_CREATE_DEFAULT, fapl_id, H5AC_dxpl_id)))
+ H5E_clear_stack(NULL);
+ full_name = (char *)H5MM_xfree(full_name);
+ } /* end if */
+ } /* end if */
- /* try searching from main file's "extpath":see description in H5F_open() & H5_build_extpath() */
- if ((ext_file == NULL) && (extpath=H5F_EXTPATH(loc.oloc->file))) {
- if (H5L_build_name(extpath, tempname, &full_name/*out*/) < 0)
- HGOTO_ERROR(H5E_LINK, H5E_CANTGET, FAIL, "can't prepend prefix to filename")
- if ((ext_file = H5F_open(full_name, ((intent & H5F_ACC_RDWR) ? H5F_ACC_RDWR : H5F_ACC_RDONLY),
- H5P_FILE_CREATE_DEFAULT, fapl_id, H5AC_dxpl_id)) == NULL)
+ /* try the relative file_name stored in temp_file_name */
+ if(ext_file == NULL) {
+ if(NULL == (ext_file = H5F_open(temp_file_name, intent, H5P_FILE_CREATE_DEFAULT, fapl_id, H5AC_dxpl_id)))
H5E_clear_stack(NULL);
- if (full_name)
- H5MM_free(full_name);
- }
+ } /* end if */
- /* try the relative file_name stored in tempname */
- if (ext_file == NULL) {
- if ((ext_file=H5F_open(tempname, ((intent & H5F_ACC_RDWR) ? H5F_ACC_RDWR : H5F_ACC_RDONLY),
- H5P_FILE_CREATE_DEFAULT, fapl_id, H5AC_dxpl_id)) == NULL)
- HGOTO_ERROR(H5E_LINK, H5E_CANTOPENFILE, FAIL, "unable to open external file")
- }
+ /* try the 'resolved' name for the parent file (i.e. the name after symlinks
+ * were resolved)
+ */
+ if(ext_file == NULL) {
+ char *ptr = NULL;
+
+ /* Copy resolved file name */
+ if(NULL == (actual_file_name = H5MM_strdup(H5F_ACTUAL_NAME(loc.oloc->file))))
+ HGOTO_ERROR(H5E_LINK, H5E_CANTALLOC, FAIL, "can't duplicate resolved file name string")
+
+ /* get last component of file_name */
+ GET_LAST_DELIMITER(actual_file_name, ptr)
+ if(ptr) {
+ /* Truncate filename portion from actual file name path */
+ *ptr = '\0';
+
+ /* Build new file name for the external file */
+ if(H5L_build_name(actual_file_name, temp_file_name, &full_name/*out*/) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTGET, FAIL, "can't prepend prefix to filename")
+ } /* end if */
+ else {
+ /* Transfer ownership of actual file name to 'full_name' variable */
+ full_name = actual_file_name;
+ actual_file_name = NULL;
+ } /* end else */
+
+ /* Try opening with the resolved name */
+ if(NULL == (ext_file = H5F_open(full_name, intent, H5P_FILE_CREATE_DEFAULT, fapl_id, H5AC_dxpl_id)))
+ HGOTO_ERROR(H5E_LINK, H5E_CANTOPENFILE, FAIL, "unable to open external file, external link file name = '%s', temp_file_name = '%s'", file_name, temp_file_name)
+ full_name = (char *)H5MM_xfree(full_name);
+ } /* end if */
- tempname = (char *)H5MM_xfree(tempname);
/* Increment the number of open objects, to hold the file open */
H5F_incr_nopen_objs(ext_file);
@@ -425,11 +463,12 @@ done:
HDONE_ERROR(H5E_ATOM, H5E_CANTRELEASE, FAIL, "unable to close atom for file access property list")
if(ext_file && H5F_try_close(ext_file) < 0)
HDONE_ERROR(H5E_LINK, H5E_CANTCLOSEFILE, FAIL, "problem closing external file")
+ full_name = (char *)H5MM_xfree(full_name);
+ temp_group_name = (char *)H5MM_xfree(temp_group_name);
+ temp_file_name = (char *)H5MM_xfree(temp_file_name);
+ actual_file_name = (char *)H5MM_xfree(actual_file_name);
if(ret_value < 0) {
- H5MM_xfree(tempname);
- H5MM_xfree(pp);
-
/* Close object if it's open and something failed */
if(ext_obj >= 0 && H5I_dec_ref(ext_obj, FALSE) < 0)
HDONE_ERROR(H5E_ATOM, H5E_CANTRELEASE, FAIL, "unable to close atom for external object")
diff --git a/src/H5config.h.in b/src/H5config.h.in
index 94601b8..bdc8ed4 100644
--- a/src/H5config.h.in
+++ b/src/H5config.h.in
@@ -307,6 +307,9 @@
/* Define if `struct videoconfig' is defined */
#undef HAVE_STRUCT_VIDEOCONFIG
+/* Define to 1 if you have the `symlink' function. */
+#undef HAVE_SYMLINK
+
/* Define to 1 if you have the `system' function. */
#undef HAVE_SYSTEM
diff --git a/src/H5private.h b/src/H5private.h
index e377d51..8ab0201 100644
--- a/src/H5private.h
+++ b/src/H5private.h
@@ -1027,6 +1027,9 @@ H5_DLL int HDfprintf (FILE *stream, const char *fmt, ...);
#ifndef HDrealloc
#define HDrealloc(M,Z) realloc(M,Z)
#endif /* HDrealloc */
+#ifndef HDrealpath
+ #define HDrealpath(F1,F2) realpath(F1,F2)
+#endif /* HDrealloc */
#ifdef H5_VMS
#ifdef __cplusplus
extern "C" {
@@ -1221,6 +1224,11 @@ H5_DLL int64_t HDstrtoll (const char *s, const char **rest, int base);
#ifndef HDstrxfrm
#define HDstrxfrm(X,Y,Z) strxfrm(X,Y,Z)
#endif /* HDstrxfrm */
+#ifdef H5_HAVE_SYMLINK
+ #ifndef HDsymlink
+ #define HDsymlink(F1,F2) symlink(F1,F2)
+ #endif /* HDsymlink */
+#endif /* H5_HAVE_SYMLINK */
#ifndef HDsysconf
#define HDsysconf(N) sysconf(N)
#endif /* HDsysconf */
@@ -1475,7 +1483,6 @@ extern char *strdup(const char *s);
#endif
#define COLON_SEPC ':'
-H5_DLL herr_t H5_build_extpath(const char *, char ** /*out*/ );
/*
@@ -2014,6 +2021,9 @@ H5_DLL uint32_t H5_checksum_lookup3(const void *data, size_t len, uint32_t initv
H5_DLL uint32_t H5_checksum_metadata(const void *data, size_t len, uint32_t initval);
H5_DLL uint32_t H5_hash_string(const char *str);
+/* Functions for building paths, etc. */
+H5_DLL herr_t H5_build_extpath(const char *, char ** /*out*/ );
+
/* Functions for debugging */
H5_DLL herr_t H5_buffer_dump(FILE *stream, int indent, uint8_t *buf,
uint8_t *marker, size_t buf_offset, size_t buf_size);
diff --git a/src/H5system.c b/src/H5system.c
index 36ec1c1..9d93d9c 100644
--- a/src/H5system.c
+++ b/src/H5system.c
@@ -627,28 +627,21 @@ HDgettimeofday(struct timeval *tv, void *tz)
#endif
-/*
- *-------------------------------------------------------------------------
- *
+/*-------------------------------------------------------------------------
* Function: H5_build_extpath
*
- * Purpose: To build the path for later searching of target file for external link.
- * This path can be either:
- * 1. The absolute path of NAME
+ * Purpose: To build the path for later searching of target file for external
+ * link. This path can be either:
+ * 1. The absolute path of NAME
* or
- * 2. The current working directory + relative path of NAME
+ * 2. The current working directory + relative path of NAME
*
* Return: Success: 0
* Failure: -1
*
* Programmer: Vailin Choi
* April 2, 2008
- * Modifications: 2nd Oct, 2008; Vailin Choi
- * Remove compiler warning for "if condition"
- *
- * Raymond Lu
- * 14 Jan. 2009
- * Add support for OpenVMS pathname
+ *
*-------------------------------------------------------------------------
*/
#define MAX_PATH_LEN 1024
@@ -656,14 +649,14 @@ HDgettimeofday(struct timeval *tv, void *tz)
herr_t
H5_build_extpath(const char *name, char **extpath/*out*/)
{
- char *full_path=NULL, *ptr=NULL;
- char *retcwd=NULL, *cwdpath=NULL, *new_name=NULL;
- int drive;
- size_t cwdlen, path_len;
+ char *full_path = NULL; /* Pointer to the full path, as built or passed in */
+ char *cwdpath = NULL; /* Pointer to the current working directory path */
+ char *new_name = NULL; /* Pointer to the name of the file */
herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_NOAPI_NOINIT(H5_build_extpath)
+ /* Clear external path pointer to begin with */
*extpath = NULL;
/*
@@ -672,14 +665,18 @@ H5_build_extpath(const char *name, char **extpath/*out*/)
* OpenVMS: <disk name>$<partition>:[path]<file name>
* i.g. SYS$SYSUSERS:[LU.HDF5.SRC]H5system.c
*/
- if (CHECK_ABSOLUTE(name)) {
- if ((full_path=H5MM_strdup(name)) == NULL)
- HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
- } else { /* relative pathname */
- if (NULL == (cwdpath = (char *)H5MM_malloc(MAX_PATH_LEN)))
- HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
- if (NULL == (new_name = (char *)H5MM_strdup(name)))
- HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+ if(CHECK_ABSOLUTE(name)) {
+ if(NULL == (full_path = (char *)H5MM_strdup(name)))
+ HGOTO_ERROR(H5E_INTERNAL, H5E_NOSPACE, FAIL, "memory allocation failed")
+ } /* end if */
+ else { /* relative pathname */
+ char *retcwd;
+ int drive;
+
+ if(NULL == (cwdpath = (char *)H5MM_malloc(MAX_PATH_LEN)))
+ HGOTO_ERROR(H5E_INTERNAL, H5E_NOSPACE, FAIL, "memory allocation failed")
+ if(NULL == (new_name = (char *)H5MM_strdup(name)))
+ HGOTO_ERROR(H5E_INTERNAL, H5E_NOSPACE, FAIL, "memory allocation failed")
/*
* Windows: name[0-1] is "<drive-letter>:"
@@ -687,29 +684,35 @@ H5_build_extpath(const char *name, char **extpath/*out*/)
* Unix: does not apply
* OpenVMS: does not apply
*/
- if (CHECK_ABS_DRIVE(name)) {
+ if(CHECK_ABS_DRIVE(name)) {
drive = name[0] - 'A' + 1;
retcwd = HDgetdcwd(drive, cwdpath, MAX_PATH_LEN);
HDstrcpy(new_name, &name[2]);
+ } /* end if */
/*
* Windows: name[0] is a '/' or '\'
* Get current drive
* Unix: does not apply
* OpenVMS: does not apply
*/
- } else if (CHECK_ABS_PATH(name) && ((drive=HDgetdrive()) != 0)) {
+ else if(CHECK_ABS_PATH(name) && (0 != (drive = HDgetdrive()))) {
sprintf(cwdpath, "%c:%c", (drive+'A'-1), name[0]);
retcwd = cwdpath;
HDstrcpy(new_name, &name[1]);
- } else /* totally relative for Unix, Windows, and OpenVMS: get current working directory */
+ }
+ /* totally relative for Unix, Windows, and OpenVMS: get current working directory */
+ else
retcwd = HDgetcwd(cwdpath, MAX_PATH_LEN);
- if (retcwd != NULL) {
+ if(retcwd != NULL) {
+ size_t cwdlen;
+ size_t path_len;
+
cwdlen = HDstrlen(cwdpath);
HDassert(cwdlen);
path_len = cwdlen + HDstrlen(new_name) + 2;
- if (NULL == (full_path = (char *)H5MM_malloc(path_len)))
- HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+ if(NULL == (full_path = (char *)H5MM_malloc(path_len)))
+ HGOTO_ERROR(H5E_INTERNAL, H5E_NOSPACE, FAIL, "memory allocation failed")
HDstrcpy(full_path, cwdpath);
#ifdef H5_VMS
@@ -721,30 +724,36 @@ H5_build_extpath(const char *name, char **extpath/*out*/)
*/
if(new_name[0] == '[') {
char *tmp = new_name;
- full_path[cwdlen-1] = '\0';
+ full_path[cwdlen - 1] = '\0';
HDstrcat(full_path, ++tmp);
- } else
+ } /* end if */
+ else
HDstrcat(full_path, new_name);
#else
- if (!CHECK_DELIMITER(cwdpath[cwdlen-1]))
+ if(!CHECK_DELIMITER(cwdpath[cwdlen - 1]))
HDstrcat(full_path, DIR_SEPS);
HDstrcat(full_path, new_name);
#endif
- }
- }
+ } /* end if */
+ } /* end else */
/* strip out the last component (the file name itself) from the path */
- if (full_path) {
+ if(full_path) {
+ char *ptr = NULL;
+
GET_LAST_DELIMITER(full_path, ptr)
HDassert(ptr);
*++ptr = '\0';
*extpath = full_path;
- }
+ } /* end if */
done:
- if (cwdpath)
+ /* Release resources */
+ if(cwdpath)
H5MM_xfree(cwdpath);
- if (new_name)
+ if(new_name)
H5MM_xfree(new_name);
+
FUNC_LEAVE_NOAPI(ret_value)
} /* H5_build_extpath() */
+
diff --git a/test/links.c b/test/links.c
index 6acfd14..8793ed8 100644
--- a/test/links.c
+++ b/test/links.c
@@ -36,57 +36,17 @@
#define LINKED_FILE "be_extlink2.h5"
#ifdef H5_VMS
-const char *FILENAME[] = {
- "links0",
- "links1",
- "links2",
- "links3",
- "links4a", /* 4 */
- "links4b", /* 5 */
- "links4c", /* 6 */
- "links4d", /* 7 */
- "links5", /* 8 */
- "links6", /* 9 */
- "links7", /* 10 */
- "links8", /* 11 */
- "extlinks0", /* 12: main files */
- "[.tmp]extlinks0", /* 13: */
- "extlinks1", /* 14: target files */
- "[.tmp]extlinks1", /* 15: */
- "extlinks2", /* 16: */
- "[.tmp]extlinks2", /* 17: */
- "extlinks3", /* 18: */
- "[.tmp]extlinks3", /* 19: */
- "extlinks4", /* 20: */
- "[.tmp]extlinks4", /* 21: */
- "extlinks5", /* 22: */
- "[.tmp]extlinks6", /* 23: */
- "extlinks7", /* 24: */
- "[.tmp]extlinks7", /* 25: */
- "[.tmp]extlinks8", /* 26: */
- "extlinks9", /* 27: */
- "[.tmp]extlinks9", /* 28: */
- "extlinks10", /* 29: */ /* TESTS for windows */
- "[.tmp]extlinks10", /* 30: */
- "[.tmp]extlinks11", /* 31: */
- "[.tmp]extlinks12", /* 32: */
- "extlinks13", /* 33: */
- "[.tmp]extlinks13", /* 34: */
- "[.tmp]extlinks14", /* 35: */
- "[.tmp]extlinks15", /* 36: */
- "extlinks16A", /* 37: */ /* TESTS for H5P_set_elink_fapl */
- "extlinks16B", /* 38: */
- "extlinks17", /* 39: */
- "extlinks18A", /* 40: */
- "extlinks18B", /* 41: */
- "extlinks19A", /* 42: */
- "extlinks19B", /* 43: */
- "extlinks20", /* 44: */
- NULL
-};
-
#define TMPDIR "[.tmp]"
-#else
+#define TMPDIR2 "[.tmp2]"
+#else /* H5_VMS */
+#define TMPDIR "tmp/"
+#define TMPDIR2 "tmp2/"
+#endif /* H5_VMS */
+
+/* Symlinks for external link symlink test */
+#define SYMLINK1 TMPDIR "sym1.h5"
+#define SYMLINK2 TMPDIR2 "sym2.h5"
+
const char *FILENAME[] = {
"links0",
"links1",
@@ -101,30 +61,30 @@ const char *FILENAME[] = {
"links7", /* 10 */
"links8", /* 11 */
"extlinks0", /* 12: main files */
- "tmp/extlinks0", /* 13: */
+ TMPDIR "extlinks0", /* 13: */
"extlinks1", /* 14: target files */
- "tmp/extlinks1", /* 15: */
+ TMPDIR "extlinks1", /* 15: */
"extlinks2", /* 16: */
- "tmp/extlinks2", /* 17: */
+ TMPDIR "extlinks2", /* 17: */
"extlinks3", /* 18: */
- "tmp/extlinks3", /* 19: */
+ TMPDIR "extlinks3", /* 19: */
"extlinks4", /* 20: */
- "tmp/extlinks4", /* 21: */
+ TMPDIR "extlinks4", /* 21: */
"extlinks5", /* 22: */
- "tmp/extlinks6", /* 23: */
+ TMPDIR "extlinks6", /* 23: */
"extlinks7", /* 24: */
- "tmp/extlinks7", /* 25: */
- "tmp/extlinks8", /* 26: */
+ TMPDIR "extlinks7", /* 25: */
+ TMPDIR "extlinks8", /* 26: */
"extlinks9", /* 27: */
- "tmp/extlinks9", /* 28: */
+ TMPDIR "extlinks9", /* 28: */
"extlinks10", /* 29: */ /* TESTS for windows */
- "tmp/extlinks10", /* 30: */
- "tmp/extlinks11", /* 31: */
- "tmp/extlinks12", /* 32: */
+ TMPDIR "extlinks10",/* 30: */
+ TMPDIR "extlinks11",/* 31: */
+ TMPDIR "extlinks12",/* 32: */
"extlinks13", /* 33: */
- "tmp/extlinks13", /* 34: */
- "tmp/extlinks14", /* 35: */
- "tmp/extlinks15", /* 36: */
+ TMPDIR "extlinks13",/* 34: */
+ TMPDIR "extlinks14",/* 35: */
+ TMPDIR "extlinks15",/* 36: */
"extlinks16A", /* 37: */ /* TESTS for H5P_set_elink_fapl */
"extlinks16B", /* 38: */
"extlinks17", /* 39: */
@@ -133,12 +93,16 @@ const char *FILENAME[] = {
"extlinks19A", /* 42: */
"extlinks19B", /* 43: */
"extlinks20", /* 44: */
+ "extlinks21A", /* 45: Files for symlink() tests*/
+ TMPDIR2 "extlinks21B",/* 46: */
+ TMPDIR2 "extlinks21C",/* 47: */
+ "extlinks21C", /* 48: (same as #47, only without the TMPDIR2 prefix) */
+ TMPDIR "extlinks21D",/* 49: */
+ TMPDIR "extlinks21E",/* 50: */
+ "extlinks21E", /* 51: (same as #50, only without the TMPDIR prefix) */
NULL
};
-#define TMPDIR "tmp"
-#endif
-
#define FAMILY_SIZE 1024
#define CORE_INCREMENT 1024
#define NUM40 40
@@ -352,6 +316,37 @@ typedef struct {
/*-------------------------------------------------------------------------
+ * Function: fix_ext_filename
+ *
+ * Purpose: Internal function to append path to file name. It handles
+ * path name of Unix, Windows, and OpenVMS.
+ *
+ * Return: void
+ *
+ * Programmer: Raymond Lu
+ * 14 Jan. 2009
+ *-------------------------------------------------------------------------
+ */
+static void
+fix_ext_filename(char *path_name, char *cwd, const char *file_name)
+{
+ HDstrcpy(path_name, cwd);
+
+#ifdef H5_VMS
+ if(file_name[0] == '[') {
+ char *tmp = file_name;
+ path_name[strlen(cwd)-1] = '\0';
+ HDstrcat(path_name, ++tmp);
+ } else
+ HDstrcat(path_name, file_name);
+#else
+ HDstrcat(path_name, "/");
+ HDstrcat(path_name, file_name);
+#endif
+}
+
+
+/*-------------------------------------------------------------------------
* Function: mklinks
*
* Purpose: Build a file with assorted links.
@@ -2754,7 +2749,7 @@ external_link_env(hid_t fapl, hbool_t new_format)
/* set up name for external linked target file: "extlinks1" */
h5_fixname(FILENAME[14], fapl, filename2, sizeof filename2);
- if (HDmkdir(TMPDIR, (mode_t)0755) < 0 && errno != EEXIST)
+ if(HDmkdir(TMPDIR, (mode_t)0755) < 0 && errno != EEXIST)
TEST_ERROR
/* set up name for target file: "tmp/extlinks1" */
@@ -2899,37 +2894,6 @@ external_link_prefix(hid_t fapl, hbool_t new_format)
/*-------------------------------------------------------------------------
- * Function: fix_ext_filename
- *
- * Purpose: Internal function to append path to file name. It handles
- * path name of Unix, Windows, and OpenVMS.
- *
- * Return: void
- *
- * Programmer: Raymond Lu
- * 14 Jan. 2009
- *-------------------------------------------------------------------------
- */
-static void
-fix_ext_filename(char *path_name, char *cwd, const char *file_name)
-{
- HDstrcpy(path_name, cwd);
-
-#ifdef H5_VMS
- if(file_name[0] == '[') {
- char *tmp = file_name;
- path_name[strlen(cwd)-1] = '\0';
- HDstrcat(path_name, ++tmp);
- } else
- HDstrcat(path_name, file_name);
-#else
- HDstrcat(path_name, "/");
- HDstrcat(path_name, file_name);
-#endif
-}
-
-
-/*-------------------------------------------------------------------------
* Function: external_link_abs_mainpath: test 3
*
* Purpose: 1. target link: "extlinks3"
@@ -6431,6 +6395,208 @@ error:
/*-------------------------------------------------------------------------
+ * Function: external_symlink
+ *
+ * Purpose: Verify functionality of external links when symlinks are
+ * used for parent/child files
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Programmer: Quincey Koziol
+ * Nov. 23, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+external_symlink(hid_t fapl, hbool_t new_format)
+{
+#ifdef H5_HAVE_SYMLINK
+ hid_t file1 = -1, file2 = -1, file3 = -1, file4 = -1, file5 = -1;
+ hid_t group2 = -1, group3 = -1, group4 = -1, group5 = -1;
+ char filename1[NAME_BUF_SIZE],
+ filename2a[NAME_BUF_SIZE],
+ filename2b[NAME_BUF_SIZE],
+ filename3a[NAME_BUF_SIZE],
+ filename3b[NAME_BUF_SIZE],
+ filename4a[NAME_BUF_SIZE],
+ filename4b[NAME_BUF_SIZE],
+ filename5a[NAME_BUF_SIZE],
+ filename5b[NAME_BUF_SIZE],
+ tmpname[NAME_BUF_SIZE],
+ cwdpath[NAME_BUF_SIZE];
+#endif /* H5_HAVE_SYMLINK */
+
+ if(new_format)
+ TESTING("external links w/symlink files (w/new group format)")
+ else
+ TESTING("external links w/symlink files")
+
+#ifdef H5_HAVE_SYMLINK
+ /* set up name for main file: "extlinks21A" */
+ h5_fixname(FILENAME[45], fapl, filename1, sizeof(filename1));
+
+ /* create tmp directory and get current working directory path */
+ if(HDmkdir(TMPDIR, (mode_t)0755) < 0 && errno != EEXIST)
+ TEST_ERROR
+ if(HDmkdir(TMPDIR2, (mode_t)0755) < 0 && errno != EEXIST)
+ TEST_ERROR
+ if(NULL == HDgetcwd(cwdpath, NAME_BUF_SIZE))
+ TEST_ERROR
+
+ /* Set up names for files in the subdirectories */
+
+ /* set up names for file #2 in temporary directory #2: "tmp2/extlinks21B" */
+ h5_fixname(FILENAME[46], fapl, filename2a, sizeof(filename2a));
+ fix_ext_filename(tmpname, cwdpath, FILENAME[46]);
+ h5_fixname(tmpname, fapl, filename2b, sizeof(filename2b));
+
+ /* Create symbolic link #1 in temporary directory #1 to file #2 in temporary directory #2 */
+ /* (i.e. tmp/sym1.h5 -> <full path to>/tmp2/extlinks21B.h5) */
+ if(HDsymlink(filename2b, SYMLINK1) < 0 && errno != EEXIST) TEST_ERROR
+
+ /* set up name for file #3 in temporary directory #2: "tmp2/extlinks21C" */
+ h5_fixname(FILENAME[47], fapl, filename3a, sizeof(filename3a));
+ h5_fixname(FILENAME[48], fapl, filename3b, sizeof(filename3b));
+
+ /* set up name for file #4 in temporary directory #1: "tmp/extlinks21D" */
+ h5_fixname(FILENAME[49], fapl, filename4a, sizeof(filename4a));
+ fix_ext_filename(tmpname, cwdpath, FILENAME[49]);
+ h5_fixname(tmpname, fapl, filename4b, sizeof(filename4b));
+
+ /* Create symbolic link #2 in temporary directory #2 to file #4 in temporary directory #1 */
+ /* (i.e. tmp2/sym2.h5 -> <full path to>/tmp/extlinks21D.h5) */
+ if(HDsymlink(filename4b, SYMLINK2) < 0 && errno != EEXIST) TEST_ERROR
+
+ /* set up name for file #5 in temporary directory #1: "tmp/extlinks21E" */
+ h5_fixname(FILENAME[50], fapl, filename5a, sizeof(filename5a));
+ h5_fixname(FILENAME[51], fapl, filename5b, sizeof(filename5b));
+
+
+ /* Create file #1 in current directory */
+ if((file1 = H5Fcreate(filename1, H5F_ACC_TRUNC, H5P_DEFAULT, fapl)) < 0) TEST_ERROR
+
+ /* Create external link to file & object in temporary directory #2, using symlink #1 name */
+ if(H5Lcreate_external(SYMLINK1, "group2", file1, "extlink2-sym", H5P_DEFAULT, H5P_DEFAULT) < 0) TEST_ERROR
+
+ /* Close file #1 */
+ if(H5Fclose(file1) < 0) TEST_ERROR
+
+
+ /* Create file #2 in tmp directory #2 */
+ if((file2 = H5Fcreate(filename2a, H5F_ACC_TRUNC, H5P_DEFAULT, fapl)) < 0) TEST_ERROR
+ if(H5Fclose(file2) < 0) TEST_ERROR
+
+ /* Re-open file #2 in tmp directory through symlink */
+ if((file2 = H5Fopen(SYMLINK1, H5F_ACC_RDWR, fapl)) < 0) TEST_ERROR
+
+ /* Create group in file #2 in temporary directory */
+ if((group2 = H5Gcreate2(file2, "group2", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR
+
+ /* Create external link to file #3 & object in temporary directory #2 */
+ if(H5Lcreate_external(filename3b, "group3", group2, "extlink3", H5P_DEFAULT, H5P_DEFAULT) < 0) TEST_ERROR
+
+ /* Close group in file #2 */
+ if(H5Gclose(group2) < 0) TEST_ERROR
+
+ /* Close file #2 */
+ if(H5Fclose(file2) < 0) TEST_ERROR
+
+
+ /* Create file #3 in temp. directory #2 */
+ if((file3 = H5Fcreate(filename3a, H5F_ACC_TRUNC, H5P_DEFAULT, fapl)) < 0) TEST_ERROR
+
+ /* Create group in file #3 */
+ if((group3 = H5Gcreate2(file3, "group3", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR
+
+ /* Create external link to file & object in temporary directory #1, using symlink #2 name */
+ if(H5Lcreate_external(SYMLINK2, "group4", group3, "extlink4-sym", H5P_DEFAULT, H5P_DEFAULT) < 0) TEST_ERROR
+
+ /* Close group in file #3 */
+ if(H5Gclose(group3) < 0) TEST_ERROR
+
+ /* Close file #3 */
+ if(H5Fclose(file3) < 0) TEST_ERROR
+
+
+ /* Create file #4 in temporary directory #1 */
+ if((file4 = H5Fcreate(filename4b, H5F_ACC_TRUNC, H5P_DEFAULT, fapl)) < 0) TEST_ERROR
+
+ /* Create group in file #4 in 'temporary' directory */
+ if((group4 = H5Gcreate2(file4, "group4", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR
+
+ /* Create external link to file #5 & object in temporary directory #1 */
+ if(H5Lcreate_external(filename5b, "group5", group4, "extlink5", H5P_DEFAULT, H5P_DEFAULT) < 0) TEST_ERROR
+
+ /* Close group in file #4 */
+ if(H5Gclose(group4) < 0) TEST_ERROR
+
+ /* Close file #4 */
+ if(H5Fclose(file4) < 0) TEST_ERROR
+
+
+ /* Create file #5 in temporary directory #1 */
+ if((file5 = H5Fcreate(filename5a, H5F_ACC_TRUNC, H5P_DEFAULT, fapl)) < 0) TEST_ERROR
+
+ /* Create group in file #5 in 'temporary' directory #1 */
+ if((group5 = H5Gcreate2(file5, "group5", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR
+ if(H5Gclose(group5) < 0) TEST_ERROR
+
+ /* Close file #5 */
+ if(H5Fclose(file5) < 0) TEST_ERROR
+
+
+ /* Actual tests... */
+
+ /* Reopen file #1 */
+ if((file1 = H5Fopen(filename1, H5F_ACC_RDWR, fapl)) < 0) TEST_ERROR
+
+ /* Open group in file #2, through external link w/symlink */
+ if((group2 = H5Gopen2(file1, "extlink2-sym", H5P_DEFAULT)) < 0) FAIL_STACK_ERROR
+ if(H5Gclose(group2) < 0) TEST_ERROR
+
+ /* Open group in file #3, through external link w/symlink to external link */
+ if((group3 = H5Gopen2(file1, "extlink2-sym/extlink3", H5P_DEFAULT)) < 0) FAIL_STACK_ERROR
+ if(H5Gclose(group3) < 0) TEST_ERROR
+
+ /* Open group in file #4, through external link w/symlink to external link w/symlink */
+ if((group4 = H5Gopen2(file1, "extlink2-sym/extlink3/extlink4-sym", H5P_DEFAULT)) < 0) FAIL_STACK_ERROR
+ if(H5Gclose(group4) < 0) TEST_ERROR
+
+ /* Open group in file #5, through external link w/symlink to external link w/symlink to external link */
+ if((group5 = H5Gopen2(file1, "extlink2-sym/extlink3/extlink4-sym/extlink5", H5P_DEFAULT)) < 0) FAIL_STACK_ERROR
+ if(H5Gclose(group5) < 0) TEST_ERROR
+
+ /* Close file #1 */
+ if(H5Fclose(file1) < 0) TEST_ERROR
+
+
+ PASSED();
+ return 0;
+
+ error:
+ H5E_BEGIN_TRY {
+ H5Gclose(group5);
+ H5Gclose(group4);
+ H5Gclose(group3);
+ H5Gclose(group2);
+ H5Fclose(file5);
+ H5Fclose(file4);
+ H5Fclose(file3);
+ H5Fclose(file2);
+ H5Fclose(file1);
+ } H5E_END_TRY;
+ return -1;
+#else /* H5_HAVE_SYMLINK */
+ SKIPPED();
+ puts(" Current file system or operating system doesn't support symbolic links");
+
+ return 0;
+#endif /* H5_HAVE_SYMLINK */
+} /* end external_symlink() */
+
+
+/*-------------------------------------------------------------------------
* Function: ud_hard_links
*
* Purpose: Check that the functionality of hard links can be duplicated
@@ -13434,6 +13600,7 @@ main(void)
nerrors += external_link_win8(my_fapl, new_format) < 0 ? 1 : 0;
nerrors += external_link_win9(my_fapl, new_format) < 0 ? 1 : 0;
#endif
+ nerrors += external_symlink(my_fapl, new_format) < 0 ? 1 : 0;
/* These tests assume that external links are a form of UD links,
* so assume that everything that passed for external links
@@ -13506,8 +13673,13 @@ main(void)
}
printf("All link tests passed.\n");
+ /* clean up symlink created by external link tests */
+ HDremove(SYMLINK1);
+ HDremove(SYMLINK2);
+
/* clean up tmp directory created by external link tests */
HDrmdir(TMPDIR);
+ HDrmdir(TMPDIR2);
return 0;