1 /*********************************************************************
2 * Copyright 2018, UCAR/Unidata
3 * See netcdf/COPYRIGHT file for copying and redistribution conditions.
4 * ********************************************************************/
5
6 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
7 * Copyright by The HDF Group. *
8 * Copyright by the Board of Trustees of the University of Illinois. *
9 * All rights reserved. *
10 * *
11 * This file is part of HDF5. The full HDF5 copyright notice, including *
12 * terms governing use, modification, and redistribution, is contained in *
13 * the COPYING file, which can be found at the root of the source code *
14 * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
15 * If you do not have access to either file, you may request a copy from *
16 * help@hdfgroup.org. *
17 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
18
19 /*
20 * @internal Inmemory support
21 *
22 * This code is derived from H5LT.c#H5LTopen_file_image.
23 * In order to make the netcdf inmemory code work, it is necessary
24 * to modify some of the callback functions; specifically
25 * image_malloc, image_realloc, and image_memcpy.
26 * <p>
27 * The changes are directed at allowing the caller to
28 * specify two things.
29 * <ol>
30 * <li> To specify (indirectly) the H5LT_FILE_IMAGE_DONT_COPY flag.
31 * This means that no attempt to realloc the caller provided memory
32 * should be made. This also means that the memory block pointer
33 * provided by the caller will be thesame returned by <em>nc_close_memio()</em>.
34 * <li> The caller overallocates the memory so that there is space
35 * to allow the file to be modified in place.
36 * </ol>
37 * <p>
38 * The existing implementation of H5LTopen_file_image has two flaws
39 * with respect to these properties.
40 * <ol>
41 * <li> The image_realloc callback fails if
42 * H5LT_FILE_IMAGE_DONT_COPY flag is set even if there is room
43 * to allow the memory block to pretend to expand (because
44 * of overallocation).
45 * <li> When the caller attempts to get the final memory block,
46 * the HDF5 library makes a copy, unless theH5LT_FILE_IMAGE_DONT_COPY
47 * flag is set. This is unnecessary. Note that in this situation,
48 * the HDF5 library will use
49 * <em>image_malloc()</em>
50 * followed by
51 * <em>image_memcpy()</em>
52 * </ol>
53 * <p>
54 * So, the callback changes to support this properly are as follows.
55 * <dl>
56 * <dt>image_realloc</dt>
57 * <dd>If there is sufficient space (because of overallocation),
58 * the pretend to realloc and return the incoming memory block
59 * instead of taking the chance of doing a real realloc.</dd>
60 * <dt>image_malloc</dt>
61 * <dd>If the operation being performed is to obtain
62 * the space to copy the final memory, then just return
63 * the original memory block. Note that this case is detectable
64 * because the callback is given the value
65 * H5FD_FILE_IMAGE_OP_PROPERTY_LIST_GET.</dd>
66 * <dt>image_memcpy</dt>
67 * <dd>Similar to the image_malloc change.
68 * Namely, if the operation being performed is to copy
69 * out the final memory contents, and the final memory block
70 * is the same as that provided by the caller originally, then
71 * just do nothing. Again, this case can be detected
72 * by the occurrence of H5FD_FILE_IMAGE_OP_PROPERTY_LIST_GET.</dd>
73 * </dl>
74 * @author Dennis Heimbigner
75 */
76
77 #include <string.h>
78 #include <stdlib.h>
79 #include <assert.h>
80 #include <stdio.h>
81
82 #include <hdf5.h>
83 #include <hdf5_hl.h>
84
85 #include "nc4internal.h"
86 #include "hdf5internal.h"
87
88 #ifndef HDrealloc
89 #define HDrealloc(x,y) realloc(x,y)
90 #endif
91 #ifndef SUCCEED
92 #define SUCCEED 0
93 #define FAIL -1
94 #endif
95 #ifndef FALSE
96 #define FALSE 0
97 #endif
98
99 #undef TRACE
100 #undef CATCH
101 #undef TRACE_UDATA
102
103 #ifdef TRACE
104 #define CATCH
105 #endif
106
107 #ifdef TRACE
108 #include <stdarg.h>
109 static void trace(const char* fcn, H5FD_file_image_op_t op, void* _udata, ...);
110 static void traceend(const char* fcn, void* _udata, uintptr_t retval);
111 static const char* traceop(H5FD_file_image_op_t op);
112 static char* traceflags(int flags);
113
114 /* In case we do not have variadic macros */
115 #define TRACE0(fcn,op,udata) trace(fcn,op,udata)
116 #define TRACE1(fcn,op,udata,x1) trace(fcn,op,udata,x1)
117 #define TRACE2(fcn,op,udata,x1,x2) trace(fcn,op,udata,x1,x2)
118 #define TRACE3(fcn,op,udata,x1,x2,x3) trace(fcn,op,udata,x1,x2,x3)
119 #define TRACEEND(fcn,udata,retval) traceend(fcn,udata,(uintptr_t)retval);
120 #else /*!TRACE*/
121 #define TRACE0(fcn,op,udata)
122 #define TRACE1(fcn,op,udata,x1)
123 #define TRACE2(fcn,op,udata,x1,x2)
124 #define TRACE3(fcn,op,udata,x1,x2,x3)
125 #define TRACEEND(fcn,udata,retval)
126 #endif
127
128 #ifdef CATCH
129 static void tracefail(const char* fcn);
130 #define TRACEFAIL(fcn) tracefail(fcn)
131 #else
132 #define TRACEFAIL(fcn)
133 #endif
134
135 #define DEFAULT_CREATE_MEMSIZE ((size_t)1<<16)
136
137 #ifndef H5LT_FILE_IMAGE_DONT_COPY
138
139 /* Flag definitions for H5LTopen_file_image() */
140 #define H5LT_FILE_IMAGE_OPEN_RW 0x0001 /* Open image for read-write */
141 #define H5LT_FILE_IMAGE_DONT_COPY 0x0002 /* The HDF5 lib won't copy */
142 /* user supplied image buffer. The same image is open with the core driver. */
143 #define H5LT_FILE_IMAGE_DONT_RELEASE 0x0004 /* The HDF5 lib won't */
144 /* deallocate user supplied image buffer. The user application is responsible */
145 /* for doing so. */
146 #define H5LT_FILE_IMAGE_ALL 0x0007
147
148 #endif /*H5LT_FILE_IMAGE_DONT_COPY*/
149
150
151 #if 0
152 /* For Lex and Yacc */
153 #define COL 3
154 #define LIMIT 512
155 #define INCREMENT 1024
156 #define TMP_LEN 256
157 #define MAX(a,b) (((a)>(b)) ? (a) : (b))
158 size_t input_len;
159 char *myinput;
160 size_t indent = 0;
161 #endif /*0*/
162
163 /* File Image operations
164
165 A file image is a representation of an HDF5 file in a memory
166 buffer. In order to perform operations on an image in a similar way
167 to a file, the application buffer is copied to a FAPL buffer, which
168 in turn is copied to a VFD buffer. Buffer copying can decrease
169 performance, especially when using large file images. A solution to
170 this issue is to simulate the copying of the application buffer,
171 when actually the same buffer is used for the FAPL and the VFD.
172 This is implemented by using callbacks that simulate the standard
173 functions for memory management (additional callbacks are used for
174 the management of associated data structures). From the application
175 standpoint, a file handle can be obtained from a file image by using
176 the API routine H5LTopen_file_image(). This function takes a flag
177 argument that indicates the HDF5 library how to handle the given image;
178 several flag values can be combined by using the bitwise OR operator.
179 Valid flag values include:
180
181 H5LT_FILE_IMAGE_OPEN_RW indicates the HDF5 library to open the file
182 image in read/write mode. Default is read-only mode.
183
184 H5LT_FILE_IMAGE_DONT_COPY indicates the HDF5 library to not copy the
185 supplied user buffer; the same buffer will be handled by the FAPL and
186 the VFD driver. Default operation copies the user buffer to the FAPL and
187 VFD driver.
188
189 H5LT_FILE_IMAGE_DONT_RELEASE indicates the HDF5 library to not release
190 the buffer handled by the FAPL and the VFD upon closing. This flag value
191 is only applicable when the flag value H5LT_FILE_IMAGE_DONT_COPY is set as
192 well. The application is responsible to release the image buffer.
193 */
194
195 /* Data structure to pass application data to callbacks. */
196 /* Modified to add NC_FILE_INFO_T ptr */
197 typedef struct {
198 void *app_image_ptr; /* Pointer to application buffer */
199 size_t app_image_size; /* Size of application buffer */
200 void *fapl_image_ptr; /* Pointer to FAPL buffer */
201 size_t fapl_image_size; /* Size of FAPL buffer */
202 int fapl_ref_count; /* Reference counter for FAPL buffer */
203 void *vfd_image_ptr; /* Pointer to VFD buffer */
204 size_t vfd_image_size; /* Size of VFD buffer */
205 int vfd_ref_count; /* Reference counter for VFD buffer */
206 unsigned flags; /* Flags indicate how the file image will */
207 /* be open */
208 int ref_count; /* Reference counter on udata struct */
209 NC_FILE_INFO_T* h5;
210 } H5LT_file_image_ud_t;
211
212 /* Unique id for file name */
213 static long file_name_counter;
214
215 /* callbacks prototypes for file image ops */
216 static void *local_image_malloc(size_t size, H5FD_file_image_op_t file_image_op, void *udata);
217 static void *local_image_memcpy(void *dest, const void *src, size_t size, H5FD_file_image_op_t file_image_op, void *udata);
218 static herr_t local_image_free(void *ptr, H5FD_file_image_op_t file_image_op, void *udata);
219 static void *local_udata_copy(void *udata);
220 static herr_t local_udata_free(void *udata);
221
222 /* Definition of callbacks for file image operations. */
223
224
225 /*-------------------------------------------------------------------------
226 * Function: image_malloc
227 *
228 * Purpose: Simulates malloc() function to avoid copying file images.
229 * The application buffer is set to the buffer on only one FAPL.
230 * Then the FAPL buffer can be copied to other FAPL buffers or
231 * to only one VFD buffer.
232 *
233 * Return: Address of "allocated" buffer, if successful. Otherwise, it returns
234 * NULL.
235 *
236 * Programmer: Christian Chilan
237 *
238 * Date: October 3, 2011
239 *
240 *-------------------------------------------------------------------------
241 */
242 static void *
local_image_malloc(size_t size,H5FD_file_image_op_t file_image_op,void * _udata)243 local_image_malloc(size_t size, H5FD_file_image_op_t file_image_op, void *_udata)
244 {
245 H5LT_file_image_ud_t *udata = (H5LT_file_image_ud_t *)_udata;
246 void * return_value = NULL;
247
248 TRACE1("malloc", file_image_op, _udata, size);
249
250 #if 0
251 /* callback is only used if the application buffer is not actually copied */
252 if (!(udata->flags & H5LT_FILE_IMAGE_DONT_COPY))
253 goto out;
254 #endif
255
256 switch ( file_image_op ) {
257 /* the app buffer is "copied" to only one FAPL. Afterwards, FAPLs can be "copied" */
258 case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_SET:
259 /* It appears that the fapl memory is never created as we use it, so
260 we expect the udata ptr to be either null or same as the app buffer.*/
261 assert(udata->fapl_image_ptr == NULL || udata->fapl_image_ptr == udata->app_image_ptr);
262
263 if (udata->app_image_ptr == NULL)
264 goto out;
265 if (udata->app_image_size != size)
266 goto out;
267 if (udata->fapl_image_ptr != NULL)
268 goto out;
269 if (udata->fapl_image_size != 0)
270 goto out;
271 if (udata->fapl_ref_count != 0)
272 goto out;
273
274 udata->fapl_image_ptr = udata->app_image_ptr;
275 udata->fapl_image_size = udata->app_image_size;
276 return_value = udata->fapl_image_ptr;
277 udata->fapl_ref_count++;
278 return_value = udata->fapl_image_ptr;
279 break;
280
281 case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_COPY:
282 if (udata->fapl_image_ptr == NULL)
283 goto out;
284 if (udata->fapl_image_size != size)
285 goto out;
286 if (udata->fapl_ref_count == 0)
287 goto out;
288
289 return_value = udata->fapl_image_ptr;
290 udata->fapl_ref_count++;
291 break;
292
293 case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_GET:
294 if (udata->fapl_image_ptr == NULL)
295 goto out;
296 /* fake the malloc by returning the current memory */
297 return_value = udata->fapl_image_ptr;
298 break;
299
300 case H5FD_FILE_IMAGE_OP_FILE_OPEN:
301 /* FAPL buffer is "copied" to only one VFD buffer */
302 if (udata->vfd_image_ptr != NULL)
303 goto out;
304 if (udata->vfd_image_size != 0)
305 goto out;
306 if (udata->vfd_ref_count != 0)
307 goto out;
308 if (udata->fapl_image_ptr == NULL)
309 goto out;
310 if (udata->fapl_image_size != size)
311 goto out;
312 if (udata->fapl_ref_count == 0)
313 goto out;
314
315 udata->vfd_image_ptr = udata->fapl_image_ptr;
316 udata->vfd_image_size = size;
317 udata->vfd_ref_count++;
318 return_value = udata->vfd_image_ptr;
319 break;
320
321 /* added unused labels to shut the compiler up */
322 case H5FD_FILE_IMAGE_OP_NO_OP:
323 case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_CLOSE:
324 case H5FD_FILE_IMAGE_OP_FILE_RESIZE:
325 case H5FD_FILE_IMAGE_OP_FILE_CLOSE:
326 default:
327 goto out;
328 } /* end switch */
329
330 TRACEEND("malloc",_udata,return_value);
331
332 return(return_value);
333
334 out:
335 TRACEFAIL("malloc");
336 return NULL;
337 } /* end image_malloc() */
338
339
340 /*-------------------------------------------------------------------------
341 * Function: image_memcpy
342 *
343 * Purpose: Simulates memcpy() function to avoid copying file images.
344 * The image buffer can be set to only one FAPL buffer, and
345 * "copied" to only one VFD buffer. The FAPL buffer can be
346 * "copied" to other FAPLs buffers.
347 *
348 * Return: The address of the destination buffer, if successful. Otherwise, it
349 * returns NULL.
350 *
351 * Programmer: Christian Chilan
352 *
353 * Date: October 3, 2011
354 *
355 *-------------------------------------------------------------------------
356 */
357 static void *
local_image_memcpy(void * dest,const void * src,size_t size,H5FD_file_image_op_t file_image_op,void * _udata)358 local_image_memcpy(void *dest, const void *src, size_t size, H5FD_file_image_op_t file_image_op,
359 void *_udata)
360 {
361 H5LT_file_image_ud_t *udata = (H5LT_file_image_ud_t *)_udata;
362
363 TRACE3("memcpy", file_image_op, _udata,dest,src,size);
364
365 #if 0
366 /* callback is only used if the application buffer is not actually copied */
367 if (!(udata->flags & H5LT_FILE_IMAGE_DONT_COPY))
368 goto out;
369 #endif
370
371 switch(file_image_op) {
372 case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_SET:
373 if (dest != udata->fapl_image_ptr)
374 goto out;
375 if (src != udata->app_image_ptr)
376 goto out;
377 if (size != udata->fapl_image_size)
378 goto out;
379 if (size != udata->app_image_size)
380 goto out;
381 if (udata->fapl_ref_count == 0)
382 goto out;
383 if (!(udata->flags & H5LT_FILE_IMAGE_DONT_COPY)) {
384 if(src != dest) {
385 memcpy(dest,src,size);
386 #ifdef TRACE
387 fprintf(stderr,"\t>>>> memcpy(%p,%p,%ld)\n",
388 dest,src,(unsigned long)size);
389 #endif
390 }
391 }
392 break;
393
394 case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_COPY:
395 if (dest != udata->fapl_image_ptr)
396 goto out;
397 if (src != udata->fapl_image_ptr)
398 goto out;
399 if (size != udata->fapl_image_size)
400 goto out;
401 if (udata->fapl_ref_count < 2)
402 goto out;
403 break;
404
405 case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_GET:
406 if (!(udata->flags & H5LT_FILE_IMAGE_DONT_COPY))
407 goto out;
408 /* test: src == dest == original */
409 if(src != dest || src != udata->fapl_image_ptr)
410 goto out;
411 break;
412
413 case H5FD_FILE_IMAGE_OP_FILE_OPEN:
414 if (dest != udata->vfd_image_ptr)
415 goto out;
416 if (src != udata->fapl_image_ptr)
417 goto out;
418 if (size != udata->vfd_image_size)
419 goto out;
420 if (size != udata->fapl_image_size)
421 goto out;
422 if (udata->fapl_ref_count == 0)
423 goto out;
424 if (udata->vfd_ref_count != 1)
425 goto out;
426 break;
427
428 /* added unused labels to shut the compiler up */
429 case H5FD_FILE_IMAGE_OP_NO_OP:
430 case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_CLOSE:
431 case H5FD_FILE_IMAGE_OP_FILE_RESIZE:
432 case H5FD_FILE_IMAGE_OP_FILE_CLOSE:
433 default:
434 goto out;
435 } /* end switch */
436
437 TRACEEND("memcpy",_udata,dest);
438 return(dest);
439
440 out:
441 TRACEFAIL("memcpy");
442 return NULL;
443 } /* end image_memcpy() */
444
445
446 /*-------------------------------------------------------------------------
447 * Function: image_realloc
448 *
449 * Purpose: Reallocates the shared application image buffer and updates data
450 * structures that manage buffer "copying".
451 *
452 * Return: Address of reallocated buffer, if successful. Otherwise, it returns
453 * NULL.
454 *
455 * Programmer: Christian Chilan
456 *
457 * Date: October 3, 2011
458 *
459 *-------------------------------------------------------------------------
460 */
461
462 /* This warning is from H5FDcore.c"
463 Be careful of non-Posix realloc() that doesn't understand
464 what to do when the first argument is null.
465 */
466
467 /* Modified:
468 1. If the realloc new size is <= existing size,
469 then pretend we did a realloc and return success.
470 This avoids unnecessary heap operations.
471 2. If the H5LT_FILE_IMAGE_DONT_COPY or
472 H5LT_FILE_IMAGE_DONT_RELEASE flag is set and the
473 realloc new size is > existing size, then fail
474 because the realloc() call may change the address
475 of the buffer. The new address cannot be
476 communicated to the application to release it.
477 3. Otherwise, use realloc(). Note that this may have the
478 side effect of freeing the previous memory chunk.
479 */
480 static void *
local_image_realloc(void * ptr,size_t size,H5FD_file_image_op_t file_image_op,void * _udata)481 local_image_realloc(void *ptr, size_t size, H5FD_file_image_op_t file_image_op, void *_udata)
482 {
483 H5LT_file_image_ud_t *udata = (H5LT_file_image_ud_t *)_udata;
484 void * return_value = NULL;
485
486 TRACE2("realloc", file_image_op, _udata, ptr, size);
487
488 #if 0
489 /* callback is only used if the application buffer is not actually copied */
490 if (!(udata->flags & H5LT_FILE_IMAGE_DONT_COPY))
491 goto out;
492 #endif
493
494 /* realloc() is not allowed if the image is open in read-only mode */
495 if (!(udata->flags & H5LT_FILE_IMAGE_OPEN_RW))
496 goto out;
497
498 /* DONT_COPY => DONT_RELEASE */
499 assert(((udata->flags & H5LT_FILE_IMAGE_DONT_COPY)?(udata->flags & H5LT_FILE_IMAGE_DONT_RELEASE):1));
500
501 /* Note that the fapl pointer is never realloc'd */
502 if (file_image_op == H5FD_FILE_IMAGE_OP_FILE_RESIZE) {
503
504 if (!(udata->flags & H5LT_FILE_IMAGE_DONT_COPY)) { /* buffer modification is allowed */
505 /* Divide code based on whether ptr == NULL or not */
506 if(ptr == NULL) {
507 /* From realloc man page: If ptr is NULL, then the call is equivalent to malloc(size),
508 for all values of size; if size is equal to zero, and ptr is not NULL, then the call
509 is equivalent to free(ptr). */
510 /* if the app_image != NULL then free it to simulate effect of realloc */
511 if(udata->app_image_ptr != NULL)
512 free(udata->app_image_ptr);
513 udata->vfd_image_ptr = malloc(size);
514 udata->vfd_ref_count++;
515 } else { /* ptr != NULL */
516 if(udata->vfd_image_ptr != ptr)
517 goto out;
518 if (udata->vfd_ref_count != 1)
519 goto out;
520 udata->vfd_image_ptr = realloc(ptr, size);
521 if(NULL == udata->vfd_image_ptr) {
522 LOG((0,"image_realloc: unable to allocate memory block of size: %lu bytes",(unsigned long)size));
523 goto out;
524 }
525 #ifdef TRACE
526 fprintf(stderr,"\t>>>> realloc(%p,%ld)=>%p\n",ptr,(unsigned long)size,udata->vfd_image_ptr);
527 #endif
528 }
529 udata->vfd_image_size = size;
530
531 /* Make sure other pointers are consistent */
532 udata->app_image_ptr = udata->vfd_image_ptr;
533 udata->fapl_image_ptr = udata->vfd_image_ptr;
534
535 } else { /* Cannot realloc, so fake it */
536 if(size <= udata->vfd_image_size) {
537 /* Ok, pretend we did a realloc but just change size*/
538 udata->vfd_image_size = size;
539 } else
540 goto out;
541 }
542 return_value = udata->vfd_image_ptr;
543 } /* end if */
544 else
545 goto out;
546
547 TRACEEND("realloc",_udata,return_value);
548 return(return_value);
549
550 out:
551 TRACEFAIL("realloc");
552 return NULL;
553 } /* end local_image_realloc() */
554
555 /*-------------------------------------------------------------------------
556 * Function: image_free
557 *
558 * Purpose: Simulates deallocation of FAPL and VFD buffers by decreasing
559 * reference counters. Shared application buffer is actually
560 * deallocated if there are no outstanding references.
561 *
562 * Return: SUCCEED or FAIL
563 *
564 * Programmer: Christian Chilan
565 *
566 * Date: October 3, 2011
567 *
568 *-------------------------------------------------------------------------
569 */
570 static herr_t
local_image_free(void * ptr,H5FD_file_image_op_t file_image_op,void * _udata)571 local_image_free(void *ptr, H5FD_file_image_op_t file_image_op, void *_udata)
572 {
573 H5LT_file_image_ud_t *udata = (H5LT_file_image_ud_t *)_udata;
574
575 TRACE1("free", file_image_op, _udata, ptr);
576
577 #if 0
578 /* callback is only used if the application buffer is not actually copied */
579 if (!(udata->flags & H5LT_FILE_IMAGE_DONT_COPY))
580 goto out;
581 #endif
582
583 switch(file_image_op) {
584 case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_CLOSE:
585 if (udata->fapl_image_ptr != ptr)
586 goto out;
587 if (udata->fapl_ref_count == 0)
588 goto out;
589
590 udata->fapl_ref_count--;
591
592 /* For the way we use it, it should still be the case that
593 the fapl pointer is same as image_ptr, so we do not need
594 to do anything */
595 assert(udata->fapl_image_ptr == udata->app_image_ptr);
596 /* clean up */
597 #if 0
598 udata->app_image_ptr = NULL;
599 udata->fapl_image_ptr = NULL;
600 #endif
601 break;
602
603 case H5FD_FILE_IMAGE_OP_FILE_CLOSE:
604 if (udata->vfd_image_ptr != ptr)
605 goto out;
606 if (udata->vfd_ref_count != 1)
607 goto out;
608
609 udata->vfd_ref_count--;
610
611 break;
612
613 /* added unused labels to keep the compiler quiet */
614 case H5FD_FILE_IMAGE_OP_NO_OP:
615 case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_SET:
616 case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_COPY:
617 case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_GET:
618 case H5FD_FILE_IMAGE_OP_FILE_OPEN:
619 case H5FD_FILE_IMAGE_OP_FILE_RESIZE:
620 default:
621 goto out;
622 } /* end switch */
623
624 TRACEEND("free",_udata,1);
625 return(SUCCEED);
626
627 out:
628 TRACEFAIL("free");
629 return(FAIL);
630 } /* end image_free() */
631
632
633 /*-------------------------------------------------------------------------
634 * Function: udata_copy
635 *
636 * Purpose: Simulates the copying of the user data structure utilized in the
637 * management of the "copying" of file images.
638 *
639 * Return: Address of "newly allocated" structure, if successful. Otherwise, it
640 * returns NULL.
641 *
642 * Programmer: Christian Chilan
643 *
644 * Date: October 3, 2011
645 *
646 *-------------------------------------------------------------------------
647 */
648 static void *
local_udata_copy(void * _udata)649 local_udata_copy(void *_udata)
650 {
651 H5LT_file_image_ud_t *udata = (H5LT_file_image_ud_t *)_udata;
652
653 TRACE0("udata_copy", 0, _udata);
654
655 #if 0
656 /* callback is only used if the application buffer is not actually copied */
657 if (!(udata->flags & H5LT_FILE_IMAGE_DONT_COPY))
658 goto out;
659 #endif
660
661 /* never copy so we only have one instance */
662 if (udata->ref_count == 0)
663 goto out;
664 udata->ref_count++;
665
666 TRACEEND("udata_copy",udata,1);
667 return(udata);
668
669 out:
670 TRACEFAIL("udata_copy");
671 return NULL;
672 } /* end udata_copy */
673
674
675 /*-------------------------------------------------------------------------
676 * Function: udata_free
677 *
678 * Purpose: Simulates deallocation of the user data structure utilized in the
679 * management of the "copying" of file images. The data structure is
680 * actually deallocated when there are no outstanding references.
681 *
682 * Return: SUCCEED or FAIL
683 *
684 * Programmer: Christian Chilan
685 *
686 * Date: October 3, 2011
687 *
688 *-------------------------------------------------------------------------
689 */
690 static herr_t
local_udata_free(void * _udata)691 local_udata_free(void *_udata)
692 {
693 H5LT_file_image_ud_t *udata = (H5LT_file_image_ud_t *)_udata;
694
695 TRACE0("udata_free", 0, _udata);
696
697 #if 0
698 /* callback is only used if the application buffer is not actually copied */
699 if (!(udata->flags & H5LT_FILE_IMAGE_DONT_COPY))
700 goto out;
701 #endif
702
703 if (udata->ref_count == 0)
704 goto out;
705 udata->ref_count--;
706
707 TRACEEND("udata_free",udata,1);
708 return(SUCCEED);
709
710 out:
711 TRACEFAIL("udata_free");
712 return(FAIL);
713 } /* end udata_free */
714
715
716 /* End of callbacks definitions for file image operations */
717
718 hid_t
NC4_image_init(NC_FILE_INFO_T * h5)719 NC4_image_init(NC_FILE_INFO_T* h5)
720 {
721 hid_t fapl = -1, file_id = -1; /* HDF5 identifiers */
722 unsigned file_open_flags = 0;/* Flags for hdf5 open */
723 char file_name[64]; /* Filename buffer */
724 size_t alloc_incr; /* Buffer allocation increment */
725 size_t min_incr = 65536; /* Minimum buffer increment */
726 double buf_prcnt = 0.1f; /* Percentage of buffer size to set
727 as increment */
728 unsigned imageflags;
729 int create = 0;
730 H5LT_file_image_ud_t *udata = NULL; /* Pointer to udata structure */
731
732 H5FD_file_image_callbacks_t callbacks = {&local_image_malloc, &local_image_memcpy,
733 &local_image_realloc, &local_image_free,
734 &local_udata_copy, &local_udata_free,
735 (void *)NULL};
736 imageflags = h5->mem.imageflags;
737 create = h5->mem.created;
738
739 /* check arguments */
740 if (h5->mem.memio.memory == NULL) {
741 if(create) {
742 if(h5->mem.memio.size == 0) h5->mem.memio.size = DEFAULT_CREATE_MEMSIZE;
743 h5->mem.memio.memory = malloc(h5->mem.memio.size);
744 } else
745 goto out; /* open requires an input buffer */
746 } else if(h5->mem.memio.size == 0)
747 goto out;
748
749 /* Create FAPL to transmit file image */
750 if ((fapl = H5Pcreate(H5P_FILE_ACCESS)) < 0)
751 goto out;
752
753 /* set allocation increment to a percentage of the supplied buffer size, or
754 * a pre-defined minimum increment value, whichever is larger
755 */
756 if ((buf_prcnt * h5->mem.memio.size) > min_incr)
757 alloc_incr = (size_t)(buf_prcnt * h5->mem.memio.size);
758 else
759 alloc_incr = min_incr;
760
761 /* Configure FAPL to use the core file driver */
762 if (H5Pset_fapl_core(fapl, alloc_incr, FALSE) < 0)
763 goto out;
764
765 /* Set callbacks for file image ops always */
766 {
767 /* Allocate buffer to communicate user data to callbacks */
768 if (NULL == (udata = (H5LT_file_image_ud_t *)calloc(1,sizeof(H5LT_file_image_ud_t))))
769 goto out;
770
771 /* Initialize udata with info about app buffer containing file image and flags */
772 udata->app_image_ptr = h5->mem.memio.memory;
773 udata->app_image_size = h5->mem.memio.size;
774 h5->mem.memio.memory = NULL; /* move control */
775 h5->mem.memio.size = 0;
776 udata->fapl_image_ptr = NULL;
777 udata->fapl_image_size = 0;
778 udata->fapl_ref_count = 0;
779 udata->vfd_image_ptr = NULL;
780 udata->vfd_image_size = 0;
781 udata->vfd_ref_count = 0;
782 udata->flags = imageflags;
783 udata->ref_count = 1; /* corresponding to the first FAPL */
784 udata->h5 = h5;
785
786 /* copy address of udata into callbacks */
787 callbacks.udata = (void *)udata;
788 /* Set file image callbacks */
789 if (H5Pset_file_image_callbacks(fapl, &callbacks) < 0)
790 goto out;
791 }
792
793 /* Assign file image in user buffer to FAPL */
794 if (H5Pset_file_image(fapl, udata->app_image_ptr, udata->app_image_size) < 0)
795 goto out;
796
797 /* define a unique file name */
798 snprintf(file_name, (sizeof(file_name) - 1), "file_image_%ld", file_name_counter++);
799
800 /* set file open/create flags */
801 if(create)
802 file_open_flags = H5F_ACC_TRUNC; /* H5Fcreate does not like H5F_ACC_RDWR */
803 else if (imageflags & H5LT_FILE_IMAGE_OPEN_RW)
804 file_open_flags = H5F_ACC_RDWR;
805 else
806 file_open_flags = H5F_ACC_RDONLY;
807
808 /* Assign file image in FAPL to the core file driver */
809 if(create) {
810 if ((file_id = nc4_H5Fcreate(file_name, file_open_flags, H5P_DEFAULT, fapl)) < 0)
811 goto out;
812 } else {
813 if ((file_id = nc4_H5Fopen(file_name, file_open_flags, fapl)) < 0)
814 goto out;
815 }
816
817 /* Maintain a backward link */
818 h5->mem.udata = (void*)udata;
819 udata = NULL;
820
821 done:
822 /* Reclaim the fapl object */
823 H5E_BEGIN_TRY {
824 if(fapl >= 0)
825 H5Pclose(fapl);
826 } H5E_END_TRY;
827 /* Return file identifier */
828 return file_id;
829
830 out:
831 /* free up udata only on error */
832 if(udata != NULL) free(udata);
833 file_id = -1;
834 goto done;
835 } /* end H5LTopen_file_image() */
836
837 void
NC4_image_finalize(void * _udata)838 NC4_image_finalize(void* _udata)
839 {
840 if(_udata != NULL) {
841 H5LT_file_image_ud_t *udata = (H5LT_file_image_ud_t*)_udata;
842 /* checks reference counts before deallocating udata */
843 #if 0
844 assert(udata->ref_count == 1 && udata->fapl_ref_count == 0 && udata->vfd_ref_count == 0);
845 if(udata->app_image_ptr != NULL) free(udata->app_image_ptr);
846 if(udata->fapl_image_ptr != NULL) free(udata->fapl_image_ptr);
847 if(udata->vfd_image_ptr != NULL) free(udata->vfd_image_ptr);
848 #endif
849 free(udata);
850 #ifdef TRACE_UDATA
851 fprintf(stderr,"\t>>>> freed: udata=%p\n",udata);
852 #endif
853 }
854 }
855
856 int
NC4_extract_file_image(NC_FILE_INFO_T * h5)857 NC4_extract_file_image(NC_FILE_INFO_T* h5)
858 {
859 int stat = NC_NOERR;
860 H5LT_file_image_ud_t *udata;
861
862 udata = (H5LT_file_image_ud_t *)h5->mem.udata;
863 assert(udata != NULL);
864
865 /* Fill in h5->mem.memio from udata */
866 h5->mem.memio.memory = udata->vfd_image_ptr;
867 h5->mem.memio.size = udata->vfd_image_size;
868
869 /* Move control */
870 udata->vfd_image_ptr = NULL;
871 udata->vfd_image_size = 0;
872
873 return stat;
874 }
875
876 #ifdef TRACE
877
878 static char*
printudata(H5LT_file_image_ud_t * udata)879 printudata(H5LT_file_image_ud_t* udata)
880 {
881 char buf[8192];
882 char tmp[8192];
883 char* flags = "";
884
885 buf[0] = '\0';
886 if(udata == NULL) return strdup("");
887 strlcat(buf,"flags=",sizeof(buf));
888 flags = traceflags(udata->flags);
889 strlcat(buf,flags,sizeof(buf));
890 if(flags != NULL) free(flags);
891 snprintf(tmp,sizeof(tmp)," ref_count=%d",udata->ref_count);
892 strlcat(buf,tmp,sizeof(tmp));
893 snprintf(tmp,sizeof(tmp)," app=(%p,%lld)",udata->app_image_ptr,(long long)udata->app_image_size);
894 strlcat(buf,tmp,sizeof(tmp));
895 snprintf(tmp,sizeof(tmp)," fapl=(%p,%lld)[%d]",udata->fapl_image_ptr,(long long)udata->fapl_image_size,udata->fapl_ref_count);
896 strlcat(buf,tmp,sizeof(tmp));
897 snprintf(tmp,sizeof(tmp)," vfd=(%p,%lld)[%d]",udata->vfd_image_ptr,(long long)udata->vfd_image_size,udata->vfd_ref_count);
898 strlcat(buf,tmp,sizeof(tmp));
899 return strdup(buf);
900 }
901
902 static void
trace(const char * fcn,H5FD_file_image_op_t op,void * _udata,...)903 trace(const char* fcn, H5FD_file_image_op_t op, void* _udata, ...)
904 {
905 H5LT_file_image_ud_t *udata = NULL;
906 va_list ap;
907 char buf[16000];
908 char tmp[8192];
909 char* ud;
910
911 va_start(ap, _udata); /* Requires the last fixed parameter (to get the address) */
912 udata = (H5LT_file_image_ud_t *)_udata;
913 buf[0] = '\0';
914 snprintf(tmp,sizeof(tmp),"trace [ %s: op=%s: ",fcn,traceop(op));
915 strlcat(buf,tmp,sizeof(tmp));
916 if(strcmp("malloc",fcn)==0) {
917 size_t size = va_arg(ap,size_t);
918 snprintf(tmp,sizeof(tmp),"size=%lld",(long long)size);
919 } else if(strcmp("realloc",fcn)==0) {
920 void* ptr = va_arg(ap,void*);
921 size_t size = va_arg(ap,size_t);
922 snprintf(tmp,sizeof(tmp),"ptr=%p, size=%lld",ptr,(long long)size);
923 } else if(strcmp("free",fcn)==0) {
924 void* ptr = va_arg(ap,void*);
925 snprintf(tmp,sizeof(tmp),"ptr=%p",ptr);
926 } else if(strcmp("memcpy",fcn)==0) {
927 void* dest = va_arg(ap,void*);
928 void* src = va_arg(ap,void*);
929 size_t size = va_arg(ap,size_t);
930 snprintf(tmp,sizeof(tmp),"dest=%p, src=%p, size=%lld",dest,src,(long long)size);
931 } else if(strcmp("udata_copy",fcn)==0) {
932 #ifdef TRACE_UDATA
933 snprintf(tmp,sizeof(tmp),"udata=%p",udata);
934 #endif
935 } else if(strcmp("udata_free",fcn)==0) {
936 #ifdef TRACE_UDATA
937 snprintf(tmp,sizeof(tmp),"udata=%p",udata);
938 #endif
939 } else {
940 snprintf(tmp,sizeof(tmp),"unknown fcn: %s",fcn);
941 }
942 strlcat(buf,tmp,sizeof(buf));
943 ud = printudata(udata);
944 strlcat(buf,"\n\tudata=",sizeof(buf));
945 strlcat(buf,ud,sizeof(tmp));
946 free(ud);
947 strlcat(buf,"\n",sizeof(buf));
948 va_end(ap);
949 fprintf(stderr,"%s",buf);
950 fflush(stderr);
951 }
952
953 static void
traceend(const char * fcn,void * _udata,uintptr_t retval)954 traceend(const char* fcn, void* _udata, uintptr_t retval)
955 {
956 char buf[16000];
957 char tmp[8192];
958 char* ud;
959 const char* tab = " ";
960
961 buf[0] = '\0';
962 H5LT_file_image_ud_t *udata = (H5LT_file_image_ud_t *)_udata;
963 snprintf(tmp,sizeof(tmp),"%s]: retval=%p",tab,(void*)retval);
964 strlcat(buf,tmp,sizeof(buf));
965 strlcat(buf," udata=",sizeof(buf));
966 ud = printudata(udata);
967 strlcat(buf,ud,sizeof(tmp));
968 free(ud);
969 strlcat(buf,"\n",sizeof(buf));
970 fprintf(stderr,"%s",buf);
971 fflush(stderr);
972 }
973
974 #endif /*TRACE*/
975
976 #ifdef CATCH
977 static void
tracefail(const char * fcn)978 tracefail(const char* fcn)
979 {
980 fprintf(stderr,"fail: %s\n",fcn);
981 fflush(stderr);
982 }
983 #endif /*CATCH*/
984
985 #ifdef TRACE
986 static char*
traceflags(int flags)987 traceflags(int flags)
988 {
989 int i;
990 char buf[8192];
991 char tmp[8192];
992 buf[0] = '\0';
993 for(i=0;i<16;i++) {
994 tmp[0] = '\0';
995 if((flags & 1<<i) == 0) continue;
996 if(i > 0) strlcat(tmp,"|",sizeof(tmp));
997 switch(1<<i) {
998 case H5LT_FILE_IMAGE_OPEN_RW: /* 0x0001 Open image for read-write */
999 strlcat(tmp,"OPEN_RW",sizeof(tmp));
1000 break;
1001 case H5LT_FILE_IMAGE_DONT_COPY: /*0x0002 the HDF5 lib won't copy */
1002 strlcat(tmp,"DONT_COPY",sizeof(tmp));
1003 break;
1004 case H5LT_FILE_IMAGE_DONT_RELEASE: /* 0x0004 The HDF5 lib won't
1005 deallocate user supplied image
1006 buffer. The user application
1007 is responsible for doing so. */
1008 strlcat(tmp,"DONT_RELEASE",sizeof(tmp));
1009 break;
1010 default: break;
1011 }
1012 strlcat(buf,tmp,sizeof(buf));
1013 }
1014 return strdup(buf);
1015 }
1016
1017 static const char*
traceop(H5FD_file_image_op_t op)1018 traceop(H5FD_file_image_op_t op)
1019 {
1020 const char* sop = NULL;
1021 switch ( op ) {
1022 case H5FD_FILE_IMAGE_OP_NO_OP:
1023 sop = "NO_OP"; break;
1024 case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_SET:
1025 sop = "PROPERTY_LIST_SET"; break;
1026 case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_COPY:
1027 sop = "PROPERTY_LIST_COPY"; break;
1028 case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_GET:
1029 sop = "PROPERTY_LIST_GET"; break;
1030 case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_CLOSE:
1031 sop = "PROPERTY_LIST_CLOSE"; break;
1032 case H5FD_FILE_IMAGE_OP_FILE_OPEN:
1033 sop = "FILE_OPEN"; break;
1034 case H5FD_FILE_IMAGE_OP_FILE_RESIZE:
1035 sop = "FILE_RESIZE"; break;
1036 case H5FD_FILE_IMAGE_OP_FILE_CLOSE:
1037 sop = "FILE_CLOSE"; break;
1038 default: break;
1039 }
1040 return sop;
1041 }
1042
1043 #endif
1044
1045