From e0cbe0c5c8bed8dc382fe5fd2a131e484b2b93f2 Mon Sep 17 00:00:00 2001 From: Quincey Koziol Date: Wed, 20 Oct 1999 12:51:03 -0500 Subject: [svn-r1785] Added stdio VFL driver, which uses the new public H5E calls. --- src/H5F.c | 8 +- src/H5FDsec2.c | 3 + src/H5FDstdio.c | 706 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/H5FDstdio.h | 20 ++ src/Makefile.in | 19 +- src/hdf5.h | 1 + 6 files changed, 745 insertions(+), 12 deletions(-) create mode 100644 src/H5FDstdio.c create mode 100644 src/H5FDstdio.h diff --git a/src/H5F.c b/src/H5F.c index 8df9104..df3602e 100644 --- a/src/H5F.c +++ b/src/H5F.c @@ -24,9 +24,10 @@ static char RcsId[] = "@(#)$Revision$"; #include /*temporary in-memory files */ #include /*family of files */ #include /*MPI-2 I/O */ -#include /*GASS I/O */ +#include /*GASS I/O */ #include /*multiple files partitioned by mem usage */ -#include /*Posix unbuffered I/O */ +#include /*Posix unbuffered I/O */ +#include /* Standard C buffered I/O */ /* Packages needed by this file... */ #include /*library functions */ @@ -203,6 +204,7 @@ H5F_init_interface(void) /* Register predefined file drivers */ H5E_BEGIN_TRY { if ((status=H5FD_SEC2)<0) goto end_registration; + if ((status=H5FD_STDIO)<0) goto end_registration; if ((status=H5FD_FAMILY)<0) goto end_registration; #ifdef HAVE_GASS if ((status=H5FD_GASS)<0) goto end_registration; @@ -1941,7 +1943,7 @@ H5Fclose(hid_t file_id) HGOTO_ERROR (H5E_ATOM, H5E_CANTINIT, FAIL, "problems closing file"); } - done: +done: FUNC_LEAVE(ret_value < 0 ? FAIL : SUCCEED); } diff --git a/src/H5FDsec2.c b/src/H5FDsec2.c index de887c9..6f13a78 100644 --- a/src/H5FDsec2.c +++ b/src/H5FDsec2.c @@ -28,8 +28,10 @@ +#ifdef MAX #undef MAX #define MAX(X,Y) ((X)>(Y)?(X):(Y)) +#endif /* MAX */ /* The driver identification number, initialized at runtime */ static hid_t H5FD_SEC2_g = 0; @@ -248,6 +250,7 @@ H5FD_sec2_open(const char *name, unsigned flags, hid_t UNUSED fapl_id, struct _BY_HANDLE_FILE_INFORMATION fileinfo; int results; #endif + /* Check arguments */ if (!name || !*name) return NULL; if (0==maxaddr || HADDR_UNDEF==maxaddr) return NULL; diff --git a/src/H5FDstdio.c b/src/H5FDstdio.c new file mode 100644 index 0000000..ac8cdc2 --- /dev/null +++ b/src/H5FDstdio.c @@ -0,0 +1,706 @@ +/* + * Copyright © 1999 NCSA + * All rights reserved. + * + * Programmer: Robb Matzke + * Wednesday, October 22, 1997 + * + * Purpose: This is the Posix stdio.h I/O subclass of H5Flow. + * + * Notes: Ported to the new H5FD architecture on 10/18/99 - QAK + * + */ +#include "hdf5.h" +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef WIN32 +#include +#endif + +#ifdef MAX +#undef MAX +#endif /* MAX */ +#define MAX(X,Y) ((X)>(Y)?(X):(Y)) + +/* The driver identification number, initialized at runtime */ +static hid_t H5FD_STDIO_g = 0; + +/* File operations */ +typedef enum { + H5FD_STDIO_OP_UNKNOWN=0, + H5FD_STDIO_OP_READ=1, + H5FD_STDIO_OP_WRITE=2, + H5FD_STDIO_OP_SEEK=3 +} H5FD_stdio_file_op; + +/* + * 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_stdio_t { + H5FD_t pub; /*public stuff, must be first */ + FILE * fp; /*the file handle */ + 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_stdio_file_op op; /*last operation */ + unsigned write_access; /* Flag to indicate the file was opened with write access */ +#ifndef WIN32 + /* + * On most systems the combination of device and i-node number uniquely + * identify a file. + */ + dev_t device; /*file device number */ + ino_t inode; /*file i-node number */ +#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. + */ + int fileindexlo; + int fileindexhi; +#endif +} H5FD_stdio_t; + +/* + * 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(long)-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) || \ + sizeof(long)fp = f; + file->op = H5FD_STDIO_OP_SEEK; + file->pos = HADDR_UNDEF; + file->write_access=write_access; /* Note the write_access for later */ + if (fseek(file->fp, 0, SEEK_END) < 0) { + file->op = H5FD_STDIO_OP_UNKNOWN; + } else { + long x = ftell (file->fp); + assert (x>=0); + file->eof = x; + } + + /* The unique key */ +#ifdef WIN32 +#error "Needs correct fileindexhi & fileindexlo, code below is from sec2 driver" + filehandle = _get_osfhandle(fd); + results = GetFileInformationByHandle(filehandle, &fileinfo); + file->fileindexhi = fileinfo.nFileIndexHigh; + file->fileindexlo = fileinfo.nFileIndexLow; +#else + fstat(fileno(file->fp), &sb); + file->device = sb.st_dev; + file->inode = sb.st_ino; +#endif + return((H5FD_t*)file); +} /* end H5FD_stdio_open() */ + + +/*------------------------------------------------------------------------- + * Function: H5F_stdio_close + * + * Purpose: Closes a file. + * + * Errors: + * IO CLOSEERROR Fclose failed. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Robb Matzke + * Wednesday, October 22, 1997 + * + * Modifications: + * Ported to VFL/H5FD layer - QAK, 10/18/99 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_stdio_close(H5FD_t *_file) +{ + H5FD_stdio_t *file = (H5FD_stdio_t*)_file; + static const char *func="H5FD_stdio_close"; /* Function Name for error reporting */ + + if (H5FD_stdio_flush(_file)<0) + H5Epush_ret(func, H5E_IO, H5E_WRITEERROR, "flush failed", -1); + if (fclose(file->fp) < 0) + H5Epush_ret(func, H5E_IO, H5E_CLOSEERROR, "fclose failed", -1); + + free(file); + + return(0); +} + + +/*------------------------------------------------------------------------- + * Function: H5FD_stdio_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: + * Stolen from the sec2 driver - QAK, 10/18/99 + * + *------------------------------------------------------------------------- + */ +static int +H5FD_stdio_cmp(const H5FD_t *_f1, const H5FD_t *_f2) +{ + const H5FD_stdio_t *f1 = (const H5FD_stdio_t*)_f1; + const H5FD_stdio_t *f2 = (const H5FD_stdio_t*)_f2; + +#ifdef WIN32 + if (f1->fileindexhi < f2->fileindexhi) return -1; + if (f1->fileindexhi > f2->fileindexhi) return 1; + + if (f1->fileindexlo < f2->fileindexlo) return -1; + if (f1->fileindexlo > f2->fileindexlo) return 1; + +#else + if (f1->device < f2->device) return -1; + if (f1->device > f2->device) return 1; + + if (f1->inode < f2->inode) return -1; + if (f1->inode > f2->inode) return 1; +#endif + return 0; +} + + +/*------------------------------------------------------------------------- + * Function: H5FD_stdio_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: + * Stolen from the sec2 driver - QAK, 10/18/99 + * + *------------------------------------------------------------------------- + */ +static haddr_t +H5FD_stdio_get_eoa(H5FD_t *_file) +{ + H5FD_stdio_t *file = (H5FD_stdio_t*)_file; + + return(file->eoa); +} + + +/*------------------------------------------------------------------------- + * Function: H5FD_stdio_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: + * Stolen from the sec2 driver - QAK, 10/18/99 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_stdio_set_eoa(H5FD_t *_file, haddr_t addr) +{ + H5FD_stdio_t *file = (H5FD_stdio_t*)_file; + + file->eoa = addr; + + return(0); +} + + +/*------------------------------------------------------------------------- + * Function: H5FD_stdio_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: + * Stolen from the sec2 driver - QAK, 10/18/99 + * + *------------------------------------------------------------------------- + */ +static haddr_t +H5FD_stdio_get_eof(H5FD_t *_file) +{ + H5FD_stdio_t *file = (H5FD_stdio_t*)_file; + + return(MAX(file->eof, file->eoa)); +} + + +/*------------------------------------------------------------------------- + * Function: H5F_stdio_read + * + * Purpose: Reads SIZE bytes beginning at address ADDR in file LF and + * places them in buffer BUF. Reading past the logical or + * physical end of file returns zeros instead of failing. + * + * Errors: + * IO READERROR Fread failed. + * IO SEEKERROR Fseek failed. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Robb Matzke + * Wednesday, October 22, 1997 + * + * Modifications: + * June 2, 1998 Albert Cheng + * Added xfer_mode argument + * + * Ported to VFL/H5FD layer - QAK, 10/18/99 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_stdio_read(H5FD_t *_file, hid_t dxpl_id, haddr_t addr, hsize_t size, + void *buf/*out*/) +{ + size_t n; + H5FD_stdio_t *file = (H5FD_stdio_t*)_file; + static const char *func="H5FD_stdio_read"; /* Function Name for error reporting */ + + /* Shut compiler up */ + dxpl_id=dxpl_id; + + /* Check for overflow */ + if (HADDR_UNDEF==addr) + H5Epush_ret (func, H5E_IO, H5E_OVERFLOW, "file address overflowed", -1); + if (REGION_OVERFLOW(addr, size)) + H5Epush_ret (func, H5E_IO, H5E_OVERFLOW, "file address overflowed", -1); + if (addr+size>file->eoa) + H5Epush_ret (func, H5E_IO, H5E_OVERFLOW, "file address overflowed", -1); + + /* Check easy cases */ + if (0 == size) + return(0); + if ((uint64_t)addr >= file->eof) { + memset(buf, 0, size); + return(0); + } + + /* + * Seek to the correct file position. + */ + if (!(file->op == H5FD_STDIO_OP_READ || file->op==H5FD_STDIO_OP_SEEK) || + file->pos != addr) { + if (fseek(file->fp, addr, SEEK_SET) < 0) { + file->op = H5FD_STDIO_OP_UNKNOWN; + file->pos = HADDR_UNDEF; + H5Epush_ret(func, H5E_IO, H5E_SEEKERROR, "fseek failed", -1); + } + file->pos = addr; + } + + /* + * Read zeros past the logical end of file (physical is handled below) + */ + if ((size_t) addr + size > file->eof) { + size_t nbytes = (size_t) addr + size - file->eof; + memset((unsigned char *)buf + size - nbytes, 0, nbytes); + size -= nbytes; + } + + /* + * Read the data. Since we're reading single-byte values, a partial read + * will advance the file position by N. If N is negative or an error + * occurs then the file position is undefined. + */ + n = fread(buf, 1, size, file->fp); + if (n <= 0 && ferror(file->fp)) { + file->op = H5FD_STDIO_OP_UNKNOWN; + file->pos = HADDR_UNDEF; + H5Epush_ret(func, H5E_IO, H5E_READERROR, "fread failed", -1); + } else if (n < size) { + memset((unsigned char *)buf + n, 0, size - n); + } + + /* + * Update the file position data. + */ + file->op = H5FD_STDIO_OP_READ; + file->pos = addr+n; /*checked for overflow above*/ + return(0); +} + + +/*------------------------------------------------------------------------- + * Function: H5F_stdio_write + * + * Purpose: Writes SIZE bytes from the beginning of BUF into file LF at + * file address ADDR. + * + * Errors: + * IO SEEKERROR Fseek failed. + * IO WRITEERROR Fwrite failed. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Robb Matzke + * Wednesday, October 22, 1997 + * + * Modifications: + * June 2, 1998 Albert Cheng + * Added xfer_mode argument + * + * Ported to VFL/H5FD layer - QAK, 10/18/99 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_stdio_write(H5FD_t *_file, hid_t dxpl_id, haddr_t addr, + hsize_t size, const void *buf) +{ + H5FD_stdio_t *file = (H5FD_stdio_t*)_file; + static const char *func="H5FD_stdio_write"; /* Function Name for error reporting */ + + /* Shut compiler up */ + dxpl_id=dxpl_id; + + /* Check for overflow conditions */ + if (HADDR_UNDEF==addr) + H5Epush_ret (func, H5E_IO, H5E_OVERFLOW, "file address overflowed", -1); + if (REGION_OVERFLOW(addr, size)) + H5Epush_ret (func, H5E_IO, H5E_OVERFLOW, "file address overflowed", -1); + if (addr+size>file->eoa) + H5Epush_ret (func, H5E_IO, H5E_OVERFLOW, "file address overflowed", -1); + + /* + * Seek to the correct file position. + */ + if (!(file->op == H5FD_STDIO_OP_WRITE || file->op==H5FD_STDIO_OP_SEEK) || + file->pos != addr) { + if (fseek(file->fp, addr, SEEK_SET) < 0) { + file->op = H5FD_STDIO_OP_UNKNOWN; + file->pos = HADDR_UNDEF; + H5Epush_ret(func, H5E_IO, H5E_SEEKERROR, "fseek failed", -1); + } + file->pos = addr; + } + + /* + * Write the buffer. On successful return, the file position will be + * advanced by the number of bytes read. Otherwise nobody knows where it + * is. + */ + if (size != fwrite(buf, 1, size, file->fp)) { + file->op = H5FD_STDIO_OP_UNKNOWN; + file->pos = HADDR_UNDEF; + H5Epush_ret(func, H5E_IO, H5E_WRITEERROR, "fwrite failed", -1); + } + + /* + * Update seek optimizing data. + */ + file->op = H5FD_STDIO_OP_WRITE; + file->pos = addr + size; + + /* Update EOF if necessary */ + if (file->pos>file->eof) + file->eof = file->pos; + + return(0); +} + + +/*------------------------------------------------------------------------- + * Function: H5F_stdio_flush + * + * Purpose: Makes sure that all data is on disk. + * + * Errors: + * IO SEEKERROR fseek failed. + * IO WRITEERROR fflush or fwrite failed. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Robb Matzke + * Wednesday, October 22, 1997 + * + * Modifications: + * Ported to VFL/H5FD layer - QAK, 10/18/99 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_stdio_flush(H5FD_t *_file) +{ + H5FD_stdio_t *file = (H5FD_stdio_t*)_file; + static const char *func="H5FD_stdio_flush"; /* Function Name for error reporting */ + + /* Only try to flush the file if we have write access */ + if(file->write_access) { + /* Makes sure that the true file size is the same (or larger) than the end-of-address. */ + if (file->eoa>file->eof) { + if (fseek(file->fp, file->eoa-1, SEEK_SET)<0) + H5Epush_ret(func, H5E_IO, H5E_SEEKERROR, "fseek failed", -1); + if (fwrite("", 1, 1, file->fp)!=1) + H5Epush_ret(func, H5E_IO, H5E_SEEKERROR, "EOF fwrite failed", -1); + file->eof = file->eoa; + file->pos = file->eoa; + /* fall through to set the IO operation */ + } + + /* + * What happens to the file position? Is it guaranteed to be the same + * after the fflush() as it was before? + */ + file->op = H5FD_STDIO_OP_UNKNOWN; + + /* + * Flush + */ + if (fflush(file->fp) < 0) + H5Epush_ret(func, H5E_IO, H5E_WRITEERROR, "fflush failed", -1); + } /* end if */ + else { + /* Double-check for problems */ + if (file->eoa>file->eof) + H5Epush_ret(func, H5E_IO, H5E_TRUNCATED, "eoa>eof!", -1); + } /* end else */ + + return(0); +} diff --git a/src/H5FDstdio.h b/src/H5FDstdio.h new file mode 100644 index 0000000..7dac8f4 --- /dev/null +++ b/src/H5FDstdio.h @@ -0,0 +1,20 @@ +/* + * Copyright © 1999 NCSA + * All rights reserved. + * + * Programmer: Robb Matzke + * Monday, August 2, 1999 + * + * Purpose: The public header file for the sec2 driver. + */ +#ifndef H5FDstdio_H +#define H5FDstdio_H + +#include + +#define H5FD_STDIO (H5FD_stdio_init()) + +__DLL__ hid_t H5FD_stdio_init(void); +__DLL__ herr_t H5Pset_fapl_stdio(hid_t fapl_id); + +#endif diff --git a/src/Makefile.in b/src/Makefile.in index 78d56ce..0e179b5 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -23,12 +23,12 @@ CLEAN=libhdf5.settings ## Source and object files for the library (lexicographically)... LIB_SRC=H5.c H5A.c H5AC.c H5B.c H5D.c H5E.c H5F.c H5Farray.c H5Fistore.c \ H5FD.c H5FDsec2.c H5FDfamily.c H5FDmpio.c H5FDcore.c H5FDmulti.c \ - H5FDgass.c H5G.c H5Gent.c H5Gnode.c H5Gstab.c H5HG.c H5HL.c H5I.c H5MF.c \ - H5MM.c H5O.c H5Oattr.c H5Ocomp.c H5Ocont.c H5Odtype.c H5Oefl.c H5Ofill.c \ - H5Olayout.c H5Omtime.c H5Oname.c H5Onull.c H5Osdspace.c H5Oshared.c \ - H5Ostab.c H5P.c H5R.c H5RA.c H5S.c H5Sall.c H5Shyper.c H5Smpio.c \ - H5Snone.c H5Spoint.c H5Sselect.c H5T.c H5Tbit.c H5Tconv.c H5Tinit.c \ - H5Tvlen.c H5TB.c H5V.c H5Z.c H5Zdeflate.c + H5FDgass.c H5FDstdio.c H5G.c H5Gent.c H5Gnode.c H5Gstab.c H5HG.c H5HL.c \ + H5I.c H5MF.c H5MM.c H5O.c H5Oattr.c H5Ocomp.c H5Ocont.c H5Odtype.c H5Oefl.c \ + H5Ofill.c H5Olayout.c H5Omtime.c H5Oname.c H5Onull.c H5Osdspace.c \ + H5Oshared.c H5Ostab.c H5P.c H5R.c H5RA.c H5S.c H5Sall.c H5Shyper.c \ + H5Smpio.c H5Snone.c H5Spoint.c H5Sselect.c H5T.c H5Tbit.c H5Tconv.c \ + H5Tinit.c H5Tvlen.c H5TB.c H5V.c H5Z.c H5Zdeflate.c LIB_OBJ=$(LIB_SRC:.c=.lo) @@ -38,9 +38,10 @@ MOSTLYCLEAN=H5detect.o H5detect H5Tinit.o H5Tinit.c ## Public header files (to be installed)... PUB_HDR=H5public.h H5Apublic.h H5ACpublic.h H5Bpublic.h H5Dpublic.h \ H5Epublic.h H5Fpublic.h H5FDpublic.h H5FDfamily.h H5FDgass.h H5FDmpio.h \ - H5FDsec2.h H5FDcore.h H5FDmulti.h H5Gpublic.h H5HGpublic.h H5HLpublic.h \ - H5Ipublic.h H5MMpublic.h H5Opublic.h H5Ppublic.h H5Rpublic.h H5RApublic.h \ - H5Spublic.h H5Tpublic.h H5Zpublic.h H5config.h hdf5.h H5api_adpt.h + H5FDsec2.h H5FDcore.h H5FDmulti.h H5FDstdio.h H5Gpublic.h H5HGpublic.h \ + H5HLpublic.h H5Ipublic.h H5MMpublic.h H5Opublic.h H5Ppublic.h H5Rpublic.h \ + H5RApublic.h H5Spublic.h H5Tpublic.h H5Zpublic.h H5config.h hdf5.h \ + H5api_adpt.h ## Other header files (not to be installed)... PRIVATE_HDR=H5private.h H5Aprivate.h H5Apkg.h H5ACprivate.h H5Bprivate.h \ diff --git a/src/hdf5.h b/src/hdf5.h index 8add04a..4fe9056 100644 --- a/src/hdf5.h +++ b/src/hdf5.h @@ -44,6 +44,7 @@ #include /* File families */ #include /* Parallel files using MPI-2 I/O */ #include /* POSIX unbuffered file I/O */ +#include /* Standard C buffered I/O */ #include /* Remote files using GASS I/O */ #include /* Usage-partitioned file family */ -- cgit v0.12