Coverage Report

Created: 2022-11-18 06:58

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