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