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