From ea8166cf62a36440450aa0d342d45d2d12995a6a Mon Sep 17 00:00:00 2001 From: Dana Robinson Date: Fri, 30 Mar 2012 16:42:47 -0500 Subject: [PATCH] [svn-r22211] STDIO VFD fixes (HDFFV-7917). Mainly Windows correctness issues (propagated from the SEC2 VFD and the old Windows VFD) and issues where large files are accessed. Tested on: 64-bit Mac OS-X 64-bit Windows 7 jam koala ostrich --- src/H5FDstdio.c | 667 +++++++++++++++++++++++++----------------------- 1 file changed, 341 insertions(+), 326 deletions(-) diff --git a/src/H5FDstdio.c b/src/H5FDstdio.c index 49e1957718..4733eba816 100644 --- a/src/H5FDstdio.c +++ b/src/H5FDstdio.c @@ -13,32 +13,24 @@ * access to either file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -/* - * Programmer: Robb Matzke - * Wednesday, October 22, 1997 +/* Programmer: Robb Matzke + * Wednesday, October 22, 1997 * - * Purpose: This is the Posix stdio.h I/O subclass of H5Flow. - * It also serves as an example of coding a simple file driver, - * therefore, it should not use any non-public definitions. - * - * Notes: Ported to the new H5FD architecture on 10/18/99 - QAK + * Purpose: The C STDIO virtual file driver which only uses calls from stdio.h. + * This also serves as an example of coding a simple file driver, + * therefore, it should not use any non-public definitions. * + * NOTE: This driver is not as well tested as the standard SEC2 driver + * and is not intended for production use! */ #include +#include #include #include #include -/* Disable certain warnings in PC-Lint: */ -/*lint --emacro( {534, 830}, H5P_FILE_ACCESS) */ -/*lint --emacro( {534, 830}, H5F_ACC_RDWR, H5F_ACC_EXCL) */ -/*lint -esym( 534, H5Eclear2, H5Epush2) */ - #include "hdf5.h" -#ifdef H5_HAVE_STDIO_H -#include -#endif #ifdef H5_HAVE_UNISTD_H #include #endif @@ -58,7 +50,6 @@ #endif - #ifdef MAX #undef MAX #endif /* MAX */ @@ -67,6 +58,9 @@ /* The driver identification number, initialized at runtime */ static hid_t H5FD_STDIO_g = 0; +/* The maximum number of bytes which can be written in a single I/O operation */ +static size_t H5_STDIO_MAX_IO_BYTES_g = (size_t)-1; + /* File operations */ typedef enum { H5FD_STDIO_OP_UNKNOWN=0, @@ -75,57 +69,71 @@ typedef enum { H5FD_STDIO_OP_SEEK=3 } H5FD_stdio_file_op; -/* - * The description of a file belonging to this driver. The `eoa' and `eof' +/* 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' + * 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. + * 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 */ + H5FD_t pub; /* public stuff, must be first */ + FILE *fp; /* the file handle */ + int fd; /* file descriptor (for truncate) */ + haddr_t eoa; /* end of allocated region */ + haddr_t eof; /* end of file; current file size */ + haddr_t pos; /* current file I/O position */ + unsigned write_access; /* Flag to indicate the file was opened with write access */ + H5FD_stdio_file_op op; /* last operation */ #ifndef H5_HAVE_WIN32_API - /* - * On most systems the combination of device and i-node number uniquely - * identify a file. + /* On most systems the combination of device and i-node number uniquely + * identify a file. Note that Cygwin, MinGW and other Windows POSIX + * environments have the stat function (which fakes inodes) + * and will use the 'device + inodes' scheme as opposed to the + * Windows code further below. */ - dev_t device; /*file device number */ - ino_t inode; /*file i-node number */ + dev_t device; /* file device number */ +#ifdef H5_VMS + ino_t inode[3]; /* file i-node number */ #else - /* - * On H5_HAVE_WIN32_API 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. + ino_t inode; /* file i-node number */ +#endif /* H5_VMS */ +#else + /* Files in windows are uniquely identified by the volume serial + * number and the file index (both low and high parts). + * + * There are caveats where these numbers can change, especially + * on FAT file systems. On NTFS, however, a file should keep + * those numbers the same until renamed or deleted (though you + * can use ReplaceFile() on NTFS to keep the numbers the same + * while renaming). + * + * See the MSDN "BY_HANDLE_FILE_INFORMATION Structure" entry for + * more information. + * + * http://msdn.microsoft.com/en-us/library/aa363788(v=VS.85).aspx */ - DWORD fileindexlo; - DWORD fileindexhi; -#endif + DWORD nFileIndexLow; + DWORD nFileIndexHigh; + DWORD dwVolumeSerialNumber; + + HANDLE hFile; /* Native windows file handle */ +#endif /* H5_HAVE_WIN32_API */ } H5FD_stdio_t; /* Use similar structure as in H5private.h by defining Windows stuff first. */ #ifdef H5_HAVE_WIN32_API - #ifndef H5_HAVE_MINGW - # define file_fseek _fseeki64 - # define file_offset_t __int64 - # define file_ftruncate _chsize_s /* Supported in VS 2005 or newer */ - # define file_ftell _ftelli64 - #endif -#endif +#ifndef H5_HAVE_MINGW + #define file_fseek _fseeki64 + #define file_offset_t __int64 + #define file_ftruncate _chsize_s /* Supported in VS 2005 or newer */ + #define file_ftell _ftelli64 +#endif /* H5_HAVE_MINGW */ +#endif /* H5_HAVE_WIN32_API */ /* Use file_xxx to indicate these are local macros, avoiding confusing * with the global HD_xxx macros. @@ -134,20 +142,19 @@ typedef struct H5FD_stdio_t { */ #ifndef file_fseek #ifdef H5_HAVE_FSEEKO64 - # define file_fseek fseeko64 - # define file_offset_t off64_t - # define file_ftruncate ftruncate64 - # define file_ftell ftello64 + #define file_fseek fseeko64 + #define file_offset_t off64_t + #define file_ftruncate ftruncate64 + #define file_ftell ftello64 #else - # define file_fseek fseeko - # define file_offset_t off_t - # define file_ftruncate ftruncate - # define file_ftell ftello - #endif -#endif + #define file_fseek fseeko + #define file_offset_t off_t + #define file_ftruncate ftruncate + #define file_ftell ftello + #endif /* H5_HAVE_FSEEKO64 */ +#endif /* file_fseek */ -/* - * These macros check for overflow of various quantities. These macros +/* 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' @@ -188,38 +195,38 @@ static herr_t H5FD_stdio_flush(H5FD_t *_file, hid_t dxpl_id, unsigned closing); static herr_t H5FD_stdio_truncate(H5FD_t *_file, hid_t dxpl_id, hbool_t closing); static const H5FD_class_t H5FD_stdio_g = { - "stdio", /*name */ - MAXADDR, /*maxaddr */ - H5F_CLOSE_WEAK, /* fc_degree */ - H5FD_stdio_term, /*terminate */ - 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_stdio_open, /*open */ - H5FD_stdio_close, /*close */ - H5FD_stdio_cmp, /*cmp */ - H5FD_stdio_query, /*query */ - NULL, /*get_type_map */ - H5FD_stdio_alloc, /*alloc */ - NULL, /*free */ - H5FD_stdio_get_eoa, /*get_eoa */ - H5FD_stdio_set_eoa, /*set_eoa */ - H5FD_stdio_get_eof, /*get_eof */ - H5FD_stdio_get_handle, /*get_handle */ - H5FD_stdio_read, /*read */ - H5FD_stdio_write, /*write */ - H5FD_stdio_flush, /*flush */ - H5FD_stdio_truncate, /*truncate */ - NULL, /*lock */ - NULL, /*unlock */ - H5FD_FLMAP_SINGLE /*fl_map */ + "stdio", /* name */ + MAXADDR, /* maxaddr */ + H5F_CLOSE_WEAK, /* fc_degree */ + H5FD_stdio_term, /* terminate */ + 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_stdio_open, /* open */ + H5FD_stdio_close, /* close */ + H5FD_stdio_cmp, /* cmp */ + H5FD_stdio_query, /* query */ + NULL, /* get_type_map */ + H5FD_stdio_alloc, /* alloc */ + NULL, /* free */ + H5FD_stdio_get_eoa, /* get_eoa */ + H5FD_stdio_set_eoa, /* set_eoa */ + H5FD_stdio_get_eof, /* get_eof */ + H5FD_stdio_get_handle, /* get_handle */ + H5FD_stdio_read, /* read */ + H5FD_stdio_write, /* write */ + H5FD_stdio_flush, /* flush */ + H5FD_stdio_truncate, /* truncate */ + NULL, /* lock */ + NULL, /* unlock */ + H5FD_FLMAP_SINGLE /* fl_map */ }; @@ -236,9 +243,6 @@ static const H5FD_class_t H5FD_stdio_g = { * Programmer: Robb Matzke * Thursday, July 29, 1999 * - * Modifications: - * Stolen from the sec2 driver - QAK, 10/18/99 - * *------------------------------------------------------------------------- */ hid_t @@ -249,8 +253,8 @@ H5FD_stdio_init(void) if (H5I_VFL!=H5Iget_type(H5FD_STDIO_g)) H5FD_STDIO_g = H5FDregister(&H5FD_stdio_g); - return(H5FD_STDIO_g); -} + return H5FD_STDIO_g; +} /* end H5FD_stdio_init() */ /*--------------------------------------------------------------------------- @@ -269,7 +273,7 @@ static herr_t H5FD_stdio_term(void) { /* Reset VFL ID */ - H5FD_STDIO_g=0; + H5FD_STDIO_g = 0; return 0; } /* end H5FD_stdio_term() */ @@ -287,15 +291,12 @@ H5FD_stdio_term(void) * Programmer: Robb Matzke * Thursday, February 19, 1998 * - * Modifications: - * Stolen from the sec2 driver - QAK, 10/18/99 - * *------------------------------------------------------------------------- */ herr_t H5Pset_fapl_stdio(hid_t fapl_id) { - static const char *func="H5FDset_fapl_stdio"; /*for error reporting*/ + static const char *func = "H5FDset_fapl_stdio"; /*for error reporting*/ /*NO TRACE*/ @@ -306,7 +307,7 @@ H5Pset_fapl_stdio(hid_t fapl_id) H5Epush_ret(func, H5E_ERR_CLS, H5E_PLIST, H5E_BADTYPE, "not a file access property list", -1) return H5Pset_driver(fapl_id, H5FD_STDIO, NULL); -} +} /* end H5Pset_fapl_stdio() */ /*------------------------------------------------------------------------- @@ -314,50 +315,44 @@ H5Pset_fapl_stdio(hid_t fapl_id) * * Purpose: Create and/or opens a Standard C file as an HDF5 file. * - * Bugs: H5F_ACC_EXCL has a race condition. (? -QAK) - * * Errors: - * IO CANTOPENFILE File doesn't exist and CREAT wasn't - * specified. - * IO CANTOPENFILE Fopen failed. - * IO FILEEXISTS File exists but CREAT and EXCL were - * specified. + * IO CANTOPENFILE File doesn't exist and CREAT wasn't + * specified. + * IO CANTOPENFILE fopen() failed. + * IO FILEEXISTS File exists but CREAT and EXCL were + * specified. * - * Return: Success: A pointer to a new file data structure. The - * public fields will be initialized by the - * caller, which is always H5FD_open(). + * 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 + * Failure: NULL * * Programmer: Robb Matzke * Wednesday, October 22, 1997 * - * Modifications: - * Ported to VFL/H5FD layer - QAK, 10/18/99 - * *------------------------------------------------------------------------- */ static H5FD_t * H5FD_stdio_open( const char *name, unsigned flags, hid_t fapl_id, haddr_t maxaddr) { - FILE *f = NULL; - unsigned write_access=0; /* File opened with write access? */ - H5FD_stdio_t *file=NULL; - static const char *func="H5FD_stdio_open"; /* Function Name for error reporting */ + FILE *f = NULL; + unsigned write_access = 0; /* File opened with write access? */ + H5FD_stdio_t *file = NULL; + static const char *func = "H5FD_stdio_open"; /* Function Name for error reporting */ #ifdef H5_HAVE_WIN32_API - HFILE filehandle; - struct _BY_HANDLE_FILE_INFORMATION fileinfo; - int fd; + struct _BY_HANDLE_FILE_INFORMATION fileinfo; #else /* H5_HAVE_WIN32_API */ - struct stat sb; + struct stat sb; #endif /* H5_HAVE_WIN32_API */ /* Sanity check on file offsets */ - assert(sizeof(file_offset_t)>=sizeof(size_t)); + assert(sizeof(file_offset_t) >= sizeof(size_t)); - /* Shut compiler up */ - fapl_id=fapl_id; + /* Quiet compiler */ + fapl_id = fapl_id; /* Clear the error stack */ H5Eclear2(H5E_DEFAULT); @@ -365,15 +360,16 @@ H5FD_stdio_open( const char *name, unsigned flags, hid_t fapl_id, /* Check arguments */ if (!name || !*name) H5Epush_ret(func, H5E_ERR_CLS, H5E_ARGS, H5E_BADVALUE, "invalid file name", NULL) - if (0==maxaddr || HADDR_UNDEF==maxaddr) + if (0 == maxaddr || HADDR_UNDEF == maxaddr) H5Epush_ret(func, H5E_ERR_CLS, H5E_ARGS, H5E_BADRANGE, "bogus maxaddr", NULL) if (ADDR_OVERFLOW(maxaddr)) H5Epush_ret(func, H5E_ERR_CLS, H5E_ARGS, H5E_OVERFLOW, "maxaddr too large", NULL) + /* Attempt to open/create the file */ if (access(name, F_OK) < 0) { if ((flags & H5F_ACC_CREAT) && (flags & H5F_ACC_RDWR)) { f = fopen(name, "wb+"); - write_access=1; /* Note the write access */ + write_access = 1; /* Note the write access */ } else H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_CANTOPENFILE, "file doesn't exist and CREAT wasn't specified", NULL) @@ -384,7 +380,7 @@ H5FD_stdio_open( const char *name, unsigned flags, hid_t fapl_id, f = fopen(name, "wb+"); else f = fopen(name, "rb+"); - write_access=1; /* Note the write access */ + write_access = 1; /* Note the write access */ } else { f = fopen(name, "rb"); } @@ -399,30 +395,46 @@ H5FD_stdio_open( const char *name, unsigned flags, hid_t fapl_id, file->fp = f; file->op = H5FD_STDIO_OP_SEEK; file->pos = HADDR_UNDEF; - file->write_access=write_access; /* Note the write_access for later */ + file->write_access = write_access; /* Note the write_access for later */ if(file_fseek(file->fp, (file_offset_t)0, SEEK_END) < 0) { file->op = H5FD_STDIO_OP_UNKNOWN; } else { - file_offset_t x = file_ftell (file->fp); - assert (x>=0); + file_offset_t x = file_ftell(file->fp); + assert (x >= 0); file->eof = (haddr_t)x; } - /* The unique key */ + /* Get the file descriptor (needed for truncate and some Windows information) */ + file->fd = fileno(file->fp); + if(file->fd < 0) + H5Epush_ret(func, H5E_ERR_CLS, H5E_FILE, H5E_CANTOPENFILE, "unable to get file descriptor", NULL); + + #ifdef H5_HAVE_WIN32_API -/*#error "Needs correct fileindexhi & fileindexlo, code below is from sec2 driver"*/ - fd = _fileno(f); - filehandle = _get_osfhandle(fd); - (void)GetFileInformationByHandle((HANDLE)filehandle, &fileinfo); - file->fileindexhi = fileinfo.nFileIndexHigh; - file->fileindexlo = fileinfo.nFileIndexLow; -#else - fstat(fileno(file->fp), &sb); + file->hFile = (HANDLE)_get_osfhandle(file->fd); + if(INVALID_HANDLE_VALUE == file->hFile) + H5Epush_ret(func, H5E_ERR_CLS, H5E_FILE, H5E_CANTOPENFILE, "unable to get Windows file handle", NULL); + + if(!GetFileInformationByHandle((HANDLE)file->hFile, &fileinfo)) + H5Epush_ret(func, H5E_ERR_CLS, H5E_FILE, H5E_CANTOPENFILE, "unable to get Windows file desinformationcriptor", NULL); + + file->nFileIndexHigh = fileinfo.nFileIndexHigh; + file->nFileIndexLow = fileinfo.nFileIndexLow; + file->dwVolumeSerialNumber = fileinfo.dwVolumeSerialNumber; +#else /* H5_HAVE_WIN32_API */ + fstat(file->fd, &sb); 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 /* H5_VMS */ file->inode = sb.st_ino; -#endif - return((H5FD_t*)file); -} /* end H5FD_stdio_open() */ +#endif /* H5_VMS */ +#endif /* H5_HAVE_WIN32_API */ + + return (H5FD_t*)file; +} /* end H5FD_stdio_open() */ /*------------------------------------------------------------------------- @@ -438,16 +450,13 @@ H5FD_stdio_open( const char *name, unsigned flags, hid_t fapl_id, * 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 */ + static const char *func = "H5FD_stdio_close"; /* Function Name for error reporting */ /* Clear the error stack */ H5Eclear2(H5E_DEFAULT); @@ -457,8 +466,8 @@ H5FD_stdio_close(H5FD_t *_file) free(file); - return(0); -} + return 0; +} /* end H5FD_stdio_close() */ /*------------------------------------------------------------------------- @@ -467,17 +476,14 @@ H5FD_stdio_close(H5FD_t *_file) * Purpose: Compares two files belonging to this driver using an * arbitrary (but consistent) ordering. * - * Return: Success: A value like strcmp() + * Return: + * Success: A value like strcmp() * - * Failure: never fails (arguments were checked by the - * caller). + * 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 @@ -490,30 +496,37 @@ H5FD_stdio_cmp(const H5FD_t *_f1, const H5FD_t *_f2) H5Eclear2(H5E_DEFAULT); #ifdef H5_HAVE_WIN32_API - if (f1->fileindexhi < f2->fileindexhi) return -1; - if (f1->fileindexhi > f2->fileindexhi) return 1; + if(f1->dwVolumeSerialNumber < f2->dwVolumeSerialNumber) return -1; + if(f1->dwVolumeSerialNumber > f2->dwVolumeSerialNumber) return 1; - if (f1->fileindexlo < f2->fileindexlo) return -1; - if (f1->fileindexlo > f2->fileindexlo) return 1; + if(f1->nFileIndexHigh < f2->nFileIndexHigh) return -1; + if(f1->nFileIndexHigh > f2->nFileIndexHigh) return 1; -#else + if(f1->nFileIndexLow < f2->nFileIndexLow) return -1; + if(f1->nFileIndexLow > f2->nFileIndexLow) return 1; +#else /* H5_HAVE_WIN32_API */ #ifdef H5_DEV_T_IS_SCALAR - if (f1->device < f2->device) return -1; - if (f1->device > f2->device) return 1; + if(f1->device < f2->device) return -1; + if(f1->device > f2->device) return 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(memcmp(&(f1->device),&(f2->device),sizeof(dev_t))<0) return -1; - if(memcmp(&(f1->device),&(f2->device),sizeof(dev_t))>0) return 1; + if(memcmp(&(f1->device),&(f2->device),sizeof(dev_t)) < 0) return -1; + if(memcmp(&(f1->device),&(f2->device),sizeof(dev_t)) > 0) return 1; #endif /* H5_DEV_T_IS_SCALAR */ +#ifdef H5_VMS + if(memcmp(&(f1->inode), &(f2->inode), 3 * sizeof(ino_t)) < 0) return -1; + if(memcmp(&(f1->inode), &(f2->inode), 3 * sizeof(ino_t)) > 0) return 1; +#else /* H5_VMS */ + if(f1->inode < f2->inode) return -1; + if(f1->inode > f2->inode) return 1; +#endif /* H5_VMS */ +#endif /* H5_HAVE_WIN32_API */ - if (f1->inode < f2->inode) return -1; - if (f1->inode > f2->inode) return 1; -#endif return 0; -} +} /* H5FD_stdio_cmp() */ /*------------------------------------------------------------------------- @@ -529,14 +542,12 @@ H5FD_stdio_cmp(const H5FD_t *_f1, const H5FD_t *_f2) * Programmer: Quincey Koziol * Friday, August 25, 2000 * - * Modifications: - * *------------------------------------------------------------------------- */ static herr_t H5FD_stdio_query(const H5FD_t *_f, unsigned long *flags /* out */) { - /* Shut compiler up */ + /* Quiet the compiler */ _f=_f; /* Set the VFL feature flags that this driver supports */ @@ -548,37 +559,35 @@ H5FD_stdio_query(const H5FD_t *_f, unsigned long *flags /* out */) *flags|=H5FD_FEAT_AGGREGATE_SMALLDATA; /* OK to aggregate "small" raw data allocations */ } - return(0); -} + return 0; +} /* end H5FD_stdio_query() */ /*------------------------------------------------------------------------- * Function: H5FD_stdio_alloc * - * Purpose: Allocates file memory. If fseeko isn't available, makes + * Purpose: Allocates file memory. If fseeko isn't available, makes * sure the file size isn't bigger than 2GB because the * parameter OFFSET of fseek is of the type LONG INT, limiting * the file size to 2GB. * - * Return: Success: Address of new memory + * Return: + * Success: Address of new memory * - * Failure: HADDR_UNDEF + * Failure: HADDR_UNDEF * * Programmer: Raymond Lu * 30 March 2007 * - * Modifications: - * *------------------------------------------------------------------------- */ static haddr_t H5FD_stdio_alloc(H5FD_t *_file, H5FD_mem_t /*UNUSED*/ type, hid_t /*UNUSED*/ dxpl_id, hsize_t size) { - H5FD_stdio_t *file = (H5FD_stdio_t*)_file; - haddr_t addr; - haddr_t ret_value; /* Return value */ + H5FD_stdio_t *file = (H5FD_stdio_t*)_file; + haddr_t addr; - /* Shut compiler up */ + /* Quiet compiler */ type = type; dxpl_id = dxpl_id; @@ -597,19 +606,16 @@ H5FD_stdio_alloc(H5FD_t *_file, H5FD_mem_t /*UNUSED*/ type, hid_t /*UNUSED*/ dxp file->eoa = addr + size; - /* Set return value */ - ret_value = addr; - - return(ret_value); -} /* H5FD_stdio_alloc() */ + return addr; +} /* end H5FD_stdio_alloc() */ /*------------------------------------------------------------------------- * 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. + * is the first address past the last byte allocated in the + * format address space. * * Return: Success: The end-of-address marker. * @@ -618,28 +624,21 @@ H5FD_stdio_alloc(H5FD_t *_file, H5FD_mem_t /*UNUSED*/ type, hid_t /*UNUSED*/ dxp * Programmer: Robb Matzke * Monday, August 2, 1999 * - * Modifications: - * Stolen from the sec2 driver - QAK, 10/18/99 - * - * Raymond Lu - * 21 Dec. 2006 - * Added the parameter TYPE. It's only used for MULTI driver. - * *------------------------------------------------------------------------- */ static haddr_t -H5FD_stdio_get_eoa(const H5FD_t *_file, H5FD_mem_t /*unused*/ type) +H5FD_stdio_get_eoa(const H5FD_t *_file, H5FD_mem_t /*UNUSED*/ type) { - const H5FD_stdio_t *file = (const H5FD_stdio_t *)_file; + const H5FD_stdio_t *file = (const H5FD_stdio_t *)_file; /* Clear the error stack */ H5Eclear2(H5E_DEFAULT); - /* Shut compiler up */ + /* Quiet compiler */ type = type; - return(file->eoa); -} + return file->eoa; +} /* end H5FD_stdio_get_eoa() */ /*------------------------------------------------------------------------- @@ -651,33 +650,27 @@ H5FD_stdio_get_eoa(const H5FD_t *_file, H5FD_mem_t /*unused*/ type) * * Return: Success: 0 * - * Failure: -1 + * Failure: Does not fail * * Programmer: Robb Matzke * Thursday, July 29, 1999 * - * Modifications: - * Stolen from the sec2 driver - QAK, 10/18/99 - * - * Raymond Lu - * 21 Dec. 2006 - * Added the parameter TYPE. It's only used for MULTI driver. *------------------------------------------------------------------------- */ static herr_t -H5FD_stdio_set_eoa(H5FD_t *_file, H5FD_mem_t /*unused*/ type, haddr_t addr) +H5FD_stdio_set_eoa(H5FD_t *_file, H5FD_mem_t /*UNUSED*/ type, haddr_t addr) { H5FD_stdio_t *file = (H5FD_stdio_t*)_file; /* Clear the error stack */ H5Eclear2(H5E_DEFAULT); - /* Shut compiler up */ + /* Quiet the compiler */ type = type; file->eoa = addr; - return(0); + return 0; } @@ -697,9 +690,6 @@ H5FD_stdio_set_eoa(H5FD_t *_file, H5FD_mem_t /*unused*/ type, haddr_t addr) * Programmer: Robb Matzke * Thursday, July 29, 1999 * - * Modifications: - * Stolen from the sec2 driver - QAK, 10/18/99 - * *------------------------------------------------------------------------- */ static haddr_t @@ -710,8 +700,8 @@ H5FD_stdio_get_eof(const H5FD_t *_file) /* Clear the error stack */ H5Eclear2(H5E_DEFAULT); - return(MAX(file->eof, file->eoa)); -} + return MAX(file->eof, file->eoa); +} /* end H5FD_stdio_get_eof() */ /*------------------------------------------------------------------------- @@ -724,64 +714,56 @@ H5FD_stdio_get_eof(const H5FD_t *_file) * Programmer: Raymond Lu * Sept. 16, 2002 * - * Modifications: - * *------------------------------------------------------------------------- */ static herr_t H5FD_stdio_get_handle(H5FD_t *_file, hid_t fapl, void** file_handle) { H5FD_stdio_t *file = (H5FD_stdio_t *)_file; - static const char *func="H5FD_stdio_get_handle"; /* Function Name for error reporting */ + static const char *func = "H5FD_stdio_get_handle"; /* Function Name for error reporting */ - /* Shut compiler up */ - fapl=fapl; + /* Quiet the compiler */ + fapl = fapl; /* Clear the error stack */ H5Eclear2(H5E_DEFAULT); *file_handle = &(file->fp); - if(*file_handle==NULL) + if(*file_handle == NULL) H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_WRITEERROR, "get handle failed", -1) - return(0); -} + + return 0; +} /* end H5FD_stdio_get_handle() */ /*------------------------------------------------------------------------- - * Function: H5F_stdio_read + * Function: H5FD_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. + * 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, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, size_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 */ + static const char *func = "H5FD_stdio_read"; /* Function Name for error reporting */ - /* Shut compiler up */ - type=type; - dxpl_id=dxpl_id; + /* Quiet the compiler */ + type = type; + dxpl_id = dxpl_id; /* Clear the error stack */ H5Eclear2(H5E_DEFAULT); @@ -796,16 +778,14 @@ H5FD_stdio_read(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, siz /* Check easy cases */ if (0 == size) - return(0); + return 0; if ((haddr_t)addr >= file->eof) { memset(buf, 0, size); - return(0); + return 0; } - /* - * Seek to the correct file position. - */ - if (!(file->op == H5FD_STDIO_OP_READ || file->op==H5FD_STDIO_OP_SEEK) || + /* Seek to the correct file position. */ + if (!(file->op == H5FD_STDIO_OP_READ || file->op == H5FD_STDIO_OP_SEEK) || file->pos != addr) { if (file_fseek(file->fp, (file_offset_t)addr, SEEK_SET) < 0) { file->op = H5FD_STDIO_OP_UNKNOWN; @@ -815,59 +795,70 @@ H5FD_stdio_read(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, siz file->pos = addr; } - /* - * Read zeros past the logical end of file (physical is handled below) - */ + /* Read zeros past the logical end of file (physical is handled below) */ if (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 + /* Read the data. Since we're reading single-byte values, a partial read * will advance the file position by N. If N is zero or an error * occurs then the file position is undefined. */ - n = fread(buf, (size_t)1, size, file->fp); - if(n == 0 && ferror(file->fp)) { - file->op = H5FD_STDIO_OP_UNKNOWN; - file->pos = HADDR_UNDEF; - H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_READERROR, "fread failed", -1) - } else if (n < size) { - memset((unsigned char *)buf + n, 0, (size - n)); - } + while(size > 0) { - /* - * Update the file position data. - */ + size_t bytes_in = 0; /* # of bytes to read */ + size_t bytes_read = 0; /* # of bytes actually read */ + size_t item_size = 1; /* size of items in bytes */ + + if(size > H5_STDIO_MAX_IO_BYTES_g) + bytes_in = H5_STDIO_MAX_IO_BYTES_g; + else + bytes_in = size; + + bytes_read = fread(buf, item_size, bytes_in, file->fp); + + if(0 == bytes_read && ferror(file->fp)) { /* error */ + file->op = H5FD_STDIO_OP_UNKNOWN; + file->pos = HADDR_UNDEF; + H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_READERROR, "fread failed", -1) + } /* end if */ + + if(0 == bytes_read && feof(file->fp)) { + /* end of file but not end of format address space */ + memset((unsigned char *)buf, 0, size); + break; + } /* end if */ + + size -= bytes_read; + addr += (haddr_t)bytes_read; + buf = (char *)buf + bytes_read; + } /* end while */ + + /* Update the file position data. */ file->op = H5FD_STDIO_OP_READ; - file->pos = addr+n; /*checked for overflow above*/ - return(0); + file->pos = addr; + + return 0; } /*------------------------------------------------------------------------- - * Function: H5F_stdio_write + * Function: H5FD_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. + * 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 @@ -875,26 +866,24 @@ H5FD_stdio_write(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, size_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 */ + static const char *func = "H5FD_stdio_write"; /* Function Name for error reporting */ - /* Shut compiler up */ - dxpl_id=dxpl_id; - type=type; + /* Quiet the compiler */ + dxpl_id = dxpl_id; + type = type; /* Clear the error stack */ H5Eclear2(H5E_DEFAULT); /* Check for overflow conditions */ - if (HADDR_UNDEF==addr) + if (HADDR_UNDEF == addr) H5Epush_ret (func, H5E_ERR_CLS, H5E_IO, H5E_OVERFLOW, "file address overflowed", -1) if (REGION_OVERFLOW(addr, size)) H5Epush_ret (func, H5E_ERR_CLS, H5E_IO, H5E_OVERFLOW, "file address overflowed", -1) - if (addr+size>file->eoa) + if (addr+size > file->eoa) H5Epush_ret (func, H5E_ERR_CLS, H5E_IO, H5E_OVERFLOW, "file address overflowed", -1) - /* - * Seek to the correct file position. - */ + /* Seek to the correct file position. */ if ((file->op != H5FD_STDIO_OP_WRITE && file->op != H5FD_STDIO_OP_SEEK) || file->pos != addr) { if (file_fseek(file->fp, (file_offset_t)addr, SEEK_SET) < 0) { @@ -905,33 +894,51 @@ H5FD_stdio_write(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, 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. + /* Write the buffer. On successful return, the file position will be + * advanced by the number of bytes read. On failure, the file position is + * undefined. */ - if(size != fwrite(buf, (size_t)1, size, file->fp)) { - file->op = H5FD_STDIO_OP_UNKNOWN; - file->pos = HADDR_UNDEF; - H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_WRITEERROR, "fwrite failed", -1) + while(size > 0) { + + size_t bytes_in = 0; /* # of bytes to write */ + size_t bytes_wrote = 0; /* # of bytes written */ + size_t item_size = 1; /* size of items in bytes */ + + if(size > H5_STDIO_MAX_IO_BYTES_g) + bytes_in = H5_STDIO_MAX_IO_BYTES_g; + else + bytes_in = size; + + bytes_wrote = fwrite(buf, item_size, bytes_in, file->fp); + + if(bytes_wrote != bytes_in || (0 == bytes_wrote && ferror(file->fp))) { /* error */ + file->op = H5FD_STDIO_OP_UNKNOWN; + file->pos = HADDR_UNDEF; + H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_WRITEERROR, "fwrite failed", -1) + } /* end if */ + + assert(bytes_wrote > 0); + assert((size_t)bytes_wrote <= size); + + size -= bytes_wrote; + addr += (haddr_t)bytes_wrote; + buf = (const char *)buf + bytes_wrote; } - /* - * Update seek optimizing data. - */ + /* Update seek optimizing data. */ file->op = H5FD_STDIO_OP_WRITE; - file->pos = addr + size; + file->pos = addr; /* Update EOF if necessary */ - if (file->pos>file->eof) + if (file->pos > file->eof) file->eof = file->pos; - return(0); + return 0; } /*------------------------------------------------------------------------- - * Function: H5F_stdio_flush + * Function: H5FD_stdio_flush * * Purpose: Makes sure that all data is on disk. * @@ -952,7 +959,7 @@ H5FD_stdio_flush(H5FD_t *_file, hid_t dxpl_id, unsigned closing) H5FD_stdio_t *file = (H5FD_stdio_t*)_file; static const char *func = "H5FD_stdio_flush"; /* Function Name for error reporting */ - /* Shut compiler up */ + /* Quiet the compiler */ dxpl_id = dxpl_id; /* Clear the error stack */ @@ -960,7 +967,6 @@ H5FD_stdio_flush(H5FD_t *_file, hid_t dxpl_id, unsigned closing) /* Only try to flush the file if we have write access */ if(file->write_access) { - /* Flush */ if(!closing) { if(fflush(file->fp) < 0) H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_WRITEERROR, "fflush failed", -1) @@ -971,12 +977,12 @@ H5FD_stdio_flush(H5FD_t *_file, hid_t dxpl_id, unsigned closing) } /* end if */ } /* end if */ - return(0); + return 0; } /* end H5FD_stdio_flush() */ /*------------------------------------------------------------------------- - * Function: H5F_stdio_truncate + * Function: H5FD_stdio_truncate * * Purpose: Makes sure that the true file size is the same (or larger) * than the end-of-address. @@ -990,9 +996,6 @@ H5FD_stdio_flush(H5FD_t *_file, hid_t dxpl_id, unsigned closing) * Programmer: Quincey Koziol * Thursday, January 31, 2008 * - * Modifications: - * Vailin Choi; June 2010 - * Fix for window failures manifested from tests in mf.c. *------------------------------------------------------------------------- */ static herr_t @@ -1001,7 +1004,7 @@ H5FD_stdio_truncate(H5FD_t *_file, hid_t dxpl_id, hbool_t closing) H5FD_stdio_t *file = (H5FD_stdio_t*)_file; static const char *func = "H5FD_stdio_truncate"; /* Function Name for error reporting */ - /* Shut compiler up */ + /* Quiet the compiler */ dxpl_id = dxpl_id; closing = closing; @@ -1012,30 +1015,42 @@ H5FD_stdio_truncate(H5FD_t *_file, hid_t dxpl_id, hbool_t closing) if(file->write_access) { /* Makes sure that the true file size is the same as the end-of-address. */ if(file->eoa != file->eof) { - int fd = fileno(file->fp); /* File descriptor for HDF5 file */ #ifdef H5_HAVE_WIN32_API - HFILE filehandle; /* Windows file handle */ - LARGE_INTEGER li; /* 64-bit integer for SetFilePointer() call */ + LARGE_INTEGER li; /* 64-bit (union) integer for SetFilePointer() call */ + DWORD dwPtrLow; /* Low-order pointer bits from SetFilePointer() + * Only used as an error code here. + */ + DWORD dwError; /* DWORD error code from GetLastError() */ + BOOL bError; /* Boolean error flag */ - /* Reset seek offset to beginning of file, so that file isn't re-extended later */ + /* Reset seek offset to beginning of file, so that file isn't re-extended later */ rewind(file->fp); - /* Map the posix file handle to a Windows file handle */ - filehandle = _get_osfhandle(fd); + /* Windows uses this odd QuadPart union for 32/64-bit portability */ + li.QuadPart = (__int64)file->eoa; - /* 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) + /* Extend the file to make sure it's large enough. + * + * Since INVALID_SET_FILE_POINTER can technically be a valid return value + * from SetFilePointer(), we also need to check GetLastError(). + */ + dwPtrLow = SetFilePointer(file->hFile, li.LowPart, &li.HighPart, FILE_BEGIN); + if(INVALID_SET_FILE_POINTER == dwPtrLow) { + dwError = GetLastError(); + if(dwError != NO_ERROR ) + H5Epush_ret(func, H5E_ERR_CLS, H5E_FILE, H5E_FILEOPEN, "unable to set file pointer", -1) + } + + bError = SetEndOfFile(file->hFile); + if(0 == bError) H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_SEEKERROR, "unable to truncate/extend file properly", -1) #else /* H5_HAVE_WIN32_API */ /* Reset seek offset to beginning of file, so that file isn't re-extended later */ rewind(file->fp); /* Truncate file to proper length */ - if(-1 == file_ftruncate(fd, (file_offset_t)file->eoa)) + if(-1 == file_ftruncate(file->fd, (file_offset_t)file->eoa)) H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_SEEKERROR, "unable to truncate/extend file properly", -1) #endif /* H5_HAVE_WIN32_API */ @@ -1050,10 +1065,10 @@ H5FD_stdio_truncate(H5FD_t *_file, hid_t dxpl_id, hbool_t closing) else { /* Double-check for problems */ if(file->eoa > file->eof) - H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_TRUNCATED, "eoa>eof!", -1) - } /* end else */ + H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_TRUNCATED, "eoa > eof!", -1) + } /* end else */ - return(0); + return 0; } /* end H5FD_stdio_truncate() */