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