Coverage Report

Created: 2025-11-18 06:24

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
224
{
137
224
    int status = NC_NOERR;
138
224
    ncio* nciop = NULL;
139
224
    NCMEMIO* memio = NULL;
140
224
    size_t minsize = initialsize;
141
142
    /* Unlike netcdf-4, INMEMORY and DISKLESS share code */
143
224
    if(fIsSet(ioflags,NC_DISKLESS))
144
0
  fSet(ioflags,NC_INMEMORY);    
145
146
    /* use asserts because this is an internal function */
147
224
    assert(fIsSet(ioflags,NC_INMEMORY));
148
224
    assert(memiop != NULL && nciopp != NULL);
149
224
    assert(path != NULL);
150
151
224
    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
224
    errno = 0;
172
173
    /* Always force the allocated size to be a multiple of pagesize */
174
224
    if(initialsize == 0) initialsize = pagesize;
175
224
    if((initialsize % pagesize) != 0)
176
210
  initialsize += (pagesize - (initialsize % pagesize));
177
178
224
    nciop = (ncio* )calloc(1,sizeof(ncio));
179
224
    if(nciop == NULL) {status = NC_ENOMEM; goto fail;}
180
181
224
    nciop->ioflags = ioflags;
182
224
    *((int*)&nciop->fd) = -1; /* caller will fix */
183
184
224
    *((ncio_relfunc**)&nciop->rel) = memio_rel;
185
224
    *((ncio_getfunc**)&nciop->get) = memio_get;
186
224
    *((ncio_movefunc**)&nciop->move) = memio_move;
187
224
    *((ncio_syncfunc**)&nciop->sync) = memio_sync;
188
224
    *((ncio_filesizefunc**)&nciop->filesize) = memio_filesize;
189
224
    *((ncio_pad_lengthfunc**)&nciop->pad_length) = memio_pad_length;
190
224
    *((ncio_closefunc**)&nciop->close) = memio_close;
191
192
224
    memio = (NCMEMIO*)calloc(1,sizeof(NCMEMIO));
193
224
    if(memio == NULL) {status = NC_ENOMEM; goto fail;}
194
224
    *((void* *)&nciop->pvt) = memio;
195
196
224
    *((char**)&nciop->path) = strdup(path);
197
224
    if(nciop->path == NULL) {status = NC_ENOMEM; goto fail;}
198
199
224
    if(memiop && memio) *memiop = memio; else free(memio);
200
224
    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
224
    memio->alloc = initialsize;
208
224
    memio->pos = 0;
209
224
    memio->size = minsize;
210
224
    memio->memory = NULL; /* filled in by caller */
211
212
224
    if(fIsSet(ioflags,NC_DISKLESS))
213
0
  memio->diskless = 1;
214
224
    if(fIsSet(ioflags,NC_INMEMORY))
215
224
  memio->inmemory = 1;
216
224
    if(fIsSet(ioflags,NC_PERSIST))
217
0
  memio->persist = 1;
218
219
224
done:
220
224
    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
224
}
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
224
{
328
224
    ncio* nciop = NULL;
329
224
    int fd = -1;
330
224
    int status = NC_NOERR;
331
224
    size_t sizehint = 0;
332
224
    NC_memio meminfo; /* use struct to avoid worrying about free'ing it */
333
224
    NCMEMIO* memio = NULL;
334
224
    size_t initialsize;
335
    /* Should be the case that diskless => inmemory but not converse */
336
224
    int diskless = (fIsSet(ioflags,NC_DISKLESS));
337
224
    int inmemory = fIsSet(ioflags,NC_INMEMORY);
338
224
    int locked = 0;
339
340
224
    assert(inmemory ? !diskless : 1);
341
342
224
    if(path == NULL || strlen(path) == 0)
343
0
        return NC_EINVAL;
344
345
224
    assert(sizehintp != NULL);
346
347
224
    sizehint = *sizehintp;
348
349
224
    memset(&meminfo,0,sizeof(meminfo));
350
351
224
    if(inmemory) { /* parameters provide the memory chunk */
352
224
  NC_memio* memparams = (NC_memio*)parameters;
353
224
        meminfo = *memparams;
354
224
        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
224
        if(!locked && fIsSet(ioflags,NC_WRITE)) {
358
0
      memparams->memory = NULL;     
359
0
  }  
360
224
    } 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
224
    initialsize = meminfo.size;
369
370
    /* create the NCMEMIO structure */
371
224
    status = memio_new(path, ioflags, initialsize, &nciop, &memio);
372
224
    if(status != NC_NOERR)
373
0
  {goto unwind_open;}
374
224
    memio->locked = locked;
375
376
    /* Initialize the memio memory */
377
224
    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
224
    if(memio->alloc > meminfo.size) {
382
210
  if(memio->locked)
383
210
      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
210
    }
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
224
    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
224
    sizehint = (size_t)(memio->alloc/2);
406
407
    /* sizehint must be multiple of 8 */
408
224
    sizehint = (sizehint / 8) * 8;
409
224
    if(sizehint < 8) sizehint = 8;
410
411
224
    fd = nc__pseudofd();
412
224
    *((int* )&nciop->fd) = fd;
413
414
224
    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
224
    if(sizehintp) *sizehintp = sizehint;
425
224
    if(nciopp) *nciopp = nciop; else {ncio_close(nciop,0);}
426
224
    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
224
}
434
435
/*
436
 *  Get file size in bytes.
437
 */
438
static int
439
memio_filesize(ncio* nciop, off_t* filesizep)
440
233
{
441
233
    NCMEMIO* memio;
442
233
    if(nciop == NULL || nciop->pvt == NULL) return NC_EINVAL;
443
233
    memio = (NCMEMIO*)nciop->pvt;
444
233
    if(filesizep != NULL) *filesizep = (off_t)memio->size;
445
233
    return NC_NOERR;
446
233
}
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
163
{
458
163
    NCMEMIO* memio;
459
163
    size_t len = (size_t)length;
460
163
    if(nciop == NULL || nciop->pvt == NULL) return NC_EINVAL;
461
163
    memio = (NCMEMIO*)nciop->pvt;
462
463
163
    if(!fIsSet(nciop->ioflags,NC_WRITE))
464
163
        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
224
{
516
224
    int status = NC_NOERR;
517
224
    NCMEMIO* memio ;
518
519
224
    if(nciop == NULL || nciop->pvt == NULL) return NC_NOERR;
520
521
224
    memio = (NCMEMIO*)nciop->pvt;
522
224
    assert(memio != NULL);
523
524
    /* See if the user wants the contents persisted to a file */
525
224
    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
224
    if(memio->memory != NULL && (!memio->locked || memio->modified)) {
531
0
  free(memio->memory);
532
0
  memio->memory = NULL;
533
0
    }
534
    /* do cleanup  */
535
224
    if(memio != NULL) free(memio);
536
224
    if(nciop->path != NULL) free((char*)nciop->path);
537
    /* Fix 38699 */
538
224
    nciop->path = NULL;
539
224
    free(nciop);
540
224
    return status;
541
224
}
542
543
static int
544
guarantee(ncio* nciop, off_t endpoint0)
545
5.08k
{
546
5.08k
    NCMEMIO* memio = (NCMEMIO*)nciop->pvt;
547
5.08k
    if(endpoint0 > memio->alloc) {
548
  /* extend the allocated memory and size */
549
163
  int status = memio_pad_length(nciop,endpoint0);
550
163
  if(status != NC_NOERR) return status;
551
163
    }
552
4.91k
    if(memio->size < endpoint0)
553
0
  memio->size = (size_t)endpoint0;
554
4.91k
    return NC_NOERR;
555
5.08k
}
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
5.08k
{
564
5.08k
    int status = NC_NOERR;
565
5.08k
    NCMEMIO* memio;
566
5.08k
    if(nciop == NULL || nciop->pvt == NULL) return NC_EINVAL;
567
5.08k
    memio = (NCMEMIO*)nciop->pvt;
568
5.08k
    status = guarantee(nciop, offset+(off_t)extent);
569
5.08k
    memio->locked++;
570
5.08k
    if(status != NC_NOERR) return status;
571
4.91k
    if(vpp) *vpp = memio->memory+offset;
572
4.91k
    return NC_NOERR;
573
5.08k
}
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.91k
{
632
4.91k
    NCMEMIO* memio;
633
4.91k
    if(nciop == NULL || nciop->pvt == NULL) return NC_EINVAL;
634
4.91k
    memio = (NCMEMIO*)nciop->pvt;
635
4.91k
    memio->locked--;
636
4.91k
    return NC_NOERR; /* do nothing */
637
4.91k
}
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
224
{
646
224
    return NC_NOERR; /* do nothing */
647
224
}
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
}