1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2  * Copyright by The HDF Group.                                               *
3  * Copyright by the Board of Trustees of the University of Illinois.         *
4  * All rights reserved.                                                      *
5  *                                                                           *
6  * This file is part of HDF5.  The full HDF5 copyright notice, including     *
7  * terms governing use, modification, and redistribution, is contained in    *
8  * the COPYING file, which can be found at the root of the source code       *
9  * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases.  *
10  * If you do not have access to either file, you may request a copy from     *
11  * help@hdfgroup.org.                                                        *
12  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
13 
14 /*
15  * Programmer:	Robb Matzke <matzke@llnl.gov>
16  *		Monday, November 10, 1997
17  *
18  * Purpose:	Implements a file driver which dispatches I/O requests to
19  *		other file drivers depending on the purpose of the address
20  *		region being accessed. For instance, all meta-data could be
21  *		place in one file while all raw data goes to some other file.
22  *		This also serves as an example of coding a complex file driver,
23  *		therefore, it should not use any non-public definitions.
24  */
25 #include <assert.h>
26 #include <stdlib.h>
27 #include <string.h>
28 
29 /* Disable certain warnings in PC-Lint: */
30 /*lint --emacro( {534, 830}, H5P_DEFAULT, H5P_FILE_ACCESS, H5P_DATASET_XFER) */
31 /*lint --emacro( {534, 830}, H5FD_MULTI) */
32 /*lint -esym( 534, H5Eclear2, H5Epush2) */
33 
34 #include "hdf5.h"
35 
36 
37 /* Our version of MAX */
38 #undef MAX
39 #define MAX(X,Y)	((X)>(Y)?(X):(Y))
40 
41 #ifndef FALSE
42 #define FALSE		0
43 #endif
44 #ifndef TRUE
45 #define TRUE		1
46 #endif
47 
48 /* Loop through all mapped files */
49 #define UNIQUE_MEMBERS(MAP,LOOPVAR) {					      \
50     H5FD_mem_t _unmapped, LOOPVAR;					      \
51     hbool_t _seen[H5FD_MEM_NTYPES];					      \
52 									      \
53     memset(_seen, 0, sizeof _seen);					      \
54     for (_unmapped=H5FD_MEM_SUPER; _unmapped<H5FD_MEM_NTYPES; _unmapped=(H5FD_mem_t)(_unmapped+1)) {  \
55 	LOOPVAR = MAP[_unmapped];					      \
56 	if (H5FD_MEM_DEFAULT==LOOPVAR) LOOPVAR=_unmapped;		      \
57 	assert(LOOPVAR>0 && LOOPVAR<H5FD_MEM_NTYPES);			      \
58 	if (_seen[LOOPVAR]++) continue;
59 
60 #define ALL_MEMBERS(LOOPVAR) {						      \
61     H5FD_mem_t LOOPVAR;							      \
62     for (LOOPVAR=H5FD_MEM_DEFAULT; LOOPVAR<H5FD_MEM_NTYPES; LOOPVAR=(H5FD_mem_t)(LOOPVAR+1)) {
63 
64 
65 #define END_MEMBERS	}}
66 
67 #define H5FD_MULT_MAX_FILE_NAME_LEN     1024
68 
69 /* The driver identification number, initialized at runtime */
70 static hid_t H5FD_MULTI_g = 0;
71 
72 /* Driver-specific file access properties */
73 typedef struct H5FD_multi_fapl_t {
74     H5FD_mem_t	memb_map[H5FD_MEM_NTYPES]; /*memory usage map		*/
75     hid_t	memb_fapl[H5FD_MEM_NTYPES];/*member access properties	*/
76     char	*memb_name[H5FD_MEM_NTYPES];/*name generators		*/
77     haddr_t	memb_addr[H5FD_MEM_NTYPES];/*starting addr per member	*/
78     hbool_t	relax;			/*less stringent error checking	*/
79 } H5FD_multi_fapl_t;
80 
81 /*
82  * The description of a file belonging to this driver. The file access
83  * properties and member names do not have to be copied into this struct
84  * since they will be held open by the file access property list which is
85  * copied into the parent file struct in H5F_open().
86  */
87 typedef struct H5FD_multi_t {
88     H5FD_t	pub;		/*public stuff, must be first		*/
89     H5FD_multi_fapl_t fa;	/*driver-specific file access properties*/
90     haddr_t	memb_next[H5FD_MEM_NTYPES];/*addr of next member	*/
91     H5FD_t	*memb[H5FD_MEM_NTYPES];	/*member pointers		*/
92     haddr_t     memb_eoa[H5FD_MEM_NTYPES]; /*EOA for individual files,
93     				 *end of allocated addresses.  v1.6 library
94                                  *have the EOA for the entire file. But it's
95                                  *meaningless for MULTI file.  We replaced it
96                                  *with the EOAs for individual files    */
97     unsigned	flags;		/*file open flags saved for debugging	*/
98     char	*name;		/*name passed to H5Fopen or H5Fcreate	*/
99 } H5FD_multi_t;
100 
101 /* Driver specific data transfer properties */
102 typedef struct H5FD_multi_dxpl_t {
103     hid_t	memb_dxpl[H5FD_MEM_NTYPES];/*member data xfer properties*/
104 } H5FD_multi_dxpl_t;
105 
106 /* Private functions */
107 static char *my_strdup(const char *s);
108 static int compute_next(H5FD_multi_t *file);
109 static int open_members(H5FD_multi_t *file);
110 
111 /* Callback prototypes */
112 static hsize_t H5FD_multi_sb_size(H5FD_t *file);
113 static herr_t H5FD_multi_sb_encode(H5FD_t *file, char *name/*out*/,
114 				   unsigned char *buf/*out*/);
115 static herr_t H5FD_multi_sb_decode(H5FD_t *file, const char *name,
116 				   const unsigned char *buf);
117 static void *H5FD_multi_fapl_get(H5FD_t *file);
118 static void *H5FD_multi_fapl_copy(const void *_old_fa);
119 static herr_t H5FD_multi_fapl_free(void *_fa);
120 static H5FD_t *H5FD_multi_open(const char *name, unsigned flags,
121 			       hid_t fapl_id, haddr_t maxaddr);
122 static herr_t H5FD_multi_close(H5FD_t *_file);
123 static int H5FD_multi_cmp(const H5FD_t *_f1, const H5FD_t *_f2);
124 static herr_t H5FD_multi_query(const H5FD_t *_f1, unsigned long *flags);
125 static herr_t H5FD_multi_get_type_map(const H5FD_t *file, H5FD_mem_t *type_map);
126 static haddr_t H5FD_multi_get_eoa(const H5FD_t *_file, H5FD_mem_t type);
127 static herr_t H5FD_multi_set_eoa(H5FD_t *_file, H5FD_mem_t type, haddr_t eoa);
128 static haddr_t H5FD_multi_get_eof(const H5FD_t *_file);
129 static herr_t  H5FD_multi_get_handle(H5FD_t *_file, hid_t fapl, void** file_handle);
130 static haddr_t H5FD_multi_alloc(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, hsize_t size);
131 static herr_t H5FD_multi_free(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr,
132 			      hsize_t size);
133 static herr_t H5FD_multi_read(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr,
134 			      size_t size, void *_buf/*out*/);
135 static herr_t H5FD_multi_write(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr,
136 			       size_t size, const void *_buf);
137 static herr_t H5FD_multi_flush(H5FD_t *_file, hid_t dxpl_id, unsigned closing);
138 static herr_t H5FD_multi_truncate(H5FD_t *_file, hid_t dxpl_id, hbool_t closing);
139 
140 /* The class struct */
141 static const H5FD_class_t H5FD_multi_g = {
142     "multi",					/*name			*/
143     HADDR_MAX,					/*maxaddr		*/
144     H5F_CLOSE_WEAK,				/* fc_degree		*/
145     H5FD_multi_sb_size,				/*sb_size		*/
146     H5FD_multi_sb_encode,			/*sb_encode		*/
147     H5FD_multi_sb_decode,			/*sb_decode		*/
148     sizeof(H5FD_multi_fapl_t),			/*fapl_size		*/
149     H5FD_multi_fapl_get,			/*fapl_get		*/
150     H5FD_multi_fapl_copy,			/*fapl_copy		*/
151     H5FD_multi_fapl_free,			/*fapl_free		*/
152     0,						/*dxpl_size		*/
153     NULL,					/*dxpl_copy		*/
154     NULL,					/*dxpl_free		*/
155     H5FD_multi_open,				/*open			*/
156     H5FD_multi_close,				/*close			*/
157     H5FD_multi_cmp,				/*cmp			*/
158     H5FD_multi_query,				/*query			*/
159     H5FD_multi_get_type_map,			/*get_type_map		*/
160     H5FD_multi_alloc,				/*alloc			*/
161     H5FD_multi_free,				/*free			*/
162     H5FD_multi_get_eoa,				/*get_eoa		*/
163     H5FD_multi_set_eoa,				/*set_eoa		*/
164     H5FD_multi_get_eof,				/*get_eof		*/
165     H5FD_multi_get_handle,                      /*get_handle            */
166     H5FD_multi_read,				/*read			*/
167     H5FD_multi_write,				/*write			*/
168     H5FD_multi_flush,				/*flush			*/
169     H5FD_multi_truncate,			/*truncate		*/
170     NULL,                                       /*lock                  */
171     NULL,                                       /*unlock                */
172     H5FD_FLMAP_DEFAULT 				/*fl_map		*/
173 };
174 
175 
176 /*-------------------------------------------------------------------------
177  * Function:	my_strdup
178  *
179  * Purpose:	Private version of strdup()
180  *
181  * Return:	Success:	Ptr to new copy of string
182  *
183  *		Failure:	NULL
184  *
185  * Programmer:	Robb Matzke
186  *              Friday, August 13, 1999
187  *
188  * Modifications:
189  *
190  *-------------------------------------------------------------------------
191  */
192 static char *
my_strdup(const char * s)193 my_strdup(const char *s)
194 {
195     char *x;
196     size_t str_len;
197 
198     if(!s)
199         return NULL;
200     str_len = strlen(s) + 1;
201     if(NULL == (x = (char *)malloc(str_len)))
202         return NULL;
203     memcpy(x, s, str_len);
204 
205     return x;
206 }
207 
208 
209 /*-------------------------------------------------------------------------
210  * Function:	H5FD_multi_init
211  *
212  * Purpose:	Initialize this driver by registering the driver with the
213  *		library.
214  *
215  * Return:	Success:	The driver ID for the multi driver.
216  *
217  *		Failure:	Negative
218  *
219  * Programmer:	Robb Matzke
220  *              Wednesday, August  4, 1999
221  *
222  * Modifications:
223  *
224  *-------------------------------------------------------------------------
225  */
226 hid_t
H5FD_multi_init(void)227 H5FD_multi_init(void)
228 {
229     /* Clear the error stack */
230     H5Eclear2(H5E_DEFAULT);
231 
232     if (H5I_VFL!=H5Iget_type(H5FD_MULTI_g)) {
233 	H5FD_MULTI_g = H5FDregister(&H5FD_multi_g);
234     }
235     return H5FD_MULTI_g;
236 }
237 
238 
239 /*---------------------------------------------------------------------------
240  * Function:	H5FD_multi_term
241  *
242  * Purpose:	Shut down the VFD
243  *
244  * Return:	<none>
245  *
246  * Programmer:  Quincey Koziol
247  *              Friday, Jan 30, 2004
248  *
249  * Modification:
250  *
251  *---------------------------------------------------------------------------
252  */
253 void
H5FD_multi_term(void)254 H5FD_multi_term(void)
255 {
256     /* Reset VFL ID */
257     H5FD_MULTI_g=0;
258 
259 } /* end H5FD_multi_term() */
260 
261 
262 /*-------------------------------------------------------------------------
263  * Function:	H5Pset_fapl_split
264  *
265  * Purpose:	Compatibility function. Makes the multi driver act like the
266  *		old split driver which stored meta data in one file and raw
267  *		data in another file.
268  *
269  * Return:	Success:	0
270  *
271  *		Failure:	-1
272  *
273  * Programmer:	Robb Matzke
274  *              Wednesday, August 11, 1999
275  *
276  * Modifications:
277  *	Albert Cheng, Sep 17, 2001
278  *	Added feature that if the raw or meta extension string contains
279  *	a "%s", it will be substituted by the filename given for H5Fopen
280  *	or H5Fcreate.  This is same as the multi-file syntax.  If no %s
281  *	is found, one is inserted at the beginning.  This is the previous
282  *	behavior.
283  *
284  *-------------------------------------------------------------------------
285  */
286 herr_t
H5Pset_fapl_split(hid_t fapl,const char * meta_ext,hid_t meta_plist_id,const char * raw_ext,hid_t raw_plist_id)287 H5Pset_fapl_split(hid_t fapl, const char *meta_ext, hid_t meta_plist_id,
288 		  const char *raw_ext, hid_t raw_plist_id)
289 {
290     H5FD_mem_t		memb_map[H5FD_MEM_NTYPES];
291     hid_t		memb_fapl[H5FD_MEM_NTYPES];
292     const char		*memb_name[H5FD_MEM_NTYPES];
293     char		meta_name[H5FD_MULT_MAX_FILE_NAME_LEN], raw_name[H5FD_MULT_MAX_FILE_NAME_LEN];
294     haddr_t		memb_addr[H5FD_MEM_NTYPES];
295 
296     /*NO TRACE*/
297 
298     /* Clear the error stack */
299     H5Eclear2(H5E_DEFAULT);
300 
301     /* Initialize */
302     ALL_MEMBERS(mt) {
303 	/* Treat global heap as raw data, not metadata */
304 	memb_map[mt] = ((mt == H5FD_MEM_DRAW || mt == H5FD_MEM_GHEAP) ? H5FD_MEM_DRAW : H5FD_MEM_SUPER);
305 	memb_fapl[mt] = -1;
306 	memb_name[mt] = NULL;
307 	memb_addr[mt] = HADDR_UNDEF;
308     } END_MEMBERS;
309 
310     /* The file access properties */
311     memb_fapl[H5FD_MEM_SUPER] = meta_plist_id;
312     memb_fapl[H5FD_MEM_DRAW] = raw_plist_id;
313 
314     /* The names */
315     /* process meta filename */
316     if(meta_ext) {
317 	if(strstr(meta_ext, "%s")) {
318             /* Note: this doesn't accommodate for when the '%s' in the user's
319              *  string is at a position >sizeof(meta_name) - QK & JK - 2013/01/17
320              */
321 	    strncpy(meta_name, meta_ext, sizeof(meta_name));
322             meta_name[sizeof(meta_name) - 1] = '\0';
323         }
324 	else
325 	    sprintf(meta_name, "%%s%s", meta_ext);
326     }
327     else {
328 	strncpy(meta_name, "%s.meta", sizeof(meta_name));
329         meta_name[sizeof(meta_name) - 1] = '\0';
330     }
331     memb_name[H5FD_MEM_SUPER] = meta_name;
332 
333     /* process raw filename */
334     if(raw_ext) {
335 	if(strstr(raw_ext, "%s")) {
336             /* Note: this doesn't accommodate for when the '%s' in the user's
337              *  string is at a position >sizeof(raw_name) - QK & JK - 2013/01/17
338              */
339 	    strncpy(raw_name, raw_ext, sizeof(raw_name));
340             raw_name[sizeof(raw_name) - 1] = '\0';
341         }
342 	else
343 	    sprintf(raw_name, "%%s%s", raw_ext);
344     }
345     else {
346 	strncpy(raw_name, "%s.raw", sizeof(raw_name));
347         raw_name[sizeof(raw_name) - 1] = '\0';
348     }
349     memb_name[H5FD_MEM_DRAW] = raw_name;
350 
351     /* The sizes */
352     memb_addr[H5FD_MEM_SUPER] = 0;
353     memb_addr[H5FD_MEM_DRAW] = HADDR_MAX/2;
354 
355     return H5Pset_fapl_multi(fapl, memb_map, memb_fapl, memb_name, memb_addr, TRUE);
356 }
357 
358 
359 /*-------------------------------------------------------------------------
360  * Function:	H5Pset_fapl_multi
361  *
362  * Purpose:	Sets the file access property list FAPL_ID to use the multi
363  *		driver. The MEMB_MAP array maps memory usage types to other
364  *		memory usage types and is the mechanism which allows the
365  *		caller to specify how many files are created. The array
366  *		contains H5FD_MEM_NTYPES entries which are either the value
367  *		H5FD_MEM_DEFAULT or a memory usage type and the number of
368  *		unique values determines the number of files which are
369  *		opened.  For each memory usage type which will be associated
370  *		with a file the MEMB_FAPL array should have a property list
371  *		and the MEMB_NAME array should be a name generator (a
372  *		printf-style format with a %s which will be replaced with the
373  *		name passed to H5FDopen(), usually from H5Fcreate() or
374  *		H5Fopen()).
375  *
376  *		If RELAX is set then opening an existing file for read-only
377  *		access will not fail if some file members are missing.  This
378  *		allows a file to be accessed in a limited sense if just the
379  *		meta data is available.
380  *
381  * Defaults:	Default values for each of the optional arguments are:
382  *
383  *		memb_map:	The default member map has the value
384  *				H5FD_MEM_DEFAULT for each element.
385  *
386  * 		memb_fapl:	The value H5P_DEFAULT for each element.
387  *
388  *		memb_name:	The string `%s-X.h5' where `X' is one of the
389  *				letters `s' (H5FD_MEM_SUPER),
390  *				`b' (H5FD_MEM_BTREE), `r' (H5FD_MEM_DRAW),
391  * 				`g' (H5FD_MEM_GHEAP), 'l' (H5FD_MEM_LHEAP),
392  * 				`o' (H5FD_MEM_OHDR).
393  *
394  * 		memb_addr:	The value HADDR_UNDEF for each element.
395  *
396  *
397  * Example:	To set up a multi file access property list which partitions
398  *		data into meta and raw files each being 1/2 of the address
399  *		space one would say:
400  *
401  * 		    H5FD_mem_t mt, memb_map[H5FD_MEM_NTYPES];
402  *		    hid_t memb_fapl[H5FD_MEM_NTYPES];
403  *		    const char *memb[H5FD_MEM_NTYPES];
404  *		    haddr_t memb_addr[H5FD_MEM_NTYPES];
405  *
406  * 		    // The mapping...
407  * 		    for (mt=0; mt<H5FD_MEM_NTYPES; mt++) {
408  *		        memb_map[mt] = H5FD_MEM_SUPER;
409  *		    }
410  * 		    memb_map[H5FD_MEM_DRAW] = H5FD_MEM_DRAW;
411  *
412  * 		    // Member information
413  * 		    memb_fapl[H5FD_MEM_SUPER] = H5P_DEFAULT;
414  *		    memb_name[H5FD_MEM_SUPER] = "%s.meta";
415  *		    memb_addr[H5FD_MEM_SUPER] = 0;
416  *
417  *		    memb_fapl[H5FD_MEM_DRAW] = H5P_DEFAULT;
418  *		    memb_name[H5FD_MEM_DRAW] = "%s.raw";
419  *		    memb_addr[H5FD_MEM_DRAW] = HADDR_MAX/2;
420  *
421  * 		    hid_t fapl = H5Pcreate(H5P_FILE_ACCESS);
422  *		    H5Pset_fapl_multi(fapl, memb_map, memb_fapl,
423  *		                      memb_name, memb_addr, TRUE);
424  *
425  *
426  * Return:	Success:	Non-negative
427  *
428  *		Failure:	Negative
429  *
430  * Programmer:	Robb Matzke
431  *              Wednesday, August  4, 1999
432  *
433  * Modifications:
434  *
435  *		Raymond Lu, 2001-10-25
436  *		Use new generic property list for argument checking.
437  *
438  *-------------------------------------------------------------------------
439  */
440 herr_t
H5Pset_fapl_multi(hid_t fapl_id,const H5FD_mem_t * memb_map,const hid_t * memb_fapl,const char * const * memb_name,const haddr_t * memb_addr,hbool_t relax)441 H5Pset_fapl_multi(hid_t fapl_id, const H5FD_mem_t *memb_map,
442 		  const hid_t *memb_fapl, const char * const *memb_name,
443 		  const haddr_t *memb_addr, hbool_t relax)
444 {
445     H5FD_multi_fapl_t	fa;
446     H5FD_mem_t		mt, mmt;
447     H5FD_mem_t		_memb_map[H5FD_MEM_NTYPES];
448     hid_t		_memb_fapl[H5FD_MEM_NTYPES];
449     char		_memb_name[H5FD_MEM_NTYPES][16];
450     const char		*_memb_name_ptrs[H5FD_MEM_NTYPES];
451     haddr_t		_memb_addr[H5FD_MEM_NTYPES];
452     static const char	*letters = "Xsbrglo";
453     static const char *func="H5FDset_fapl_multi";  /* Function Name for error reporting */
454 
455     /*NO TRACE*/
456 
457     /* Clear the error stack */
458     H5Eclear2(H5E_DEFAULT);
459 
460     /* Check arguments and supply default values */
461     if(H5I_GENPROP_LST != H5Iget_type(fapl_id) ||
462             TRUE != H5Pisa_class(fapl_id, H5P_FILE_ACCESS))
463         H5Epush_ret(func, H5E_ERR_CLS, H5E_PLIST, H5E_BADVALUE, "not an access list", -1)
464     if (!memb_map) {
465 	for (mt=H5FD_MEM_DEFAULT; mt<H5FD_MEM_NTYPES; mt=(H5FD_mem_t)(mt+1))
466 	    _memb_map[mt] = H5FD_MEM_DEFAULT;
467 	memb_map = _memb_map;
468     }
469     if (!memb_fapl) {
470 	for (mt=H5FD_MEM_DEFAULT; mt<H5FD_MEM_NTYPES; mt=(H5FD_mem_t)(mt+1))
471 	    _memb_fapl[mt] = H5Pcreate(H5P_FILE_ACCESS);
472 	memb_fapl = _memb_fapl;
473     }
474     if (!memb_name) {
475 	assert(strlen(letters)==H5FD_MEM_NTYPES);
476 	for (mt=H5FD_MEM_DEFAULT; mt<H5FD_MEM_NTYPES; mt=(H5FD_mem_t)(mt+1)) {
477 	    sprintf(_memb_name[mt], "%%s-%c.h5", letters[mt]);
478 	    _memb_name_ptrs[mt] = _memb_name[mt];
479 	}
480 	memb_name = _memb_name_ptrs;
481     }
482     if (!memb_addr) {
483 	for (mt=H5FD_MEM_DEFAULT; mt<H5FD_MEM_NTYPES; mt=(H5FD_mem_t)(mt+1))
484 	    _memb_addr[mt] = (hsize_t)(mt ? (mt - 1) : 0) * (HADDR_MAX / (H5FD_MEM_NTYPES-1));
485 	memb_addr = _memb_addr;
486     }
487 
488     for (mt=H5FD_MEM_DEFAULT; mt<H5FD_MEM_NTYPES; mt=(H5FD_mem_t)(mt+1)) {
489 	/* Map usage type */
490 	mmt = memb_map[mt];
491 	if (mmt<0 || mmt>=H5FD_MEM_NTYPES)
492             H5Epush_ret(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADRANGE, "file resource type out of range", -1)
493 	if (H5FD_MEM_DEFAULT==mmt) mmt = mt;
494 
495 	/*
496 	 * All members of MEMB_FAPL must be either defaults or actual file
497 	 * access property lists.
498 	 */
499 	if (H5P_DEFAULT!=memb_fapl[mmt] && TRUE!=H5Pisa_class(memb_fapl[mmt], H5P_FILE_ACCESS))
500             H5Epush_ret(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "file resource type incorrect", -1)
501 
502 	/* All names must be defined */
503 	if (!memb_name[mmt] || !memb_name[mmt][0])
504             H5Epush_ret(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "file resource type not set", -1)
505     }
506 
507     /*
508      * Initialize driver specific information. No need to copy it into the FA
509      * struct since all members will be copied by H5Pset_driver().
510      */
511     memcpy(fa.memb_map, memb_map, H5FD_MEM_NTYPES*sizeof(H5FD_mem_t));
512     memcpy(fa.memb_fapl, memb_fapl, H5FD_MEM_NTYPES*sizeof(hid_t));
513     memcpy(fa.memb_name, memb_name, H5FD_MEM_NTYPES*sizeof(char*));
514     memcpy(fa.memb_addr, memb_addr, H5FD_MEM_NTYPES*sizeof(haddr_t));
515     fa.relax = relax;
516 
517     /* Patch up H5P_DEFAULT property lists for members */
518     for (mt=H5FD_MEM_DEFAULT; mt<H5FD_MEM_NTYPES; mt=(H5FD_mem_t)(mt+1)) {
519         if(fa.memb_fapl[mt]==H5P_DEFAULT)
520             fa.memb_fapl[mt] = H5Pcreate(H5P_FILE_ACCESS);
521     }
522     return H5Pset_driver(fapl_id, H5FD_MULTI, &fa);
523 }
524 
525 
526 /*-------------------------------------------------------------------------
527  * Function:	H5Pget_fapl_multi
528  *
529  * Purpose:	Returns information about the multi file access property
530  *		list though the function arguments which are the same as for
531  *		H5Pset_fapl_multi() above.
532  *
533  * Return:	Success:	Non-negative
534  *
535  *		Failure:	Negative
536  *
537  * Programmer:	Robb Matzke
538  *              Wednesday, August  4, 1999
539  *
540  * Modifications:
541  *
542  *              Raymond Lu, 2001-10-25
543  *              Use new generic property list for argument checking.
544  *
545  *-------------------------------------------------------------------------
546  */
547 herr_t
H5Pget_fapl_multi(hid_t fapl_id,H5FD_mem_t * memb_map,hid_t * memb_fapl,char ** memb_name,haddr_t * memb_addr,hbool_t * relax)548 H5Pget_fapl_multi(hid_t fapl_id, H5FD_mem_t *memb_map/*out*/,
549 		  hid_t *memb_fapl/*out*/, char **memb_name/*out*/,
550 		  haddr_t *memb_addr/*out*/, hbool_t *relax)
551 {
552     H5FD_multi_fapl_t	*fa;
553     H5FD_mem_t		mt;
554     static const char *func="H5FDget_fapl_multi";  /* Function Name for error reporting */
555 
556     /*NO TRACE*/
557 
558     /* Clear the error stack */
559     H5Eclear2(H5E_DEFAULT);
560 
561     if(H5I_GENPROP_LST != H5Iget_type(fapl_id) ||
562             TRUE != H5Pisa_class(fapl_id, H5P_FILE_ACCESS))
563         H5Epush_ret(func, H5E_ERR_CLS, H5E_PLIST, H5E_BADTYPE, "not an access list", -1)
564     if(H5FD_MULTI != H5Pget_driver(fapl_id))
565         H5Epush_ret(func, H5E_ERR_CLS, H5E_PLIST, H5E_BADVALUE, "incorrect VFL driver", -1)
566     if(NULL == (fa= (H5FD_multi_fapl_t *)H5Pget_driver_info(fapl_id)))
567         H5Epush_ret(func, H5E_ERR_CLS, H5E_PLIST, H5E_BADVALUE, "bad VFL driver info", -1)
568 
569     if (memb_map)
570         memcpy(memb_map, fa->memb_map, H5FD_MEM_NTYPES*sizeof(H5FD_mem_t));
571     if (memb_fapl) {
572 	for (mt=H5FD_MEM_DEFAULT; mt<H5FD_MEM_NTYPES; mt=(H5FD_mem_t)(mt+1)) {
573 	    if (fa->memb_fapl[mt]>=0)
574 		memb_fapl[mt] = H5Pcopy(fa->memb_fapl[mt]);
575 	    else
576 		memb_fapl[mt] = fa->memb_fapl[mt]; /*default or bad ID*/
577 	}
578     }
579     if(memb_name) {
580 	for(mt = H5FD_MEM_DEFAULT; mt < H5FD_MEM_NTYPES; mt = (H5FD_mem_t)(mt + 1)) {
581 	    if(fa->memb_name[mt])
582 		memb_name[mt] = my_strdup(fa->memb_name[mt]);
583 	    else
584 		memb_name[mt] = NULL;
585 	}
586     }
587     if (memb_addr)
588 	memcpy(memb_addr, fa->memb_addr, H5FD_MEM_NTYPES*sizeof(haddr_t));
589     if (relax)
590 	*relax = fa->relax;
591 
592     return 0;
593 }
594 
595 
596 /*-------------------------------------------------------------------------
597  * Function:	H5FD_multi_sb_size
598  *
599  * Purpose:	Returns the size of the private information to be stored in
600  *		the superblock.
601  *
602  * Return:	Success:	The super block driver data size.
603  *
604  *		Failure:	never fails
605  *
606  * Programmer:	Robb Matzke
607  *              Monday, August 16, 1999
608  *
609  * Modifications:
610  *
611  *-------------------------------------------------------------------------
612  */
613 static hsize_t
H5FD_multi_sb_size(H5FD_t * _file)614 H5FD_multi_sb_size(H5FD_t *_file)
615 {
616     H5FD_multi_t	*file = (H5FD_multi_t*)_file;
617     unsigned		nseen = 0;
618     hsize_t		nbytes = 8; /*size of header*/
619 
620     /* Clear the error stack */
621     H5Eclear2(H5E_DEFAULT);
622 
623     /* How many unique files? */
624     UNIQUE_MEMBERS(file->fa.memb_map, mt) {
625 	nseen++;
626     } END_MEMBERS;
627 
628     /* Addresses and EOA markers */
629     nbytes += nseen * 2 * 8;
630 
631     /* Name templates */
632     UNIQUE_MEMBERS(file->fa.memb_map, mt) {
633         size_t n = strlen(file->fa.memb_name[mt])+1;
634         nbytes += (n+7) & ~((size_t)0x0007);
635     } END_MEMBERS;
636 
637     return nbytes;
638 }
639 
640 
641 /*-------------------------------------------------------------------------
642  * Function:	H5FD_multi_sb_encode
643  *
644  * Purpose:	Encode driver information for the superblock. The NAME
645  *		argument is a nine-byte buffer which will be initialized with
646  *		an eight-character name/version number and null termination.
647  *
648  *		The encoding is a six-byte member mapping followed two bytes
649  *		which are unused. For each unique file in usage-type order
650  *		encode all the starting addresses as unsigned 64-bit integers,
651  *		then all the EOA values as unsigned 64-bit integers, then all
652  *		the template names as null terminated strings which are
653  *		multiples of 8 characters.
654  *
655  * Return:	Success:	0
656  *
657  *		Failure:	-1
658  *
659  * Programmer:	Robb Matzke
660  *              Monday, August 16, 1999
661  *
662  * Modifications:
663  *
664  *-------------------------------------------------------------------------
665  */
666 static herr_t
H5FD_multi_sb_encode(H5FD_t * _file,char * name,unsigned char * buf)667 H5FD_multi_sb_encode(H5FD_t *_file, char *name/*out*/,
668 		     unsigned char *buf/*out*/)
669 {
670     H5FD_multi_t	*file = (H5FD_multi_t*)_file;
671     haddr_t		memb_eoa;
672     unsigned char	*p;
673     size_t		nseen;
674     size_t		i;
675     H5FD_mem_t		m;
676     static const char *func="H5FD_multi_sb_encode";  /* Function Name for error reporting */
677 
678     /* Clear the error stack */
679     H5Eclear2(H5E_DEFAULT);
680 
681     /* Name and version number */
682     strncpy(name, "NCSAmulti", (size_t)8);
683     name[8] = '\0';
684 
685     assert(7==H5FD_MEM_NTYPES);
686 
687     for (m=H5FD_MEM_SUPER; m<H5FD_MEM_NTYPES; m=(H5FD_mem_t)(m+1)) {
688         buf[m-1] = (unsigned char)file->fa.memb_map[m];
689     }
690     buf[6] = 0;
691     buf[7] = 0;
692 
693     /*
694      * Copy the starting addresses and EOA values into the buffer in order of
695      * usage type but only for types which map to something unique.
696      */
697 
698     /* Encode all starting addresses and EOA values */
699     nseen = 0;
700     p = buf+8;
701     assert(sizeof(haddr_t)<=8);
702     UNIQUE_MEMBERS(file->fa.memb_map, mt) {
703         memcpy(p, &(file->fa.memb_addr[mt]), sizeof(haddr_t));
704         p += sizeof(haddr_t);
705         memb_eoa = H5FDget_eoa(file->memb[mt], mt);
706         memcpy(p, &memb_eoa, sizeof(haddr_t));
707         p += sizeof(haddr_t);
708         nseen++;
709     } END_MEMBERS;
710     if (H5Tconvert(H5T_NATIVE_HADDR, H5T_STD_U64LE, nseen*2, buf+8, NULL, H5P_DEFAULT)<0)
711         H5Epush_ret(func, H5E_ERR_CLS, H5E_DATATYPE, H5E_CANTCONVERT, "can't convert superblock info", -1)
712 
713     /* Encode all name templates */
714     p = buf + 8 + nseen*2*8;
715     UNIQUE_MEMBERS(file->fa.memb_map, mt) {
716         size_t n = strlen(file->fa.memb_name[mt]) + 1;
717         strncpy((char *)p, file->fa.memb_name[mt], n);
718         p += n;
719         for (i=n; i%8; i++)
720             *p++ = '\0';
721     } END_MEMBERS;
722 
723     return 0;
724 } /* end H5FD_multi_sb_encode() */
725 
726 
727 /*-------------------------------------------------------------------------
728  * Function:	H5FD_multi_sb_decode
729  *
730  * Purpose:	Decodes the superblock information for this driver. The NAME
731  *		argument is the eight-character (plus null termination) name
732  *		stored in the file.
733  *
734  *		The FILE argument is updated according to the information in
735  *		the superblock. This may mean that some member files are
736  *		closed and others are opened.
737  *
738  * Return:	Success:	0
739  *
740  *		Failure:	-1
741  *
742  * Programmer:	Robb Matzke
743  *              Monday, August 16, 1999
744  *
745  *-------------------------------------------------------------------------
746  */
747 static herr_t
H5FD_multi_sb_decode(H5FD_t * _file,const char * name,const unsigned char * buf)748 H5FD_multi_sb_decode(H5FD_t *_file, const char *name, const unsigned char *buf)
749 {
750     H5FD_multi_t	*file = (H5FD_multi_t*)_file;
751     char		x[2*H5FD_MEM_NTYPES*8];
752     H5FD_mem_t		map[H5FD_MEM_NTYPES];
753     int			i;
754     size_t		nseen=0;
755     hbool_t		map_changed=FALSE;
756     hbool_t		in_use[H5FD_MEM_NTYPES];
757     const char		*memb_name[H5FD_MEM_NTYPES];
758     haddr_t		memb_addr[H5FD_MEM_NTYPES];
759     haddr_t		memb_eoa[H5FD_MEM_NTYPES];
760     haddr_t		*ap;
761     static const char *func="H5FD_multi_sb_decode";  /* Function Name for error reporting */
762 
763     /* Clear the error stack */
764     H5Eclear2(H5E_DEFAULT);
765 
766     /* Make sure the name/version number is correct */
767     if (strcmp(name, "NCSAmult"))
768         H5Epush_ret(func, H5E_ERR_CLS, H5E_FILE, H5E_BADVALUE, "invalid multi superblock", -1)
769 
770     /* Set default values */
771     ALL_MEMBERS(mt) {
772         memb_addr[mt] = HADDR_UNDEF;
773         memb_eoa[mt] = HADDR_UNDEF;
774         memb_name[mt] = NULL;
775     } END_MEMBERS;
776 
777     /*
778      * Read the map and count the unique members.
779      */
780     memset(map, 0, sizeof map);
781 
782     for (i=0; i<6; i++) {
783         map[i+1] = (H5FD_mem_t)buf[i];
784         if (file->fa.memb_map[i+1]!=map[i+1])
785             map_changed=TRUE;
786     }
787 
788     UNIQUE_MEMBERS(map, mt) {
789         nseen++;
790     } END_MEMBERS;
791     buf += 8;
792 
793     /* Decode Address and EOA values */
794     assert(sizeof(haddr_t)<=8);
795     memcpy(x, buf, (nseen*2*8));
796     buf += nseen*2*8;
797     if (H5Tconvert(H5T_STD_U64LE, H5T_NATIVE_HADDR, nseen*2, x, NULL, H5P_DEFAULT)<0)
798         H5Epush_ret(func, H5E_ERR_CLS, H5E_DATATYPE, H5E_CANTCONVERT, "can't convert superblock info", -1)
799     ap = (haddr_t*)x;
800     UNIQUE_MEMBERS(map, mt) {
801         memb_addr[_unmapped] = *ap++;
802         memb_eoa[_unmapped] = *ap++;
803     } END_MEMBERS;
804 
805     /* Decode name templates */
806     UNIQUE_MEMBERS(map, mt) {
807         size_t n = strlen((const char *)buf)+1;
808         memb_name[_unmapped] = (const char *)buf;
809         buf += (n+7) & ~((unsigned)0x0007);
810     } END_MEMBERS;
811 
812     /*
813      * Use the mapping saved in the superblock in preference to the one
814      * already set for the file. Since we may have opened files which are no
815      * longer needed we should close all those files. We'll open the new
816      * files at the end.
817      */
818     if (map_changed) {
819         /* Commit map */
820         ALL_MEMBERS(mt) {
821             file->fa.memb_map[mt] = map[mt];
822         } END_MEMBERS;
823 
824         /* Close files which are unused now */
825         memset(in_use, 0, sizeof in_use);
826         UNIQUE_MEMBERS(map, mt) {
827             in_use[mt] = TRUE;
828         } END_MEMBERS;
829         ALL_MEMBERS(mt) {
830             if (!in_use[mt] && file->memb[mt]) {
831                 (void)H5FDclose(file->memb[mt]);
832                 file->memb[mt] = NULL;
833             }
834             file->fa.memb_map[mt] = map[mt];
835         } END_MEMBERS;
836     }
837 
838     /* Commit member starting addresses and name templates */
839     ALL_MEMBERS(mt) {
840         file->fa.memb_addr[mt] = memb_addr[mt];
841         if (memb_name[mt]) {
842             if (file->fa.memb_name[mt])
843                 free(file->fa.memb_name[mt]);
844             file->fa.memb_name[mt] = my_strdup(memb_name[mt]);
845         }
846     } END_MEMBERS;
847     if (compute_next(file)<0)
848         H5Epush_ret(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "compute_next() failed", -1)
849 
850     /* Open all necessary files */
851     if (open_members(file)<0)
852         H5Epush_ret(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "open_members() failed", -1)
853 
854     /* Set the EOA marker for all open files */
855     UNIQUE_MEMBERS(file->fa.memb_map, mt) {
856         if (file->memb[mt])
857             if(H5FDset_eoa(file->memb[mt], mt, memb_eoa[mt])<0)
858                 H5Epush_ret(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_CANTSET, "set_eoa() failed", -1)
859 
860         /* Save the individual EOAs in one place for later comparison (in H5FD_multi_set_eoa) */
861         file->memb_eoa[mt] = memb_eoa[mt];
862     } END_MEMBERS;
863 
864     return 0;
865 } /* end H5FD_multi_sb_decode() */
866 
867 
868 /*-------------------------------------------------------------------------
869  * Function:	H5FD_multi_fapl_get
870  *
871  * Purpose:	Returns a file access property list which indicates how the
872  *		specified file is being accessed. The return list could be
873  *		used to access another file the same way.
874  *
875  * Return:	Success:	Ptr to new file access property list with all
876  *				members copied from the file struct.
877  *
878  *		Failure:	NULL
879  *
880  * Programmer:	Robb Matzke
881  *              Friday, August 13, 1999
882  *
883  * Modifications:
884  *
885  *-------------------------------------------------------------------------
886  */
887 static void *
H5FD_multi_fapl_get(H5FD_t * _file)888 H5FD_multi_fapl_get(H5FD_t *_file)
889 {
890     H5FD_multi_t	*file = (H5FD_multi_t*)_file;
891 
892     /* Clear the error stack */
893     H5Eclear2(H5E_DEFAULT);
894 
895     return H5FD_multi_fapl_copy(&(file->fa));
896 }
897 
898 
899 /*-------------------------------------------------------------------------
900  * Function:	H5FD_multi_fapl_copy
901  *
902  * Purpose:	Copies the multi-specific file access properties.
903  *
904  * Return:	Success:	Ptr to a new property list
905  *
906  *		Failure:	NULL
907  *
908  * Programmer:	Robb Matzke
909  *              Wednesday, August  4, 1999
910  *
911  * Modifications:
912  *
913  *-------------------------------------------------------------------------
914  */
915 static void *
H5FD_multi_fapl_copy(const void * _old_fa)916 H5FD_multi_fapl_copy(const void *_old_fa)
917 {
918     const H5FD_multi_fapl_t *old_fa = (const H5FD_multi_fapl_t*)_old_fa;
919     H5FD_multi_fapl_t *new_fa = (H5FD_multi_fapl_t *)malloc(sizeof(H5FD_multi_fapl_t));
920     int nerrors = 0;
921     static const char *func="H5FD_multi_fapl_copy";  /* Function Name for error reporting */
922 
923     assert(new_fa);
924 
925     /* Clear the error stack */
926     H5Eclear2(H5E_DEFAULT);
927 
928     memcpy(new_fa, old_fa, sizeof(H5FD_multi_fapl_t));
929     ALL_MEMBERS(mt) {
930 	if (old_fa->memb_fapl[mt]>=0) {
931 	    new_fa->memb_fapl[mt] = H5Pcopy(old_fa->memb_fapl[mt]);
932 	    if(new_fa->memb_fapl[mt]<0)
933                 nerrors++;
934 	}
935 	if (old_fa->memb_name[mt]) {
936 	    new_fa->memb_name[mt] = my_strdup(old_fa->memb_name[mt]);
937 	    assert(new_fa->memb_name[mt]);
938 	}
939     } END_MEMBERS;
940 
941     if (nerrors) {
942         ALL_MEMBERS(mt) {
943             if (new_fa->memb_fapl[mt]>=0)
944                 (void)H5Pclose(new_fa->memb_fapl[mt]);
945             if (new_fa->memb_name[mt])
946                 free(new_fa->memb_name[mt]);
947         } END_MEMBERS;
948         free(new_fa);
949         H5Epush_ret(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "invalid freespace objects", NULL)
950     }
951     return new_fa;
952 }
953 
954 
955 /*-------------------------------------------------------------------------
956  * Function:	H5FD_multi_fapl_free
957  *
958  * Purpose:	Frees the multi-specific file access properties.
959  *
960  * Return:	Success:	0
961  *
962  *		Failure:	-1
963  *
964  * Programmer:	Robb Matzke
965  *              Wednesday, August  4, 1999
966  *
967  * Modifications:
968  *
969  *-------------------------------------------------------------------------
970  */
971 static herr_t
H5FD_multi_fapl_free(void * _fa)972 H5FD_multi_fapl_free(void *_fa)
973 {
974     H5FD_multi_fapl_t	*fa = (H5FD_multi_fapl_t*)_fa;
975     static const char *func="H5FD_multi_fapl_free";  /* Function Name for error reporting */
976 
977     /* Clear the error stack */
978     H5Eclear2(H5E_DEFAULT);
979 
980     ALL_MEMBERS(mt) {
981 	if (fa->memb_fapl[mt]>=0)
982             if(H5Pclose(fa->memb_fapl[mt])<0)
983                 H5Epush_ret(func, H5E_ERR_CLS, H5E_FILE, H5E_CANTCLOSEOBJ, "can't close property list", -1)
984 	if (fa->memb_name[mt])
985             free(fa->memb_name[mt]);
986     } END_MEMBERS;
987     free(fa);
988 
989     return 0;
990 }
991 
992 
993 /*-------------------------------------------------------------------------
994  * Function:	H5FD_multi_open
995  *
996  * Purpose:	Creates and/or opens a multi HDF5 file.
997  *
998  * Return:	Success:	A pointer to a new file data structure. The
999  *				public fields will be initialized by the
1000  *				caller, which is always H5FD_open().
1001  *
1002  *		Failure:	NULL
1003  *
1004  * Programmer:	Robb Matzke
1005  *              Wednesday, August  4, 1999
1006  *
1007  * Modifications:
1008  *
1009  *-------------------------------------------------------------------------
1010  */
1011 static H5FD_t *
H5FD_multi_open(const char * name,unsigned flags,hid_t fapl_id,haddr_t maxaddr)1012 H5FD_multi_open(const char *name, unsigned flags, hid_t fapl_id,
1013 		haddr_t maxaddr)
1014 {
1015     H5FD_multi_t	*file=NULL;
1016     hid_t		close_fapl=-1;
1017     H5FD_multi_fapl_t	*fa;
1018     H5FD_mem_t		m;
1019     static const char *func="H5FD_multi_open";  /* Function Name for error reporting */
1020 
1021     /* Clear the error stack */
1022     H5Eclear2(H5E_DEFAULT);
1023 
1024     /* Check arguments */
1025     if (!name || !*name)
1026         H5Epush_ret(func, H5E_ERR_CLS, H5E_ARGS, H5E_BADVALUE, "invalid file name", NULL)
1027     if (0==maxaddr || HADDR_UNDEF==maxaddr)
1028         H5Epush_ret(func, H5E_ERR_CLS, H5E_ARGS, H5E_BADRANGE, "bogus maxaddr", NULL)
1029 
1030     /*
1031      * Initialize the file from the file access properties, using default
1032      * values if necessary.  Make sure to use CALLOC here because the code
1033      * in H5FD_multi_set_eoa depends on the proper initialization of memb_eoa
1034      * in H5FD_multi_t.
1035      */
1036     if(NULL == (file = (H5FD_multi_t *)calloc((size_t)1, sizeof(H5FD_multi_t))))
1037         H5Epush_ret(func, H5E_ERR_CLS, H5E_RESOURCE, H5E_NOSPACE, "memory allocation failed", NULL)
1038     if(H5P_FILE_ACCESS_DEFAULT==fapl_id || H5FD_MULTI!=H5Pget_driver(fapl_id)) {
1039         close_fapl = fapl_id = H5Pcreate(H5P_FILE_ACCESS);
1040         if(H5Pset_fapl_multi(fapl_id, NULL, NULL, NULL, NULL, TRUE)<0)
1041             H5Epush_goto(func, H5E_ERR_CLS, H5E_FILE, H5E_CANTSET, "can't set property value", error)
1042     }
1043     fa = (H5FD_multi_fapl_t *)H5Pget_driver_info(fapl_id);
1044     assert(fa);
1045     ALL_MEMBERS(mt) {
1046 	file->fa.memb_map[mt] = fa->memb_map[mt];
1047 	file->fa.memb_addr[mt] = fa->memb_addr[mt];
1048 	if (fa->memb_fapl[mt]>=0)
1049 	    file->fa.memb_fapl[mt] = H5Pcopy(fa->memb_fapl[mt]);
1050 	else
1051 	    file->fa.memb_fapl[mt] = fa->memb_fapl[mt];
1052 	if (fa->memb_name[mt])
1053 	    file->fa.memb_name[mt] = my_strdup(fa->memb_name[mt]);
1054 	else
1055 	    file->fa.memb_name[mt] = NULL;
1056     } END_MEMBERS;
1057     file->fa.relax = fa->relax;
1058     file->flags = flags;
1059     file->name = my_strdup(name);
1060     if (close_fapl>=0)
1061         if(H5Pclose(close_fapl)<0)
1062             H5Epush_goto(func, H5E_ERR_CLS, H5E_FILE, H5E_CANTCLOSEOBJ, "can't close property list", error)
1063 
1064     /* Compute derived properties and open member files */
1065     if (compute_next(file)<0)
1066         H5Epush_goto(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "compute_next() failed", error);
1067     if (open_members(file)<0)
1068         H5Epush_goto(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "open_members() failed", error);
1069 
1070     /* We must have opened at least the superblock file */
1071     if (H5FD_MEM_DEFAULT==(m=file->fa.memb_map[H5FD_MEM_SUPER]))
1072         m = H5FD_MEM_SUPER;
1073     if (NULL==file->memb[m])
1074         goto error;
1075 
1076     return (H5FD_t*)file;
1077 
1078 error:
1079     /* Cleanup and fail */
1080     if (file) {
1081 	ALL_MEMBERS(mt) {
1082 	    if (file->memb[mt]) (void)H5FDclose(file->memb[mt]);
1083 	    if (file->fa.memb_fapl[mt]>=0) (void)H5Pclose(file->fa.memb_fapl[mt]);
1084 	    if (file->fa.memb_name[mt]) free(file->fa.memb_name[mt]);
1085 	} END_MEMBERS;
1086 	if (file->name) free(file->name);
1087 	free(file);
1088     }
1089     return NULL;
1090 }
1091 
1092 
1093 /*-------------------------------------------------------------------------
1094  * Function:	H5FD_multi_close
1095  *
1096  * Purpose:	Closes a multi file.
1097  *
1098  * Return:	Success:	Non-negative
1099  *
1100  *		Failure:	Negative with as many members closed as
1101  *				possible. The only subsequent operation
1102  *				permitted on the file is a close operation.
1103  *
1104  * Programmer:	Robb Matzke
1105  *              Wednesday, August  4, 1999
1106  *
1107  * Modifications:
1108  *
1109  *-------------------------------------------------------------------------
1110  */
1111 static herr_t
H5FD_multi_close(H5FD_t * _file)1112 H5FD_multi_close(H5FD_t *_file)
1113 {
1114     H5FD_multi_t	*file = (H5FD_multi_t*)_file;
1115     int			nerrors=0;
1116     static const char *func="H5FD_multi_close";  /* Function Name for error reporting */
1117 
1118     /* Clear the error stack */
1119     H5Eclear2(H5E_DEFAULT);
1120 
1121     /* Close as many members as possible */
1122     ALL_MEMBERS(mt) {
1123 	if (file->memb[mt]) {
1124 	    if (H5FDclose(file->memb[mt])<0) {
1125             nerrors++;
1126 	    } else {
1127             file->memb[mt] = NULL;
1128 	    }
1129 	}
1130     } END_MEMBERS;
1131     if (nerrors)
1132         H5Epush_ret(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "error closing member files", -1)
1133 
1134     /* Clean up other stuff */
1135     ALL_MEMBERS(mt) {
1136 	if (file->fa.memb_fapl[mt]>=0) (void)H5Pclose(file->fa.memb_fapl[mt]);
1137 	if (file->fa.memb_name[mt]) free(file->fa.memb_name[mt]);
1138     } END_MEMBERS;
1139     free(file->name);
1140     free(file);
1141     return 0;
1142 }
1143 
1144 
1145 /*-------------------------------------------------------------------------
1146  * Function:	H5FD_multi_cmp
1147  *
1148  * Purpose:	Compares two file families to see if they are the same. It
1149  *		does this by comparing the first common member of the two
1150  *		families.  If the families have no members in common then the
1151  *		file with the earliest member is smaller than the other file.
1152  *		We abort if neither file has any members.
1153  *
1154  * Return:	Success:	like strcmp()
1155  *
1156  *		Failure:	never fails (arguments were checked by the
1157  *				caller).
1158  *
1159  * Programmer:	Robb Matzke
1160  *              Wednesday, August  4, 1999
1161  *
1162  * Modifications:
1163  *
1164  *-------------------------------------------------------------------------
1165  */
1166 static int
H5FD_multi_cmp(const H5FD_t * _f1,const H5FD_t * _f2)1167 H5FD_multi_cmp(const H5FD_t *_f1, const H5FD_t *_f2)
1168 {
1169     const H5FD_multi_t	*f1 = (const H5FD_multi_t*)_f1;
1170     const H5FD_multi_t	*f2 = (const H5FD_multi_t*)_f2;
1171     H5FD_mem_t		out_mt = H5FD_MEM_DEFAULT;
1172     int			cmp=0;
1173 
1174     /* Clear the error stack */
1175     H5Eclear2(H5E_DEFAULT);
1176 
1177     ALL_MEMBERS(mt) {
1178         out_mt = mt;
1179 	if (f1->memb[mt] && f2->memb[mt]) break;
1180 	if (!cmp) {
1181 	    if (f1->memb[mt]) cmp = -1;
1182 	    else if (f2->memb[mt]) cmp = 1;
1183 	}
1184     } END_MEMBERS;
1185     assert(cmp || out_mt<H5FD_MEM_NTYPES);
1186     if (out_mt>=H5FD_MEM_NTYPES) return cmp;
1187 
1188     return H5FDcmp(f1->memb[out_mt], f2->memb[out_mt]);
1189 }
1190 
1191 
1192 /*-------------------------------------------------------------------------
1193  * Function:	H5FD_multi_query
1194  *
1195  * Purpose:	Set the flags that this VFL driver is capable of supporting.
1196  *              (listed in H5FDpublic.h)
1197  *
1198  * Return:	Success:	non-negative
1199  *
1200  *		Failure:	negative
1201  *
1202  * Programmer:	Quincey Koziol
1203  *              Tuesday, September 26, 2000
1204  *
1205  * Modifications:
1206  *
1207  *-------------------------------------------------------------------------
1208  */
1209 static herr_t
H5FD_multi_query(const H5FD_t * _f,unsigned long * flags)1210 H5FD_multi_query(const H5FD_t *_f, unsigned long *flags /* out */)
1211 {
1212     /* Shut compiler up */
1213     _f=_f;
1214 
1215     /* Set the VFL feature flags that this driver supports */
1216     if(flags) {
1217         *flags = 0;
1218         *flags |= H5FD_FEAT_DATA_SIEVE;       /* OK to perform data sieving for faster raw data reads & writes */
1219         *flags |= H5FD_FEAT_AGGREGATE_SMALLDATA; /* OK to aggregate "small" raw data allocations */
1220     } /* end if */
1221 
1222     return(0);
1223 } /* end H5FD_multi_query() */
1224 
1225 
1226 /*-------------------------------------------------------------------------
1227  * Function:	H5FD_multi_get_type_map
1228  *
1229  * Purpose:	Retrieve the memory type mapping for this file
1230  *
1231  * Return:	Success:	non-negative
1232  *		Failure:	negative
1233  *
1234  * Programmer:	Quincey Koziol
1235  *              Tuesday, October  9, 2008
1236  *
1237  *-------------------------------------------------------------------------
1238  */
1239 static herr_t
H5FD_multi_get_type_map(const H5FD_t * _file,H5FD_mem_t * type_map)1240 H5FD_multi_get_type_map(const H5FD_t *_file, H5FD_mem_t *type_map)
1241 {
1242     const H5FD_multi_t	*file = (const H5FD_multi_t*)_file;
1243 
1244     /* Copy file's free space type mapping */
1245     memcpy(type_map, file->fa.memb_map, sizeof(file->fa.memb_map));
1246 
1247     return(0);
1248 } /* end H5FD_multi_get_type_map() */
1249 
1250 
1251 /*-------------------------------------------------------------------------
1252  * Function:	H5FD_multi_get_eoa
1253  *
1254  * Purpose:	Returns the end-of-address marker for the file. The EOA
1255  *		marker is the first address past the last byte allocated in
1256  *		the format address space.
1257  *
1258  * Return:	Success:	The end-of-address-marker
1259  *
1260  *		Failure:	HADDR_UNDEF
1261  *
1262  * Programmer:	Robb Matzke
1263  *              Wednesday, August  4, 1999
1264  *
1265  * Modifications:
1266  *              Raymond Lu
1267  *              21 Dec. 2006
1268  *              Added the parameter TYPE.  It's only used for MULTI driver.
1269  *              If the TYPE is H5FD_MEM_DEFAULT, simply find the biggest
1270  *              EOA of individual file because the EOA for the whole file
1271  *              is meaningless.
1272  *
1273  *-------------------------------------------------------------------------
1274  */
1275 static haddr_t
H5FD_multi_get_eoa(const H5FD_t * _file,H5FD_mem_t type)1276 H5FD_multi_get_eoa(const H5FD_t *_file, H5FD_mem_t type)
1277 {
1278     const H5FD_multi_t	*file = (const H5FD_multi_t*)_file;
1279     haddr_t eoa = 0;
1280     haddr_t memb_eoa = 0;
1281     static const char *func="H5FD_multi_get_eoa";  /* Function Name for error reporting */
1282 
1283     /* Clear the error stack */
1284     H5Eclear2(H5E_DEFAULT);
1285 
1286     /* The library used to have EOA for the whole file.  But it's
1287      * taken out because it makes little sense for MULTI files.
1288      * However, the library sometimes queries it through H5F_get_eoa.
1289      * Here the code finds the biggest EOA for individual file if
1290      * the query is for TYPE == H5FD_MEM_DEFAULT.
1291      */
1292     if(H5FD_MEM_DEFAULT == type) {
1293         UNIQUE_MEMBERS(file->fa.memb_map, mt) {
1294 	    if (file->memb[mt]) {
1295                 /* Retrieve EOA */
1296 	        H5E_BEGIN_TRY {
1297                     memb_eoa = H5FDget_eoa(file->memb[mt], mt);
1298 	        } H5E_END_TRY;
1299 
1300 	        if (HADDR_UNDEF==memb_eoa)
1301                     H5Epush_ret(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "member file has unknown eoa", HADDR_UNDEF)
1302 	    } else if (file->fa.relax) {
1303 	        /*
1304 	         * The member is not open yet (maybe it doesn't exist). Make the
1305 	         * best guess about the end-of-file.
1306 	         */
1307 	        memb_eoa = file->memb_next[mt];
1308 	        assert(HADDR_UNDEF!=memb_eoa);
1309 	    } else {
1310                 H5Epush_ret(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "bad eoa", HADDR_UNDEF)
1311 	    }
1312 
1313             if(memb_eoa > eoa)
1314                 eoa = memb_eoa;
1315         } END_MEMBERS;
1316     } else {
1317         H5FD_mem_t mmt = file->fa.memb_map[type];
1318         if (H5FD_MEM_DEFAULT==mmt) mmt = type;
1319 
1320 	if (file->memb[mmt]) {
1321             H5E_BEGIN_TRY {
1322 	        eoa = H5FDget_eoa(file->memb[mmt], mmt);
1323             } H5E_END_TRY;
1324 
1325 	    if (HADDR_UNDEF==eoa)
1326                 H5Epush_ret(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "member file has unknown eoa", HADDR_UNDEF)
1327 	    if (eoa>0) eoa += file->fa.memb_addr[mmt];
1328 	} else if (file->fa.relax) {
1329 	    /*
1330 	     * The member is not open yet (maybe it doesn't exist). Make the
1331 	     * best guess about the end-of-file.
1332 	     */
1333 	    eoa = file->memb_next[mmt];
1334 	    assert(HADDR_UNDEF!=eoa);
1335 	 } else {
1336             H5Epush_ret(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "bad eoa", HADDR_UNDEF)
1337 	 }
1338     }
1339 
1340     return eoa;
1341 } /* end H5FD_multi_get_eoa() */
1342 
1343 
1344 /*-------------------------------------------------------------------------
1345  * Function:	H5FD_multi_set_eoa
1346  *
1347  * Purpose:	Set the end-of-address marker for the file by savig the new
1348  *		EOA value in the file struct. Also set the EOA marker for the
1349  *		subfile in which the new EOA value falls. We don't set the
1350  *		EOA values of any other subfiles.
1351  *
1352  * Return:	Success:	0
1353  *
1354  *		Failure:	-1
1355  *
1356  * Programmer:	Robb Matzke
1357  *              Wednesday, August  4, 1999
1358  *
1359  * Modifications:
1360  *              Raymond Lu
1361  *              10 January 2007
1362  *              EOA for the whole file is discarded because it's meaningless
1363  *              for MULTI file.  This function only sets eoa for individual
1364  *              file.
1365  *
1366  *              Raymond Lu
1367  *              21 June 2011
1368  *              Backward compatibility of EOA.  Please the comment in the
1369  *              code.
1370  *-------------------------------------------------------------------------
1371  */
1372 static herr_t
H5FD_multi_set_eoa(H5FD_t * _file,H5FD_mem_t type,haddr_t eoa)1373 H5FD_multi_set_eoa(H5FD_t *_file, H5FD_mem_t type, haddr_t eoa)
1374 {
1375     H5FD_multi_t	*file = (H5FD_multi_t*)_file;
1376     H5FD_mem_t		mmt;
1377     herr_t		status;
1378     static const char *func="H5FD_multi_set_eoa";  /* Function Name for error reporting */
1379 
1380     /* Clear the error stack */
1381     H5Eclear2(H5E_DEFAULT);
1382 
1383     mmt = file->fa.memb_map[type];
1384     if(H5FD_MEM_DEFAULT == mmt)
1385         mmt = type;
1386 
1387     /* Handle backward compatibility in a quick and simple way.  v1.6 library had EOA for the entire virtual
1388      * file.  But it wasn't meaningful.  So v1.8 library doesn't have it anymore.  It saves the EOA for the
1389      * metadata file, instead.  Here we try to figure out whether the EOA is from a v1.6 file by comparing its
1390      * value.  If it is a big value, we assume it's from v1.6 and simply discard it. This is the normal case
1391      * when the metadata file has the smallest starting address.  If the metadata file has the biggest address,
1392      * the EOAs of v1.6 and v1.8 files are the same.  It won't cause any trouble.  (Please see Issue 2598
1393      * in Jira) SLU - 2011/6/21
1394      */
1395     if(H5FD_MEM_SUPER == type && file->memb_eoa[H5FD_MEM_SUPER] > 0 && eoa > file->memb_eoa[H5FD_MEM_SUPER])
1396         return 0;
1397 
1398     assert(eoa >= file->fa.memb_addr[mmt]);
1399     assert(eoa < file->memb_next[mmt]);
1400 
1401     H5E_BEGIN_TRY {
1402 	status = H5FDset_eoa(file->memb[mmt], mmt, (eoa - file->fa.memb_addr[mmt]));
1403     } H5E_END_TRY;
1404     if (status<0)
1405         H5Epush_ret(func, H5E_ERR_CLS, H5E_FILE, H5E_BADVALUE, "member H5FDset_eoa failed", -1)
1406 
1407     return 0;
1408 } /* end H5FD_multi_set_eoa() */
1409 
1410 
1411 /*-------------------------------------------------------------------------
1412  * Function:	H5FD_multi_get_eof
1413  *
1414  * Purpose:	Returns the end-of-file marker, which is the greater of
1415  *		either the total multi size or the current EOA marker.
1416  *
1417  * Return:	Success:	End of file address, the first address past
1418  *				the end of the multi of files or the current
1419  *				EOA, whichever is larger.
1420  *
1421  *		Failure:      	HADDR_UNDEF
1422  *
1423  * Programmer:	Robb Matzke
1424  *              Wednesday, August  4, 1999
1425  *
1426  * Modifications:
1427  *              Raymond Lu
1428  *              5 January 2007
1429  *              Multi driver no longer has EOA for the whole file.  Calculate
1430  *              it in the same way as EOF instead.
1431  *
1432  *-------------------------------------------------------------------------
1433  */
1434 static haddr_t
H5FD_multi_get_eof(const H5FD_t * _file)1435 H5FD_multi_get_eof(const H5FD_t *_file)
1436 {
1437     const H5FD_multi_t	*file = (const H5FD_multi_t*)_file;
1438     haddr_t		eof=0, tmp_eof;
1439     haddr_t		eoa=0, tmp_eoa;
1440     static const char *func="H5FD_multi_get_eof";  /* Function Name for error reporting */
1441 
1442     /* Clear the error stack */
1443     H5Eclear2(H5E_DEFAULT);
1444 
1445     UNIQUE_MEMBERS(file->fa.memb_map, mt) {
1446 	if (file->memb[mt]) {
1447             /* Retrieve EOF */
1448 	    H5E_BEGIN_TRY {
1449 		tmp_eof = H5FDget_eof(file->memb[mt]);
1450 	    } H5E_END_TRY;
1451 
1452 	    if (HADDR_UNDEF==tmp_eof)
1453                 H5Epush_ret(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "member file has unknown eof", HADDR_UNDEF)
1454 	    if (tmp_eof>0) tmp_eof += file->fa.memb_addr[mt];
1455 
1456             /* Retrieve EOA */
1457 	    H5E_BEGIN_TRY {
1458 		tmp_eoa = H5FDget_eoa(file->memb[mt], mt);
1459 	    } H5E_END_TRY;
1460 
1461 	    if (HADDR_UNDEF==tmp_eoa)
1462                 H5Epush_ret(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "member file has unknown eoa", HADDR_UNDEF)
1463 	    if (tmp_eoa>0) tmp_eoa += file->fa.memb_addr[mt];
1464 	} else if (file->fa.relax) {
1465 	    /*
1466 	     * The member is not open yet (maybe it doesn't exist). Make the
1467 	     * best guess about the end-of-file.
1468 	     */
1469 	    tmp_eof = file->memb_next[mt];
1470 	    assert(HADDR_UNDEF!=tmp_eof);
1471 
1472 	    tmp_eoa = file->memb_next[mt];
1473 	    assert(HADDR_UNDEF!=tmp_eoa);
1474 	} else {
1475             H5Epush_ret(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "bad eof", HADDR_UNDEF)
1476 	}
1477 
1478 	if (tmp_eof>eof) eof = tmp_eof;
1479 	if (tmp_eoa>eoa) eoa = tmp_eoa;
1480     } END_MEMBERS;
1481 
1482     return MAX(eoa, eof);
1483 }
1484 
1485 
1486 /*-------------------------------------------------------------------------
1487  * Function:       H5FD_multi_get_handle
1488  *
1489  * Purpose:        Returns the file handle of MULTI file driver.
1490  *
1491  * Returns:        Non-negative if succeed or negative if fails.
1492  *
1493  * Programmer:     Raymond Lu
1494  *                 Sept. 16, 2002
1495  *
1496  * Modifications:
1497  *
1498  *-------------------------------------------------------------------------
1499  */
1500 static herr_t
H5FD_multi_get_handle(H5FD_t * _file,hid_t fapl,void ** file_handle)1501 H5FD_multi_get_handle(H5FD_t *_file, hid_t fapl, void** file_handle)
1502 {
1503     H5FD_multi_t        *file = (H5FD_multi_t *)_file;
1504     H5FD_mem_t          type, mmt;
1505     static const char   *func="H5FD_multi_get_handle";  /* Function Name for error reporting */
1506 
1507     /* Get data type for multi driver */
1508     if(H5Pget_multi_type(fapl, &type) < 0)
1509         H5Epush_ret(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "can't get data type for multi driver", -1)
1510     if(type<H5FD_MEM_DEFAULT || type>=H5FD_MEM_NTYPES)
1511         H5Epush_ret(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "data type is out of range", -1)
1512     mmt = file->fa.memb_map[type];
1513     if(H5FD_MEM_DEFAULT==mmt) mmt = type;
1514 
1515     return (H5FDget_vfd_handle(file->memb[mmt], fapl, file_handle));
1516 }
1517 
1518 
1519 /*-------------------------------------------------------------------------
1520  * Function:	H5FD_multi_alloc
1521  *
1522  * Purpose:	Allocate file memory.
1523  *
1524  * Return:	Success:	Address of new memory
1525  *
1526  *		Failure:	HADDR_UNDEF
1527  *
1528  * Programmer:	Robb Matzke
1529  *              Thursday, August 12, 1999
1530  *
1531  * Modifications:
1532  *
1533  *-------------------------------------------------------------------------
1534  */
1535 static haddr_t
H5FD_multi_alloc(H5FD_t * _file,H5FD_mem_t type,hid_t dxpl_id,hsize_t size)1536 H5FD_multi_alloc(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, hsize_t size)
1537 {
1538     H5FD_multi_t	*file = (H5FD_multi_t*)_file;
1539     H5FD_mem_t		mmt;
1540     haddr_t		addr;
1541     static const char *func="H5FD_multi_alloc";  /* Function Name for error reporting */
1542 
1543     mmt = file->fa.memb_map[type];
1544     if (H5FD_MEM_DEFAULT==mmt) mmt = type;
1545 
1546     if (HADDR_UNDEF==(addr=H5FDalloc(file->memb[mmt], mmt, dxpl_id, size)))
1547         H5Epush_ret(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "member file can't alloc", HADDR_UNDEF)
1548     addr += file->fa.memb_addr[mmt];
1549 
1550 /*#ifdef TMP
1551     if ( addr + size > file->eoa ) {
1552 
1553 	if ( H5FD_multi_set_eoa(_file, addr + size) < 0 ) {
1554 
1555             H5Epush_ret(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, \
1556 			"can't set eoa", HADDR_UNDEF)
1557 	}
1558     }
1559 #else
1560     if ( addr + size > file->eoa )
1561 	file->eoa = addr + size;
1562 #endif */
1563 
1564     return addr;
1565 }
1566 
1567 
1568 /*-------------------------------------------------------------------------
1569  * Function:	H5FD_multi_free
1570  *
1571  * Purpose:	Frees memory
1572  *
1573  * Return:	Success:	0
1574  *
1575  *		Failure:	-1
1576  *
1577  * Programmer:	Robb Matzke
1578  *              Thursday, August 12, 1999
1579  *
1580  * Modifications:
1581  *
1582  *-------------------------------------------------------------------------
1583  */
1584 static herr_t
H5FD_multi_free(H5FD_t * _file,H5FD_mem_t type,hid_t dxpl_id,haddr_t addr,hsize_t size)1585 H5FD_multi_free(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, hsize_t size)
1586 {
1587     H5FD_multi_t	*file = (H5FD_multi_t*)_file;
1588     H5FD_mem_t		mmt;
1589 
1590     /* Clear the error stack */
1591     H5Eclear2(H5E_DEFAULT);
1592 
1593     mmt = file->fa.memb_map[type];
1594     if (H5FD_MEM_DEFAULT==mmt) mmt = type;
1595 
1596     assert(addr>=file->fa.memb_addr[mmt]);
1597     assert(addr+size<=file->memb_next[mmt]);
1598     return H5FDfree(file->memb[mmt], mmt, dxpl_id, addr-file->fa.memb_addr[mmt], size);
1599 }
1600 
1601 
1602 /*-------------------------------------------------------------------------
1603  * Function:	H5FD_multi_read
1604  *
1605  * Purpose:	Reads SIZE bytes of data from FILE beginning at address ADDR
1606  *		into buffer BUF according to data transfer properties in
1607  *		DXPL_ID.
1608  *
1609  * Return:	Success:	Zero. Result is stored in caller-supplied
1610  *				buffer BUF.
1611  *
1612  *		Failure:	-1, contents of buffer BUF are undefined.
1613  *
1614  * Programmer:	Robb Matzke
1615  *              Wednesday, August  4, 1999
1616  *
1617  *-------------------------------------------------------------------------
1618  */
1619 static herr_t
H5FD_multi_read(H5FD_t * _file,H5FD_mem_t type,hid_t dxpl_id,haddr_t addr,size_t size,void * _buf)1620 H5FD_multi_read(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr,
1621     size_t size, void *_buf/*out*/)
1622 {
1623     H5FD_multi_t	*file = (H5FD_multi_t*)_file;
1624     H5FD_multi_dxpl_t	dx;
1625     htri_t              prop_exists = FALSE;    /* Whether the multi VFD DXPL property already exists */
1626     H5FD_mem_t		mt, mmt, hi = H5FD_MEM_DEFAULT;
1627     haddr_t		start_addr = 0;
1628 
1629     /* Clear the error stack */
1630     H5Eclear2(H5E_DEFAULT);
1631 
1632     /* Find the file to which this address belongs */
1633     for(mt = H5FD_MEM_SUPER; mt < H5FD_MEM_NTYPES; mt = (H5FD_mem_t)(mt + 1)) {
1634 	mmt = file->fa.memb_map[mt];
1635 	if(H5FD_MEM_DEFAULT == mmt)
1636             mmt = mt;
1637 	assert(mmt > 0 && mmt < H5FD_MEM_NTYPES);
1638 
1639 	if(file->fa.memb_addr[mmt] > addr)
1640             continue;
1641 	if(file->fa.memb_addr[mmt] >= start_addr) {
1642 	    start_addr = file->fa.memb_addr[mmt];
1643 	    hi = mmt;
1644 	} /* end if */
1645     } /* end for */
1646     assert(hi > 0);
1647 
1648     /* Read from that member */
1649     return H5FDread(file->memb[hi], type, (prop_exists ? dx.memb_dxpl[hi] : H5P_DEFAULT),
1650             addr - start_addr, size, _buf);
1651 } /* end H5FD_multi_read() */
1652 
1653 
1654 /*-------------------------------------------------------------------------
1655  * Function:	H5FD_multi_write
1656  *
1657  * Purpose:	Writes SIZE bytes of data to FILE beginning at address ADDR
1658  *		from buffer BUF according to data transfer properties in
1659  *		DXPL_ID.
1660  *
1661  * Return:	Success:	Zero
1662  *
1663  *		Failure:	-1
1664  *
1665  * Programmer:	Robb Matzke
1666  *              Wednesday, August  4, 1999
1667  *
1668  *-------------------------------------------------------------------------
1669  */
1670 static herr_t
H5FD_multi_write(H5FD_t * _file,H5FD_mem_t type,hid_t dxpl_id,haddr_t addr,size_t size,const void * _buf)1671 H5FD_multi_write(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr,
1672     size_t size, const void *_buf)
1673 {
1674     H5FD_multi_t	*file = (H5FD_multi_t*)_file;
1675     H5FD_multi_dxpl_t	dx;
1676     htri_t              prop_exists = FALSE;    /* Whether the multi VFD DXPL property already exists */
1677     H5FD_mem_t		mt, mmt, hi = H5FD_MEM_DEFAULT;
1678     haddr_t		start_addr = 0;
1679 
1680     /* Clear the error stack */
1681     H5Eclear2(H5E_DEFAULT);
1682 
1683     /* Find the file to which this address belongs */
1684     for(mt = H5FD_MEM_SUPER; mt < H5FD_MEM_NTYPES; mt = (H5FD_mem_t)(mt + 1)) {
1685 	mmt = file->fa.memb_map[mt];
1686 	if(H5FD_MEM_DEFAULT == mmt)
1687             mmt = mt;
1688 	assert(mmt > 0 && mmt<H5FD_MEM_NTYPES);
1689 
1690 	if(file->fa.memb_addr[mmt] > addr)
1691             continue;
1692 	if(file->fa.memb_addr[mmt] >= start_addr) {
1693 	    start_addr = file->fa.memb_addr[mmt];
1694 	    hi = mmt;
1695 	} /* end if */
1696     } /* end for */
1697     assert(hi > 0);
1698 
1699     /* Write to that member */
1700     return H5FDwrite(file->memb[hi], type, (prop_exists ? dx.memb_dxpl[hi] : H5P_DEFAULT),
1701             addr - start_addr, size, _buf);
1702 } /* end H5FD_multi_write() */
1703 
1704 
1705 /*-------------------------------------------------------------------------
1706  * Function:	H5FD_multi_flush
1707  *
1708  * Purpose:	Flushes all multi members.
1709  *
1710  * Return:	Success:	0
1711  *
1712  *		Failure:	-1, as many files flushed as possible.
1713  *
1714  * Programmer:	Robb Matzke
1715  *              Wednesday, August  4, 1999
1716  *
1717  *-------------------------------------------------------------------------
1718  */
1719 static herr_t
H5FD_multi_flush(H5FD_t * _file,hid_t dxpl_id,unsigned closing)1720 H5FD_multi_flush(H5FD_t *_file, hid_t dxpl_id, unsigned closing)
1721 {
1722     H5FD_multi_t	*file = (H5FD_multi_t*)_file;
1723     H5FD_mem_t		mt;
1724     int			nerrors=0;
1725     static const char *func="H5FD_multi_flush";  /* Function Name for error reporting */
1726 
1727 #if 0
1728     H5FD_mem_t		mmt;
1729 
1730     /* Debugging stuff... */
1731     fprintf(stderr, "multifile access information:\n");
1732 
1733     /* print the map */
1734     fprintf(stderr, "    map=");
1735     for (mt=1; mt<H5FD_MEM_NTYPES; mt++) {
1736 	mmt = file->memb_map[mt];
1737 	if (H5FD_MEM_DEFAULT==mmt) mmt = mt;
1738 	fprintf(stderr, "%s%d", 1==mt?"":",", (int)mmt);
1739     }
1740     fprintf(stderr, "\n");
1741 
1742     /* print info about each file */
1743     fprintf(stderr, "      File             Starting            Allocated                 Next Member\n");
1744     fprintf(stderr, "    Number              Address                 Size              Address Name\n");
1745     fprintf(stderr, "    ------ -------------------- -------------------- -------------------- ------------------------------\n");
1746 
1747     for (mt=1; mt<H5FD_MEM_NTYPES; mt++) {
1748 	if (HADDR_UNDEF!=file->memb_addr[mt]) {
1749 	    haddr_t eoa = H5FDget_eoa(file->memb[mt], mt);
1750 	    fprintf(stderr, "    %6d %20llu %20llu %20llu %s\n",
1751 		    (int)mt, (unsigned long long)(file->memb_addr[mt]),
1752 		    (unsigned long long)eoa,
1753 		    (unsigned long long)(file->memb_next[mt]),
1754 		    file->memb_name[mt]);
1755 	}
1756     }
1757 #endif
1758 
1759     /* Clear the error stack */
1760     H5Eclear2(H5E_DEFAULT);
1761 
1762     /* Flush each file */
1763     for (mt=H5FD_MEM_SUPER; mt<H5FD_MEM_NTYPES; mt=(H5FD_mem_t)(mt+1)) {
1764 	if (file->memb[mt]) {
1765 	    H5E_BEGIN_TRY {
1766 		if (H5FDflush(file->memb[mt],dxpl_id,closing)<0) nerrors++;
1767 	    } H5E_END_TRY;
1768 	}
1769     }
1770     if (nerrors)
1771         H5Epush_ret(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "error flushing member files", -1)
1772 
1773     return 0;
1774 }
1775 
1776 
1777 /*-------------------------------------------------------------------------
1778  * Function:	H5FD_multi_truncate
1779  *
1780  * Purpose:	Truncates all multi members.
1781  *
1782  * Return:	Success:	0
1783  *		Failure:	-1, as many files truncated as possible.
1784  *
1785  * Programmer:	Quincey Koziol
1786  *              Thursday, January 31, 2008
1787  *
1788  *-------------------------------------------------------------------------
1789  */
1790 static herr_t
H5FD_multi_truncate(H5FD_t * _file,hid_t dxpl_id,hbool_t closing)1791 H5FD_multi_truncate(H5FD_t *_file, hid_t dxpl_id, hbool_t closing)
1792 {
1793     H5FD_multi_t	*file = (H5FD_multi_t*)_file;
1794     H5FD_mem_t		mt;
1795     int			nerrors=0;
1796     static const char *func="H5FD_multi_truncate";  /* Function Name for error reporting */
1797 
1798     /* Clear the error stack */
1799     H5Eclear2(H5E_DEFAULT);
1800 
1801     /* Truncate each file */
1802     for(mt = H5FD_MEM_SUPER; mt < H5FD_MEM_NTYPES; mt = (H5FD_mem_t)(mt + 1)) {
1803 	if(file->memb[mt]) {
1804 	    H5E_BEGIN_TRY {
1805 		if(H5FDtruncate(file->memb[mt], dxpl_id, closing) < 0)
1806                     nerrors++;
1807 	    } H5E_END_TRY;
1808 	}
1809     }
1810     if(nerrors)
1811         H5Epush_ret(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "error truncating member files", -1)
1812 
1813     return 0;
1814 } /* end H5FD_multi_truncate() */
1815 
1816 
1817 /*-------------------------------------------------------------------------
1818  * Function:	compute_next
1819  *
1820  * Purpose:	Compute the memb_next[] values of the file based on the
1821  *		file's member map and the member starting addresses.
1822  *
1823  * Return:	Success:	0
1824  *
1825  *		Failure:	-1
1826  *
1827  * Programmer:	Robb Matzke
1828  *              Monday, August 23, 1999
1829  *
1830  * Modifications:
1831  *
1832  *-------------------------------------------------------------------------
1833  */
1834 static int
compute_next(H5FD_multi_t * file)1835 compute_next(H5FD_multi_t *file)
1836 {
1837     /* Clear the error stack */
1838     H5Eclear2(H5E_DEFAULT);
1839 
1840     ALL_MEMBERS(mt) {
1841 	file->memb_next[mt] = HADDR_UNDEF;
1842     } END_MEMBERS;
1843 
1844     UNIQUE_MEMBERS(file->fa.memb_map, mt1) {
1845 	UNIQUE_MEMBERS(file->fa.memb_map, mt2) {
1846 	    if (file->fa.memb_addr[mt1]<file->fa.memb_addr[mt2] &&
1847 		(HADDR_UNDEF==file->memb_next[mt1] ||
1848 		 file->memb_next[mt1]>file->fa.memb_addr[mt2])) {
1849 		file->memb_next[mt1] = file->fa.memb_addr[mt2];
1850 	    }
1851 	} END_MEMBERS;
1852 	if (HADDR_UNDEF==file->memb_next[mt1]) {
1853 	    file->memb_next[mt1] = HADDR_MAX; /*last member*/
1854 	}
1855     } END_MEMBERS;
1856 
1857     return 0;
1858 }
1859 
1860 
1861 /*-------------------------------------------------------------------------
1862  * Function:	open_members
1863  *
1864  * Purpose:	Opens all members which are not opened yet.
1865  *
1866  * Return:	Success:	0
1867  *
1868  *		Failure:	-1
1869  *
1870  * Programmer:	Robb Matzke
1871  *              Monday, August 23, 1999
1872  *
1873  * Modifications:
1874  *
1875  *-------------------------------------------------------------------------
1876  */
1877 static int
open_members(H5FD_multi_t * file)1878 open_members(H5FD_multi_t *file)
1879 {
1880     char	tmp[H5FD_MULT_MAX_FILE_NAME_LEN];
1881     int		nerrors=0;
1882     static const char *func="(H5FD_multi)open_members";  /* Function Name for error reporting */
1883 
1884     /* Clear the error stack */
1885     H5Eclear2(H5E_DEFAULT);
1886 
1887     UNIQUE_MEMBERS(file->fa.memb_map, mt) {
1888 	if(file->memb[mt])
1889             continue; /*already open*/
1890 	assert(file->fa.memb_name[mt]);
1891         /* Note: This truncates the user's filename down to only sizeof(tmp)
1892          *      characters. -QK & JK, 2013/01/17
1893          */
1894 	sprintf(tmp, file->fa.memb_name[mt], file->name);
1895 
1896 	H5E_BEGIN_TRY {
1897 	    file->memb[mt] = H5FDopen(tmp, file->flags, file->fa.memb_fapl[mt], HADDR_UNDEF);
1898 	} H5E_END_TRY;
1899 	if(!file->memb[mt]) {
1900 	    if(!file->fa.relax || (file->flags & H5F_ACC_RDWR))
1901 		nerrors++;
1902 	}
1903     } END_MEMBERS;
1904     if (nerrors)
1905         H5Epush_ret(func, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "error opening member files", -1)
1906 
1907     return 0;
1908 }
1909 
1910 
1911 #ifdef _H5private_H
1912 /*
1913  * This is not related to the functionality of the driver code.
1914  * It is added here to trigger warning if HDF5 private definitions are included
1915  * by mistake.  The code should use only HDF5 public API and definitions.
1916  */
1917 #error "Do not use HDF5 private definitions"
1918 #endif
1919