Coverage Report

Created: 2025-10-28 07:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/netcdf-c/libsrc/memio.c
Line
Count
Source
1
/*
2
 *  Copyright 2018, University Corporation for Atmospheric Research
3
 *  See netcdf/COPYRIGHT file for copying and redistribution conditions.
4
 */
5
6
#include "config.h"
7
#include <assert.h>
8
#include <stdlib.h>
9
#include <stdio.h>
10
#include <errno.h>
11
#include <string.h>
12
#include <sys/types.h>
13
#ifdef HAVE_UNISTD_H
14
#include <unistd.h>
15
#endif
16
#ifdef HAVE_FCNTL_H
17
#include <fcntl.h>
18
#endif
19
#ifdef HAVE_DIRENT_H
20
#include <dirent.h>
21
#endif
22
#ifdef _WIN32
23
#include <windows.h>
24
#include <winbase.h>
25
#include <io.h>
26
#endif
27
28
#include "ncdispatch.h"
29
#include "nc3internal.h"
30
#include "netcdf_mem.h"
31
#include "ncpathmgr.h"
32
#include "ncrc.h"
33
#include "ncbytes.h"
34
#include "ncutil.h"
35
36
#undef DEBUG
37
38
#ifndef HAVE_SSIZE_T
39
typedef int ssize_t;
40
#endif
41
42
#ifdef DEBUG
43
#include <stdio.h>
44
#endif
45
46
#ifndef SEEK_SET
47
#define SEEK_SET 0
48
#define SEEK_CUR 1
49
#define SEEK_END 2
50
#endif
51
52
/* Define the mode flags for create: let umask rule */
53
#define OPENMODE 0666
54
55
#include "ncio.h"
56
#include "fbits.h"
57
#include "rnd.h"
58
59
/* #define INSTRUMENT 1 */
60
#if INSTRUMENT /* debugging */
61
#undef NDEBUG
62
#include <stdio.h>
63
#include "instr.h"
64
#endif
65
66
#ifndef MEMIO_MAXBLOCKSIZE
67
#define MEMIO_MAXBLOCKSIZE 268435456 /* sanity check, about X_SIZE_T_MAX/8 */
68
#endif
69
70
#undef MIN  /* system may define MIN somewhere and complain */
71
#define MIN(mm,nn) (((mm) < (nn)) ? (mm) : (nn))
72
73
#if !defined(NDEBUG) && !defined(X_INT_MAX)
74
#define  X_INT_MAX 2147483647
75
#endif
76
77
#if 0 /* !defined(NDEBUG) && !defined(X_ALIGN) */
78
#define  X_ALIGN 4
79
#else
80
#undef X_ALIGN
81
#endif
82
83
#define REALLOCBUG
84
#ifdef REALLOCBUG
85
/* There is some kind of realloc bug that I cannot solve yet */
86
0
#define reallocx(m,new,old) realloc(m,new)
87
#else
88
static void*
89
reallocx(void* mem, size_t newsize, size_t oldsize)
90
{
91
    void* m = malloc(newsize);
92
    if(m != NULL) {
93
        memcpy(m,mem,oldsize);
94
  free(mem);
95
    }
96
    return m;
97
}
98
#endif
99
100
/* Private data for memio */
101
102
typedef struct NCMEMIO {
103
    int locked; /* => we cannot realloc or free*/
104
    int modified; /* => we realloc'd memory at least once */
105
    int persist; /* => save to a file; triggered by NC_PERSIST*/
106
    char* memory;
107
    size_t alloc;
108
    size_t size;
109
    size_t pos;
110
    /* Convenience flags */
111
    int diskless;
112
    int inmemory; /* assert(inmemory iff !diskless */
113
} NCMEMIO;
114
115
/* Forward */
116
static int memio_rel(ncio *const nciop, off_t offset, int rflags);
117
static int memio_get(ncio *const nciop, off_t offset, size_t extent, int rflags, void **const vpp);
118
static int memio_move(ncio *const nciop, off_t to, off_t from, size_t nbytes, int rflags);
119
static int memio_sync(ncio *const nciop);
120
static int memio_filesize(ncio* nciop, off_t* filesizep);
121
static int memio_pad_length(ncio* nciop, off_t length);
122
static int memio_close(ncio* nciop, int);
123
static int readfile(const char* path, NC_memio*);
124
static int writefile(const char* path, NCMEMIO*);
125
static int fileiswriteable(const char* path);
126
static int fileexists(const char* path);
127
128
/* Mnemonic */
129
#define DOOPEN 1
130
131
static size_t pagesize = 0;
132
133
/*! Create a new ncio struct to hold info about the file. */
134
static int
135
memio_new(const char* path, int ioflags, size_t initialsize, ncio** nciopp, NCMEMIO** memiop)
136
291
{
137
291
    int status = NC_NOERR;
138
291
    ncio* nciop = NULL;
139
291
    NCMEMIO* memio = NULL;
140
291
    size_t minsize = initialsize;
141
142
    /* Unlike netcdf-4, INMEMORY and DISKLESS share code */
143
291
    if(fIsSet(ioflags,NC_DISKLESS))
144
0
  fSet(ioflags,NC_INMEMORY);    
145
146
    /* use asserts because this is an internal function */
147
291
    assert(fIsSet(ioflags,NC_INMEMORY));
148
291
    assert(memiop != NULL && nciopp != NULL);
149
291
    assert(path != NULL);
150
151
291
    if(pagesize == 0) {
152
#if defined (_WIN32) || defined(_WIN64)
153
      SYSTEM_INFO info;
154
      GetSystemInfo (&info);
155
      pagesize = info.dwPageSize;
156
#elif defined HAVE_SYSCONF
157
      long pgval = -1;
158
1
      pgval = sysconf(_SC_PAGE_SIZE);
159
1
      if(pgval < 0) {
160
0
          status = NC_EIO;
161
0
          goto fail;
162
0
      }
163
1
      pagesize = (size_t)pgval;
164
#elif defined HAVE_GETPAGESIZE
165
      pagesize = (size_t)getpagesize();
166
#else
167
      pagesize = 4096; /* good guess */
168
#endif
169
1
    }
170
171
291
    errno = 0;
172
173
    /* Always force the allocated size to be a multiple of pagesize */
174
291
    if(initialsize == 0) initialsize = pagesize;
175
291
    if((initialsize % pagesize) != 0)
176
277
  initialsize += (pagesize - (initialsize % pagesize));
177
178
291
    nciop = (ncio* )calloc(1,sizeof(ncio));
179
291
    if(nciop == NULL) {status = NC_ENOMEM; goto fail;}
180
181
291
    nciop->ioflags = ioflags;
182
291
    *((int*)&nciop->fd) = -1; /* caller will fix */
183
184
291
    *((ncio_relfunc**)&nciop->rel) = memio_rel;
185
291
    *((ncio_getfunc**)&nciop->get) = memio_get;
186
291
    *((ncio_movefunc**)&nciop->move) = memio_move;
187
291
    *((ncio_syncfunc**)&nciop->sync) = memio_sync;
188
291
    *((ncio_filesizefunc**)&nciop->filesize) = memio_filesize;
189
291
    *((ncio_pad_lengthfunc**)&nciop->pad_length) = memio_pad_length;
190
291
    *((ncio_closefunc**)&nciop->close) = memio_close;
191
192
291
    memio = (NCMEMIO*)calloc(1,sizeof(NCMEMIO));
193
291
    if(memio == NULL) {status = NC_ENOMEM; goto fail;}
194
291
    *((void* *)&nciop->pvt) = memio;
195
196
291
    *((char**)&nciop->path) = strdup(path);
197
291
    if(nciop->path == NULL) {status = NC_ENOMEM; goto fail;}
198
199
291
    if(memiop && memio) *memiop = memio; else free(memio);
200
291
    if(nciopp && nciop) *nciopp = nciop;
201
0
    else {
202
0
        if(nciop->path != NULL) free((char*)nciop->path);
203
  /* Fix 38699 */
204
0
  nciop->path = NULL;
205
0
        free(nciop);
206
0
    }
207
291
    memio->alloc = initialsize;
208
291
    memio->pos = 0;
209
291
    memio->size = minsize;
210
291
    memio->memory = NULL; /* filled in by caller */
211
212
291
    if(fIsSet(ioflags,NC_DISKLESS))
213
0
  memio->diskless = 1;
214
291
    if(fIsSet(ioflags,NC_INMEMORY))
215
291
  memio->inmemory = 1;
216
291
    if(fIsSet(ioflags,NC_PERSIST))
217
0
  memio->persist = 1;
218
219
291
done:
220
291
    return status;
221
222
0
fail:
223
0
    if(memio != NULL) free(memio);
224
0
    if(nciop != NULL) {
225
0
        if(nciop->path != NULL) free((char*)nciop->path);
226
  /* Fix 38699 */
227
0
  nciop->path = NULL;
228
0
        free(nciop);
229
0
    }
230
0
    goto done;
231
291
}
232
233
/* Create a file, and the ncio struct to go with it.
234
235
   path - path of file to create.
236
   ioflags - flags from nc_create
237
   initialsz - From the netcdf man page: "The argument
238
               initialsize sets the initial size of the file at creation time."
239
   igeto -
240
   igetsz -
241
   sizehintp - the size of a page of data for buffered reads and writes.
242
   parameters - arbitrary data
243
   nciopp - pointer to a pointer that will get location of newly
244
   created and inited ncio struct.
245
   mempp - pointer to pointer to the initial memory read.
246
*/
247
int
248
memio_create(const char* path, int ioflags,
249
    size_t initialsz,
250
    off_t igeto, size_t igetsz, size_t* sizehintp,
251
    void* parameters /*ignored*/,
252
    ncio* *nciopp, void** const mempp)
253
0
{
254
0
    ncio* nciop;
255
0
    int fd;
256
0
    int status;
257
0
    NCMEMIO* memio = NULL;
258
259
0
    if(path == NULL ||* path == 0)
260
0
        return NC_EINVAL;
261
    
262
0
    status = memio_new(path, ioflags, initialsz, &nciop, &memio);
263
0
    if(status != NC_NOERR)
264
0
        return status;
265
266
0
    if(memio->persist) {
267
  /* Verify the file is writeable or does not exist*/
268
0
  if(fileexists(path) && !fileiswriteable(path))
269
0
      {status = EPERM; goto unwind_open;}  
270
0
    }
271
272
    /* Allocate the memory for this file */
273
0
    memio->memory = (char*)malloc((size_t)memio->alloc);
274
0
    if(memio->memory == NULL) {status = NC_ENOMEM; goto unwind_open;}
275
0
    memio->locked = 0;
276
277
#ifdef DEBUG
278
fprintf(stderr,"memio_create: initial memory: %lu/%lu\n",(unsigned long)memio->memory,(unsigned long)memio->alloc);
279
#endif
280
281
0
    fd = nc__pseudofd();
282
0
    *((int* )&nciop->fd) = fd;
283
284
0
    fSet(nciop->ioflags, NC_WRITE); /* Always writeable */
285
286
0
    if(igetsz != 0)
287
0
    {
288
0
        status = nciop->get(nciop,
289
0
                igeto, igetsz,
290
0
                RGN_WRITE,
291
0
                mempp);
292
0
        if(status != NC_NOERR)
293
0
            goto unwind_open;
294
0
    }
295
296
    /* Pick a default sizehint */
297
0
    if(sizehintp) *sizehintp = (size_t)pagesize;
298
299
0
    *nciopp = nciop;
300
0
    return NC_NOERR;
301
302
0
unwind_open:
303
0
    memio_close(nciop,1);
304
0
    return status;
305
0
}
306
307
/* This function opens the data file or inmemory data
308
   path - path of data file.
309
   ioflags - flags passed into nc_open.
310
   igeto - looks like this function can do an initial page get, and
311
   igeto is going to be the offset for that. But it appears to be
312
   unused
313
   igetsz - the size in bytes of initial page get (a.k.a. extent). Not
314
   ever used in the library.
315
   sizehintp - the size of a page of data for buffered reads and writes.
316
   parameters - arbitrary data
317
   nciopp - pointer to pointer that will get address of newly created
318
   and inited ncio struct.
319
   mempp - pointer to pointer to the initial memory read.
320
*/
321
int
322
memio_open(const char* path,
323
    int ioflags,
324
    off_t igeto, size_t igetsz, size_t* sizehintp,
325
    void* parameters,
326
    ncio* *nciopp, void** const mempp)
327
291
{
328
291
    ncio* nciop = NULL;
329
291
    int fd = -1;
330
291
    int status = NC_NOERR;
331
291
    size_t sizehint = 0;
332
291
    NC_memio meminfo; /* use struct to avoid worrying about free'ing it */
333
291
    NCMEMIO* memio = NULL;
334
291
    size_t initialsize;
335
    /* Should be the case that diskless => inmemory but not converse */
336
291
    int diskless = (fIsSet(ioflags,NC_DISKLESS));
337
291
    int inmemory = fIsSet(ioflags,NC_INMEMORY);
338
291
    int locked = 0;
339
340
291
    assert(inmemory ? !diskless : 1);
341
342
291
    if(path == NULL || strlen(path) == 0)
343
0
        return NC_EINVAL;
344
345
291
    assert(sizehintp != NULL);
346
347
291
    sizehint = *sizehintp;
348
349
291
    memset(&meminfo,0,sizeof(meminfo));
350
351
291
    if(inmemory) { /* parameters provide the memory chunk */
352
291
  NC_memio* memparams = (NC_memio*)parameters;
353
291
        meminfo = *memparams;
354
291
        locked = fIsSet(meminfo.flags,NC_MEMIO_LOCKED);
355
  /* As a safeguard, if !locked and NC_WRITE is set,
356
           then we must take control of the incoming memory */
357
291
        if(!locked && fIsSet(ioflags,NC_WRITE)) {
358
0
      memparams->memory = NULL;     
359
0
  }  
360
291
    } else { /* read the file into a chunk of memory*/
361
0
  assert(diskless);
362
0
  status = readfile(path,&meminfo);
363
0
  if(status != NC_NOERR)
364
0
      {goto unwind_open;}
365
0
    }
366
367
    /* Fix up initial size */
368
291
    initialsize = meminfo.size;
369
370
    /* create the NCMEMIO structure */
371
291
    status = memio_new(path, ioflags, initialsize, &nciop, &memio);
372
291
    if(status != NC_NOERR)
373
0
  {goto unwind_open;}
374
291
    memio->locked = locked;
375
376
    /* Initialize the memio memory */
377
291
    memio->memory = meminfo.memory;
378
379
    /* memio_new may have modified the allocated size, in which case,
380
       reallocate the memory unless the memory is locked. */    
381
291
    if(memio->alloc > meminfo.size) {
382
277
  if(memio->locked)
383
277
      memio->alloc = meminfo.size; /* force it back to what it was */
384
0
  else {
385
0
     void* oldmem = memio->memory;
386
0
     memio->memory = reallocx(oldmem,memio->alloc,meminfo.size);
387
0
     if(memio->memory == NULL)
388
0
         {status = NC_ENOMEM; goto unwind_open;}
389
0
  }
390
277
    }
391
392
#ifdef DEBUG
393
fprintf(stderr,"memio_open: initial memory: %lu/%lu\n",(unsigned long)memio->memory,(unsigned long)memio->alloc);
394
#endif
395
396
291
    if(memio->persist) {
397
  /* Verify the file is writeable and exists */
398
0
  if(!fileexists(path))
399
0
      {status = ENOENT; goto unwind_open;}  
400
0
  if(!fileiswriteable(path))
401
0
      {status = EACCES; goto unwind_open;}  
402
0
    }
403
404
    /* Use half the filesize as the blocksize ; why? */
405
291
    sizehint = (size_t)(memio->alloc/2);
406
407
    /* sizehint must be multiple of 8 */
408
291
    sizehint = (sizehint / 8) * 8;
409
291
    if(sizehint < 8) sizehint = 8;
410
411
291
    fd = nc__pseudofd();
412
291
    *((int* )&nciop->fd) = fd;
413
414
291
    if(igetsz != 0)
415
0
    {
416
0
        status = nciop->get(nciop,
417
0
                igeto, igetsz,
418
0
                0,
419
0
                mempp);
420
0
        if(status != NC_NOERR)
421
0
            goto unwind_open;
422
0
    }
423
424
291
    if(sizehintp) *sizehintp = sizehint;
425
291
    if(nciopp) *nciopp = nciop; else {ncio_close(nciop,0);}
426
291
    return NC_NOERR;
427
428
0
unwind_open:
429
0
    if(fd >= 0)
430
0
      close(fd);
431
0
    memio_close(nciop,0);
432
0
    return status;
433
291
}
434
435
/*
436
 *  Get file size in bytes.
437
 */
438
static int
439
memio_filesize(ncio* nciop, off_t* filesizep)
440
302
{
441
302
    NCMEMIO* memio;
442
302
    if(nciop == NULL || nciop->pvt == NULL) return NC_EINVAL;
443
302
    memio = (NCMEMIO*)nciop->pvt;
444
302
    if(filesizep != NULL) *filesizep = (off_t)memio->size;
445
302
    return NC_NOERR;
446
302
}
447
448
/*
449
 *  Sync any changes to disk, then truncate or extend file so its size
450
 *  is length.  This is only intended to be called before close, if the
451
 *  file is open for writing and the actual size does not match the
452
 *  calculated size, perhaps as the result of having been previously
453
 *  written in NOFILL mode.
454
 */
455
static int
456
memio_pad_length(ncio* nciop, off_t length)
457
200
{
458
200
    NCMEMIO* memio;
459
200
    size_t len = (size_t)length;
460
200
    if(nciop == NULL || nciop->pvt == NULL) return NC_EINVAL;
461
200
    memio = (NCMEMIO*)nciop->pvt;
462
463
200
    if(!fIsSet(nciop->ioflags,NC_WRITE))
464
200
        return EPERM; /* attempt to write readonly file*/
465
0
    if(memio->locked)
466
0
  return NC_EINMEMORY;
467
468
0
    if(len > memio->alloc) {
469
        /* Realloc the allocated memory to a multiple of the pagesize*/
470
0
  size_t newsize = (size_t)len;
471
0
  void* newmem = NULL;
472
  /* Round to a multiple of pagesize */
473
0
  if((newsize % pagesize) != 0)
474
0
      newsize += (pagesize - (newsize % pagesize));
475
476
0
        newmem = (char*)reallocx(memio->memory,newsize,memio->alloc);
477
0
        if(newmem == NULL) return NC_ENOMEM;
478
  /* If not copy is set, then fail if the newmem address is different
479
           from old address */
480
0
  if(newmem != memio->memory) {
481
0
      memio->modified++;
482
0
      if(memio->locked) {
483
0
    free(newmem);
484
0
    return NC_EINMEMORY;
485
0
      }
486
0
        }
487
  /* zero out the extra memory */
488
0
        memset((void*)((char*)newmem+memio->alloc),0,(size_t)(newsize - memio->alloc));
489
490
#ifdef DEBUG
491
fprintf(stderr,"realloc: %lu/%lu -> %lu/%lu\n",
492
(unsigned long)memio->memory,(unsigned long)memio->alloc,
493
(unsigned long)newmem,(unsigned long)newsize);
494
#endif
495
0
  memio->memory = newmem;
496
0
  memio->alloc = newsize;
497
0
  memio->modified = 1;
498
0
    }
499
0
    memio->size = len;
500
0
    return NC_NOERR;
501
0
}
502
503
/*! Write out any dirty buffers to disk.
504
505
  Write out any dirty buffers to disk and ensure that next read will get data from disk.
506
  Sync any changes, then close the open file associated with the ncio struct, and free its memory.
507
508
  @param[in] nciop pointer to ncio to close.
509
  @param[in] doUnlink if true, unlink file
510
  @return NC_NOERR on success, error code on failure.
511
*/
512
513
static int
514
memio_close(ncio* nciop, int doUnlink)
515
291
{
516
291
    int status = NC_NOERR;
517
291
    NCMEMIO* memio ;
518
519
291
    if(nciop == NULL || nciop->pvt == NULL) return NC_NOERR;
520
521
291
    memio = (NCMEMIO*)nciop->pvt;
522
291
    assert(memio != NULL);
523
524
    /* See if the user wants the contents persisted to a file */
525
291
    if(memio->persist && memio->memory != NULL) {
526
0
  status = writefile(nciop->path,memio);    
527
0
    }
528
529
    /* We only free the memio memory if file is not locked or has been modified */
530
291
    if(memio->memory != NULL && (!memio->locked || memio->modified)) {
531
0
  free(memio->memory);
532
0
  memio->memory = NULL;
533
0
    }
534
    /* do cleanup  */
535
291
    if(memio != NULL) free(memio);
536
291
    if(nciop->path != NULL) free((char*)nciop->path);
537
    /* Fix 38699 */
538
291
    nciop->path = NULL;
539
291
    free(nciop);
540
291
    return status;
541
291
}
542
543
static int
544
guarantee(ncio* nciop, off_t endpoint0)
545
4.99k
{
546
4.99k
    NCMEMIO* memio = (NCMEMIO*)nciop->pvt;
547
4.99k
    if(endpoint0 > memio->alloc) {
548
  /* extend the allocated memory and size */
549
200
  int status = memio_pad_length(nciop,endpoint0);
550
200
  if(status != NC_NOERR) return status;
551
200
    }
552
4.79k
    if(memio->size < endpoint0)
553
0
  memio->size = (size_t)endpoint0;
554
4.79k
    return NC_NOERR;
555
4.99k
}
556
557
/*
558
 * Request that the region (offset, extent)
559
 * be made available through *vpp.
560
 */
561
static int
562
memio_get(ncio* const nciop, off_t offset, size_t extent, int rflags, void** const vpp)
563
4.99k
{
564
4.99k
    int status = NC_NOERR;
565
4.99k
    NCMEMIO* memio;
566
4.99k
    if(nciop == NULL || nciop->pvt == NULL) return NC_EINVAL;
567
4.99k
    memio = (NCMEMIO*)nciop->pvt;
568
4.99k
    status = guarantee(nciop, offset+(off_t)extent);
569
4.99k
    memio->locked++;
570
4.99k
    if(status != NC_NOERR) return status;
571
4.79k
    if(vpp) *vpp = memio->memory+offset;
572
4.79k
    return NC_NOERR;
573
4.99k
}
574
575
/*
576
 * Like memmove(), safely move possibly overlapping data.
577
 */
578
static int
579
memio_move(ncio* const nciop, off_t to, off_t from, size_t nbytes, int ignored)
580
0
{
581
0
    int status = NC_NOERR;
582
0
    NCMEMIO* memio;
583
584
0
    if(nciop == NULL || nciop->pvt == NULL) return NC_EINVAL;
585
0
    memio = (NCMEMIO*)nciop->pvt;
586
0
    if(from < to) {
587
       /* extend if "to" is not currently allocated */
588
0
       status = guarantee(nciop,to+(off_t)nbytes);
589
0
       if(status != NC_NOERR) return status;
590
0
    }
591
    /* check for overlap */
592
0
    if((to + (off_t)nbytes) > from || (from + (off_t)nbytes) > to) {
593
  /* Ranges overlap */
594
0
#ifdef HAVE_MEMMOVE
595
0
        memmove((void*)(memio->memory+to),(void*)(memio->memory+from),nbytes);
596
#else
597
        off_t overlap;
598
  off_t nbytes1;
599
        if((from + nbytes) > to) {
600
      overlap = ((from + nbytes) - to); /* # bytes of overlap */
601
      nbytes1 = (nbytes - overlap); /* # bytes of non-overlap */
602
      /* move the non-overlapping part */
603
            memcpy((void*)(memio->memory+(to+overlap)),
604
                   (void*)(memio->memory+(from+overlap)),
605
       nbytes1);
606
      /* move the overlapping part */
607
      memcpy((void*)(memio->memory+to),
608
                   (void*)(memio->memory+from),
609
       overlap);
610
  } else { /*((to + nbytes) > from) */
611
      overlap = ((to + nbytes) - from); /* # bytes of overlap */
612
      nbytes1 = (nbytes - overlap); /* # bytes of non-overlap */
613
      /* move the non-overlapping part */
614
            memcpy((void*)(memio->memory+to),
615
                   (void*)(memio->memory+from),
616
       nbytes1);
617
      /* move the overlapping part */
618
      memcpy((void*)(memio->memory+(to+nbytes1)),
619
                   (void*)(memio->memory+(from+nbytes1)),
620
       overlap);
621
  }
622
#endif
623
0
    } else {/* no overlap */
624
0
  memcpy((void*)(memio->memory+to),(void*)(memio->memory+from),nbytes);
625
0
    }
626
0
    return status;
627
0
}
628
629
static int
630
memio_rel(ncio* const nciop, off_t offset, int rflags)
631
4.79k
{
632
4.79k
    NCMEMIO* memio;
633
4.79k
    if(nciop == NULL || nciop->pvt == NULL) return NC_EINVAL;
634
4.79k
    memio = (NCMEMIO*)nciop->pvt;
635
4.79k
    memio->locked--;
636
4.79k
    return NC_NOERR; /* do nothing */
637
4.79k
}
638
639
/*
640
 * Write out any dirty buffers to disk and
641
 * ensure that next read will get data from disk.
642
 */
643
static int
644
memio_sync(ncio* const nciop)
645
291
{
646
291
    return NC_NOERR; /* do nothing */
647
291
}
648
649
/* "Hidden" Internal function to extract the 
650
   the size and/or contents of the memory.
651
*/
652
int
653
memio_extract(ncio* const nciop, size_t* sizep, void** memoryp)
654
0
{
655
0
    int status = NC_NOERR;
656
0
    NCMEMIO* memio = NULL;
657
658
0
    if(nciop == NULL || nciop->pvt == NULL) return NC_NOERR;
659
0
    memio = (NCMEMIO*)nciop->pvt;
660
0
    assert(memio != NULL);
661
0
    if(sizep) *sizep = memio->size;
662
663
0
    if(memoryp && memio->memory != NULL) {
664
0
  *memoryp = memio->memory;
665
0
  memio->memory = NULL; /* make sure it does not get free'd */
666
0
    }
667
0
    return status;
668
0
}
669
670
/* Return 1 if file exists, 0 otherwise */
671
static int
672
fileexists(const char* path)
673
0
{
674
0
    int ok;
675
    /* See if the file exists at all */
676
0
    ok = NCaccess(path,ACCESS_MODE_EXISTS);
677
0
    if(ok < 0) /* file does not exist */
678
0
      return 0;
679
0
    return 1;
680
0
}
681
682
/* Return 1 if file is writeable, return 0 otherwise;
683
   assumes fileexists has been checked already */
684
static int
685
fileiswriteable(const char* path)
686
0
{
687
0
    int ok;
688
    /* if W is ok */
689
0
    ok = NCaccess(path,ACCESS_MODE_W);
690
0
    if(ok < 0)
691
0
  return 0;
692
0
    return 1;
693
0
}
694
695
#if 0 /* not used */
696
/* Return 1 if file is READABLE, return 0 otherwise;
697
   assumes fileexists has been checked already */
698
static int
699
fileisreadable(const char* path)
700
{
701
    int ok;
702
    /* if RW is ok */
703
    ok = NCaccess(path,ACCESS_MODE_R);
704
    if(ok < 0)
705
  return 0;
706
    return 1;
707
}
708
#endif
709
710
/* Read contents of a disk file into a memory chunk */
711
static int
712
readfile(const char* path, NC_memio* memio)
713
0
{
714
0
    int status = NC_NOERR;
715
0
    FILE* f = NULL;
716
0
    NCbytes* buf = ncbytesnew();
717
718
0
    if((status = NC_readfile(path,buf))) goto done;
719
0
    if(memio) {
720
0
  memio->size = ncbyteslength(buf);
721
0
  memio->memory = ncbytesextract(buf);
722
0
    }
723
724
0
done:
725
0
    ncbytesfree(buf);
726
0
    if(f != NULL) fclose(f);
727
0
    return status;    
728
0
}
729
730
/* write contents of a memory chunk back into a disk file */
731
static int
732
writefile(const char* path, NCMEMIO* memio)
733
0
{
734
0
    int status = NC_NOERR;
735
736
0
    if(memio) {
737
0
        if((status = NC_writefile(path,memio->size,memio->memory))) goto done;
738
0
    }
739
0
done:
740
0
    return status;    
741
0
}