Coverage Report

Created: 2026-11-12 08:28

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