diff options
-rw-r--r-- | configure.in | 3 | ||||
-rw-r--r-- | release_docs/RELEASE.txt | 4 | ||||
-rw-r--r-- | src/H5AC.c | 2 | ||||
-rw-r--r-- | src/H5F.c | 198 | ||||
-rw-r--r-- | src/H5FD.c | 6 | ||||
-rw-r--r-- | src/H5FDlog.c | 20 | ||||
-rw-r--r-- | src/H5FDpublic.h | 6 | ||||
-rw-r--r-- | src/H5FDsec2.c | 44 | ||||
-rw-r--r-- | src/H5FDsec2.h | 1 | ||||
-rw-r--r-- | src/H5Fdbg.c | 4 | ||||
-rw-r--r-- | src/H5Fpkg.h | 10 | ||||
-rw-r--r-- | src/H5Fprivate.h | 13 | ||||
-rw-r--r-- | src/H5Fquery.c | 130 | ||||
-rw-r--r-- | src/H5Gloc.c | 4 | ||||
-rw-r--r-- | src/H5Lexternal.c | 205 | ||||
-rw-r--r-- | src/H5config.h.in | 3 | ||||
-rw-r--r-- | src/H5private.h | 12 | ||||
-rw-r--r-- | src/H5system.c | 89 | ||||
-rw-r--r-- | test/links.c | 372 |
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 ---------------- @@ -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) @@ -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 */ @@ -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; |