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:  Raymond Lu <slu@hdfgroup.uiuc.edu>
18  *              Wednesday, 20 September 2006
19  *
20  * Purpose:  The Direct I/O file driver forces the data to be written to
21  *    the file directly without being copied into system kernel
22  *    buffer.  The main system support this feature is Linux.
23  */
24 
25 /* Interface initialization */
26 #define H5_INTERFACE_INIT_FUNC  H5FD_direct_init_interface
27 
28 /* For system function posix_memalign - Commented it out because copper isn't able to compile
29  * this file. */
30 /* #define _XOPEN_SOURCE 600 */
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 "H5FDdirect.h"    /* Direct 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 #ifdef H5_HAVE_DIRECT
43 
44 /* The driver identification number, initialized at runtime */
45 static hid_t H5FD_DIRECT_g = 0;
46 
47 /* File operations */
48 #define OP_UNKNOWN  0
49 #define OP_READ    1
50 #define OP_WRITE  2
51 
52 /* Driver-specific file access properties */
53 typedef struct H5FD_direct_fapl_t {
54     size_t  mboundary;  /* Memory boundary for alignment    */
55     size_t  fbsize;    /* File system block size      */
56     size_t  cbsize;    /* Maximal buffer size for copying user data  */
57     hbool_t     must_align;     /* Decides if data alignment is required        */
58 } H5FD_direct_fapl_t;
59 
60 /*
61  * The description of a file belonging to this driver. The `eoa' and `eof'
62  * determine the amount of hdf5 address space in use and the high-water mark
63  * of the file (the current size of the underlying Unix file). The `pos'
64  * value is used to eliminate file position updates when they would be a
65  * no-op. Unfortunately we've found systems that use separate file position
66  * indicators for reading and writing so the lseek can only be eliminated if
67  * the current operation is the same as the previous operation.  When opening
68  * a file the `eof' will be set to the current file size, `eoa' will be set
69  * to zero, `pos' will be set to H5F_ADDR_UNDEF (as it is when an error
70  * occurs), and `op' will be set to H5F_OP_UNKNOWN.
71  */
72 typedef struct H5FD_direct_t {
73     H5FD_t  pub;      /*public stuff, must be first  */
74     int    fd;      /*the unix file      */
75     haddr_t  eoa;      /*end of allocated region  */
76     haddr_t  eof;      /*end of file; current file size*/
77     haddr_t  pos;      /*current file I/O position  */
78     int    op;      /*last operation    */
79     H5FD_direct_fapl_t  fa;    /*file access properties  */
80 #ifndef H5_HAVE_WIN32_API
81     /*
82      * On most systems the combination of device and i-node number uniquely
83      * identify a file.
84      */
85     dev_t  device;      /*file device number    */
86 #ifdef H5_VMS
87     ino_t  inode[3];    /*file i-node number    */
88 #else
89     ino_t  inode;      /*file i-node number    */
90 #endif /*H5_VMS*/
91 #else
92     /*
93      * On H5_HAVE_WIN32_API the low-order word of a unique identifier associated with the
94      * file and the volume serial number uniquely identify a file. This number
95      * (which, both? -rpm) may change when the system is restarted or when the
96      * file is opened. After a process opens a file, the identifier is
97      * constant until the file is closed. An application can use this
98      * identifier and the volume serial number to determine whether two
99      * handles refer to the same file.
100      */
101     DWORD fileindexlo;
102     DWORD fileindexhi;
103 #endif
104 } H5FD_direct_t;
105 
106 /*
107  * These macros check for overflow of various quantities.  These macros
108  * assume that HDoff_t is signed and haddr_t and size_t are unsigned.
109  *
110  * ADDR_OVERFLOW:  Checks whether a file address of type `haddr_t'
111  *      is too large to be represented by the second argument
112  *      of the file seek function.
113  *
114  * SIZE_OVERFLOW:  Checks whether a buffer size of type `hsize_t' is too
115  *      large to be represented by the `size_t' type.
116  *
117  * REGION_OVERFLOW:  Checks whether an address and size pair describe data
118  *      which can be addressed entirely by the second
119  *      argument of the file seek function.
120  */
121 #define MAXADDR (((haddr_t)1<<(8*sizeof(HDoff_t)-1))-1)
122 #define ADDR_OVERFLOW(A)  (HADDR_UNDEF==(A) ||            \
123          ((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 void *H5FD_direct_fapl_get(H5FD_t *file);
131 static void *H5FD_direct_fapl_copy(const void *_old_fa);
132 static H5FD_t *H5FD_direct_open(const char *name, unsigned flags, hid_t fapl_id,
133             haddr_t maxaddr);
134 static herr_t H5FD_direct_close(H5FD_t *_file);
135 static int H5FD_direct_cmp(const H5FD_t *_f1, const H5FD_t *_f2);
136 static herr_t H5FD_direct_query(const H5FD_t *_f1, unsigned long *flags);
137 static haddr_t H5FD_direct_get_eoa(const H5FD_t *_file, H5FD_mem_t type);
138 static herr_t H5FD_direct_set_eoa(H5FD_t *_file, H5FD_mem_t type, haddr_t addr);
139 static haddr_t H5FD_direct_get_eof(const H5FD_t *_file);
140 static herr_t  H5FD_direct_get_handle(H5FD_t *_file, hid_t fapl, void** file_handle);
141 static herr_t H5FD_direct_read(H5FD_t *_file, H5FD_mem_t type, hid_t fapl_id, haddr_t addr,
142            size_t size, void *buf);
143 static herr_t H5FD_direct_write(H5FD_t *_file, H5FD_mem_t type, hid_t fapl_id, haddr_t addr,
144             size_t size, const void *buf);
145 static herr_t H5FD_direct_truncate(H5FD_t *_file, hid_t dxpl_id, hbool_t closing);
146 
147 static const H5FD_class_t H5FD_direct_g = {
148     "direct",          /*name      */
149     MAXADDR,          /*maxaddr    */
150     H5F_CLOSE_WEAK,        /* fc_degree    */
151     NULL,          /*sb_size    */
152     NULL,          /*sb_encode    */
153     NULL,          /*sb_decode    */
154     sizeof(H5FD_direct_fapl_t),                 /*fapl_size    */
155     H5FD_direct_fapl_get,            /*fapl_get    */
156     H5FD_direct_fapl_copy,            /*fapl_copy    */
157     NULL,                /*fapl_free    */
158     0,            /*dxpl_size    */
159     NULL,          /*dxpl_copy    */
160     NULL,          /*dxpl_free    */
161     H5FD_direct_open,              /*open      */
162     H5FD_direct_close,                    /*close      */
163     H5FD_direct_cmp,              /*cmp      */
164     H5FD_direct_query,                    /*query      */
165     NULL,          /*get_type_map    */
166     NULL,          /*alloc      */
167     NULL,          /*free      */
168     H5FD_direct_get_eoa,      /*get_eoa    */
169     H5FD_direct_set_eoa,       /*set_eoa    */
170     H5FD_direct_get_eof,      /*get_eof    */
171     H5FD_direct_get_handle,                     /*get_handle            */
172     H5FD_direct_read,        /*read      */
173     H5FD_direct_write,        /*write      */
174     NULL,          /*flush      */
175     H5FD_direct_truncate,      /*truncate    */
176     NULL,                                       /*lock                  */
177     NULL,                                       /*unlock                */
178     H5FD_FLMAP_DICHOTOMY                        /*fl_map                */
179 };
180 
181 /* Declare a free list to manage the H5FD_direct_t struct */
182 H5FL_DEFINE_STATIC(H5FD_direct_t);
183 
184 
185 /*--------------------------------------------------------------------------
186 NAME
187    H5FD_direct_init_interface -- Initialize interface-specific information
188 USAGE
189     herr_t H5FD_direct_init_interface()
190 
191 RETURNS
192     Non-negative on success/Negative on failure
193 DESCRIPTION
194     Initializes any interface-specific data or routines.  (Just calls
195     H5FD_direct_init currently).
196 
197 --------------------------------------------------------------------------*/
198 static herr_t
H5FD_direct_init_interface(void)199 H5FD_direct_init_interface(void)
200 {
201     FUNC_ENTER_NOAPI_NOINIT_NOERR
202 
203     FUNC_LEAVE_NOAPI(H5FD_direct_init())
204 } /* H5FD_direct_init_interface() */
205 
206 
207 /*-------------------------------------------------------------------------
208  * Function:  H5FD_direct_init
209  *
210  * Purpose:  Initialize this driver by registering the driver with the
211  *    library.
212  *
213  * Return:  Success:  The driver ID for the direct driver.
214  *
215  *    Failure:  Negative.
216  *
217  * Programmer:  Raymond Lu
218  *              Wednesday, 20 September 2006
219  *
220  * Modifications:
221  *
222  *-------------------------------------------------------------------------
223  */
224 hid_t
H5FD_direct_init(void)225 H5FD_direct_init(void)
226 {
227     hid_t ret_value;        /* Return value */
228 
229     FUNC_ENTER_NOAPI(FAIL)
230 
231     if (H5I_VFL!=H5I_get_type(H5FD_DIRECT_g))
232         H5FD_DIRECT_g = H5FD_register(&H5FD_direct_g,sizeof(H5FD_class_t),FALSE);
233 
234     /* Set return value */
235     ret_value=H5FD_DIRECT_g;
236 
237 done:
238     FUNC_LEAVE_NOAPI(ret_value)
239 }
240 
241 
242 /*---------------------------------------------------------------------------
243  * Function:  H5FD_direct_term
244  *
245  * Purpose:  Shut down the VFD
246  *
247  * Return:  <none>
248  *
249  * Programmer:  Raymond Lu
250  *              Wednesday, 20 September 2006
251  *
252  * Modification:
253  *
254  *---------------------------------------------------------------------------
255  */
256 void
H5FD_direct_term(void)257 H5FD_direct_term(void)
258 {
259     FUNC_ENTER_NOAPI_NOINIT_NOERR
260 
261     /* Reset VFL ID */
262     H5FD_DIRECT_g=0;
263 
264     FUNC_LEAVE_NOAPI_VOID
265 } /* end H5FD_direct_term() */
266 
267 
268 /*-------------------------------------------------------------------------
269  * Function:  H5Pset_fapl_direct
270  *
271  * Purpose:  Modify the file access property list to use the H5FD_DIRECT
272  *    driver defined in this source file.  There are no driver
273  *    specific properties.
274  *
275  * Return:  Non-negative on success/Negative on failure
276  *
277  * Programmer:  Raymond Lu
278  *    Wednesday, 20 September 2006
279  *
280  * Modifications:
281  *
282  *-------------------------------------------------------------------------
283  */
284 herr_t
H5Pset_fapl_direct(hid_t fapl_id,size_t boundary,size_t block_size,size_t cbuf_size)285 H5Pset_fapl_direct(hid_t fapl_id, size_t boundary, size_t block_size, size_t cbuf_size)
286 {
287     H5P_genplist_t      *plist;      /* Property list pointer */
288     H5FD_direct_fapl_t  fa;
289     herr_t     ret_value;
290 
291     FUNC_ENTER_API(FAIL)
292     H5TRACE4("e", "izzz", fapl_id, boundary, block_size, cbuf_size);
293 
294     if(NULL == (plist = H5P_object_verify(fapl_id,H5P_FILE_ACCESS)))
295         HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access property list")
296 
297     if(boundary != 0)
298       fa.mboundary = boundary;
299     else
300   fa.mboundary = MBOUNDARY_DEF;
301     if(block_size != 0)
302       fa.fbsize = block_size;
303     else
304   fa.fbsize = FBSIZE_DEF;
305     if(cbuf_size != 0)
306       fa.cbsize = cbuf_size;
307     else
308   fa.cbsize = CBSIZE_DEF;
309 
310     /* Set the default to be true for data alignment */
311     fa.must_align = TRUE;
312 
313     /* Copy buffer size must be a multiple of file block size */
314     if(fa.cbsize % fa.fbsize != 0)
315         HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "copy buffer size must be a multiple of block size")
316 
317     ret_value= H5P_set_driver(plist, H5FD_DIRECT, &fa);
318 
319 done:
320     FUNC_LEAVE_API(ret_value)
321 }
322 
323 
324 /*-------------------------------------------------------------------------
325  * Function:  H5Pget_fapl_direct
326  *
327  * Purpose:  Returns information about the direct file access property
328  *    list though the function arguments.
329  *
330  * Return:  Success:  Non-negative
331  *
332  *    Failure:  Negative
333  *
334  * Programmer:  Raymond Lu
335  *              Wednesday, October 18, 2006
336  *
337  * Modifications:
338  *
339  *-------------------------------------------------------------------------
340  */
341 herr_t
H5Pget_fapl_direct(hid_t fapl_id,size_t * boundary,size_t * block_size,size_t * cbuf_size)342 H5Pget_fapl_direct(hid_t fapl_id, size_t *boundary/*out*/, size_t *block_size/*out*/,
343     size_t *cbuf_size/*out*/)
344 {
345     H5FD_direct_fapl_t  *fa;
346     H5P_genplist_t *plist;      /* Property list pointer */
347     herr_t      ret_value=SUCCEED;       /* Return value */
348 
349     FUNC_ENTER_API(FAIL)
350     H5TRACE4("e", "ixxx", fapl_id, boundary, block_size, cbuf_size);
351 
352     if(NULL == (plist = H5P_object_verify(fapl_id,H5P_FILE_ACCESS)))
353         HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access list")
354     if (H5FD_DIRECT!=H5P_get_driver(plist))
355         HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "incorrect VFL driver")
356     if (NULL==(fa=H5P_get_driver_info(plist)))
357         HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "bad VFL driver info")
358     if (boundary)
359         *boundary = fa->mboundary;
360     if (block_size)
361   *block_size = fa->fbsize;
362     if (cbuf_size)
363   *cbuf_size = fa->cbsize;
364 
365 done:
366     FUNC_LEAVE_API(ret_value)
367 }
368 
369 
370 /*-------------------------------------------------------------------------
371  * Function:  H5FD_direct_fapl_get
372  *
373  * Purpose:  Returns a file access property list which indicates how the
374  *    specified file is being accessed. The return list could be
375  *    used to access another file the same way.
376  *
377  * Return:  Success:  Ptr to new file access property list with all
378  *        members copied from the file struct.
379  *
380  *    Failure:  NULL
381  *
382  * Programmer:  Raymond Lu
383  *              Wednesday, 18 October 2006
384  *
385  * Modifications:
386  *
387  *-------------------------------------------------------------------------
388  */
389 static void *
H5FD_direct_fapl_get(H5FD_t * _file)390 H5FD_direct_fapl_get(H5FD_t *_file)
391 {
392     H5FD_direct_t  *file = (H5FD_direct_t*)_file;
393     void *ret_value;    /* Return value */
394 
395     FUNC_ENTER_NOAPI_NOINIT
396 
397     /* Set return value */
398     ret_value= H5FD_direct_fapl_copy(&(file->fa));
399 
400 done:
401     FUNC_LEAVE_NOAPI(ret_value)
402 } /* end H5FD_direct_fapl_get() */
403 
404 
405 /*-------------------------------------------------------------------------
406  * Function:  H5FD_direct_fapl_copy
407  *
408  * Purpose:  Copies the direct-specific file access properties.
409  *
410  * Return:  Success:  Ptr to a new property list
411  *
412  *    Failure:  NULL
413  *
414  * Programmer:  Raymond Lu
415  *              Wednesday, 18 October 2006
416  *
417  * Modifications:
418  *
419  *-------------------------------------------------------------------------
420  */
421 static void *
H5FD_direct_fapl_copy(const void * _old_fa)422 H5FD_direct_fapl_copy(const void *_old_fa)
423 {
424     const H5FD_direct_fapl_t *old_fa = (const H5FD_direct_fapl_t*)_old_fa;
425     H5FD_direct_fapl_t *new_fa = H5MM_malloc(sizeof(H5FD_direct_fapl_t));
426 
427     FUNC_ENTER_NOAPI_NOINIT_NOERR
428 
429     HDassert(new_fa);
430 
431     /* Copy the general information */
432     HDmemcpy(new_fa, old_fa, sizeof(H5FD_direct_fapl_t));
433 
434     FUNC_LEAVE_NOAPI(new_fa)
435 } /* end H5FD_direct_fapl_copy() */
436 
437 
438 /*-------------------------------------------------------------------------
439  * Function:  H5FD_direct_open
440  *
441  * Purpose:  Create and/or opens a Unix file for direct I/O as an HDF5 file.
442  *
443  * Return:  Success:  A pointer to a new file data structure. The
444  *        public fields will be initialized by the
445  *        caller, which is always H5FD_open().
446  *
447  *    Failure:  NULL
448  *
449  * Programmer:  Raymond Lu
450  *              Wednesday, 20 September 2006
451  *
452  * Modifications:
453  *
454  *-------------------------------------------------------------------------
455  */
456 static H5FD_t *
H5FD_direct_open(const char * name,unsigned flags,hid_t fapl_id,haddr_t maxaddr)457 H5FD_direct_open(const char *name, unsigned flags, hid_t fapl_id, haddr_t maxaddr)
458 {
459     int      o_flags;
460     int      fd=(-1);
461     H5FD_direct_t  *file=NULL;
462     H5FD_direct_fapl_t  *fa;
463 #ifdef H5_HAVE_WIN32_API
464     HFILE     filehandle;
465     struct _BY_HANDLE_FILE_INFORMATION fileinfo;
466 #endif
467     h5_stat_t    sb;
468     H5P_genplist_t   *plist;      /* Property list */
469     int                 *buf1, *buf2;
470     H5FD_t    *ret_value;
471 
472     FUNC_ENTER_NOAPI_NOINIT
473 
474     /* Sanity check on file offsets */
475     HDassert(sizeof(HDoff_t)>=sizeof(size_t));
476 
477     /* Check arguments */
478     if (!name || !*name)
479         HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "invalid file name")
480     if (0==maxaddr || HADDR_UNDEF==maxaddr)
481         HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, NULL, "bogus maxaddr")
482     if (ADDR_OVERFLOW(maxaddr))
483         HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, NULL, "bogus maxaddr")
484 
485     /* Build the open flags */
486     o_flags = (H5F_ACC_RDWR & flags) ? O_RDWR : O_RDONLY;
487     if (H5F_ACC_TRUNC & flags) o_flags |= O_TRUNC;
488     if (H5F_ACC_CREAT & flags) o_flags |= O_CREAT;
489     if (H5F_ACC_EXCL & flags) o_flags |= O_EXCL;
490 
491     /* Flag for Direct I/O */
492     o_flags |= O_DIRECT;
493 
494     /* Open the file */
495     if ((fd=HDopen(name, o_flags, 0666))<0)
496         HSYS_GOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to open file")
497 
498     if (HDfstat(fd, &sb)<0)
499         HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, NULL, "unable to fstat file")
500 
501     /* Create the new file struct */
502     if (NULL==(file=H5FL_CALLOC(H5FD_direct_t)))
503         HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "unable to allocate file struct")
504 
505     /* Get the driver specific information */
506     if(NULL == (plist = H5P_object_verify(fapl_id,H5P_FILE_ACCESS)))
507         HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a file access property list")
508     if(NULL == (fa = (H5FD_direct_fapl_t *)H5P_get_driver_info(plist)))
509         HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, NULL, "bad VFL driver info")
510 
511     file->fd = fd;
512     H5_ASSIGN_OVERFLOW(file->eof,sb.st_size,h5_stat_size_t,haddr_t);
513     file->pos = HADDR_UNDEF;
514     file->op = OP_UNKNOWN;
515 #ifdef H5_HAVE_WIN32_API
516     filehandle = _get_osfhandle(fd);
517     (void)GetFileInformationByHandle((HANDLE)filehandle, &fileinfo);
518     file->fileindexhi = fileinfo.nFileIndexHigh;
519     file->fileindexlo = fileinfo.nFileIndexLow;
520 #else
521     file->device = sb.st_dev;
522 #ifdef H5_VMS
523     file->inode[0] = sb.st_ino[0];
524     file->inode[1] = sb.st_ino[1];
525     file->inode[2] = sb.st_ino[2];
526 #else
527     file->inode = sb.st_ino;
528 #endif /*H5_VMS*/
529 #endif /*H5_HAVE_WIN32_API*/
530     file->fa.mboundary = fa->mboundary;
531     file->fa.fbsize = fa->fbsize;
532     file->fa.cbsize = fa->cbsize;
533 
534     /* Try to decide if data alignment is required.  The reason to check it here
535      * is to handle correctly the case that the file is in a different file system
536      * than the one where the program is running.
537      */
538     buf1 = (int *)HDmalloc(sizeof(int));
539     if(HDposix_memalign(&buf2, file->fa.mboundary, file->fa.fbsize) != 0)
540         HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, NULL, "HDposix_memalign failed")
541 
542     if(o_flags & O_CREAT) {
543         if(HDwrite(file->fd, (void*)buf1, sizeof(int))<0) {
544             if(HDwrite(file->fd, (void*)buf2, file->fa.fbsize)<0)
545                 HGOTO_ERROR(H5E_FILE, H5E_WRITEERROR, NULL, "file system may not support Direct I/O")
546             else
547                 file->fa.must_align = TRUE;
548         } else {
549             file->fa.must_align = FALSE;
550             HDftruncate(file->fd, (HDoff_t)0);
551         }
552     } else {
553         if(HDread(file->fd, (void*)buf1, sizeof(int))<0) {
554             if(HDread(file->fd, (void*)buf2, file->fa.fbsize)<0)
555                 HGOTO_ERROR(H5E_FILE, H5E_READERROR, NULL, "file system may not support Direct I/O")
556             else
557                 file->fa.must_align = TRUE;
558         } else {
559             if(o_flags & O_RDWR) {
560                 if(HDlseek(file->fd, (HDoff_t)0, SEEK_SET) < 0)
561                     HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, NULL, "unable to seek to proper position")
562                 if(HDwrite(file->fd, (void *)buf1, sizeof(int))<0)
563                     file->fa.must_align = TRUE;
564                 else
565                     file->fa.must_align = FALSE;
566             } else
567                 file->fa.must_align = FALSE;
568         }
569     }
570 
571     if(buf1)
572         HDfree(buf1);
573     if(buf2)
574         HDfree(buf2);
575 
576     /* Set return value */
577     ret_value=(H5FD_t*)file;
578 
579 done:
580     if(ret_value==NULL) {
581         if(fd>=0)
582             HDclose(fd);
583     } /* end if */
584 
585     FUNC_LEAVE_NOAPI(ret_value)
586 }
587 
588 
589 /*-------------------------------------------------------------------------
590  * Function:  H5FD_direct_close
591  *
592  * Purpose:  Closes the file.
593  *
594  * Return:  Success:  0
595  *
596  *    Failure:  -1, file not closed.
597  *
598  * Programmer:  Raymond Lu
599  *              Wednesday, 20 September 2006
600  *
601  * Modifications:
602  *
603  *-------------------------------------------------------------------------
604  */
605 static herr_t
H5FD_direct_close(H5FD_t * _file)606 H5FD_direct_close(H5FD_t *_file)
607 {
608     H5FD_direct_t  *file = (H5FD_direct_t*)_file;
609     herr_t        ret_value=SUCCEED;       /* Return value */
610 
611     FUNC_ENTER_NOAPI_NOINIT
612 
613     if (HDclose(file->fd)<0)
614         HSYS_GOTO_ERROR(H5E_IO, H5E_CANTCLOSEFILE, FAIL, "unable to close file")
615 
616     H5FL_FREE(H5FD_direct_t,file);
617 
618 done:
619     FUNC_LEAVE_NOAPI(ret_value)
620 }
621 
622 
623 /*-------------------------------------------------------------------------
624  * Function:  H5FD_direct_cmp
625  *
626  * Purpose:  Compares two files belonging to this driver using an
627  *    arbitrary (but consistent) ordering.
628  *
629  * Return:  Success:  A value like strcmp()
630  *
631  *    Failure:  never fails (arguments were checked by the
632  *        caller).
633  *
634  * Programmer:  Raymond Lu
635  *              Thursday, 21 September 2006
636  *
637  * Modifications:
638  *
639  *-------------------------------------------------------------------------
640  */
641 static int
H5FD_direct_cmp(const H5FD_t * _f1,const H5FD_t * _f2)642 H5FD_direct_cmp(const H5FD_t *_f1, const H5FD_t *_f2)
643 {
644     const H5FD_direct_t  *f1 = (const H5FD_direct_t*)_f1;
645     const H5FD_direct_t  *f2 = (const H5FD_direct_t*)_f2;
646     int ret_value=0;
647 
648     FUNC_ENTER_NOAPI_NOINIT_NOERR
649 
650 #ifdef H5_HAVE_WIN32_API
651     if (f1->fileindexhi < f2->fileindexhi) HGOTO_DONE(-1)
652     if (f1->fileindexhi > f2->fileindexhi) HGOTO_DONE(1)
653 
654     if (f1->fileindexlo < f2->fileindexlo) HGOTO_DONE(-1)
655     if (f1->fileindexlo > f2->fileindexlo) HGOTO_DONE(1)
656 
657 #else
658 #ifdef H5_DEV_T_IS_SCALAR
659     if (f1->device < f2->device) HGOTO_DONE(-1)
660     if (f1->device > f2->device) HGOTO_DONE(1)
661 #else /* H5_DEV_T_IS_SCALAR */
662     /* If dev_t isn't a scalar value on this system, just use memcmp to
663      * determine if the values are the same or not.  The actual return value
664      * shouldn't really matter...
665      */
666     if(HDmemcmp(&(f1->device),&(f2->device),sizeof(dev_t))<0) HGOTO_DONE(-1)
667     if(HDmemcmp(&(f1->device),&(f2->device),sizeof(dev_t))>0) HGOTO_DONE(1)
668 #endif /* H5_DEV_T_IS_SCALAR */
669 
670 #ifndef H5_VMS
671     if (f1->inode < f2->inode) HGOTO_DONE(-1)
672     if (f1->inode > f2->inode) HGOTO_DONE(1)
673 #else
674     if(HDmemcmp(&(f1->inode),&(f2->inode),3*sizeof(ino_t))<0) HGOTO_DONE(-1)
675     if(HDmemcmp(&(f1->inode),&(f2->inode),3*sizeof(ino_t))>0) HGOTO_DONE(1)
676 #endif /*H5_VMS*/
677 
678 #endif
679 
680 done:
681     FUNC_LEAVE_NOAPI(ret_value)
682 }
683 
684 
685 /*-------------------------------------------------------------------------
686  * Function:  H5FD_direct_query
687  *
688  * Purpose:  Set the flags that this VFL driver is capable of supporting.
689  *              (listed in H5FDpublic.h)
690  *
691  * Return:  Success:  non-negative
692  *
693  *    Failure:  negative
694  *
695  * Programmer:  Raymond Lu
696  *              Thursday, 21 September 2006
697  *
698  * Modifications:
699  *
700  *-------------------------------------------------------------------------
701  */
702 static herr_t
H5FD_direct_query(const H5FD_t UNUSED * _f,unsigned long * flags)703 H5FD_direct_query(const H5FD_t UNUSED * _f, unsigned long *flags /* out */)
704 {
705     FUNC_ENTER_NOAPI_NOINIT_NOERR
706 
707     /* Set the VFL feature flags that this driver supports */
708     if(flags) {
709         *flags = 0;
710         *flags|=H5FD_FEAT_AGGREGATE_METADATA; /* OK to aggregate metadata allocations */
711         *flags|=H5FD_FEAT_ACCUMULATE_METADATA; /* OK to accumulate metadata for faster writes */
712         *flags|=H5FD_FEAT_DATA_SIEVE;       /* OK to perform data sieving for faster raw data reads & writes */
713         *flags|=H5FD_FEAT_AGGREGATE_SMALLDATA; /* OK to aggregate "small" raw data allocations */
714     }
715 
716     FUNC_LEAVE_NOAPI(SUCCEED)
717 }
718 
719 
720 /*-------------------------------------------------------------------------
721  * Function:  H5FD_direct_get_eoa
722  *
723  * Purpose:  Gets the end-of-address marker for the file. The EOA marker
724  *    is the first address past the last byte allocated in the
725  *    format address space.
726  *
727  * Return:  Success:  The end-of-address marker.
728  *
729  *    Failure:  HADDR_UNDEF
730  *
731  * Programmer:  Raymond Lu
732  *              Wednesday, 20 September 2006
733  *
734  * Modifications:
735  *              Raymond Lu
736  *              21 Dec. 2006
737  *              Added the parameter TYPE.  It's only used for MULTI driver.
738  *
739  *-------------------------------------------------------------------------
740  */
741 static haddr_t
H5FD_direct_get_eoa(const H5FD_t * _file,H5FD_mem_t UNUSED type)742 H5FD_direct_get_eoa(const H5FD_t *_file, H5FD_mem_t UNUSED type)
743 {
744     const H5FD_direct_t  *file = (const H5FD_direct_t*)_file;
745 
746     FUNC_ENTER_NOAPI_NOINIT_NOERR
747 
748     FUNC_LEAVE_NOAPI(file->eoa)
749 }
750 
751 
752 /*-------------------------------------------------------------------------
753  * Function:  H5FD_direct_set_eoa
754  *
755  * Purpose:  Set the end-of-address marker for the file. This function is
756  *    called shortly after an existing HDF5 file is opened in order
757  *    to tell the driver where the end of the HDF5 data is located.
758  *
759  * Return:  Success:  0
760  *
761  *    Failure:  -1
762  *
763  * Programmer:  Raymond Lu
764  *              Wednesday, 20 September 2006
765  *
766  * Modifications:
767  *              Raymond Lu
768  *              21 Dec. 2006
769  *              Added the parameter TYPE.  It's only used for MULTI driver.
770  *
771  *-------------------------------------------------------------------------
772  */
773 static herr_t
H5FD_direct_set_eoa(H5FD_t * _file,H5FD_mem_t UNUSED type,haddr_t addr)774 H5FD_direct_set_eoa(H5FD_t *_file, H5FD_mem_t UNUSED type, haddr_t addr)
775 {
776     H5FD_direct_t  *file = (H5FD_direct_t*)_file;
777 
778     FUNC_ENTER_NOAPI_NOINIT_NOERR
779 
780     file->eoa = addr;
781 
782     FUNC_LEAVE_NOAPI(SUCCEED)
783 }
784 
785 
786 /*-------------------------------------------------------------------------
787  * Function:  H5FD_direct_get_eof
788  *
789  * Purpose:  Returns the end-of-file marker, which is the greater of
790  *    either the Unix end-of-file or the HDF5 end-of-address
791  *    markers.
792  *
793  * Return:  Success:  End of file address, the first address past
794  *        the end of the "file", either the Unix file
795  *        or the HDF5 file.
796  *
797  *    Failure:  HADDR_UNDEF
798  *
799  * Programmer:  Raymond Lu
800  *              Wednesday, 20 September 2006
801  *
802  * Modifications:
803  *
804  *-------------------------------------------------------------------------
805  */
806 static haddr_t
H5FD_direct_get_eof(const H5FD_t * _file)807 H5FD_direct_get_eof(const H5FD_t *_file)
808 {
809     const H5FD_direct_t  *file = (const H5FD_direct_t*)_file;
810 
811     FUNC_ENTER_NOAPI_NOINIT
812 
813     FUNC_LEAVE_NOAPI(MAX(file->eof, file->eoa))
814 }
815 
816 
817 /*-------------------------------------------------------------------------
818  * Function:       H5FD_diect_get_handle
819  *
820  * Purpose:        Returns the file handle of direct file driver.
821  *
822  * Returns:        Non-negative if succeed or negative if fails.
823  *
824  * Programmer:     Raymond Lu
825  *                 21 September 2006
826  *
827  * Modifications:
828  *
829  *-------------------------------------------------------------------------
830  */
831 static herr_t
H5FD_direct_get_handle(H5FD_t * _file,hid_t UNUSED fapl,void ** file_handle)832 H5FD_direct_get_handle(H5FD_t *_file, hid_t UNUSED fapl, void** file_handle)
833 {
834     H5FD_direct_t       *file = (H5FD_direct_t *)_file;
835     herr_t              ret_value = SUCCEED;
836 
837     FUNC_ENTER_NOAPI_NOINIT
838 
839     if(!file_handle)
840         HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file handle not valid")
841     *file_handle = &(file->fd);
842 
843 done:
844     FUNC_LEAVE_NOAPI(ret_value)
845 }
846 
847 
848 /*-------------------------------------------------------------------------
849  * Function:  H5FD_direct_read
850  *
851  * Purpose:  Reads SIZE bytes of data from FILE beginning at address ADDR
852  *    into buffer BUF according to data transfer properties in
853  *    DXPL_ID.
854  *
855  * Return:  Success:  Zero. Result is stored in caller-supplied
856  *        buffer BUF.
857  *
858  *    Failure:  -1, Contents of buffer BUF are undefined.
859  *
860  * Programmer:  Raymond Lu
861  *              Thursday, 21 September 2006
862  *
863  * Modifications:
864  *
865  *-------------------------------------------------------------------------
866  */
867 static herr_t
H5FD_direct_read(H5FD_t * _file,H5FD_mem_t UNUSED type,hid_t UNUSED dxpl_id,haddr_t addr,size_t size,void * buf)868 H5FD_direct_read(H5FD_t *_file, H5FD_mem_t UNUSED type, hid_t UNUSED dxpl_id, haddr_t addr,
869          size_t size, void *buf/*out*/)
870 {
871     H5FD_direct_t  *file = (H5FD_direct_t*)_file;
872     ssize_t    nbytes;
873     hbool_t    _must_align = TRUE;
874     herr_t        ret_value=SUCCEED;       /* Return value */
875     size_t    alloc_size;
876     void    *copy_buf = NULL, *p2;
877     size_t    _boundary;
878     size_t    _fbsize;
879     size_t    _cbsize;
880     haddr_t    read_size;              /* Size to read into copy buffer */
881     size_t    copy_size = size;       /* Size remaining to read when using copy buffer */
882     size_t              copy_offset;            /* Offset into copy buffer of the requested data */
883 
884     FUNC_ENTER_NOAPI_NOINIT
885 
886     HDassert(file && file->pub.cls);
887     HDassert(buf);
888 
889     /* Check for overflow conditions */
890     if (HADDR_UNDEF==addr)
891         HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "addr undefined")
892     if (REGION_OVERFLOW(addr, size))
893         HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow")
894     if((addr + size) > file->eoa)
895         HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow")
896 
897     /* If the system doesn't require data to be aligned, read the data in
898      * the same way as sec2 driver.
899      */
900     _must_align = file->fa.must_align;
901 
902     /* Get the memory boundary for alignment, file system block size, and maximal
903      * copy buffer size.
904      */
905     _boundary = file->fa.mboundary;
906     _fbsize = file->fa.fbsize;
907     _cbsize = file->fa.cbsize;
908 
909     /* if the data is aligned or the system doesn't require data to be aligned,
910      * read it directly from the file.  If not, read a bigger
911      * and aligned data first, then copy the data into memory buffer.
912      */
913     if(!_must_align || ((addr%_fbsize==0) && (size%_fbsize==0) && ((size_t)buf%_boundary==0))) {
914       /* Seek to the correct location */
915       if ((addr!=file->pos || OP_READ!=file->op) &&
916         HDlseek(file->fd, (HDoff_t)addr, SEEK_SET)<0)
917     HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to seek to proper position")
918        /* Read the aligned data in file first, being careful of interrupted
919        * system calls and partial results. */
920       while (size>0) {
921     do {
922         nbytes = HDread(file->fd, buf, size);
923     } while (-1==nbytes && EINTR==errno);
924     if (-1==nbytes) /* error */
925         HSYS_GOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "file read failed")
926     if (0==nbytes) {
927         /* end of file but not end of format address space */
928         HDmemset(buf, 0, size);
929         break;
930     }
931     HDassert(nbytes>=0);
932     HDassert((size_t)nbytes<=size);
933     H5_CHECK_OVERFLOW(nbytes,ssize_t,size_t);
934     size -= (size_t)nbytes;
935     H5_CHECK_OVERFLOW(nbytes,ssize_t,haddr_t);
936     addr += (haddr_t)nbytes;
937     buf = (char*)buf + nbytes;
938       }
939     } else {
940             /* Calculate where we will begin copying from the copy buffer */
941             copy_offset = (size_t)(addr % _fbsize);
942 
943       /* allocate memory needed for the Direct IO option up to the maximal
944        * copy buffer size. Make a bigger buffer for aligned I/O if size is
945        * smaller than maximal copy buffer. */
946       alloc_size = ((copy_offset + size - 1) / _fbsize + 1) * _fbsize;
947       if(alloc_size > _cbsize)
948         alloc_size = _cbsize;
949       HDassert(!(alloc_size % _fbsize));
950       if (HDposix_memalign(&copy_buf, _boundary, alloc_size) != 0)
951     HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "HDposix_memalign failed")
952 
953             /* look for the aligned position for reading the data */
954             HDassert(!(((addr / _fbsize) * _fbsize) % _fbsize));
955             if(HDlseek(file->fd, (HDoff_t)((addr / _fbsize) * _fbsize),
956                     SEEK_SET) < 0)
957                 HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to seek to proper position")
958 
959       /*
960        * Read the aligned data in file into aligned buffer first, then copy the data
961        * into the final buffer.  If the data size is bigger than maximal copy buffer
962        * size, do the reading by segment (the outer while loop).  If not, do one step
963        * reading.
964        */
965       do {
966          /* Read the aligned data in file first.  Not able to handle interrupted
967      * system calls and partial results like sec2 driver does because the
968      * data may no longer be aligned. It's expecially true when the data in
969      * file is smaller than ALLOC_SIZE. */
970         HDmemset(copy_buf, 0, alloc_size);
971 
972                 /* Calculate how much data we have to read in this iteration
973                  * (including unused parts of blocks) */
974                 if((copy_size + copy_offset) < alloc_size)
975                     read_size = ((copy_size + copy_offset - 1) / _fbsize + 1)
976                             * _fbsize;
977                 else
978                     read_size = alloc_size;
979 
980                 HDassert(!(read_size % _fbsize));
981         do {
982         nbytes = HDread(file->fd, copy_buf, read_size);
983         } while(-1==nbytes && EINTR==errno);
984 
985         if (-1==nbytes) /* error */
986         HSYS_GOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "file read failed")
987 
988         /* Copy the needed data from the copy buffer to the output
989          * buffer, and update copy_size.  If the copy buffer does not
990                  * contain the rest of the data, just copy what's in the copy
991                  * buffer and also update read_addr and copy_offset to read the
992                  * next section of data. */
993         p2 = (unsigned char*)copy_buf + copy_offset;
994         if((copy_size + copy_offset) <= alloc_size) {
995             HDmemcpy(buf, p2, copy_size);
996             buf = (unsigned char *)buf + copy_size;
997             copy_size = 0;
998                 } /* end if */
999                 else {
1000                     HDmemcpy(buf, p2, alloc_size - copy_offset);
1001                     buf = (unsigned char*)buf + alloc_size - copy_offset;
1002                     copy_size -= alloc_size - copy_offset;
1003                     copy_offset = 0;
1004                 } /* end else */
1005       } while (copy_size > 0);
1006 
1007       /*Final step: update address*/
1008       addr = (haddr_t)(((addr + size - 1) / _fbsize + 1) * _fbsize);
1009 
1010       if(copy_buf) {
1011                 HDfree(copy_buf);
1012                 copy_buf = NULL;
1013             } /* end if */
1014     }
1015 
1016     /* Update current position */
1017     file->pos = addr;
1018     file->op = OP_READ;
1019 
1020 done:
1021     if(ret_value<0) {
1022         if(copy_buf)
1023             HDfree(copy_buf);
1024 
1025         /* Reset last file I/O information */
1026         file->pos = HADDR_UNDEF;
1027         file->op = OP_UNKNOWN;
1028     } /* end if */
1029 
1030     FUNC_LEAVE_NOAPI(ret_value)
1031 }
1032 
1033 
1034 /*-------------------------------------------------------------------------
1035  * Function:  H5FD_direct_write
1036  *
1037  * Purpose:  Writes SIZE bytes of data to FILE beginning at address ADDR
1038  *    from buffer BUF according to data transfer properties in
1039  *    DXPL_ID.
1040  *
1041  * Return:  Success:  Zero
1042  *
1043  *    Failure:  -1
1044  *
1045  * Programmer:  Raymond Lu
1046  *              Thursday, 21 September 2006
1047  *
1048  * Modifications:
1049  *
1050  *-------------------------------------------------------------------------
1051  */
1052 static herr_t
H5FD_direct_write(H5FD_t * _file,H5FD_mem_t UNUSED type,hid_t UNUSED dxpl_id,haddr_t addr,size_t size,const void * buf)1053 H5FD_direct_write(H5FD_t *_file, H5FD_mem_t UNUSED type, hid_t UNUSED dxpl_id, haddr_t addr,
1054     size_t size, const void *buf)
1055 {
1056     H5FD_direct_t  *file = (H5FD_direct_t*)_file;
1057     ssize_t    nbytes;
1058     hbool_t    _must_align = TRUE;
1059     herr_t        ret_value=SUCCEED;       /* Return value */
1060     size_t    alloc_size;
1061     void    *copy_buf = NULL, *p1;
1062     const void    *p3;
1063     size_t    _boundary;
1064     size_t    _fbsize;
1065     size_t    _cbsize;
1066     haddr_t             write_addr;             /* Address to write copy buffer */
1067     haddr_t             write_size;             /* Size to write from copy buffer */
1068     haddr_t             read_size;              /* Size to read into copy buffer */
1069     size_t              copy_size = size;       /* Size remaining to write when using copy buffer */
1070     size_t              copy_offset;            /* Offset into copy buffer of the data to write */
1071 
1072     FUNC_ENTER_NOAPI_NOINIT
1073 
1074     HDassert(file && file->pub.cls);
1075     HDassert(buf);
1076 
1077     /* Check for overflow conditions */
1078     if (HADDR_UNDEF==addr)
1079         HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "addr undefined")
1080     if (REGION_OVERFLOW(addr, size))
1081         HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow")
1082     if (addr+size>file->eoa)
1083         HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow")
1084 
1085     /* If the system doesn't require data to be aligned, read the data in
1086      * the same way as sec2 driver.
1087      */
1088     _must_align = file->fa.must_align;
1089 
1090     /* Get the memory boundary for alignment, file system block size, and maximal
1091      * copy buffer size.
1092      */
1093     _boundary = file->fa.mboundary;
1094     _fbsize = file->fa.fbsize;
1095     _cbsize = file->fa.cbsize;
1096 
1097     /* if the data is aligned or the system doesn't require data to be aligned,
1098      * write it directly to the file.  If not, read a bigger and aligned data
1099      * first, update buffer with user data, then write the data out.
1100      */
1101     if(!_must_align || ((addr%_fbsize==0) && (size%_fbsize==0) && ((size_t)buf%_boundary==0))) {
1102       /* Seek to the correct location */
1103       if ((addr!=file->pos || OP_WRITE!=file->op) &&
1104         HDlseek(file->fd, (HDoff_t)addr, SEEK_SET)<0)
1105     HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to seek to proper position")
1106 
1107       while (size>0) {
1108     do {
1109         nbytes = HDwrite(file->fd, buf, size);
1110     } while (-1==nbytes && EINTR==errno);
1111     if (-1==nbytes) /* error */
1112         HSYS_GOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "file write failed")
1113     HDassert(nbytes>0);
1114     HDassert((size_t)nbytes<=size);
1115     H5_CHECK_OVERFLOW(nbytes,ssize_t,size_t);
1116     size -= (size_t)nbytes;
1117     H5_CHECK_OVERFLOW(nbytes,ssize_t,haddr_t);
1118     addr += (haddr_t)nbytes;
1119     buf = (const char*)buf + nbytes;
1120       }
1121     } else {
1122             /* Calculate where we will begin reading from (on disk) and where we
1123              * will begin copying from the copy buffer */
1124             write_addr = (addr / _fbsize) * _fbsize;
1125             copy_offset = (size_t)(addr % _fbsize);
1126 
1127       /* allocate memory needed for the Direct IO option up to the maximal
1128        * copy buffer size. Make a bigger buffer for aligned I/O if size is
1129        * smaller than maximal copy buffer.
1130        */
1131       alloc_size = ((copy_offset + size - 1) / _fbsize + 1) * _fbsize;
1132             if(alloc_size > _cbsize)
1133                 alloc_size = _cbsize;
1134             HDassert(!(alloc_size % _fbsize));
1135 
1136       if (HDposix_memalign(&copy_buf, _boundary, alloc_size) != 0)
1137     HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "HDposix_memalign failed")
1138 
1139             /* look for the right position for reading or writing the data */
1140             if(HDlseek(file->fd, (HDoff_t)write_addr, SEEK_SET) < 0)
1141                 HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to seek to proper position")
1142 
1143       p3 = buf;
1144       do {
1145                 /* Calculate how much data we have to write in this iteration
1146                  * (including unused parts of blocks) */
1147                 if((copy_size + copy_offset) < alloc_size)
1148                     write_size = ((copy_size + copy_offset - 1) / _fbsize + 1)
1149                             * _fbsize;
1150                 else
1151                     write_size = alloc_size;
1152 
1153         /*
1154           * Read the aligned data first if the aligned region doesn't fall
1155          * entirely in the range to be writen.  Not able to handle interrupted
1156      * system calls and partial results like sec2 driver does because the
1157      * data may no longer be aligned. It's expecially true when the data in
1158      * file is smaller than ALLOC_SIZE.  Only read the entire section if
1159                  * both ends are misaligned, otherwise only read the block on the
1160                  * misaligned end.
1161          */
1162         HDmemset(copy_buf, 0, _fbsize);
1163 
1164                 if(copy_offset > 0) {
1165                     if((write_addr + write_size) > (addr + size)) {
1166                         HDassert((write_addr + write_size) - (addr + size) < _fbsize);
1167                         read_size = write_size;
1168                         p1 = copy_buf;
1169                     } /* end if */
1170                     else {
1171                         read_size = _fbsize;
1172                         p1 = copy_buf;
1173                     } /* end else */
1174                 } /* end if */
1175                 else if((write_addr + write_size) > (addr + size)) {
1176                     HDassert((write_addr + write_size) - (addr + size) < _fbsize);
1177                     read_size = _fbsize;
1178                     p1 = (unsigned char *)copy_buf + write_size - _fbsize;
1179 
1180                     /* Seek to the last block, for reading */
1181                     HDassert(!((write_addr + write_size - _fbsize) % _fbsize));
1182                     if(HDlseek(file->fd,
1183                             (HDoff_t)(write_addr + write_size - _fbsize),
1184                             SEEK_SET) < 0)
1185                         HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to seek to proper position")
1186                 } /* end if */
1187                 else
1188                     p1 = NULL;
1189 
1190                 if(p1) {
1191                     HDassert(!(read_size % _fbsize));
1192                     do {
1193                         nbytes = HDread(file->fd, p1, read_size);
1194                     } while (-1==nbytes && EINTR==errno);
1195 
1196                     if (-1==nbytes) /* error */
1197                         HSYS_GOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "file read failed")
1198                 } /* end if */
1199 
1200         /* look for the right position and append or copy the data to be written to
1201           * the aligned buffer.
1202                * Consider all possible situations here: file address is not aligned on
1203                * file block size; the end of data address is not aligned; the end of data
1204                * address is aligned; data size is smaller or bigger than maximal copy size.
1205          */
1206         p1 = (unsigned char *)copy_buf + copy_offset;
1207         if((copy_size + copy_offset) <= alloc_size) {
1208                     HDmemcpy(p1, p3, copy_size);
1209                     copy_size = 0;
1210                 } /* end if */
1211                 else {
1212                     HDmemcpy(p1, p3, alloc_size - copy_offset);
1213                     p3 = (const unsigned char *)p3 + (alloc_size - copy_offset);
1214                     copy_size -= alloc_size - copy_offset;
1215                     copy_offset = 0;
1216                 } /* end else */
1217 
1218         /*look for the aligned position for writing the data*/
1219         HDassert(!(write_addr % _fbsize));
1220         if(HDlseek(file->fd, (HDoff_t)write_addr, SEEK_SET) < 0)
1221         HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to seek to proper position")
1222 
1223         /*
1224           * Write the data. It doesn't truncate the extra data introduced by
1225      * alignment because that step is done in H5FD_direct_flush.
1226          */
1227         HDassert(!(write_size % _fbsize));
1228     do {
1229         nbytes = HDwrite(file->fd, copy_buf, write_size);
1230     } while (-1==nbytes && EINTR==errno);
1231 
1232     if (-1==nbytes) /* error */
1233         HSYS_GOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "file write failed")
1234 
1235               /* update the write address */
1236               write_addr += write_size;
1237   } while (copy_size > 0);
1238 
1239   /*Update the address and size*/
1240   addr = write_addr;
1241   buf = (const char*)buf + size;
1242 
1243   if(copy_buf) {
1244       HDfree(copy_buf);
1245       copy_buf = NULL;
1246         } /* end if */
1247     }
1248 
1249     /* Update current position and eof */
1250     file->pos = addr;
1251     file->op = OP_WRITE;
1252     if (file->pos>file->eof)
1253         file->eof = file->pos;
1254 
1255 done:
1256     if(ret_value<0) {
1257         if(copy_buf)
1258             HDfree(copy_buf);
1259 
1260         /* Reset last file I/O information */
1261         file->pos = HADDR_UNDEF;
1262         file->op = OP_UNKNOWN;
1263     } /* end if */
1264 
1265     FUNC_LEAVE_NOAPI(ret_value)
1266 }
1267 
1268 
1269 /*-------------------------------------------------------------------------
1270  * Function:  H5FD_direct_truncate
1271  *
1272  * Purpose:  Makes sure that the true file size is the same (or larger)
1273  *    than the end-of-address.
1274  *
1275  * Return:  Success:  Non-negative
1276  *
1277  *    Failure:  Negative
1278  *
1279  * Programmer:  Raymond Lu
1280  *              Thursday, 21 September 2006
1281  *
1282  *-------------------------------------------------------------------------
1283  */
1284 static herr_t
H5FD_direct_truncate(H5FD_t * _file,hid_t UNUSED dxpl_id,hbool_t UNUSED closing)1285 H5FD_direct_truncate(H5FD_t *_file, hid_t UNUSED dxpl_id, hbool_t UNUSED closing)
1286 {
1287     H5FD_direct_t  *file = (H5FD_direct_t*)_file;
1288     herr_t        ret_value = SUCCEED;       /* Return value */
1289 
1290     FUNC_ENTER_NOAPI_NOINIT
1291 
1292     HDassert(file);
1293 
1294     /* Extend the file to make sure it's large enough */
1295     if (file->eoa!=file->eof) {
1296 #ifdef H5_HAVE_WIN32_API
1297         HFILE filehandle;   /* Windows file handle */
1298         LARGE_INTEGER li;   /* 64-bit integer for SetFilePointer() call */
1299 
1300         /* Map the posix file handle to a Windows file handle */
1301         filehandle = _get_osfhandle(file->fd);
1302 
1303         /* Translate 64-bit integers into form Windows wants */
1304         /* [This algorithm is from the Windows documentation for SetFilePointer()] */
1305         li.QuadPart = (LONGLONG)file->eoa;
1306         (void)SetFilePointer((HANDLE)filehandle,li.LowPart,&li.HighPart,FILE_BEGIN);
1307         if(SetEndOfFile((HANDLE)filehandle)==0)
1308             HGOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to extend file properly")
1309 #else /* H5_HAVE_WIN32_API */
1310         if (-1==HDftruncate(file->fd, (HDoff_t)file->eoa))
1311             HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to extend file properly")
1312 #endif /* H5_HAVE_WIN32_API */
1313 
1314         /* Update the eof value */
1315         file->eof = file->eoa;
1316 
1317         /* Reset last file I/O information */
1318         file->pos = HADDR_UNDEF;
1319         file->op = OP_UNKNOWN;
1320     }
1321     else if (file->fa.must_align){
1322   /*Even though eof is equal to eoa, file is still truncated because Direct I/O
1323    *write introduces some extra data for alignment.
1324    */
1325         if (-1==HDftruncate(file->fd, (HDoff_t)file->eof))
1326             HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to extend file properly")
1327     }
1328 
1329 done:
1330     FUNC_LEAVE_NOAPI(ret_value)
1331 } /* end H5FD_direct_truncate() */
1332 #endif /* H5_HAVE_DIRECT */
1333 
1334