Coverage Report

Created: 2023-05-28 06:42

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