1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2  * Copyright by The HDF Group.                                               *
3  * Copyright by the Board of Trustees of the University of Illinois.         *
4  * All rights reserved.                                                      *
5  *                                                                           *
6  * This file is part of HDF5.  The full HDF5 copyright notice, including     *
7  * terms governing use, modification, and redistribution, is contained in    *
8  * the COPYING file, which can be found at the root of the source code       *
9  * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases.  *
10  * If you do not have access to either file, you may request a copy from     *
11  * help@hdfgroup.org.                                                        *
12  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
13 
14 /* Programmer:  Robb Matzke <matzke@llnl.gov>
15  *              Wednesday, October 22, 1997
16  *
17  * Purpose: The C STDIO virtual file driver which only uses calls from stdio.h.
18  *          This also serves as an example of coding a simple file driver,
19  *          therefore, it should not use any non-public definitions.
20  *
21  * NOTE:    This driver is not as well tested as the standard SEC2 driver
22  *          and is not intended for production use!
23  */
24 #include <assert.h>
25 #include <errno.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <sys/stat.h>
30 
31 #include "hdf5.h"
32 
33 #ifdef H5_HAVE_FLOCK
34 /* Needed for lock type definitions (e.g., LOCK_EX) */
35 #include <sys/file.h>
36 #endif /* H5_HAVE_FLOCK */
37 
38 #ifdef H5_HAVE_UNISTD_H
39 #include <unistd.h>
40 #endif
41 
42 #ifdef H5_HAVE_WIN32_API
43 /* The following two defines must be before any windows headers are included */
44 #define WIN32_LEAN_AND_MEAN    /* Exclude rarely-used stuff from Windows headers */
45 #define NOGDI                  /* Exclude Graphic Display Interface macros */
46 
47 #include <windows.h>
48 #include <io.h>
49 
50 #endif /* H5_HAVE_WIN32_API */
51 
52 /* The driver identification number, initialized at runtime */
53 static hid_t H5FD_STDIO_g = 0;
54 
55 /* The maximum number of bytes which can be written in a single I/O operation */
56 static size_t H5_STDIO_MAX_IO_BYTES_g = (size_t)-1;
57 
58 /* File operations */
59 typedef enum {
60     H5FD_STDIO_OP_UNKNOWN=0,
61     H5FD_STDIO_OP_READ=1,
62     H5FD_STDIO_OP_WRITE=2,
63     H5FD_STDIO_OP_SEEK=3
64 } H5FD_stdio_file_op;
65 
66 /* The description of a file belonging to this driver. The 'eoa' and 'eof'
67  * determine the amount of hdf5 address space in use and the high-water mark
68  * of the file (the current size of the underlying Unix file). The 'pos'
69  * value is used to eliminate file position updates when they would be a
70  * no-op. Unfortunately we've found systems that use separate file position
71  * indicators for reading and writing so the lseek can only be eliminated if
72  * the current operation is the same as the previous operation.  When opening
73  * a file the 'eof' will be set to the current file size, 'eoa' will be set
74  * to zero, 'pos' will be set to H5F_ADDR_UNDEF (as it is when an error
75  * occurs), and 'op' will be set to H5F_OP_UNKNOWN.
76  */
77 typedef struct H5FD_stdio_t {
78     H5FD_t      pub;            /* public stuff, must be first      */
79     FILE        *fp;            /* the file handle                  */
80     int         fd;             /* file descriptor (for truncate)   */
81     haddr_t     eoa;            /* end of allocated region          */
82     haddr_t     eof;            /* end of file; current file size   */
83     haddr_t     pos;            /* current file I/O position        */
84     unsigned    write_access;   /* Flag to indicate the file was opened with write access */
85     H5FD_stdio_file_op op;  /* last operation */
86 #ifndef H5_HAVE_WIN32_API
87     /* On most systems the combination of device and i-node number uniquely
88      * identify a file.  Note that Cygwin, MinGW and other Windows POSIX
89      * environments have the stat function (which fakes inodes)
90      * and will use the 'device + inodes' scheme as opposed to the
91      * Windows code further below.
92      */
93     dev_t           device;     /* file device number   */
94     ino_t           inode;      /* file i-node number   */
95 #else
96     /* Files in windows are uniquely identified by the volume serial
97      * number and the file index (both low and high parts).
98      *
99      * There are caveats where these numbers can change, especially
100      * on FAT file systems.  On NTFS, however, a file should keep
101      * those numbers the same until renamed or deleted (though you
102      * can use ReplaceFile() on NTFS to keep the numbers the same
103      * while renaming).
104      *
105      * See the MSDN "BY_HANDLE_FILE_INFORMATION Structure" entry for
106      * more information.
107      *
108      * http://msdn.microsoft.com/en-us/library/aa363788(v=VS.85).aspx
109      */
110     DWORD           nFileIndexLow;
111     DWORD           nFileIndexHigh;
112     DWORD           dwVolumeSerialNumber;
113 
114     HANDLE          hFile;      /* Native windows file handle */
115 #endif  /* H5_HAVE_WIN32_API */
116 } H5FD_stdio_t;
117 
118 /* Use similar structure as in H5private.h by defining Windows stuff first. */
119 #ifdef H5_HAVE_WIN32_API
120 #ifndef H5_HAVE_MINGW
121     #define file_fseek      _fseeki64
122     #define file_offset_t   __int64
123     #define file_ftruncate  _chsize_s   /* Supported in VS 2005 or newer */
124     #define file_ftell      _ftelli64
125 #endif /* H5_HAVE_MINGW */
126 #endif /* H5_HAVE_WIN32_API */
127 
128 /* If these functions weren't re-defined for Windows, give them
129  * more platform-independent names.
130  */
131 #ifndef file_fseek
132     #define file_fseek      fseeko
133     #define file_offset_t   off_t
134     #define file_ftruncate  ftruncate
135     #define file_ftell      ftello
136 #endif /* file_fseek */
137 
138 /* These macros check for overflow of various quantities.  These macros
139  * assume that file_offset_t is signed and haddr_t and size_t are unsigned.
140  *
141  * ADDR_OVERFLOW:  Checks whether a file address of type `haddr_t'
142  *      is too large to be represented by the second argument
143  *      of the file seek function.
144  *
145  * SIZE_OVERFLOW:  Checks whether a buffer size of type `hsize_t' is too
146  *      large to be represented by the `size_t' type.
147  *
148  * REGION_OVERFLOW:  Checks whether an address and size pair describe data
149  *      which can be addressed entirely by the second
150  *      argument of the file seek function.
151  */
152 /* adding for windows NT filesystem support. */
153 #define MAXADDR (((haddr_t)1<<(8*sizeof(file_offset_t)-1))-1)
154 #define ADDR_OVERFLOW(A)  (HADDR_UNDEF==(A) || ((A) & ~(haddr_t)MAXADDR))
155 #define SIZE_OVERFLOW(Z)  ((Z) & ~(hsize_t)MAXADDR)
156 #define REGION_OVERFLOW(A,Z)  (ADDR_OVERFLOW(A) || SIZE_OVERFLOW(Z) || \
157     HADDR_UNDEF==(A)+(Z) || (file_offset_t)((A)+(Z))<(file_offset_t)(A))
158 
159 /* Prototypes */
160 static herr_t H5FD_stdio_term(void);
161 static H5FD_t *H5FD_stdio_open(const char *name, unsigned flags,
162                  hid_t fapl_id, haddr_t maxaddr);
163 static herr_t H5FD_stdio_close(H5FD_t *lf);
164 static int H5FD_stdio_cmp(const H5FD_t *_f1, const H5FD_t *_f2);
165 static herr_t H5FD_stdio_query(const H5FD_t *_f1, unsigned long *flags);
166 static haddr_t H5FD_stdio_alloc(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, hsize_t size);
167 static haddr_t H5FD_stdio_get_eoa(const H5FD_t *_file, H5FD_mem_t type);
168 static herr_t H5FD_stdio_set_eoa(H5FD_t *_file, H5FD_mem_t type, haddr_t addr);
169 static haddr_t H5FD_stdio_get_eof(const H5FD_t *_file, H5FD_mem_t type);
170 static herr_t  H5FD_stdio_get_handle(H5FD_t *_file, hid_t fapl, void** file_handle);
171 static herr_t H5FD_stdio_read(H5FD_t *lf, H5FD_mem_t type, hid_t fapl_id, haddr_t addr,
172                 size_t size, void *buf);
173 static herr_t H5FD_stdio_write(H5FD_t *lf, H5FD_mem_t type, hid_t fapl_id, haddr_t addr,
174                 size_t size, const void *buf);
175 static herr_t H5FD_stdio_flush(H5FD_t *_file, hid_t dxpl_id, hbool_t closing);
176 static herr_t H5FD_stdio_truncate(H5FD_t *_file, hid_t dxpl_id, hbool_t closing);
177 static herr_t H5FD_stdio_lock(H5FD_t *_file, hbool_t rw);
178 static herr_t H5FD_stdio_unlock(H5FD_t *_file);
179 
180 static const H5FD_class_t H5FD_stdio_g = {
181     "stdio",                    /* name         */
182     MAXADDR,                    /* maxaddr      */
183     H5F_CLOSE_WEAK,             /* fc_degree    */
184     H5FD_stdio_term,            /* terminate    */
185     NULL,                       /* sb_size      */
186     NULL,                       /* sb_encode    */
187     NULL,                       /* sb_decode    */
188     0,                          /* fapl_size    */
189     NULL,                       /* fapl_get     */
190     NULL,                       /* fapl_copy    */
191     NULL,                       /* fapl_free    */
192     0,                          /* dxpl_size    */
193     NULL,                       /* dxpl_copy    */
194     NULL,                       /* dxpl_free    */
195     H5FD_stdio_open,            /* open         */
196     H5FD_stdio_close,           /* close        */
197     H5FD_stdio_cmp,             /* cmp          */
198     H5FD_stdio_query,           /* query        */
199     NULL,                       /* get_type_map */
200     H5FD_stdio_alloc,           /* alloc        */
201     NULL,                       /* free         */
202     H5FD_stdio_get_eoa,         /* get_eoa      */
203     H5FD_stdio_set_eoa,         /* set_eoa      */
204     H5FD_stdio_get_eof,         /* get_eof      */
205     H5FD_stdio_get_handle,      /* get_handle   */
206     H5FD_stdio_read,            /* read         */
207     H5FD_stdio_write,           /* write        */
208     H5FD_stdio_flush,           /* flush        */
209     H5FD_stdio_truncate,        /* truncate     */
210     H5FD_stdio_lock,            /* lock         */
211     H5FD_stdio_unlock,          /* unlock       */
212     H5FD_FLMAP_DICHOTOMY	/* fl_map       */
213 };
214 
215 
216 /*-------------------------------------------------------------------------
217  * Function:  H5FD_stdio_init
218  *
219  * Purpose:  Initialize this driver by registering the driver with the
220  *    library.
221  *
222  * Return:  Success:  The driver ID for the stdio driver.
223  *
224  *    Failure:  Negative.
225  *
226  * Programmer:  Robb Matzke
227  *              Thursday, July 29, 1999
228  *
229  *-------------------------------------------------------------------------
230  */
231 hid_t
H5FD_stdio_init(void)232 H5FD_stdio_init(void)
233 {
234     /* Clear the error stack */
235     H5Eclear2(H5E_DEFAULT);
236 
237     if (H5I_VFL!=H5Iget_type(H5FD_STDIO_g))
238         H5FD_STDIO_g = H5FDregister(&H5FD_stdio_g);
239     return H5FD_STDIO_g;
240 } /* end H5FD_stdio_init() */
241 
242 
243 /*---------------------------------------------------------------------------
244  * Function:  H5FD_stdio_term
245  *
246  * Purpose:  Shut down the VFD
247  *
248  * Returns:     Non-negative on success or negative on failure
249  *
250  * Programmer:  Quincey Koziol
251  *              Friday, Jan 30, 2004
252  *
253  *---------------------------------------------------------------------------
254  */
255 static herr_t
H5FD_stdio_term(void)256 H5FD_stdio_term(void)
257 {
258     /* Reset VFL ID */
259     H5FD_STDIO_g = 0;
260 
261     return 0;
262 } /* end H5FD_stdio_term() */
263 
264 
265 /*-------------------------------------------------------------------------
266  * Function:  H5Pset_fapl_stdio
267  *
268  * Purpose:  Modify the file access property list to use the H5FD_STDIO
269  *    driver defined in this source file.  There are no driver
270  *    specific properties.
271  *
272  * Return:  Non-negative on success/Negative on failure
273  *
274  * Programmer:  Robb Matzke
275  *    Thursday, February 19, 1998
276  *
277  *-------------------------------------------------------------------------
278  */
279 herr_t
H5Pset_fapl_stdio(hid_t fapl_id)280 H5Pset_fapl_stdio(hid_t fapl_id)
281 {
282     static const char *func = "H5FDset_fapl_stdio";  /*for error reporting*/
283 
284     /*NO TRACE*/
285 
286     /* Clear the error stack */
287     H5Eclear2(H5E_DEFAULT);
288 
289     if(0 == H5Pisa_class(fapl_id, H5P_FILE_ACCESS))
290         H5Epush_ret(func, H5E_ERR_CLS, H5E_PLIST, H5E_BADTYPE, "not a file access property list", -1)
291 
292     return H5Pset_driver(fapl_id, H5FD_STDIO, NULL);
293 } /* end H5Pset_fapl_stdio() */
294 
295 
296 /*-------------------------------------------------------------------------
297  * Function:  H5FD_stdio_open
298  *
299  * Purpose:  Create and/or opens a Standard C file as an HDF5 file.
300  *
301  * Errors:
302  *  IO  CANTOPENFILE    File doesn't exist and CREAT wasn't
303  *                      specified.
304  *  IO  CANTOPENFILE    fopen() failed.
305  *  IO  FILEEXISTS      File exists but CREAT and EXCL were
306  *                      specified.
307  *
308  * Return:
309  *      Success:    A pointer to a new file data structure. The
310  *                  public fields will be initialized by the
311  *                  caller, which is always H5FD_open().
312  *
313  *      Failure:    NULL
314  *
315  * Programmer:  Robb Matzke
316  *    Wednesday, October 22, 1997
317  *
318  *-------------------------------------------------------------------------
319  */
320 static H5FD_t *
H5FD_stdio_open(const char * name,unsigned flags,hid_t fapl_id,haddr_t maxaddr)321 H5FD_stdio_open( const char *name, unsigned flags, hid_t /*UNUSED*/ fapl_id,
322     haddr_t maxaddr)
323 {
324     FILE                *f = NULL;
325     unsigned            write_access = 0;           /* File opened with write access? */
326     H5FD_stdio_t        *file = NULL;
327     static const char   *func = "H5FD_stdio_open";  /* Function Name for error reporting */
328 #ifdef H5_HAVE_WIN32_API
329     struct _BY_HANDLE_FILE_INFORMATION fileinfo;
330 #else /* H5_HAVE_WIN32_API */
331     struct stat         sb;
332 #endif  /* H5_HAVE_WIN32_API */
333 
334     /* Sanity check on file offsets */
335     assert(sizeof(file_offset_t) >= sizeof(size_t));
336 
337     /* Quiet compiler */
338     fapl_id = fapl_id;
339 
340     /* Clear the error stack */
341     H5Eclear2(H5E_DEFAULT);
342 
343     /* Check arguments */
344     if (!name || !*name)
345         H5Epush_ret(func, H5E_ERR_CLS, H5E_ARGS, H5E_BADVALUE, "invalid file name", NULL)
346     if (0 == maxaddr || HADDR_UNDEF == maxaddr)
347         H5Epush_ret(func, H5E_ERR_CLS, H5E_ARGS, H5E_BADRANGE, "bogus maxaddr", NULL)
348     if (ADDR_OVERFLOW(maxaddr))
349         H5Epush_ret(func, H5E_ERR_CLS, H5E_ARGS, H5E_OVERFLOW, "maxaddr too large", NULL)
350 
351     /* Tentatively open file in read-only mode, to check for existence */
352     if(flags & H5F_ACC_RDWR)
353         f = fopen(name, "rb+");
354     else
355         f = fopen(name, "rb");
356 
357     if(!f) {
358         /* File doesn't exist */
359         if(flags & H5F_ACC_CREAT) {
360             assert(flags & H5F_ACC_RDWR);
361             f = fopen(name, "wb+");
362             write_access = 1;     /* Note the write access */
363         }
364         else
365             H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_CANTOPENFILE, "file doesn't exist and CREAT wasn't specified", NULL)
366     } else if(flags & H5F_ACC_EXCL) {
367         /* File exists, but EXCL is passed.  Fail. */
368         assert(flags & H5F_ACC_CREAT);
369         fclose(f);
370         H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_FILEEXISTS, "file exists but CREAT and EXCL were specified", NULL)
371     } else if(flags & H5F_ACC_RDWR) {
372         if(flags & H5F_ACC_TRUNC)
373             f = freopen(name, "wb+", f);
374         write_access = 1;     /* Note the write access */
375     } /* end if */
376     /* Note there is no need to reopen if neither TRUNC nor EXCL are specified,
377      * as the tentative open will work */
378 
379     if(!f)
380         H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_CANTOPENFILE, "fopen failed", NULL)
381 
382     /* Build the return value */
383     if(NULL == (file = (H5FD_stdio_t *)calloc((size_t)1, sizeof(H5FD_stdio_t)))) {
384         fclose(f);
385         H5Epush_ret(func, H5E_ERR_CLS, H5E_RESOURCE, H5E_NOSPACE, "memory allocation failed", NULL)
386     } /* end if */
387     file->fp = f;
388     file->op = H5FD_STDIO_OP_SEEK;
389     file->pos = HADDR_UNDEF;
390     file->write_access = write_access;    /* Note the write_access for later */
391     if(file_fseek(file->fp, (file_offset_t)0, SEEK_END) < 0) {
392         file->op = H5FD_STDIO_OP_UNKNOWN;
393     } else {
394         file_offset_t x = file_ftell(file->fp);
395         assert (x >= 0);
396         file->eof = (haddr_t)x;
397     }
398 
399     /* Get the file descriptor (needed for truncate and some Windows information) */
400 #ifdef H5_HAVE_WIN32_API
401     file->fd = _fileno(file->fp);
402 #else /* H5_HAVE_WIN32_API */
403     file->fd = fileno(file->fp);
404 #endif /* H5_HAVE_WIN32_API */
405     if(file->fd < 0) {
406         free(file);
407         fclose(f);
408         H5Epush_ret(func, H5E_ERR_CLS, H5E_FILE, H5E_CANTOPENFILE, "unable to get file descriptor", NULL);
409     } /* end if */
410 
411 
412 #ifdef H5_HAVE_WIN32_API
413     file->hFile = (HANDLE)_get_osfhandle(file->fd);
414     if(INVALID_HANDLE_VALUE == file->hFile) {
415         free(file);
416         fclose(f);
417         H5Epush_ret(func, H5E_ERR_CLS, H5E_FILE, H5E_CANTOPENFILE, "unable to get Windows file handle", NULL);
418     } /* end if */
419 
420     if(!GetFileInformationByHandle((HANDLE)file->hFile, &fileinfo)) {
421         free(file);
422         fclose(f);
423         H5Epush_ret(func, H5E_ERR_CLS, H5E_FILE, H5E_CANTOPENFILE, "unable to get Windows file descriptor information", NULL);
424     } /* end if */
425 
426     file->nFileIndexHigh = fileinfo.nFileIndexHigh;
427     file->nFileIndexLow = fileinfo.nFileIndexLow;
428     file->dwVolumeSerialNumber = fileinfo.dwVolumeSerialNumber;
429 #else /* H5_HAVE_WIN32_API */
430     if(fstat(file->fd, &sb) < 0) {
431         free(file);
432         fclose(f);
433         H5Epush_ret(func, H5E_ERR_CLS, H5E_FILE, H5E_BADFILE, "unable to fstat file", NULL)
434     } /* end if */
435     file->device = sb.st_dev;
436     file->inode = sb.st_ino;
437 #endif /* H5_HAVE_WIN32_API */
438 
439     return((H5FD_t*)file);
440 } /* end H5FD_stdio_open() */
441 
442 
443 /*-------------------------------------------------------------------------
444  * Function:  H5F_stdio_close
445  *
446  * Purpose:  Closes a file.
447  *
448  * Errors:
449  *    IO    CLOSEERROR  Fclose failed.
450  *
451  * Return:  Non-negative on success/Negative on failure
452  *
453  * Programmer:  Robb Matzke
454  *    Wednesday, October 22, 1997
455  *
456  *-------------------------------------------------------------------------
457  */
458 static herr_t
H5FD_stdio_close(H5FD_t * _file)459 H5FD_stdio_close(H5FD_t *_file)
460 {
461     H5FD_stdio_t  *file = (H5FD_stdio_t*)_file;
462     static const char *func = "H5FD_stdio_close";  /* Function Name for error reporting */
463 
464     /* Clear the error stack */
465     H5Eclear2(H5E_DEFAULT);
466 
467     if (fclose(file->fp) < 0)
468         H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_CLOSEERROR, "fclose failed", -1)
469 
470     free(file);
471 
472     return 0;
473 } /* end H5FD_stdio_close() */
474 
475 
476 /*-------------------------------------------------------------------------
477  * Function:  H5FD_stdio_cmp
478  *
479  * Purpose:  Compares two files belonging to this driver using an
480  *    arbitrary (but consistent) ordering.
481  *
482  * Return:
483  *      Success:    A value like strcmp()
484  *
485  *      Failure:    never fails (arguments were checked by the caller).
486  *
487  * Programmer:  Robb Matzke
488  *              Thursday, July 29, 1999
489  *
490  *-------------------------------------------------------------------------
491  */
492 static int
H5FD_stdio_cmp(const H5FD_t * _f1,const H5FD_t * _f2)493 H5FD_stdio_cmp(const H5FD_t *_f1, const H5FD_t *_f2)
494 {
495     const H5FD_stdio_t  *f1 = (const H5FD_stdio_t*)_f1;
496     const H5FD_stdio_t  *f2 = (const H5FD_stdio_t*)_f2;
497 
498     /* Clear the error stack */
499     H5Eclear2(H5E_DEFAULT);
500 
501 #ifdef H5_HAVE_WIN32_API
502     if(f1->dwVolumeSerialNumber < f2->dwVolumeSerialNumber) return -1;
503     if(f1->dwVolumeSerialNumber > f2->dwVolumeSerialNumber) return 1;
504 
505     if(f1->nFileIndexHigh < f2->nFileIndexHigh) return -1;
506     if(f1->nFileIndexHigh > f2->nFileIndexHigh) return 1;
507 
508     if(f1->nFileIndexLow < f2->nFileIndexLow) return -1;
509     if(f1->nFileIndexLow > f2->nFileIndexLow) return 1;
510 #else /* H5_HAVE_WIN32_API */
511 #ifdef H5_DEV_T_IS_SCALAR
512     if(f1->device < f2->device) return -1;
513     if(f1->device > f2->device) return 1;
514 #else /* H5_DEV_T_IS_SCALAR */
515     /* If dev_t isn't a scalar value on this system, just use memcmp to
516      * determine if the values are the same or not.  The actual return value
517      * shouldn't really matter...
518      */
519     if(memcmp(&(f1->device),&(f2->device),sizeof(dev_t)) < 0) return -1;
520     if(memcmp(&(f1->device),&(f2->device),sizeof(dev_t)) > 0) return 1;
521 #endif /* H5_DEV_T_IS_SCALAR */
522     if(f1->inode < f2->inode) return -1;
523     if(f1->inode > f2->inode) return 1;
524 #endif /* H5_HAVE_WIN32_API */
525 
526     return 0;
527 } /* H5FD_stdio_cmp() */
528 
529 
530 /*-------------------------------------------------------------------------
531  * Function:  H5FD_stdio_query
532  *
533  * Purpose:  Set the flags that this VFL driver is capable of supporting.
534  *              (listed in H5FDpublic.h)
535  *
536  * Return:  Success:  non-negative
537  *
538  *    Failure:  negative
539  *
540  * Programmer:  Quincey Koziol
541  *              Friday, August 25, 2000
542  *
543  *-------------------------------------------------------------------------
544  */
545 static herr_t
H5FD_stdio_query(const H5FD_t * _f,unsigned long * flags)546 H5FD_stdio_query(const H5FD_t *_f, unsigned long /*OUT*/ *flags)
547 {
548     /* Quiet the compiler */
549     _f=_f;
550 
551     /* Set the VFL feature flags that this driver supports.
552      *
553      * Note that this VFD does not support SWMR due to the unpredictable
554      * nature of the buffering layer.
555      */
556     if(flags) {
557         *flags = 0;
558         *flags |= H5FD_FEAT_AGGREGATE_METADATA;     /* OK to aggregate metadata allocations                             */
559         *flags |= H5FD_FEAT_ACCUMULATE_METADATA;    /* OK to accumulate metadata for faster writes                      */
560         *flags |= H5FD_FEAT_DATA_SIEVE;             /* OK to perform data sieving for faster raw data reads & writes    */
561         *flags |= H5FD_FEAT_AGGREGATE_SMALLDATA;    /* OK to aggregate "small" raw data allocations                     */
562         *flags |= H5FD_FEAT_DEFAULT_VFD_COMPATIBLE; /* VFD creates a file which can be opened with the default VFD      */
563     }
564 
565     return 0;
566 } /* end H5FD_stdio_query() */
567 
568 
569 /*-------------------------------------------------------------------------
570  * Function:  H5FD_stdio_alloc
571  *
572  * Purpose:     Allocates file memory. If fseeko isn't available, makes
573  *              sure the file size isn't bigger than 2GB because the
574  *              parameter OFFSET of fseek is of the type LONG INT, limiting
575  *              the file size to 2GB.
576  *
577  * Return:
578  *      Success:    Address of new memory
579  *
580  *      Failure:    HADDR_UNDEF
581  *
582  * Programmer:  Raymond Lu
583  *              30 March 2007
584  *
585  *-------------------------------------------------------------------------
586  */
587 static haddr_t
H5FD_stdio_alloc(H5FD_t * _file,H5FD_mem_t type,hid_t dxpl_id,hsize_t size)588 H5FD_stdio_alloc(H5FD_t *_file, H5FD_mem_t /*UNUSED*/ type, hid_t /*UNUSED*/ dxpl_id, hsize_t size)
589 {
590     H5FD_stdio_t    *file = (H5FD_stdio_t*)_file;
591     haddr_t         addr;
592 
593     /* Quiet compiler */
594     type = type;
595     dxpl_id = dxpl_id;
596 
597     /* Clear the error stack */
598     H5Eclear2(H5E_DEFAULT);
599 
600     /* Compute the address for the block to allocate */
601     addr = file->eoa;
602 
603     file->eoa = addr + size;
604 
605     return addr;
606 } /* end H5FD_stdio_alloc() */
607 
608 
609 /*-------------------------------------------------------------------------
610  * Function:  H5FD_stdio_get_eoa
611  *
612  * Purpose:  Gets the end-of-address marker for the file. The EOA marker
613  *           is the first address past the last byte allocated in the
614  *           format address space.
615  *
616  * Return:  Success:  The end-of-address marker.
617  *
618  *    Failure:  HADDR_UNDEF
619  *
620  * Programmer:  Robb Matzke
621  *              Monday, August  2, 1999
622  *
623  *-------------------------------------------------------------------------
624  */
625 static haddr_t
H5FD_stdio_get_eoa(const H5FD_t * _file,H5FD_mem_t type)626 H5FD_stdio_get_eoa(const H5FD_t *_file, H5FD_mem_t /*UNUSED*/ type)
627 {
628     const H5FD_stdio_t *file = (const H5FD_stdio_t *)_file;
629 
630     /* Clear the error stack */
631     H5Eclear2(H5E_DEFAULT);
632 
633     /* Quiet compiler */
634     type = type;
635 
636     return file->eoa;
637 } /* end H5FD_stdio_get_eoa() */
638 
639 
640 /*-------------------------------------------------------------------------
641  * Function:  H5FD_stdio_set_eoa
642  *
643  * Purpose:  Set the end-of-address marker for the file. This function is
644  *    called shortly after an existing HDF5 file is opened in order
645  *    to tell the driver where the end of the HDF5 data is located.
646  *
647  * Return:  Success:  0
648  *
649  *    Failure:  Does not fail
650  *
651  * Programmer:  Robb Matzke
652  *              Thursday, July 29, 1999
653  *
654  *-------------------------------------------------------------------------
655  */
656 static herr_t
H5FD_stdio_set_eoa(H5FD_t * _file,H5FD_mem_t type,haddr_t addr)657 H5FD_stdio_set_eoa(H5FD_t *_file, H5FD_mem_t /*UNUSED*/ type, haddr_t addr)
658 {
659     H5FD_stdio_t  *file = (H5FD_stdio_t*)_file;
660 
661     /* Clear the error stack */
662     H5Eclear2(H5E_DEFAULT);
663 
664     /* Quiet the compiler */
665     type = type;
666 
667     file->eoa = addr;
668 
669     return 0;
670 }
671 
672 
673 /*-------------------------------------------------------------------------
674  * Function:  H5FD_stdio_get_eof
675  *
676  * Purpose:  Returns the end-of-file marker, which is the greater of
677  *    either the Unix end-of-file or the HDF5 end-of-address
678  *    markers.
679  *
680  * Return:  Success:  End of file address, the first address past
681  *        the end of the "file", either the Unix file
682  *        or the HDF5 file.
683  *
684  *    Failure:  HADDR_UNDEF
685  *
686  * Programmer:  Robb Matzke
687  *              Thursday, July 29, 1999
688  *
689  *-------------------------------------------------------------------------
690  */
691 static haddr_t
H5FD_stdio_get_eof(const H5FD_t * _file,H5FD_mem_t type)692 H5FD_stdio_get_eof(const H5FD_t *_file, H5FD_mem_t /*UNUSED*/ type)
693 {
694     const H5FD_stdio_t  *file = (const H5FD_stdio_t *)_file;
695 
696     /* Quiet the compiler */
697     type = type;
698 
699     /* Clear the error stack */
700     H5Eclear2(H5E_DEFAULT);
701 
702     /* Quiet the compiler */
703     type = type;
704 
705     return(file->eof);
706 } /* end H5FD_stdio_get_eof() */
707 
708 
709 /*-------------------------------------------------------------------------
710  * Function:       H5FD_stdio_get_handle
711  *
712  * Purpose:        Returns the file handle of stdio file driver.
713  *
714  * Returns:        Non-negative if succeed or negative if fails.
715  *
716  * Programmer:     Raymond Lu
717  *                 Sept. 16, 2002
718  *
719  *-------------------------------------------------------------------------
720  */
721 static herr_t
H5FD_stdio_get_handle(H5FD_t * _file,hid_t fapl,void ** file_handle)722 H5FD_stdio_get_handle(H5FD_t *_file, hid_t /*UNUSED*/ fapl, void **file_handle)
723 {
724     H5FD_stdio_t       *file = (H5FD_stdio_t *)_file;
725     static const char  *func = "H5FD_stdio_get_handle";  /* Function Name for error reporting */
726 
727     /* Quiet the compiler */
728     fapl = fapl;
729 
730     /* Clear the error stack */
731     H5Eclear2(H5E_DEFAULT);
732 
733     *file_handle = &(file->fp);
734     if(*file_handle == NULL)
735         H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_WRITEERROR, "get handle failed", -1)
736 
737     return 0;
738 } /* end H5FD_stdio_get_handle() */
739 
740 
741 /*-------------------------------------------------------------------------
742  * Function:  H5FD_stdio_read
743  *
744  * Purpose:  Reads SIZE bytes beginning at address ADDR in file LF and
745  *    places them in buffer BUF.  Reading past the logical or
746  *    physical end of file returns zeros instead of failing.
747  *
748  * Errors:
749  *    IO    READERROR  fread failed.
750  *    IO    SEEKERROR  fseek failed.
751  *
752  * Return:  Non-negative on success/Negative on failure
753  *
754  * Programmer:  Robb Matzke
755  *    Wednesday, October 22, 1997
756  *
757  *-------------------------------------------------------------------------
758  */
759 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)760 H5FD_stdio_read(H5FD_t *_file, H5FD_mem_t /*UNUSED*/ type, hid_t /*UNUSED*/ dxpl_id,
761     haddr_t addr, size_t size, void /*OUT*/ *buf)
762 {
763     H5FD_stdio_t    *file = (H5FD_stdio_t*)_file;
764     static const char *func = "H5FD_stdio_read";  /* Function Name for error reporting */
765 
766     /* Quiet the compiler */
767     type = type;
768     dxpl_id = dxpl_id;
769 
770     /* Clear the error stack */
771     H5Eclear2(H5E_DEFAULT);
772 
773     /* Check for overflow */
774     if (HADDR_UNDEF==addr)
775         H5Epush_ret (func, H5E_ERR_CLS, H5E_IO, H5E_OVERFLOW, "file address overflowed", -1)
776     if (REGION_OVERFLOW(addr, size))
777         H5Epush_ret (func, H5E_ERR_CLS, H5E_IO, H5E_OVERFLOW, "file address overflowed", -1)
778 
779     /* Check easy cases */
780     if (0 == size)
781         return 0;
782     if ((haddr_t)addr >= file->eof) {
783         memset(buf, 0, size);
784         return 0;
785     }
786 
787     /* Seek to the correct file position. */
788     if (!(file->op == H5FD_STDIO_OP_READ || file->op == H5FD_STDIO_OP_SEEK) ||
789             file->pos != addr) {
790         if (file_fseek(file->fp, (file_offset_t)addr, SEEK_SET) < 0) {
791             file->op = H5FD_STDIO_OP_UNKNOWN;
792             file->pos = HADDR_UNDEF;
793             H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_SEEKERROR, "fseek failed", -1)
794         }
795         file->pos = addr;
796     }
797 
798     /* Read zeros past the logical end of file (physical is handled below) */
799     if (addr + size > file->eof) {
800         size_t nbytes = (size_t) (addr + size - file->eof);
801         memset((unsigned char *)buf + size - nbytes, 0, nbytes);
802         size -= nbytes;
803     }
804 
805     /* Read the data.  Since we're reading single-byte values, a partial read
806      * will advance the file position by N.  If N is zero or an error
807      * occurs then the file position is undefined.
808      */
809     while(size > 0) {
810 
811         size_t bytes_in        = 0;    /* # of bytes to read       */
812         size_t bytes_read      = 0;    /* # of bytes actually read */
813         size_t item_size       = 1;    /* size of items in bytes */
814 
815         if(size > H5_STDIO_MAX_IO_BYTES_g)
816             bytes_in = H5_STDIO_MAX_IO_BYTES_g;
817         else
818             bytes_in = size;
819 
820         bytes_read = fread(buf, item_size, bytes_in, file->fp);
821 
822         if(0 == bytes_read && ferror(file->fp)) { /* error */
823             file->op = H5FD_STDIO_OP_UNKNOWN;
824             file->pos = HADDR_UNDEF;
825             H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_READERROR, "fread failed", -1)
826         } /* end if */
827 
828         if(0 == bytes_read && feof(file->fp)) {
829             /* end of file but not end of format address space */
830             memset((unsigned char *)buf, 0, size);
831             break;
832         } /* end if */
833 
834         size -= bytes_read;
835         addr += (haddr_t)bytes_read;
836         buf = (char *)buf + bytes_read;
837     } /* end while */
838 
839     /* Update the file position data. */
840     file->op = H5FD_STDIO_OP_READ;
841     file->pos = addr;
842 
843     return 0;
844 }
845 
846 
847 /*-------------------------------------------------------------------------
848  * Function:  H5FD_stdio_write
849  *
850  * Purpose:  Writes SIZE bytes from the beginning of BUF into file LF at
851  *    file address ADDR.
852  *
853  * Errors:
854  *    IO    SEEKERROR   fseek failed.
855  *    IO    WRITEERROR  fwrite failed.
856  *
857  * Return:  Non-negative on success/Negative on failure
858  *
859  * Programmer:  Robb Matzke
860  *    Wednesday, October 22, 1997
861  *
862  *-------------------------------------------------------------------------
863  */
864 static herr_t
H5FD_stdio_write(H5FD_t * _file,H5FD_mem_t type,hid_t dxpl_id,haddr_t addr,size_t size,const void * buf)865 H5FD_stdio_write(H5FD_t *_file, H5FD_mem_t /*UNUSED*/ type, hid_t /*UNUSED*/ dxpl_id,
866     haddr_t addr, size_t size, const void *buf)
867 {
868     H5FD_stdio_t    *file = (H5FD_stdio_t*)_file;
869     static const char *func = "H5FD_stdio_write";  /* Function Name for error reporting */
870 
871     /* Quiet the compiler */
872     dxpl_id = dxpl_id;
873     type = type;
874 
875     /* Clear the error stack */
876     H5Eclear2(H5E_DEFAULT);
877 
878     /* Check for overflow conditions */
879     if (HADDR_UNDEF == addr)
880         H5Epush_ret (func, H5E_ERR_CLS, H5E_IO, H5E_OVERFLOW, "file address overflowed", -1)
881     if (REGION_OVERFLOW(addr, size))
882         H5Epush_ret (func, H5E_ERR_CLS, H5E_IO, H5E_OVERFLOW, "file address overflowed", -1)
883 
884     /* Seek to the correct file position. */
885     if ((file->op != H5FD_STDIO_OP_WRITE && file->op != H5FD_STDIO_OP_SEEK) ||
886                 file->pos != addr) {
887         if (file_fseek(file->fp, (file_offset_t)addr, SEEK_SET) < 0) {
888             file->op = H5FD_STDIO_OP_UNKNOWN;
889             file->pos = HADDR_UNDEF;
890             H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_SEEKERROR, "fseek failed", -1)
891         }
892         file->pos = addr;
893     }
894 
895     /* Write the buffer.  On successful return, the file position will be
896      * advanced by the number of bytes read.  On failure, the file position is
897      * undefined.
898      */
899     while(size > 0) {
900 
901         size_t bytes_in        = 0;    /* # of bytes to write  */
902         size_t bytes_wrote     = 0;    /* # of bytes written   */
903         size_t item_size       = 1;    /* size of items in bytes */
904 
905         if(size > H5_STDIO_MAX_IO_BYTES_g)
906             bytes_in = H5_STDIO_MAX_IO_BYTES_g;
907         else
908             bytes_in = size;
909 
910         bytes_wrote = fwrite(buf, item_size, bytes_in, file->fp);
911 
912         if(bytes_wrote != bytes_in || (0 == bytes_wrote && ferror(file->fp))) { /* error */
913             file->op = H5FD_STDIO_OP_UNKNOWN;
914             file->pos = HADDR_UNDEF;
915             H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_WRITEERROR, "fwrite failed", -1)
916         } /* end if */
917 
918         assert(bytes_wrote > 0);
919         assert((size_t)bytes_wrote <= size);
920 
921         size -= bytes_wrote;
922         addr += (haddr_t)bytes_wrote;
923         buf = (const char *)buf + bytes_wrote;
924     }
925 
926     /* Update seek optimizing data. */
927     file->op = H5FD_STDIO_OP_WRITE;
928     file->pos = addr;
929 
930     /* Update EOF if necessary */
931     if (file->pos > file->eof)
932         file->eof = file->pos;
933 
934     return 0;
935 }
936 
937 
938 /*-------------------------------------------------------------------------
939  * Function:  H5FD_stdio_flush
940  *
941  * Purpose:  Makes sure that all data is on disk.
942  *
943  * Errors:
944  *    IO    SEEKERROR     fseek failed.
945  *    IO    WRITEERROR    fflush or fwrite failed.
946  *
947  * Return:  Non-negative on success/Negative on failure
948  *
949  * Programmer:  Robb Matzke
950  *    Wednesday, October 22, 1997
951  *
952  *-------------------------------------------------------------------------
953  */
954 static herr_t
H5FD_stdio_flush(H5FD_t * _file,hid_t dxpl_id,hbool_t closing)955 H5FD_stdio_flush(H5FD_t *_file, hid_t /*UNUSED*/ dxpl_id, hbool_t closing)
956 {
957     H5FD_stdio_t  *file = (H5FD_stdio_t*)_file;
958     static const char *func = "H5FD_stdio_flush";  /* Function Name for error reporting */
959 
960     /* Quiet the compiler */
961     dxpl_id = dxpl_id;
962 
963     /* Clear the error stack */
964     H5Eclear2(H5E_DEFAULT);
965 
966     /* Only try to flush the file if we have write access */
967     if(file->write_access) {
968         if(!closing) {
969             if(fflush(file->fp) < 0)
970                 H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_WRITEERROR, "fflush failed", -1)
971 
972             /* Reset last file I/O information */
973             file->pos = HADDR_UNDEF;
974             file->op = H5FD_STDIO_OP_UNKNOWN;
975         } /* end if */
976     } /* end if */
977 
978     return 0;
979 } /* end H5FD_stdio_flush() */
980 
981 
982 /*-------------------------------------------------------------------------
983  * Function:  H5FD_stdio_truncate
984  *
985  * Purpose:  Makes sure that the true file size is the same (or larger)
986  *    than the end-of-address.
987  *
988  * Errors:
989  *    IO    SEEKERROR     fseek failed.
990  *    IO    WRITEERROR    fflush or fwrite failed.
991  *
992  * Return:  Non-negative on success/Negative on failure
993  *
994  * Programmer:  Quincey Koziol
995  *    Thursday, January 31, 2008
996  *
997  *-------------------------------------------------------------------------
998  */
999 static herr_t
H5FD_stdio_truncate(H5FD_t * _file,hid_t dxpl_id,hbool_t closing)1000 H5FD_stdio_truncate(H5FD_t *_file, hid_t /*UNUSED*/ dxpl_id,
1001     hbool_t /*UNUSED*/ closing)
1002 {
1003     H5FD_stdio_t  *file = (H5FD_stdio_t*)_file;
1004     static const char *func = "H5FD_stdio_truncate";  /* Function Name for error reporting */
1005 
1006     /* Quiet the compiler */
1007     dxpl_id = dxpl_id;
1008     closing = closing;
1009 
1010     /* Clear the error stack */
1011     H5Eclear2(H5E_DEFAULT);
1012 
1013     /* Only try to flush the file if we have write access */
1014     if(file->write_access) {
1015         /* Makes sure that the true file size is the same as the end-of-address. */
1016         if(file->eoa != file->eof) {
1017 
1018 #ifdef H5_HAVE_WIN32_API
1019             LARGE_INTEGER   li;         /* 64-bit (union) integer for SetFilePointer() call */
1020             DWORD           dwPtrLow;   /* Low-order pointer bits from SetFilePointer()
1021                                          * Only used as an error code here.
1022                                          */
1023             DWORD           dwError;    /* DWORD error code from GetLastError() */
1024             BOOL            bError;     /* Boolean error flag */
1025 
1026             /* Reset seek offset to beginning of file, so that file isn't re-extended later */
1027             rewind(file->fp);
1028 
1029             /* Windows uses this odd QuadPart union for 32/64-bit portability */
1030             li.QuadPart = (__int64)file->eoa;
1031 
1032             /* Extend the file to make sure it's large enough.
1033              *
1034              * Since INVALID_SET_FILE_POINTER can technically be a valid return value
1035              * from SetFilePointer(), we also need to check GetLastError().
1036              */
1037             dwPtrLow = SetFilePointer(file->hFile, li.LowPart, &li.HighPart, FILE_BEGIN);
1038             if(INVALID_SET_FILE_POINTER == dwPtrLow) {
1039                 dwError = GetLastError();
1040                 if(dwError != NO_ERROR )
1041                     H5Epush_ret(func, H5E_ERR_CLS, H5E_FILE, H5E_FILEOPEN, "unable to set file pointer", -1)
1042             }
1043 
1044             bError = SetEndOfFile(file->hFile);
1045             if(0 == bError)
1046                 H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_SEEKERROR, "unable to truncate/extend file properly", -1)
1047 #else /* H5_HAVE_WIN32_API */
1048             /* Reset seek offset to beginning of file, so that file isn't re-extended later */
1049             rewind(file->fp);
1050 
1051             /* Truncate file to proper length */
1052             if(-1 == file_ftruncate(file->fd, (file_offset_t)file->eoa))
1053                 H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_SEEKERROR, "unable to truncate/extend file properly", -1)
1054 #endif /* H5_HAVE_WIN32_API */
1055 
1056             /* Update the eof value */
1057             file->eof = file->eoa;
1058 
1059             /* Reset last file I/O information */
1060             file->pos = HADDR_UNDEF;
1061             file->op = H5FD_STDIO_OP_UNKNOWN;
1062         } /* end if */
1063     } /* end if */
1064     else {
1065         /* Double-check for problems */
1066         if(file->eoa > file->eof)
1067             H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_TRUNCATED, "eoa > eof!", -1)
1068     } /* end else */
1069 
1070     return 0;
1071 } /* end H5FD_stdio_truncate() */
1072 
1073 
1074 /*-------------------------------------------------------------------------
1075  * Function:    H5FD_stdio_lock
1076  *
1077  * Purpose:     Lock a file via flock
1078  *              NOTE: This function is a no-op if flock() is not present.
1079  *
1080  * Errors:
1081  *    IO    FCNTL    flock failed.
1082  *
1083  * Return:      Non-negative on success/Negative on failure
1084  *
1085  * Programmer:  Vailin Choi; March 2015
1086  *
1087  *-------------------------------------------------------------------------
1088  */
1089 static herr_t
H5FD_stdio_lock(H5FD_t * _file,hbool_t rw)1090 H5FD_stdio_lock(H5FD_t *_file, hbool_t rw)
1091 {
1092 #ifdef H5_HAVE_FLOCK
1093     H5FD_stdio_t  *file = (H5FD_stdio_t*)_file;     /* VFD file struct                      */
1094     int lock_flags;                                 /* file locking flags                   */
1095     static const char *func = "H5FD_stdio_lock";  	/* Function Name for error reporting    */
1096 
1097     /* Clear the error stack */
1098     H5Eclear2(H5E_DEFAULT);
1099 
1100     assert(file);
1101 
1102     /* Set exclusive or shared lock based on rw status */
1103     lock_flags = rw ? LOCK_EX : LOCK_SH;
1104 
1105     /* Place a non-blocking lock on the file */
1106     if(flock(file->fd, lock_flags | LOCK_NB) < 0) {
1107         if(ENOSYS == errno)
1108             H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_FCNTL, "file locking disabled on this file system (use HDF5_USE_FILE_LOCKING environment variable to override)", -1)
1109         else
1110             H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_FCNTL, "file lock failed", -1)
1111     } /* end if */
1112 
1113     /* Flush the stream */
1114     if(fflush(file->fp) < 0)
1115         H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_WRITEERROR, "fflush failed", -1)
1116 
1117 #endif /* H5_HAVE_FLOCK */
1118 
1119     return 0;
1120 } /* end H5FD_stdio_lock() */
1121 
1122 /*-------------------------------------------------------------------------
1123  * Function:    H5F_stdio_unlock
1124  *
1125  * Purpose:     Unlock a file via flock
1126  *              NOTE: This function is a no-op if flock() is not present.
1127  *
1128  * Errors:
1129  *    IO    FCNTL    flock failed.
1130  *
1131  * Return:      Non-negative on success/Negative on failure
1132  *
1133  * Programmer:  Vailin Choi; March 2015
1134  *
1135  *-------------------------------------------------------------------------
1136  */
1137 static herr_t
H5FD_stdio_unlock(H5FD_t * _file)1138 H5FD_stdio_unlock(H5FD_t *_file)
1139 {
1140 #ifdef H5_HAVE_FLOCK
1141     H5FD_stdio_t  *file = (H5FD_stdio_t*)_file;         /* VFD file struct                      */
1142     static const char *func = "H5FD_stdio_unlock";  	/* Function Name for error reporting    */
1143 
1144     /* Clear the error stack */
1145     H5Eclear2(H5E_DEFAULT);
1146 
1147     assert(file);
1148 
1149     /* Flush the stream */
1150     if(fflush(file->fp) < 0)
1151         H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_WRITEERROR, "fflush failed", -1)
1152 
1153     /* Place a non-blocking lock on the file */
1154     if(flock(file->fd, LOCK_UN) < 0) {
1155         if(ENOSYS == errno)
1156             H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_FCNTL, "file locking disabled on this file system (use HDF5_USE_FILE_LOCKING environment variable to override)", -1)
1157         else
1158             H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_FCNTL, "file unlock failed", -1)
1159     } /* end if */
1160 
1161 #endif /* H5_HAVE_FLOCK */
1162 
1163     return 0;
1164 } /* end H5FD_stdio_unlock() */
1165 
1166 
1167 #ifdef _H5private_H
1168 /*
1169  * This is not related to the functionality of the driver code.
1170  * It is added here to trigger warning if HDF5 private definitions are included
1171  * by mistake.  The code should use only HDF5 public API and definitions.
1172  */
1173 #error "Do not use HDF5 private definitions"
1174 #endif
1175 
1176