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