Files
hdf5/src/H5FDsec2.c
Quincey Koziol 1d8a1b22f1 [svn-r17972] Description:
Bring r17971 from trunk to 1.8 branch:

    Allow the core VFD to properly support opening backing store files through
symbolic links and have the external links in the file be treated in the same
way as for the sec2 driver.

Tested on:
	FreeBSD/32 6.3 (duty) in debug mode
	(h5committested on trunk)
2009-12-06 22:27:19 -05:00

950 lines
32 KiB
C
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Copyright by The HDF Group. *
* Copyright by the Board of Trustees of the University of Illinois. *
* All rights reserved. *
* *
* This file is part of HDF5. The full HDF5 copyright notice, including *
* terms governing use, modification, and redistribution, is contained in *
* the files COPYING and Copyright.html. COPYING can be found at the root *
* of the source code distribution tree; Copyright.html can be found at the *
* root level of an installed copy of the electronic HDF5 document set and *
* is linked from the top-level documents page. It can also be found at *
* http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have *
* access to either file, you may request a copy from help@hdfgroup.org. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
* Programmer: Robb Matzke <matzke@llnl.gov>
* Thursday, July 29, 1999
*
* Purpose: The POSIX unbuffered file driver using only the HDF5 public
* API and with a few optimizations: the lseek() call is made
* only when the current file position is unknown or needs to be
* changed based on previous I/O through this driver (don't mix
* I/O from this driver with I/O from other parts of the
* application to the same file).
*/
/* Interface initialization */
#define H5_INTERFACE_INIT_FUNC H5FD_sec2_init_interface
#include "H5private.h" /* Generic Functions */
#include "H5Eprivate.h" /* Error handling */
#include "H5Fprivate.h" /* File access */
#include "H5FDprivate.h" /* File drivers */
#include "H5FDsec2.h" /* Sec2 file driver */
#include "H5FLprivate.h" /* Free Lists */
#include "H5Iprivate.h" /* IDs */
#include "H5MMprivate.h" /* Memory management */
#include "H5Pprivate.h" /* Property lists */
/* The driver identification number, initialized at runtime */
static hid_t H5FD_SEC2_g = 0;
/* File operations */
typedef enum {
OP_UNKNOWN = 0, /* Unknown last file operation */
OP_READ = 1, /* Last file I/O operation was a read */
OP_WRITE = 2 /* Last file I/O operation was a write */
} H5FD_sec2_file_op_t;
#define H5FD_SEC2_MAX_FILENAME_LEN 1024
/*
* The description of a file belonging to this driver. The `eoa' and `eof'
* determine the amount of hdf5 address space in use and the high-water mark
* of the file (the current size of the underlying Unix file). The `pos'
* value is used to eliminate file position updates when they would be a
* no-op. Unfortunately we've found systems that use separate file position
* indicators for reading and writing so the lseek can only be eliminated if
* the current operation is the same as the previous operation. When opening
* a file the `eof' will be set to the current file size, `eoa' will be set
* to zero, `pos' will be set to H5F_ADDR_UNDEF (as it is when an error
* occurs), and `op' will be set to H5F_OP_UNKNOWN.
*/
typedef struct H5FD_sec2_t {
H5FD_t pub; /*public stuff, must be first */
int fd; /*the unix file */
haddr_t eoa; /*end of allocated region */
haddr_t eof; /*end of file; current file size*/
haddr_t pos; /*current file I/O position */
H5FD_sec2_file_op_t op; /*last operation */
char filename[H5FD_SEC2_MAX_FILENAME_LEN]; /* Copy of file name from open operation */
#ifndef _WIN32
/*
* On most systems the combination of device and i-node number uniquely
* identify a file.
*/
dev_t device; /*file device number */
#ifdef H5_VMS
ino_t inode[3]; /*file i-node number */
#else
ino_t inode; /*file i-node number */
#endif /*H5_VMS*/
#else
/*
* On _WIN32 the low-order word of a unique identifier associated with the
* file and the volume serial number uniquely identify a file. This number
* (which, both? -rpm) may change when the system is restarted or when the
* file is opened. After a process opens a file, the identifier is
* constant until the file is closed. An application can use this
* identifier and the volume serial number to determine whether two
* handles refer to the same file.
*/
DWORD fileindexlo;
DWORD fileindexhi;
#endif
/* Information from properties set by 'h5repart' tool */
hbool_t fam_to_sec2; /* Whether to eliminate the family driver info
* and convert this file to a single file */
} H5FD_sec2_t;
/*
* This driver supports systems that have the lseek64() function by defining
* some macros here so we don't have to have conditional compilations later
* throughout the code.
*
* file_offset_t: The datatype for file offsets, the second argument of
* the lseek() or lseek64() call.
*
*/
/* adding for windows NT file system support. */
#ifdef H5_HAVE_LSEEK64
# define file_offset_t off64_t
#elif defined (_WIN32) && !defined(__MWERKS__)
# /*MSVC*/
# define file_offset_t __int64
#else
# define file_offset_t off_t
#endif
/*
* These macros check for overflow of various quantities. These macros
* assume that file_offset_t is signed and haddr_t and size_t are unsigned.
*
* ADDR_OVERFLOW: Checks whether a file address of type `haddr_t'
* is too large to be represented by the second argument
* of the file seek function.
*
* SIZE_OVERFLOW: Checks whether a buffer size of type `hsize_t' is too
* large to be represented by the `size_t' type.
*
* REGION_OVERFLOW: Checks whether an address and size pair describe data
* which can be addressed entirely by the second
* argument of the file seek function.
*/
#define MAXADDR (((haddr_t)1<<(8*sizeof(file_offset_t)-1))-1)
#define ADDR_OVERFLOW(A) (HADDR_UNDEF==(A) || \
((A) & ~(haddr_t)MAXADDR))
#define SIZE_OVERFLOW(Z) ((Z) & ~(hsize_t)MAXADDR)
#define REGION_OVERFLOW(A,Z) (ADDR_OVERFLOW(A) || SIZE_OVERFLOW(Z) || \
HADDR_UNDEF==(A)+(Z) || \
(file_offset_t)((A)+(Z))<(file_offset_t)(A))
/* Prototypes */
static H5FD_t *H5FD_sec2_open(const char *name, unsigned flags, hid_t fapl_id,
haddr_t maxaddr);
static herr_t H5FD_sec2_close(H5FD_t *_file);
static int H5FD_sec2_cmp(const H5FD_t *_f1, const H5FD_t *_f2);
static herr_t H5FD_sec2_query(const H5FD_t *_f1, unsigned long *flags);
static haddr_t H5FD_sec2_get_eoa(const H5FD_t *_file, H5FD_mem_t type);
static herr_t H5FD_sec2_set_eoa(H5FD_t *_file, H5FD_mem_t type, haddr_t addr);
static haddr_t H5FD_sec2_get_eof(const H5FD_t *_file);
static herr_t H5FD_sec2_get_handle(H5FD_t *_file, hid_t fapl, void** file_handle);
static herr_t H5FD_sec2_read(H5FD_t *_file, H5FD_mem_t type, hid_t fapl_id, haddr_t addr,
size_t size, void *buf);
static herr_t H5FD_sec2_write(H5FD_t *_file, H5FD_mem_t type, hid_t fapl_id, haddr_t addr,
size_t size, const void *buf);
static herr_t H5FD_sec2_truncate(H5FD_t *_file, hid_t dxpl_id, hbool_t closing);
static const H5FD_class_t H5FD_sec2_g = {
"sec2", /*name */
MAXADDR, /*maxaddr */
H5F_CLOSE_WEAK, /* fc_degree */
NULL, /*sb_size */
NULL, /*sb_encode */
NULL, /*sb_decode */
0, /*fapl_size */
NULL, /*fapl_get */
NULL, /*fapl_copy */
NULL, /*fapl_free */
0, /*dxpl_size */
NULL, /*dxpl_copy */
NULL, /*dxpl_free */
H5FD_sec2_open, /*open */
H5FD_sec2_close, /*close */
H5FD_sec2_cmp, /*cmp */
H5FD_sec2_query, /*query */
NULL, /*get_type_map */
NULL, /*alloc */
NULL, /*free */
H5FD_sec2_get_eoa, /*get_eoa */
H5FD_sec2_set_eoa, /*set_eoa */
H5FD_sec2_get_eof, /*get_eof */
H5FD_sec2_get_handle, /*get_handle */
H5FD_sec2_read, /*read */
H5FD_sec2_write, /*write */
NULL, /*flush */
H5FD_sec2_truncate, /*truncate */
NULL, /*lock */
NULL, /*unlock */
H5FD_FLMAP_SINGLE /*fl_map */
};
/* Declare a free list to manage the H5FD_sec2_t struct */
H5FL_DEFINE_STATIC(H5FD_sec2_t);
/*--------------------------------------------------------------------------
NAME
H5FD_sec2_init_interface -- Initialize interface-specific information
USAGE
herr_t H5FD_sec2_init_interface()
RETURNS
Non-negative on success/Negative on failure
DESCRIPTION
Initializes any interface-specific data or routines. (Just calls
H5FD_sec2_init currently).
--------------------------------------------------------------------------*/
static herr_t
H5FD_sec2_init_interface(void)
{
FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5FD_sec2_init_interface)
FUNC_LEAVE_NOAPI(H5FD_sec2_init())
} /* H5FD_sec2_init_interface() */
/*-------------------------------------------------------------------------
* Function: H5FD_sec2_init
*
* Purpose: Initialize this driver by registering the driver with the
* library.
*
* Return: Success: The driver ID for the sec2 driver.
* Failure: Negative.
*
* Programmer: Robb Matzke
* Thursday, July 29, 1999
*
*-------------------------------------------------------------------------
*/
hid_t
H5FD_sec2_init(void)
{
hid_t ret_value; /* Return value */
FUNC_ENTER_NOAPI(H5FD_sec2_init, FAIL)
if(H5I_VFL != H5I_get_type(H5FD_SEC2_g))
H5FD_SEC2_g = H5FD_register(&H5FD_sec2_g, sizeof(H5FD_class_t), FALSE);
/* Set return value */
ret_value = H5FD_SEC2_g;
done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5FD_sec2_init() */
/*---------------------------------------------------------------------------
* Function: H5FD_sec2_term
*
* Purpose: Shut down the VFD
*
* Return: <none>
*
* Programmer: Quincey Koziol
* Friday, Jan 30, 2004
*
*---------------------------------------------------------------------------
*/
void
H5FD_sec2_term(void)
{
FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5FD_sec2_term)
/* Reset VFL ID */
H5FD_SEC2_g = 0;
FUNC_LEAVE_NOAPI_VOID
} /* end H5FD_sec2_term() */
/*-------------------------------------------------------------------------
* Function: H5Pset_fapl_sec2
*
* Purpose: Modify the file access property list to use the H5FD_SEC2
* driver defined in this source file. There are no driver
* specific properties.
*
* Return: Non-negative on success/Negative on failure
*
* Programmer: Robb Matzke
* Thursday, February 19, 1998
*
*-------------------------------------------------------------------------
*/
herr_t
H5Pset_fapl_sec2(hid_t fapl_id)
{
H5P_genplist_t *plist; /* Property list pointer */
herr_t ret_value;
FUNC_ENTER_API(H5Pset_fapl_sec2, FAIL)
H5TRACE1("e", "i", fapl_id);
if(NULL == (plist = H5P_object_verify(fapl_id,H5P_FILE_ACCESS)))
HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access property list")
ret_value= H5P_set_driver(plist, H5FD_SEC2, NULL);
done:
FUNC_LEAVE_API(ret_value)
}
/*-------------------------------------------------------------------------
* Function: H5FD_sec2_open
*
* Purpose: Create and/or opens a Unix file as an HDF5 file.
*
* Return: Success: A pointer to a new file data structure. The
* public fields will be initialized by the
* caller, which is always H5FD_open().
*
* Failure: NULL
*
* Programmer: Robb Matzke
* Thursday, July 29, 1999
*
* Modifications:
*
*-------------------------------------------------------------------------
*/
static H5FD_t *
H5FD_sec2_open(const char *name, unsigned flags, hid_t fapl_id, haddr_t maxaddr)
{
H5FD_sec2_t *file = NULL; /* sec2 VFD info */
int fd = (-1); /* File descriptor */
int o_flags; /* Flags for open() call */
#ifdef _WIN32
HFILE filehandle;
struct _BY_HANDLE_FILE_INFORMATION fileinfo;
#endif
h5_stat_t sb;
H5FD_t *ret_value; /* Return value */
FUNC_ENTER_NOAPI(H5FD_sec2_open, NULL)
/* Sanity check on file offsets */
HDassert(sizeof(file_offset_t) >= sizeof(size_t));
/* Check arguments */
if(!name || !*name)
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "invalid file name")
if(0 == maxaddr || HADDR_UNDEF == maxaddr)
HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, NULL, "bogus 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;
/* Open the file */
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)))
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);
file->pos = HADDR_UNDEF;
file->op = OP_UNKNOWN;
#ifdef _WIN32
filehandle = _get_osfhandle(fd);
(void)GetFileInformationByHandle((HANDLE)filehandle, &fileinfo);
file->fileindexhi = fileinfo.nFileIndexHigh;
file->fileindexlo = fileinfo.nFileIndexLow;
#else /* _WIN32 */
file->device = sb.st_dev;
#ifdef H5_VMS
file->inode[0] = sb.st_ino[0];
file->inode[1] = sb.st_ino[1];
file->inode[2] = sb.st_ino[2];
#else
file->inode = sb.st_ino;
#endif /*H5_VMS*/
#endif /* _WIN32 */
/* Retain a copy of the name used to open the file, for possible error reporting */
HDstrncpy(file->filename, name, sizeof(file->filename));
file->filename[sizeof(file->filename) - 1] = '\0';
/* Check for non-default FAPL */
if(H5P_FILE_ACCESS_DEFAULT != fapl_id) {
H5P_genplist_t *plist; /* Property list pointer */
/* Get the FAPL */
if(NULL == (plist = (H5P_genplist_t *)H5I_object(fapl_id)))
HGOTO_ERROR(H5E_VFL, H5E_BADTYPE, NULL, "not a file access property list")
/* This step is for h5repart tool only. If user wants to change file driver from
* family to sec2 while using h5repart, this private property should be set so that
* in the later step, the library can ignore the family driver information saved
* in the superblock.
*/
if(H5P_exist_plist(plist, H5F_ACS_FAMILY_TO_SEC2_NAME) > 0)
if(H5P_get(plist, H5F_ACS_FAMILY_TO_SEC2_NAME, &file->fam_to_sec2) < 0)
HGOTO_ERROR(H5E_VFL, H5E_CANTGET, NULL, "can't get property of changing family to sec2")
} /* end if */
/* Set return value */
ret_value = (H5FD_t*)file;
done:
if(NULL == ret_value) {
if(fd >= 0)
HDclose(fd);
if(file)
file = H5FL_FREE(H5FD_sec2_t, file);
} /* end if */
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5FD_sec2_open() */
/*-------------------------------------------------------------------------
* Function: H5FD_sec2_close
*
* Purpose: Closes a Unix file.
*
* Return: Success: 0
*
* Failure: -1, file not closed.
*
* Programmer: Robb Matzke
* Thursday, July 29, 1999
*
*-------------------------------------------------------------------------
*/
static herr_t
H5FD_sec2_close(H5FD_t *_file)
{
H5FD_sec2_t *file = (H5FD_sec2_t*)_file;
herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_NOAPI(H5FD_sec2_close, FAIL)
/* Sanity check */
HDassert(file);
/* Close the underlying file */
if(HDclose(file->fd) < 0)
HSYS_GOTO_ERROR(H5E_IO, H5E_CANTCLOSEFILE, FAIL, "unable to close file")
/* Release the file info */
file = H5FL_FREE(H5FD_sec2_t, file);
done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5FD_sec2_close() */
/*-------------------------------------------------------------------------
* Function: H5FD_sec2_cmp
*
* Purpose: Compares two files belonging to this driver using an
* arbitrary (but consistent) ordering.
*
* Return: Success: A value like strcmp()
*
* Failure: never fails (arguments were checked by the
* caller).
*
* Programmer: Robb Matzke
* Thursday, July 29, 1999
*
* Modifications:
*
*-------------------------------------------------------------------------
*/
static int
H5FD_sec2_cmp(const H5FD_t *_f1, const H5FD_t *_f2)
{
const H5FD_sec2_t *f1 = (const H5FD_sec2_t*)_f1;
const H5FD_sec2_t *f2 = (const H5FD_sec2_t*)_f2;
int ret_value=0;
FUNC_ENTER_NOAPI(H5FD_sec2_cmp, H5FD_VFD_DEFAULT)
#ifdef _WIN32
if (f1->fileindexhi < f2->fileindexhi) HGOTO_DONE(-1)
if (f1->fileindexhi > f2->fileindexhi) HGOTO_DONE(1)
if (f1->fileindexlo < f2->fileindexlo) HGOTO_DONE(-1)
if (f1->fileindexlo > f2->fileindexlo) HGOTO_DONE(1)
#else
#ifdef H5_DEV_T_IS_SCALAR
if (f1->device < f2->device) HGOTO_DONE(-1)
if (f1->device > f2->device) HGOTO_DONE(1)
#else /* H5_DEV_T_IS_SCALAR */
/* If dev_t isn't a scalar value on this system, just use memcmp to
* determine if the values are the same or not. The actual return value
* shouldn't really matter...
*/
if(HDmemcmp(&(f1->device),&(f2->device),sizeof(dev_t))<0) HGOTO_DONE(-1)
if(HDmemcmp(&(f1->device),&(f2->device),sizeof(dev_t))>0) HGOTO_DONE(1)
#endif /* H5_DEV_T_IS_SCALAR */
#ifndef H5_VMS
if (f1->inode < f2->inode) HGOTO_DONE(-1)
if (f1->inode > f2->inode) HGOTO_DONE(1)
#else
if(HDmemcmp(&(f1->inode),&(f2->inode),3*sizeof(ino_t))<0) HGOTO_DONE(-1)
if(HDmemcmp(&(f1->inode),&(f2->inode),3*sizeof(ino_t))>0) HGOTO_DONE(1)
#endif /*H5_VMS*/
#endif
done:
FUNC_LEAVE_NOAPI(ret_value)
}
/*-------------------------------------------------------------------------
* Function: H5FD_sec2_query
*
* Purpose: Set the flags that this VFL driver is capable of supporting.
* (listed in H5FDpublic.h)
*
* Return: Success: non-negative
* Failure: negative
*
* Programmer: Quincey Koziol
* Friday, August 25, 2000
*
*-------------------------------------------------------------------------
*/
static herr_t
H5FD_sec2_query(const H5FD_t *_file, unsigned long *flags /* out */)
{
const H5FD_sec2_t *file = (const H5FD_sec2_t*)_file; /* sec2 VFD info */
FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5FD_sec2_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_POSIX_COMPAT_HANDLE; /* VFD handle is POSIX I/O call compatible */
/* Check for flags that are set by h5repart */
if(file->fam_to_sec2)
*flags |= H5FD_FEAT_IGNORE_DRVRINFO; /* Ignore the driver info when file is opened (which eliminates it) */
} /* end if */
FUNC_LEAVE_NOAPI(SUCCEED)
} /* end H5FD_sec2_query() */
/*-------------------------------------------------------------------------
* Function: H5FD_sec2_get_eoa
*
* Purpose: Gets the end-of-address marker for the file. The EOA marker
* is the first address past the last byte allocated in the
* format address space.
*
* Return: Success: The end-of-address marker.
*
* Failure: HADDR_UNDEF
*
* Programmer: Robb Matzke
* Monday, August 2, 1999
*
* Modifications:
* Raymond Lu
* 21 Dec. 2006
* Added the parameter TYPE. It's only used for MULTI driver.
*
*-------------------------------------------------------------------------
*/
static haddr_t
H5FD_sec2_get_eoa(const H5FD_t *_file, H5FD_mem_t UNUSED type)
{
const H5FD_sec2_t *file = (const H5FD_sec2_t*)_file;
haddr_t ret_value; /* Return value */
FUNC_ENTER_NOAPI(H5FD_sec2_get_eoa, HADDR_UNDEF)
/* Set return value */
ret_value = file->eoa;
done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5FD_sec2_get_eoa() */
/*-------------------------------------------------------------------------
* Function: H5FD_sec2_set_eoa
*
* Purpose: Set the end-of-address marker for the file. This function is
* called shortly after an existing HDF5 file is opened in order
* to tell the driver where the end of the HDF5 data is located.
*
* Return: Success: 0
*
* Failure: -1
*
* Programmer: Robb Matzke
* Thursday, July 29, 1999
*
* Modifications:
* Raymond Lu
* 21 Dec. 2006
* Added the parameter TYPE. It's only used for MULTI driver.
*
*-------------------------------------------------------------------------
*/
static herr_t
H5FD_sec2_set_eoa(H5FD_t *_file, H5FD_mem_t UNUSED type, haddr_t addr)
{
H5FD_sec2_t *file = (H5FD_sec2_t*)_file;
herr_t ret_value=SUCCEED; /* Return value */
FUNC_ENTER_NOAPI(H5FD_sec2_set_eoa, FAIL)
file->eoa = addr;
done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5FD_sec2_set_eoa() */
/*-------------------------------------------------------------------------
* Function: H5FD_sec2_get_eof
*
* Purpose: Returns the end-of-file marker, which is the greater of
* either the Unix end-of-file or the HDF5 end-of-address
* markers.
*
* Return: Success: End of file address, the first address past
* the end of the "file", either the Unix file
* or the HDF5 file.
*
* Failure: HADDR_UNDEF
*
* Programmer: Robb Matzke
* Thursday, July 29, 1999
*
* Modifications:
*
*-------------------------------------------------------------------------
*/
static haddr_t
H5FD_sec2_get_eof(const H5FD_t *_file)
{
const H5FD_sec2_t *file = (const H5FD_sec2_t*)_file;
haddr_t ret_value; /* Return value */
FUNC_ENTER_NOAPI(H5FD_sec2_get_eof, HADDR_UNDEF)
/* Set return value */
ret_value=MAX(file->eof, file->eoa);
done:
FUNC_LEAVE_NOAPI(ret_value)
}
/*-------------------------------------------------------------------------
* Function: H5FD_sec2_get_handle
*
* Purpose: Returns the file handle of sec2 file driver.
*
* Returns: Non-negative if succeed or negative if fails.
*
* Programmer: Raymond Lu
* Sept. 16, 2002
*
*-------------------------------------------------------------------------
*/
/* ARGSUSED */
static herr_t
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;
FUNC_ENTER_NOAPI(H5FD_sec2_get_handle, FAIL)
if(!file_handle)
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file handle not valid")
*file_handle = &(file->fd);
done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5FD_sec2_get_handle() */
/*-------------------------------------------------------------------------
* Function: H5FD_sec2_read
*
* Purpose: Reads SIZE bytes of data from FILE beginning at address ADDR
* into buffer BUF according to data transfer properties in
* DXPL_ID.
*
* Return: Success: Zero. Result is stored in caller-supplied
* buffer BUF.
* Failure: -1, Contents of buffer BUF are undefined.
*
* Programmer: Robb Matzke
* Thursday, July 29, 1999
*
*-------------------------------------------------------------------------
*/
/* ARGSUSED */
static herr_t
H5FD_sec2_read(H5FD_t *_file, H5FD_mem_t UNUSED type, hid_t UNUSED dxpl_id,
haddr_t addr, size_t size, void *buf/*out*/)
{
H5FD_sec2_t *file = (H5FD_sec2_t*)_file;
ssize_t nbytes;
herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_NOAPI(H5FD_sec2_read, FAIL)
HDassert(file && file->pub.cls);
HDassert(buf);
/* Check for overflow conditions */
if(!H5F_addr_defined(addr))
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "addr undefined, addr = %llu", (unsigned long long)addr)
if(REGION_OVERFLOW(addr, size))
HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow, addr = %llu", (unsigned long long)addr)
if((addr + size) > file->eoa)
HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow, addr = %llu", (unsigned long long)addr)
/* Seek to the correct location */
if((addr != file->pos || OP_READ != file->op) &&
HDlseek(file->fd, (file_offset_t)addr, SEEK_SET) < 0)
HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to seek to proper position")
/*
* Read data, being careful of interrupted system calls, partial results,
* and the end of the file.
*/
while(size > 0) {
do {
nbytes = HDread(file->fd, buf, size);
} while(-1 == nbytes && EINTR == errno);
if(-1 == nbytes) { /* error */
int myerrno = errno;
time_t mytime = HDtime(NULL);
file_offset_t myoffset = HDlseek(file->fd, (file_offset_t)0, SEEK_CUR);
HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "file read failed: time = %s, filename = '%s', file descriptor = %d, errno = %d, error message = '%s', buf = %p, size = %lu, offset = %llu", HDctime(&mytime), file->filename, file->fd, myerrno, HDstrerror(myerrno), buf, (unsigned long)size, (unsigned long long)myoffset);
} /* end if */
if(0 == nbytes) {
/* end of file but not end of format address space */
HDmemset(buf, 0, size);
break;
} /* end if */
HDassert(nbytes >= 0);
HDassert((size_t)nbytes <= size);
H5_CHECK_OVERFLOW(nbytes, ssize_t, size_t);
size -= (size_t)nbytes;
H5_CHECK_OVERFLOW(nbytes, ssize_t, haddr_t);
addr += (haddr_t)nbytes;
buf = (char *)buf + nbytes;
} /* end while */
/* Update current position */
file->pos = addr;
file->op = OP_READ;
done:
if(ret_value < 0) {
/* Reset last file I/O information */
file->pos = HADDR_UNDEF;
file->op = OP_UNKNOWN;
} /* end if */
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5FD_sec2_read() */
/*-------------------------------------------------------------------------
* Function: H5FD_sec2_write
*
* Purpose: Writes SIZE bytes of data to FILE beginning at address ADDR
* from buffer BUF according to data transfer properties in
* DXPL_ID.
*
* Return: Success: Zero
* Failure: -1
*
* Programmer: Robb Matzke
* Thursday, July 29, 1999
*
*-------------------------------------------------------------------------
*/
/* ARGSUSED */
static herr_t
H5FD_sec2_write(H5FD_t *_file, H5FD_mem_t UNUSED type, hid_t UNUSED dxpl_id, haddr_t addr,
size_t size, const void *buf)
{
H5FD_sec2_t *file = (H5FD_sec2_t*)_file;
ssize_t nbytes;
herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_NOAPI(H5FD_sec2_write, FAIL)
HDassert(file && file->pub.cls);
HDassert(buf);
/* Check for overflow conditions */
if(!H5F_addr_defined(addr))
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "addr undefined, addr = %llu", (unsigned long long)addr)
if(REGION_OVERFLOW(addr, size))
HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow, addr = %llu", (unsigned long long)addr)
if((addr + size) > file->eoa)
HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow, addr = %llu", (unsigned long long)addr)
/* Seek to the correct location */
if((addr != file->pos || OP_WRITE != file->op) &&
HDlseek(file->fd, (file_offset_t)addr, SEEK_SET) < 0)
HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to seek to proper position")
/*
* Write the data, being careful of interrupted system calls and partial
* results
*/
while(size > 0) {
do {
nbytes = HDwrite(file->fd, buf, size);
} while(-1 == nbytes && EINTR == errno);
if(-1 == nbytes) { /* error */
int myerrno = errno;
time_t mytime = HDtime(NULL);
file_offset_t myoffset = HDlseek(file->fd, (file_offset_t)0, SEEK_CUR);
HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "file write failed: time = %s, filename = '%s', file descriptor = %d, errno = %d, error message = '%s', buf = %p, size = %lu, offset = %llu", HDctime(&mytime), file->filename, file->fd, myerrno, HDstrerror(myerrno), buf, (unsigned long)size, (unsigned long long)myoffset);
} /* end if */
HDassert(nbytes > 0);
HDassert((size_t)nbytes <= size);
H5_CHECK_OVERFLOW(nbytes, ssize_t, size_t);
size -= (size_t)nbytes;
H5_CHECK_OVERFLOW(nbytes, ssize_t, haddr_t);
addr += (haddr_t)nbytes;
buf = (const char *)buf + nbytes;
} /* end while */
/* Update current position and eof */
file->pos = addr;
file->op = OP_WRITE;
if(file->pos > file->eof)
file->eof = file->pos;
done:
if(ret_value < 0) {
/* Reset last file I/O information */
file->pos = HADDR_UNDEF;
file->op = OP_UNKNOWN;
} /* end if */
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5FD_sec2_write() */
/*-------------------------------------------------------------------------
* Function: H5FD_sec2_truncate
*
* Purpose: Makes sure that the true file size is the same (or larger)
* than the end-of-address.
*
* Return: Success: Non-negative
*
* Failure: Negative
*
* Programmer: Robb Matzke
* Wednesday, August 4, 1999
*
*-------------------------------------------------------------------------
*/
/* ARGSUSED */
static herr_t
H5FD_sec2_truncate(H5FD_t *_file, hid_t UNUSED dxpl_id, hbool_t UNUSED closing)
{
H5FD_sec2_t *file = (H5FD_sec2_t*)_file;
herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_NOAPI(H5FD_sec2_truncate, FAIL)
HDassert(file);
/* Extend the file to make sure it's large enough */
if(!H5F_addr_eq(file->eoa, file->eof)) {
#ifdef _WIN32
HFILE filehandle; /* Windows file handle */
LARGE_INTEGER li; /* 64-bit integer for SetFilePointer() call */
/* Map the posix file handle to a Windows file handle */
filehandle = _get_osfhandle(file->fd);
/* Translate 64-bit integers into form Windows wants */
/* [This algorithm is from the Windows documentation for SetFilePointer()] */
li.QuadPart = (LONGLONG)file->eoa;
(void)SetFilePointer((HANDLE)filehandle, li.LowPart, &li.HighPart, FILE_BEGIN);
if(SetEndOfFile((HANDLE)filehandle) == 0)
HGOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to extend file properly")
#else /* _WIN32 */
#ifdef H5_VMS
/* Reset seek offset to the beginning of the file, so that the file isn't
* re-extended later. This may happen on Open VMS. */
if(-1 == HDlseek(file->fd, (file_offset_t)0, SEEK_SET))
HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to seek to proper position")
#endif
if(-1 == HDftruncate(file->fd, (file_offset_t)file->eoa))
HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to extend file properly")
#endif /* _WIN32 */
/* Update the eof value */
file->eof = file->eoa;
/* Reset last file I/O information */
file->pos = HADDR_UNDEF;
file->op = OP_UNKNOWN;
} /* end if */
done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5FD_sec2_truncate() */