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://www.hdfgroup.org/licenses. *
10 * If you do not have access to either file, you may request a copy from *
11 * help@hdfgroup.org. *
12 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
13
14 /*
15 * Programmer: Robb Matzke
16 * Thursday, July 29, 1999
17 *
18 * Purpose: The POSIX unbuffered file driver using only the HDF5 public
19 * API and with a few optimizations: the lseek() call is made
20 * only when the current file position is unknown or needs to be
21 * changed based on previous I/O through this driver (don't mix
22 * I/O from this driver with I/O from other parts of the
23 * application to the same file).
24 */
25
26 #include "H5FDdrvr_module.h" /* This source code file is part of the H5FD driver module */
27
28 #include "H5private.h" /* Generic Functions */
29 #include "H5Eprivate.h" /* Error handling */
30 #include "H5Fprivate.h" /* File access */
31 #include "H5FDprivate.h" /* File drivers */
32 #include "H5FDsec2.h" /* Sec2 file driver */
33 #include "H5FLprivate.h" /* Free Lists */
34 #include "H5Iprivate.h" /* IDs */
35 #include "H5MMprivate.h" /* Memory management */
36 #include "H5Pprivate.h" /* Property lists */
37
38 /* The driver identification number, initialized at runtime */
39 static hid_t H5FD_SEC2_g = 0;
40
41 /* Whether to ignore file locks when disabled (env var value) */
42 static htri_t ignore_disabled_file_locks_s = FAIL;
43
44 /* The description of a file belonging to this driver. The 'eoa' and 'eof'
45 * determine the amount of hdf5 address space in use and the high-water mark
46 * of the file (the current size of the underlying filesystem file). The
47 * 'pos' value is used to eliminate file position updates when they would be a
48 * no-op. Unfortunately we've found systems that use separate file position
49 * indicators for reading and writing so the lseek can only be eliminated if
50 * the current operation is the same as the previous operation. When opening
51 * a file the 'eof' will be set to the current file size, `eoa' will be set
52 * to zero, 'pos' will be set to H5F_ADDR_UNDEF (as it is when an error
53 * occurs), and 'op' will be set to H5F_OP_UNKNOWN.
54 */
55 typedef struct H5FD_sec2_t {
56 H5FD_t pub; /* public stuff, must be first */
57 int fd; /* the filesystem file descriptor */
58 haddr_t eoa; /* end of allocated region */
59 haddr_t eof; /* end of file; current file size */
60 haddr_t pos; /* current file I/O position */
61 H5FD_file_op_t op; /* last operation */
62 hbool_t ignore_disabled_file_locks;
63 char filename[H5FD_MAX_FILENAME_LEN]; /* Copy of file name from open operation */
64 #ifndef H5_HAVE_WIN32_API
65 /* On most systems the combination of device and i-node number uniquely
66 * identify a file. Note that Cygwin, MinGW and other Windows POSIX
67 * environments have the stat function (which fakes inodes)
68 * and will use the 'device + inodes' scheme as opposed to the
69 * Windows code further below.
70 */
71 dev_t device; /* file device number */
72 ino_t inode; /* file i-node number */
73 #else
74 /* Files in windows are uniquely identified by the volume serial
75 * number and the file index (both low and high parts).
76 *
77 * There are caveats where these numbers can change, especially
78 * on FAT file systems. On NTFS, however, a file should keep
79 * those numbers the same until renamed or deleted (though you
80 * can use ReplaceFile() on NTFS to keep the numbers the same
81 * while renaming).
82 *
83 * See the MSDN "BY_HANDLE_FILE_INFORMATION Structure" entry for
84 * more information.
85 *
86 * http://msdn.microsoft.com/en-us/library/aa363788(v=VS.85).aspx
87 */
88 DWORD nFileIndexLow;
89 DWORD nFileIndexHigh;
90 DWORD dwVolumeSerialNumber;
91
92 HANDLE hFile; /* Native windows file handle */
93 #endif /* H5_HAVE_WIN32_API */
94
95 /* Information from properties set by 'h5repart' tool
96 *
97 * Whether to eliminate the family driver info and convert this file to
98 * a single file.
99 */
100 hbool_t fam_to_single;
101 } H5FD_sec2_t;
102
103 /*
104 * These macros check for overflow of various quantities. These macros
105 * assume that HDoff_t is signed and haddr_t and size_t are unsigned.
106 *
107 * ADDR_OVERFLOW: Checks whether a file address of type `haddr_t'
108 * is too large to be represented by the second argument
109 * of the file seek function.
110 *
111 * SIZE_OVERFLOW: Checks whether a buffer size of type `hsize_t' is too
112 * large to be represented by the `size_t' type.
113 *
114 * REGION_OVERFLOW: Checks whether an address and size pair describe data
115 * which can be addressed entirely by the second
116 * argument of the file seek function.
117 */
118 #define MAXADDR (((haddr_t)1 << (8 * sizeof(HDoff_t) - 1)) - 1)
119 #define ADDR_OVERFLOW(A) (HADDR_UNDEF == (A) || ((A) & ~(haddr_t)MAXADDR))
120 #define SIZE_OVERFLOW(Z) ((Z) & ~(hsize_t)MAXADDR)
121 #define REGION_OVERFLOW(A, Z) \
122 (ADDR_OVERFLOW(A) || SIZE_OVERFLOW(Z) || HADDR_UNDEF == (A) + (Z) || (HDoff_t)((A) + (Z)) < (HDoff_t)(A))
123
124 /* Prototypes */
125 static herr_t H5FD__sec2_term(void);
126 static H5FD_t *H5FD__sec2_open(const char *name, unsigned flags, hid_t fapl_id, haddr_t maxaddr);
127 static herr_t H5FD__sec2_close(H5FD_t *_file);
128 static int H5FD__sec2_cmp(const H5FD_t *_f1, const H5FD_t *_f2);
129 static herr_t H5FD__sec2_query(const H5FD_t *_f1, unsigned long *flags);
130 static haddr_t H5FD__sec2_get_eoa(const H5FD_t *_file, H5FD_mem_t type);
131 static herr_t H5FD__sec2_set_eoa(H5FD_t *_file, H5FD_mem_t type, haddr_t addr);
132 static haddr_t H5FD__sec2_get_eof(const H5FD_t *_file, H5FD_mem_t type);
133 static herr_t H5FD__sec2_get_handle(H5FD_t *_file, hid_t fapl, void **file_handle);
134 static herr_t H5FD__sec2_read(H5FD_t *_file, H5FD_mem_t type, hid_t fapl_id, haddr_t addr, size_t size,
135 void *buf);
136 static herr_t H5FD__sec2_write(H5FD_t *_file, H5FD_mem_t type, hid_t fapl_id, haddr_t addr, size_t size,
137 const void *buf);
138 static herr_t H5FD__sec2_truncate(H5FD_t *_file, hid_t dxpl_id, hbool_t closing);
139 static herr_t H5FD__sec2_lock(H5FD_t *_file, hbool_t rw);
140 static herr_t H5FD__sec2_unlock(H5FD_t *_file);
141
142 static const H5FD_class_t H5FD_sec2_g = {
143 "sec2", /* name */
144 MAXADDR, /* maxaddr */
145 H5F_CLOSE_WEAK, /* fc_degree */
146 H5FD__sec2_term, /* terminate */
147 NULL, /* sb_size */
148 NULL, /* sb_encode */
149 NULL, /* sb_decode */
150 0, /* fapl_size */
151 NULL, /* fapl_get */
152 NULL, /* fapl_copy */
153 NULL, /* fapl_free */
154 0, /* dxpl_size */
155 NULL, /* dxpl_copy */
156 NULL, /* dxpl_free */
157 H5FD__sec2_open, /* open */
158 H5FD__sec2_close, /* close */
159 H5FD__sec2_cmp, /* cmp */
160 H5FD__sec2_query, /* query */
161 NULL, /* get_type_map */
162 NULL, /* alloc */
163 NULL, /* free */
164 H5FD__sec2_get_eoa, /* get_eoa */
165 H5FD__sec2_set_eoa, /* set_eoa */
166 H5FD__sec2_get_eof, /* get_eof */
167 H5FD__sec2_get_handle, /* get_handle */
168 H5FD__sec2_read, /* read */
169 H5FD__sec2_write, /* write */
170 NULL, /* flush */
171 H5FD__sec2_truncate, /* truncate */
172 H5FD__sec2_lock, /* lock */
173 H5FD__sec2_unlock, /* unlock */
174 H5FD_FLMAP_DICHOTOMY /* fl_map */
175 };
176
177 /* Declare a free list to manage the H5FD_sec2_t struct */
178 H5FL_DEFINE_STATIC(H5FD_sec2_t);
179
180 /*-------------------------------------------------------------------------
181 * Function: H5FD__init_package
182 *
183 * Purpose: Initializes any interface-specific data or routines.
184 *
185 * Return: Non-negative on success/Negative on failure
186 *
187 *-------------------------------------------------------------------------
188 */
189 static herr_t
H5FD__init_package(void)190 H5FD__init_package(void)
191 {
192 char * lock_env_var = NULL; /* Environment variable pointer */
193 herr_t ret_value = SUCCEED;
194
195 FUNC_ENTER_STATIC
196
197 /* Check the use disabled file locks environment variable */
198 lock_env_var = HDgetenv("HDF5_USE_FILE_LOCKING");
199 if (lock_env_var && !HDstrcmp(lock_env_var, "BEST_EFFORT"))
200 ignore_disabled_file_locks_s = TRUE; /* Override: Ignore disabled locks */
201 else if (lock_env_var && (!HDstrcmp(lock_env_var, "TRUE") || !HDstrcmp(lock_env_var, "1")))
202 ignore_disabled_file_locks_s = FALSE; /* Override: Don't ignore disabled locks */
203 else
204 ignore_disabled_file_locks_s = FAIL; /* Environment variable not set, or not set correctly */
205
206 if (H5FD_sec2_init() < 0)
207 HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "unable to initialize sec2 VFD")
208
209 done:
210 FUNC_LEAVE_NOAPI(ret_value)
211 } /* H5FD__init_package() */
212
213 /*-------------------------------------------------------------------------
214 * Function: H5FD_sec2_init
215 *
216 * Purpose: Initialize this driver by registering the driver with the
217 * library.
218 *
219 * Return: Success: The driver ID for the sec2 driver
220 * Failure: H5I_INVALID_HID
221 *
222 * Programmer: Robb Matzke
223 * Thursday, July 29, 1999
224 *
225 *-------------------------------------------------------------------------
226 */
227 hid_t
H5FD_sec2_init(void)228 H5FD_sec2_init(void)
229 {
230 hid_t ret_value = H5I_INVALID_HID; /* Return value */
231
232 FUNC_ENTER_NOAPI(H5I_INVALID_HID)
233
234 if (H5I_VFL != H5I_get_type(H5FD_SEC2_g))
235 H5FD_SEC2_g = H5FD_register(&H5FD_sec2_g, sizeof(H5FD_class_t), FALSE);
236
237 /* Set return value */
238 ret_value = H5FD_SEC2_g;
239
240 done:
241 FUNC_LEAVE_NOAPI(ret_value)
242 } /* end H5FD_sec2_init() */
243
244 /*---------------------------------------------------------------------------
245 * Function: H5FD__sec2_term
246 *
247 * Purpose: Shut down the VFD
248 *
249 * Returns: SUCCEED (Can't fail)
250 *
251 * Programmer: Quincey Koziol
252 * Friday, Jan 30, 2004
253 *
254 *---------------------------------------------------------------------------
255 */
256 static herr_t
H5FD__sec2_term(void)257 H5FD__sec2_term(void)
258 {
259 FUNC_ENTER_STATIC_NOERR
260
261 /* Reset VFL ID */
262 H5FD_SEC2_g = 0;
263
264 FUNC_LEAVE_NOAPI(SUCCEED)
265 } /* end H5FD__sec2_term() */
266
267 /*-------------------------------------------------------------------------
268 * Function: H5Pset_fapl_sec2
269 *
270 * Purpose: Modify the file access property list to use the H5FD_SEC2
271 * driver defined in this source file. There are no driver
272 * specific properties.
273 *
274 * Return: SUCCEED/FAIL
275 *
276 * Programmer: Robb Matzke
277 * Thursday, February 19, 1998
278 *
279 *-------------------------------------------------------------------------
280 */
281 herr_t
H5Pset_fapl_sec2(hid_t fapl_id)282 H5Pset_fapl_sec2(hid_t fapl_id)
283 {
284 H5P_genplist_t *plist; /* Property list pointer */
285 herr_t ret_value;
286
287 FUNC_ENTER_API(FAIL)
288 H5TRACE1("e", "i", fapl_id);
289
290 if (NULL == (plist = H5P_object_verify(fapl_id, H5P_FILE_ACCESS)))
291 HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access property list")
292
293 ret_value = H5P_set_driver(plist, H5FD_SEC2, NULL);
294
295 done:
296 FUNC_LEAVE_API(ret_value)
297 } /* end H5Pset_fapl_sec2() */
298
299 /*-------------------------------------------------------------------------
300 * Function: H5FD__sec2_open
301 *
302 * Purpose: Create and/or opens a file as an HDF5 file.
303 *
304 * Return: Success: A pointer to a new file data structure. The
305 * public fields will be initialized by the
306 * caller, which is always H5FD_open().
307 * Failure: NULL
308 *
309 * Programmer: Robb Matzke
310 * Thursday, July 29, 1999
311 *
312 *-------------------------------------------------------------------------
313 */
314 static H5FD_t *
H5FD__sec2_open(const char * name,unsigned flags,hid_t fapl_id,haddr_t maxaddr)315 H5FD__sec2_open(const char *name, unsigned flags, hid_t fapl_id, haddr_t maxaddr)
316 {
317 H5FD_sec2_t *file = NULL; /* sec2 VFD info */
318 int fd = -1; /* File descriptor */
319 int o_flags; /* Flags for open() call */
320 #ifdef H5_HAVE_WIN32_API
321 struct _BY_HANDLE_FILE_INFORMATION fileinfo;
322 #endif
323 h5_stat_t sb;
324 H5P_genplist_t *plist; /* Property list pointer */
325 H5FD_t * ret_value = NULL; /* Return value */
326
327 FUNC_ENTER_STATIC
328
329 /* Sanity check on file offsets */
330 HDcompile_assert(sizeof(HDoff_t) >= sizeof(size_t));
331
332 /* Check arguments */
333 if (!name || !*name)
334 HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "invalid file name")
335 if (0 == maxaddr || HADDR_UNDEF == maxaddr)
336 HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, NULL, "bogus maxaddr")
337 if (ADDR_OVERFLOW(maxaddr))
338 HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, NULL, "bogus maxaddr")
339
340 /* Build the open flags */
341 o_flags = (H5F_ACC_RDWR & flags) ? O_RDWR : O_RDONLY;
342 if (H5F_ACC_TRUNC & flags)
343 o_flags |= O_TRUNC;
344 if (H5F_ACC_CREAT & flags)
345 o_flags |= O_CREAT;
346 if (H5F_ACC_EXCL & flags)
347 o_flags |= O_EXCL;
348
349 /* Open the file */
350 if ((fd = HDopen(name, o_flags, H5_POSIX_CREATE_MODE_RW)) < 0) {
351 int myerrno = errno;
352 HGOTO_ERROR(
353 H5E_FILE, H5E_CANTOPENFILE, NULL,
354 "unable to open file: name = '%s', errno = %d, error message = '%s', flags = %x, o_flags = %x",
355 name, myerrno, HDstrerror(myerrno), flags, (unsigned)o_flags);
356 } /* end if */
357
358 if (HDfstat(fd, &sb) < 0)
359 HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, NULL, "unable to fstat file")
360
361 /* Create the new file struct */
362 if (NULL == (file = H5FL_CALLOC(H5FD_sec2_t)))
363 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "unable to allocate file struct")
364
365 file->fd = fd;
366 H5_CHECKED_ASSIGN(file->eof, haddr_t, sb.st_size, h5_stat_size_t);
367 file->pos = HADDR_UNDEF;
368 file->op = OP_UNKNOWN;
369 #ifdef H5_HAVE_WIN32_API
370 file->hFile = (HANDLE)_get_osfhandle(fd);
371 if (INVALID_HANDLE_VALUE == file->hFile)
372 HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to get Windows file handle")
373
374 if (!GetFileInformationByHandle((HANDLE)file->hFile, &fileinfo))
375 HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to get Windows file information")
376
377 file->nFileIndexHigh = fileinfo.nFileIndexHigh;
378 file->nFileIndexLow = fileinfo.nFileIndexLow;
379 file->dwVolumeSerialNumber = fileinfo.dwVolumeSerialNumber;
380 #else /* H5_HAVE_WIN32_API */
381 file->device = sb.st_dev;
382 file->inode = sb.st_ino;
383 #endif /* H5_HAVE_WIN32_API */
384
385 /* Get the FAPL */
386 if (NULL == (plist = (H5P_genplist_t *)H5I_object(fapl_id)))
387 HGOTO_ERROR(H5E_VFL, H5E_BADTYPE, NULL, "not a file access property list")
388
389 /* Check the file locking flags in the fapl */
390 if (ignore_disabled_file_locks_s != FAIL)
391 /* The environment variable was set, so use that preferentially */
392 file->ignore_disabled_file_locks = ignore_disabled_file_locks_s;
393 else {
394 /* Use the value in the property list */
395 if (H5P_get(plist, H5F_ACS_IGNORE_DISABLED_FILE_LOCKS_NAME, &file->ignore_disabled_file_locks) < 0)
396 HGOTO_ERROR(H5E_VFL, H5E_CANTGET, NULL, "can't get ignore disabled file locks property")
397 }
398
399 /* Retain a copy of the name used to open the file, for possible error reporting */
400 HDstrncpy(file->filename, name, sizeof(file->filename));
401 file->filename[sizeof(file->filename) - 1] = '\0';
402
403 /* Check for non-default FAPL */
404 if (H5P_FILE_ACCESS_DEFAULT != fapl_id) {
405
406 /* This step is for h5repart tool only. If user wants to change file driver from
407 * family to one that uses single files (sec2, etc.) while using h5repart, this
408 * private property should be set so that in the later step, the library can ignore
409 * the family driver information saved in the superblock.
410 */
411 if (H5P_exist_plist(plist, H5F_ACS_FAMILY_TO_SINGLE_NAME) > 0)
412 if (H5P_get(plist, H5F_ACS_FAMILY_TO_SINGLE_NAME, &file->fam_to_single) < 0)
413 HGOTO_ERROR(H5E_VFL, H5E_CANTGET, NULL, "can't get property of changing family to single")
414 } /* end if */
415
416 /* Set return value */
417 ret_value = (H5FD_t *)file;
418
419 done:
420 if (NULL == ret_value) {
421 if (fd >= 0)
422 HDclose(fd);
423 if (file)
424 file = H5FL_FREE(H5FD_sec2_t, file);
425 } /* end if */
426
427 FUNC_LEAVE_NOAPI(ret_value)
428 } /* end H5FD__sec2_open() */
429
430 /*-------------------------------------------------------------------------
431 * Function: H5FD__sec2_close
432 *
433 * Purpose: Closes an HDF5 file.
434 *
435 * Return: Success: SUCCEED
436 * Failure: FAIL, file not closed.
437 *
438 * Programmer: Robb Matzke
439 * Thursday, July 29, 1999
440 *
441 *-------------------------------------------------------------------------
442 */
443 static herr_t
H5FD__sec2_close(H5FD_t * _file)444 H5FD__sec2_close(H5FD_t *_file)
445 {
446 H5FD_sec2_t *file = (H5FD_sec2_t *)_file;
447 herr_t ret_value = SUCCEED; /* Return value */
448
449 FUNC_ENTER_STATIC
450
451 /* Sanity check */
452 HDassert(file);
453
454 /* Close the underlying file */
455 if (HDclose(file->fd) < 0)
456 HSYS_GOTO_ERROR(H5E_IO, H5E_CANTCLOSEFILE, FAIL, "unable to close file")
457
458 /* Release the file info */
459 file = H5FL_FREE(H5FD_sec2_t, file);
460
461 done:
462 FUNC_LEAVE_NOAPI(ret_value)
463 } /* end H5FD__sec2_close() */
464
465 /*-------------------------------------------------------------------------
466 * Function: H5FD__sec2_cmp
467 *
468 * Purpose: Compares two files belonging to this driver using an
469 * arbitrary (but consistent) ordering.
470 *
471 * Return: Success: A value like strcmp()
472 * Failure: never fails (arguments were checked by the
473 * caller).
474 *
475 * Programmer: Robb Matzke
476 * Thursday, July 29, 1999
477 *
478 *-------------------------------------------------------------------------
479 */
480 static int
H5FD__sec2_cmp(const H5FD_t * _f1,const H5FD_t * _f2)481 H5FD__sec2_cmp(const H5FD_t *_f1, const H5FD_t *_f2)
482 {
483 const H5FD_sec2_t *f1 = (const H5FD_sec2_t *)_f1;
484 const H5FD_sec2_t *f2 = (const H5FD_sec2_t *)_f2;
485 int ret_value = 0;
486
487 FUNC_ENTER_STATIC_NOERR
488
489 #ifdef H5_HAVE_WIN32_API
490 if (f1->dwVolumeSerialNumber < f2->dwVolumeSerialNumber)
491 HGOTO_DONE(-1)
492 if (f1->dwVolumeSerialNumber > f2->dwVolumeSerialNumber)
493 HGOTO_DONE(1)
494
495 if (f1->nFileIndexHigh < f2->nFileIndexHigh)
496 HGOTO_DONE(-1)
497 if (f1->nFileIndexHigh > f2->nFileIndexHigh)
498 HGOTO_DONE(1)
499
500 if (f1->nFileIndexLow < f2->nFileIndexLow)
501 HGOTO_DONE(-1)
502 if (f1->nFileIndexLow > f2->nFileIndexLow)
503 HGOTO_DONE(1)
504 #else /* H5_HAVE_WIN32_API */
505 #ifdef H5_DEV_T_IS_SCALAR
506 if (f1->device < f2->device)
507 HGOTO_DONE(-1)
508 if (f1->device > f2->device)
509 HGOTO_DONE(1)
510 #else /* H5_DEV_T_IS_SCALAR */
511 /* If dev_t isn't a scalar value on this system, just use memcmp to
512 * determine if the values are the same or not. The actual return value
513 * shouldn't really matter...
514 */
515 if (HDmemcmp(&(f1->device), &(f2->device), sizeof(dev_t)) < 0)
516 HGOTO_DONE(-1)
517 if (HDmemcmp(&(f1->device), &(f2->device), sizeof(dev_t)) > 0)
518 HGOTO_DONE(1)
519 #endif /* H5_DEV_T_IS_SCALAR */
520 if (f1->inode < f2->inode)
521 HGOTO_DONE(-1)
522 if (f1->inode > f2->inode)
523 HGOTO_DONE(1)
524 #endif /* H5_HAVE_WIN32_API */
525
526 done:
527 FUNC_LEAVE_NOAPI(ret_value)
528 } /* end H5FD__sec2_cmp() */
529
530 /*-------------------------------------------------------------------------
531 * Function: H5FD__sec2_query
532 *
533 * Purpose: Set the flags that this VFL driver is capable of supporting.
534 * (listed in H5FDpublic.h)
535 *
536 * Return: SUCCEED (Can't fail)
537 *
538 * Programmer: Quincey Koziol
539 * Friday, August 25, 2000
540 *
541 *-------------------------------------------------------------------------
542 */
543 static herr_t
H5FD__sec2_query(const H5FD_t * _file,unsigned long * flags)544 H5FD__sec2_query(const H5FD_t *_file, unsigned long *flags /* out */)
545 {
546 const H5FD_sec2_t *file = (const H5FD_sec2_t *)_file; /* sec2 VFD info */
547
548 FUNC_ENTER_STATIC_NOERR
549
550 /* Set the VFL feature flags that this driver supports */
551 /* Notice: the Mirror VFD Writer currently uses only the Sec2 driver as
552 * the underying driver -- as such, the Mirror VFD implementation copies
553 * these feature flags as its own. Any modifications made here must be
554 * reflected in H5FDmirror.c
555 * -- JOS 2020-01-13
556 */
557 if (flags) {
558 *flags = 0;
559 *flags |= H5FD_FEAT_AGGREGATE_METADATA; /* OK to aggregate metadata allocations */
560 *flags |= H5FD_FEAT_ACCUMULATE_METADATA; /* OK to accumulate metadata for faster writes */
561 *flags |= H5FD_FEAT_DATA_SIEVE; /* OK to perform data sieving for faster raw data reads & writes */
562 *flags |= H5FD_FEAT_AGGREGATE_SMALLDATA; /* OK to aggregate "small" raw data allocations */
563 *flags |= H5FD_FEAT_POSIX_COMPAT_HANDLE; /* get_handle callback returns a POSIX file descriptor */
564 *flags |=
565 H5FD_FEAT_SUPPORTS_SWMR_IO; /* VFD supports the single-writer/multiple-readers (SWMR) pattern */
566 *flags |= H5FD_FEAT_DEFAULT_VFD_COMPATIBLE; /* VFD creates a file which can be opened with the default
567 VFD */
568
569 /* Check for flags that are set by h5repart */
570 if (file && file->fam_to_single)
571 *flags |= H5FD_FEAT_IGNORE_DRVRINFO; /* Ignore the driver info when file is opened (which
572 eliminates it) */
573 } /* end if */
574
575 FUNC_LEAVE_NOAPI(SUCCEED)
576 } /* end H5FD__sec2_query() */
577
578 /*-------------------------------------------------------------------------
579 * Function: H5FD__sec2_get_eoa
580 *
581 * Purpose: Gets the end-of-address marker for the file. The EOA marker
582 * is the first address past the last byte allocated in the
583 * format address space.
584 *
585 * Return: The end-of-address marker.
586 *
587 * Programmer: Robb Matzke
588 * Monday, August 2, 1999
589 *
590 *-------------------------------------------------------------------------
591 */
592 static haddr_t
H5FD__sec2_get_eoa(const H5FD_t * _file,H5FD_mem_t H5_ATTR_UNUSED type)593 H5FD__sec2_get_eoa(const H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type)
594 {
595 const H5FD_sec2_t *file = (const H5FD_sec2_t *)_file;
596
597 FUNC_ENTER_STATIC_NOERR
598
599 FUNC_LEAVE_NOAPI(file->eoa)
600 } /* end H5FD__sec2_get_eoa() */
601
602 /*-------------------------------------------------------------------------
603 * Function: H5FD__sec2_set_eoa
604 *
605 * Purpose: Set the end-of-address marker for the file. This function is
606 * called shortly after an existing HDF5 file is opened in order
607 * to tell the driver where the end of the HDF5 data is located.
608 *
609 * Return: SUCCEED (Can't fail)
610 *
611 * Programmer: Robb Matzke
612 * Thursday, July 29, 1999
613 *
614 *-------------------------------------------------------------------------
615 */
616 static herr_t
H5FD__sec2_set_eoa(H5FD_t * _file,H5FD_mem_t H5_ATTR_UNUSED type,haddr_t addr)617 H5FD__sec2_set_eoa(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, haddr_t addr)
618 {
619 H5FD_sec2_t *file = (H5FD_sec2_t *)_file;
620
621 FUNC_ENTER_STATIC_NOERR
622
623 file->eoa = addr;
624
625 FUNC_LEAVE_NOAPI(SUCCEED)
626 } /* end H5FD__sec2_set_eoa() */
627
628 /*-------------------------------------------------------------------------
629 * Function: H5FD__sec2_get_eof
630 *
631 * Purpose: Returns the end-of-file marker, which is the greater of
632 * either the filesystem end-of-file or the HDF5 end-of-address
633 * markers.
634 *
635 * Return: End of file address, the first address past the end of the
636 * "file", either the filesystem file or the HDF5 file.
637 *
638 * Programmer: Robb Matzke
639 * Thursday, July 29, 1999
640 *
641 *-------------------------------------------------------------------------
642 */
643 static haddr_t
H5FD__sec2_get_eof(const H5FD_t * _file,H5FD_mem_t H5_ATTR_UNUSED type)644 H5FD__sec2_get_eof(const H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type)
645 {
646 const H5FD_sec2_t *file = (const H5FD_sec2_t *)_file;
647
648 FUNC_ENTER_STATIC_NOERR
649
650 FUNC_LEAVE_NOAPI(file->eof)
651 } /* end H5FD__sec2_get_eof() */
652
653 /*-------------------------------------------------------------------------
654 * Function: H5FD__sec2_get_handle
655 *
656 * Purpose: Returns the file handle of sec2 file driver.
657 *
658 * Returns: SUCCEED/FAIL
659 *
660 * Programmer: Raymond Lu
661 * Sept. 16, 2002
662 *
663 *-------------------------------------------------------------------------
664 */
665 static herr_t
H5FD__sec2_get_handle(H5FD_t * _file,hid_t H5_ATTR_UNUSED fapl,void ** file_handle)666 H5FD__sec2_get_handle(H5FD_t *_file, hid_t H5_ATTR_UNUSED fapl, void **file_handle)
667 {
668 H5FD_sec2_t *file = (H5FD_sec2_t *)_file;
669 herr_t ret_value = SUCCEED;
670
671 FUNC_ENTER_STATIC
672
673 if (!file_handle)
674 HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file handle not valid")
675
676 *file_handle = &(file->fd);
677
678 done:
679 FUNC_LEAVE_NOAPI(ret_value)
680 } /* end H5FD__sec2_get_handle() */
681
682 /*-------------------------------------------------------------------------
683 * Function: H5FD__sec2_read
684 *
685 * Purpose: Reads SIZE bytes of data from FILE beginning at address ADDR
686 * into buffer BUF according to data transfer properties in
687 * DXPL_ID.
688 *
689 * Return: Success: SUCCEED. Result is stored in caller-supplied
690 * buffer BUF.
691 * Failure: FAIL, Contents of buffer BUF are undefined.
692 *
693 * Programmer: Robb Matzke
694 * Thursday, July 29, 1999
695 *
696 *-------------------------------------------------------------------------
697 */
698 static herr_t
H5FD__sec2_read(H5FD_t * _file,H5FD_mem_t H5_ATTR_UNUSED type,hid_t H5_ATTR_UNUSED dxpl_id,haddr_t addr,size_t size,void * buf)699 H5FD__sec2_read(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, hid_t H5_ATTR_UNUSED dxpl_id, haddr_t addr,
700 size_t size, void *buf /*out*/)
701 {
702 H5FD_sec2_t *file = (H5FD_sec2_t *)_file;
703 HDoff_t offset = (HDoff_t)addr;
704 herr_t ret_value = SUCCEED; /* Return value */
705
706 FUNC_ENTER_STATIC
707
708 HDassert(file && file->pub.cls);
709 HDassert(buf);
710
711 /* Check for overflow conditions */
712 if (!H5F_addr_defined(addr))
713 HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "addr undefined, addr = %llu", (unsigned long long)addr)
714 if (REGION_OVERFLOW(addr, size))
715 HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow, addr = %llu", (unsigned long long)addr)
716
717 #ifndef H5_HAVE_PREADWRITE
718 /* Seek to the correct location (if we don't have pread) */
719 if (addr != file->pos || OP_READ != file->op)
720 if (HDlseek(file->fd, (HDoff_t)addr, SEEK_SET) < 0)
721 HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to seek to proper position")
722 #endif /* H5_HAVE_PREADWRITE */
723
724 /* Read data, being careful of interrupted system calls, partial results,
725 * and the end of the file.
726 */
727 while (size > 0) {
728 h5_posix_io_t bytes_in = 0; /* # of bytes to read */
729 h5_posix_io_ret_t bytes_read = -1; /* # of bytes actually read */
730
731 /* Trying to read more bytes than the return type can handle is
732 * undefined behavior in POSIX.
733 */
734 if (size > H5_POSIX_MAX_IO_BYTES)
735 bytes_in = H5_POSIX_MAX_IO_BYTES;
736 else
737 bytes_in = (h5_posix_io_t)size;
738
739 do {
740 #ifdef H5_HAVE_PREADWRITE
741 bytes_read = HDpread(file->fd, buf, bytes_in, offset);
742 if (bytes_read > 0)
743 offset += bytes_read;
744 #else
745 bytes_read = HDread(file->fd, buf, bytes_in);
746 #endif /* H5_HAVE_PREADWRITE */
747 } while (-1 == bytes_read && EINTR == errno);
748
749 if (-1 == bytes_read) { /* error */
750 int myerrno = errno;
751 time_t mytime = HDtime(NULL);
752
753 offset = HDlseek(file->fd, (HDoff_t)0, SEEK_CUR);
754
755 HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL,
756 "file read failed: time = %s, filename = '%s', file descriptor = %d, errno = %d, "
757 "error message = '%s', buf = %p, total read size = %llu, bytes this sub-read = %llu, "
758 "bytes actually read = %llu, offset = %llu",
759 HDctime(&mytime), file->filename, file->fd, myerrno, HDstrerror(myerrno), buf,
760 (unsigned long long)size, (unsigned long long)bytes_in,
761 (unsigned long long)bytes_read, (unsigned long long)offset);
762 } /* end if */
763
764 if (0 == bytes_read) {
765 /* end of file but not end of format address space */
766 HDmemset(buf, 0, size);
767 break;
768 } /* end if */
769
770 HDassert(bytes_read >= 0);
771 HDassert((size_t)bytes_read <= size);
772
773 size -= (size_t)bytes_read;
774 addr += (haddr_t)bytes_read;
775 buf = (char *)buf + bytes_read;
776 } /* end while */
777
778 /* Update current position */
779 file->pos = addr;
780 file->op = OP_READ;
781
782 done:
783 if (ret_value < 0) {
784 /* Reset last file I/O information */
785 file->pos = HADDR_UNDEF;
786 file->op = OP_UNKNOWN;
787 } /* end if */
788
789 FUNC_LEAVE_NOAPI(ret_value)
790 } /* end H5FD__sec2_read() */
791
792 /*-------------------------------------------------------------------------
793 * Function: H5FD__sec2_write
794 *
795 * Purpose: Writes SIZE bytes of data to FILE beginning at address ADDR
796 * from buffer BUF according to data transfer properties in
797 * DXPL_ID.
798 *
799 * Return: SUCCEED/FAIL
800 *
801 * Programmer: Robb Matzke
802 * Thursday, July 29, 1999
803 *
804 *-------------------------------------------------------------------------
805 */
806 static herr_t
H5FD__sec2_write(H5FD_t * _file,H5FD_mem_t H5_ATTR_UNUSED type,hid_t H5_ATTR_UNUSED dxpl_id,haddr_t addr,size_t size,const void * buf)807 H5FD__sec2_write(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, hid_t H5_ATTR_UNUSED dxpl_id, haddr_t addr,
808 size_t size, const void *buf)
809 {
810 H5FD_sec2_t *file = (H5FD_sec2_t *)_file;
811 HDoff_t offset = (HDoff_t)addr;
812 herr_t ret_value = SUCCEED; /* Return value */
813
814 FUNC_ENTER_STATIC
815
816 HDassert(file && file->pub.cls);
817 HDassert(buf);
818
819 /* Check for overflow conditions */
820 if (!H5F_addr_defined(addr))
821 HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "addr undefined, addr = %llu", (unsigned long long)addr)
822 if (REGION_OVERFLOW(addr, size))
823 HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow, addr = %llu, size = %llu",
824 (unsigned long long)addr, (unsigned long long)size)
825
826 #ifndef H5_HAVE_PREADWRITE
827 /* Seek to the correct location (if we don't have pwrite) */
828 if (addr != file->pos || OP_WRITE != file->op)
829 if (HDlseek(file->fd, (HDoff_t)addr, SEEK_SET) < 0)
830 HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to seek to proper position")
831 #endif /* H5_HAVE_PREADWRITE */
832
833 /* Write the data, being careful of interrupted system calls and partial
834 * results
835 */
836 while (size > 0) {
837 h5_posix_io_t bytes_in = 0; /* # of bytes to write */
838 h5_posix_io_ret_t bytes_wrote = -1; /* # of bytes written */
839
840 /* Trying to write more bytes than the return type can handle is
841 * undefined behavior in POSIX.
842 */
843 if (size > H5_POSIX_MAX_IO_BYTES)
844 bytes_in = H5_POSIX_MAX_IO_BYTES;
845 else
846 bytes_in = (h5_posix_io_t)size;
847
848 do {
849 #ifdef H5_HAVE_PREADWRITE
850 bytes_wrote = HDpwrite(file->fd, buf, bytes_in, offset);
851 if (bytes_wrote > 0)
852 offset += bytes_wrote;
853 #else
854 bytes_wrote = HDwrite(file->fd, buf, bytes_in);
855 #endif /* H5_HAVE_PREADWRITE */
856 } while (-1 == bytes_wrote && EINTR == errno);
857
858 if (-1 == bytes_wrote) { /* error */
859 int myerrno = errno;
860 time_t mytime = HDtime(NULL);
861
862 offset = HDlseek(file->fd, (HDoff_t)0, SEEK_CUR);
863
864 HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL,
865 "file write failed: time = %s, filename = '%s', file descriptor = %d, errno = %d, "
866 "error message = '%s', buf = %p, total write size = %llu, bytes this sub-write = "
867 "%llu, bytes actually written = %llu, offset = %llu",
868 HDctime(&mytime), file->filename, file->fd, myerrno, HDstrerror(myerrno), buf,
869 (unsigned long long)size, (unsigned long long)bytes_in,
870 (unsigned long long)bytes_wrote, (unsigned long long)offset);
871 } /* end if */
872
873 HDassert(bytes_wrote > 0);
874 HDassert((size_t)bytes_wrote <= size);
875
876 size -= (size_t)bytes_wrote;
877 addr += (haddr_t)bytes_wrote;
878 buf = (const char *)buf + bytes_wrote;
879 } /* end while */
880
881 /* Update current position and eof */
882 file->pos = addr;
883 file->op = OP_WRITE;
884 if (file->pos > file->eof)
885 file->eof = file->pos;
886
887 done:
888 if (ret_value < 0) {
889 /* Reset last file I/O information */
890 file->pos = HADDR_UNDEF;
891 file->op = OP_UNKNOWN;
892 } /* end if */
893
894 FUNC_LEAVE_NOAPI(ret_value)
895 } /* end H5FD__sec2_write() */
896
897 /*-------------------------------------------------------------------------
898 * Function: H5FD__sec2_truncate
899 *
900 * Purpose: Makes sure that the true file size is the same (or larger)
901 * than the end-of-address.
902 *
903 * Return: SUCCEED/FAIL
904 *
905 * Programmer: Robb Matzke
906 * Wednesday, August 4, 1999
907 *
908 *-------------------------------------------------------------------------
909 */
910 static herr_t
H5FD__sec2_truncate(H5FD_t * _file,hid_t H5_ATTR_UNUSED dxpl_id,hbool_t H5_ATTR_UNUSED closing)911 H5FD__sec2_truncate(H5FD_t *_file, hid_t H5_ATTR_UNUSED dxpl_id, hbool_t H5_ATTR_UNUSED closing)
912 {
913 H5FD_sec2_t *file = (H5FD_sec2_t *)_file;
914 herr_t ret_value = SUCCEED; /* Return value */
915
916 FUNC_ENTER_STATIC
917
918 HDassert(file);
919
920 /* Extend the file to make sure it's large enough */
921 if (!H5F_addr_eq(file->eoa, file->eof)) {
922 #ifdef H5_HAVE_WIN32_API
923 LARGE_INTEGER li; /* 64-bit (union) integer for SetFilePointer() call */
924 DWORD dwPtrLow; /* Low-order pointer bits from SetFilePointer()
925 * Only used as an error code here.
926 */
927 DWORD dwError; /* DWORD error code from GetLastError() */
928 BOOL bError; /* Boolean error flag */
929
930 /* Windows uses this odd QuadPart union for 32/64-bit portability */
931 li.QuadPart = (__int64)file->eoa;
932
933 /* Extend the file to make sure it's large enough.
934 *
935 * Since INVALID_SET_FILE_POINTER can technically be a valid return value
936 * from SetFilePointer(), we also need to check GetLastError().
937 */
938 dwPtrLow = SetFilePointer(file->hFile, li.LowPart, &li.HighPart, FILE_BEGIN);
939 if (INVALID_SET_FILE_POINTER == dwPtrLow) {
940 dwError = GetLastError();
941 if (dwError != NO_ERROR)
942 HGOTO_ERROR(H5E_FILE, H5E_FILEOPEN, FAIL, "unable to set file pointer")
943 }
944
945 bError = SetEndOfFile(file->hFile);
946 if (0 == bError)
947 HGOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to extend file properly")
948 #else /* H5_HAVE_WIN32_API */
949 if (-1 == HDftruncate(file->fd, (HDoff_t)file->eoa))
950 HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to extend file properly")
951 #endif /* H5_HAVE_WIN32_API */
952
953 /* Update the eof value */
954 file->eof = file->eoa;
955
956 /* Reset last file I/O information */
957 file->pos = HADDR_UNDEF;
958 file->op = OP_UNKNOWN;
959 } /* end if */
960
961 done:
962 FUNC_LEAVE_NOAPI(ret_value)
963 } /* end H5FD__sec2_truncate() */
964
965 /*-------------------------------------------------------------------------
966 * Function: H5FD__sec2_lock
967 *
968 * Purpose: To place an advisory lock on a file.
969 * The lock type to apply depends on the parameter "rw":
970 * TRUE--opens for write: an exclusive lock
971 * FALSE--opens for read: a shared lock
972 *
973 * Return: SUCCEED/FAIL
974 *
975 * Programmer: Vailin Choi; May 2013
976 *
977 *-------------------------------------------------------------------------
978 */
979 static herr_t
H5FD__sec2_lock(H5FD_t * _file,hbool_t rw)980 H5FD__sec2_lock(H5FD_t *_file, hbool_t rw)
981 {
982 H5FD_sec2_t *file = (H5FD_sec2_t *)_file; /* VFD file struct */
983 int lock_flags; /* file locking flags */
984 herr_t ret_value = SUCCEED; /* Return value */
985
986 FUNC_ENTER_STATIC
987
988 HDassert(file);
989
990 /* Set exclusive or shared lock based on rw status */
991 lock_flags = rw ? LOCK_EX : LOCK_SH;
992
993 /* Place a non-blocking lock on the file */
994 if (HDflock(file->fd, lock_flags | LOCK_NB) < 0) {
995 if (file->ignore_disabled_file_locks && ENOSYS == errno) {
996 /* When errno is set to ENOSYS, the file system does not support
997 * locking, so ignore it.
998 */
999 errno = 0;
1000 }
1001 else
1002 HSYS_GOTO_ERROR(H5E_VFL, H5E_CANTLOCKFILE, FAIL, "unable to lock file")
1003 }
1004
1005 done:
1006 FUNC_LEAVE_NOAPI(ret_value)
1007 } /* end H5FD__sec2_lock() */
1008
1009 /*-------------------------------------------------------------------------
1010 * Function: H5FD__sec2_unlock
1011 *
1012 * Purpose: To remove the existing lock on the file
1013 *
1014 * Return: SUCCEED/FAIL
1015 *
1016 * Programmer: Vailin Choi; May 2013
1017 *
1018 *-------------------------------------------------------------------------
1019 */
1020 static herr_t
H5FD__sec2_unlock(H5FD_t * _file)1021 H5FD__sec2_unlock(H5FD_t *_file)
1022 {
1023 H5FD_sec2_t *file = (H5FD_sec2_t *)_file; /* VFD file struct */
1024 herr_t ret_value = SUCCEED; /* Return value */
1025
1026 FUNC_ENTER_STATIC
1027
1028 HDassert(file);
1029
1030 if (HDflock(file->fd, LOCK_UN) < 0) {
1031 if (file->ignore_disabled_file_locks && ENOSYS == errno) {
1032 /* When errno is set to ENOSYS, the file system does not support
1033 * locking, so ignore it.
1034 */
1035 errno = 0;
1036 }
1037 else
1038 HSYS_GOTO_ERROR(H5E_VFL, H5E_CANTUNLOCKFILE, FAIL, "unable to unlock file")
1039 }
1040
1041 done:
1042 FUNC_LEAVE_NOAPI(ret_value)
1043 } /* end H5FD__sec2_unlock() */
1044