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