From 1bc79f977be67f734a44fd237be6f05b5fb25f53 Mon Sep 17 00:00:00 2001 From: Quincey Koziol Date: Tue, 1 Dec 2009 08:39:05 -0500 Subject: [svn-r17939] Description: Handle external links from symlinked files by adding another check to look for "child" files for links from the actual location of the "parent" file, instead of from the location of the symlink. Tested on: FreeBSD/32 6.3 (duty) in debug mode FreeBSD/64 6.3 (liberty) w/C++ & FORTRAN, in debug mode Linux/32 2.6 (jam) w/PGI compilers, w/default API=1.8.x, w/C++ & FORTRAN, w/threadsafe, in debug mode Linux/64-amd64 2.6 (smirom) w/Intel compilers, w/default API=1.6.x, w/C++ & FORTRAN, in production mode Solaris/32 2.10 (linew) w/deprecated symbols disabled, w/C++ & FORTRAN, w/szip filter, in production mode Linux/64-ia64 2.6 (cobalt) w/Intel compilers, w/C++ & FORTRAN, in production mode Linux/64-ia64 2.4 (tg-login3) w/parallel, w/FORTRAN, in debug mode Linux/64-amd64 2.6 (abe) w/parallel, w/FORTRAN, in production mode Mac OS X/32 10.6.2 (amazon) in debug mode Mac OS X/32 10.6.2 (amazon) w/C++ & FORTRAN, w/threadsafe, in production mode --- configure | 17 ++- configure.in | 3 +- src/H5AC.c | 2 +- src/H5F.c | 198 +++++++++++++++++------------ src/H5FD.c | 6 +- src/H5FDlog.c | 20 ++- src/H5FDpublic.h | 6 + src/H5FDsec2.c | 44 ++++--- src/H5FDsec2.h | 1 + src/H5Fdbg.c | 4 +- src/H5Fpkg.h | 12 +- src/H5Fprivate.h | 13 +- src/H5Fquery.c | 130 ++++++++++++++++--- src/H5Gloc.c | 4 +- src/H5Lexternal.c | 205 ++++++++++++++++++------------ src/H5config.h.in | 3 + src/H5private.h | 12 +- src/H5system.c | 89 +++++++------ test/links.c | 372 +++++++++++++++++++++++++++++++++++++++--------------- 19 files changed, 765 insertions(+), 376 deletions(-) diff --git a/configure b/configure index 2e215bf..323e143 100755 --- a/configure +++ b/configure @@ -1,5 +1,5 @@ #! /bin/sh -# From configure.in Id: configure.in 17902 2009-11-17 15:27:25Z hdftest . +# From configure.in Id: configure.in 17924 2009-11-23 22:34:51Z koziol . # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.64 for HDF5 1.9.52. # @@ -24779,7 +24779,20 @@ _ACEOF fi done -for ac_func in snprintf srandom strdup system tmpfile vasprintf waitpid +for ac_func in snprintf srandom strdup symlink system +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +eval as_val=\$$as_ac_var + if test "x$as_val" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + +for ac_func in tmpfile vasprintf waitpid do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" diff --git a/configure.in b/configure.in index 0d4963b..2717fb4 100644 --- a/configure.in +++ b/configure.in @@ -1978,7 +1978,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/src/H5AC.c b/src/H5AC.c index 9fd2e8f..9273c0c 100644 --- a/src/H5AC.c +++ b/src/H5AC.c @@ -2493,7 +2493,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 0195b5a..7e9a32e 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. @@ -1118,7 +1083,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") @@ -1168,7 +1134,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 @@ -1198,7 +1163,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") /* @@ -1284,7 +1249,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 @@ -1342,10 +1307,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; @@ -2007,8 +1976,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") @@ -2109,37 +2079,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 - * 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. @@ -2194,6 +2133,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 @@ -2729,6 +2762,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 * @@ -2764,10 +2800,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 ed24506..c8ec658 100644 --- a/src/H5FDpublic.h +++ b/src/H5FDpublic.h @@ -204,6 +204,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 2c86647..181a153 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 d703a80..73962bb 100644 --- a/src/H5Fpkg.h +++ b/src/H5Fpkg.h @@ -224,7 +224,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 */ @@ -232,7 +232,7 @@ typedef struct H5F_file_t { /* File space allocation information */ H5F_file_space_type_t fs_strategy; /* File space handling strategy */ - hsize_t fs_threshold; /* Free space section threshold */ + hsize_t fs_threshold; /* Free space section threshold */ hbool_t use_tmp_space; /* Whether temp. file space allocation is allowed */ haddr_t tmp_addr; /* Next address to use for temp. space in the file */ unsigned fs_aggr_merge[H5FD_MEM_NTYPES]; /* Flags for whether free space can merge with aggregator(s) */ @@ -252,14 +252,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 13a111d..6031746 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)) @@ -469,12 +471,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); @@ -503,6 +508,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 + * 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 ":" */ - 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 ada5321..8f56db0 100644 --- a/src/H5private.h +++ b/src/H5private.h @@ -1033,6 +1033,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" { @@ -1227,6 +1230,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 */ @@ -1481,7 +1489,6 @@ extern char *strdup(const char *s); #endif #define COLON_SEPC ':' -H5_DLL herr_t H5_build_extpath(const char *, char ** /*out*/ ); /* @@ -2288,6 +2295,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: $:[path] * 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 ":" @@ -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 60607c9..37b03cf 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 -> /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 -> /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; -- cgit v0.12