/src/netcdf-c/libsrc/mmapio.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 |  | #if HAVE_CONFIG_H | 
| 7 |  | #include <config.h> | 
| 8 |  | #endif | 
| 9 |  |  | 
| 10 |  | #include <assert.h> | 
| 11 |  | #include <stdlib.h> | 
| 12 |  | #include <errno.h> | 
| 13 |  | #include <string.h> | 
| 14 |  | #ifdef HAVE_FCNTL_H | 
| 15 |  | #include <fcntl.h> | 
| 16 |  | #endif | 
| 17 |  | #ifdef _MSC_VER /* Microsoft Compilers */ | 
| 18 |  | #include <io.h> | 
| 19 |  | #endif | 
| 20 |  | #ifdef HAVE_UNISTD_H | 
| 21 |  | #include <unistd.h> | 
| 22 |  | #endif | 
| 23 |  | #include "nc3internal.h" | 
| 24 |  | #include "ncpathmgr.h" | 
| 25 |  |  | 
| 26 |  | #undef DEBUG | 
| 27 |  |  | 
| 28 |  | #ifdef DEBUG | 
| 29 |  | #include <stdio.h> | 
| 30 |  | #endif | 
| 31 |  |  | 
| 32 |  | #include <sys/mman.h> | 
| 33 |  |  | 
| 34 |  | #ifndef MAP_ANONYMOUS | 
| 35 |  | #  ifdef MAP_ANON | 
| 36 |  | #    define MAP_ANONYMOUS MAP_ANON | 
| 37 |  | #  endif | 
| 38 |  | #endif | 
| 39 |  |  | 
| 40 |  | /* !MAP_ANONYMOUS => !HAVE_MMAP */ | 
| 41 |  | #ifndef MAP_ANONYMOUS | 
| 42 |  | #error mmap not fully implemented: missing MAP_ANONYMOUS | 
| 43 |  | #endif | 
| 44 |  |  | 
| 45 |  | #ifdef HAVE_MREMAP | 
| 46 |  |   /* This is conditionalized by __USE_GNU ; why? */ | 
| 47 |  |   extern void *mremap(void*,size_t,size_t,int); | 
| 48 |  | # ifndef MREMAP_MAYMOVE | 
| 49 | 0 | #   define MREMAP_MAYMOVE 1 | 
| 50 |  | # endif | 
| 51 |  | #endif /*HAVE_MREMAP*/ | 
| 52 |  |  | 
| 53 |  | #ifndef SEEK_SET | 
| 54 |  | #define SEEK_SET 0 | 
| 55 |  | #define SEEK_CUR 1 | 
| 56 |  | #define SEEK_END 2 | 
| 57 |  | #endif | 
| 58 |  |  | 
| 59 |  | /* Define the mode flags for create: let umask decide */ | 
| 60 |  | #define OPENMODE 0666 | 
| 61 |  |  | 
| 62 |  | #include "ncio.h" | 
| 63 |  | #include "fbits.h" | 
| 64 |  | #include "rnd.h" | 
| 65 |  |  | 
| 66 |  | /* #define INSTRUMENT 1 */ | 
| 67 |  | #if INSTRUMENT /* debugging */ | 
| 68 |  | #undef NDEBUG | 
| 69 |  | #include <stdio.h> | 
| 70 |  | #include "instr.h" | 
| 71 |  | #endif | 
| 72 |  |  | 
| 73 |  | #ifndef MMAP_MAXBLOCKSIZE | 
| 74 |  | #define MMAP_MAXBLOCKSIZE 268435456 /* sanity check, about X_SIZE_T_MAX/8 */ | 
| 75 |  | #endif | 
| 76 |  |  | 
| 77 |  | #undef MIN  /* system may define MIN somewhere and complain */ | 
| 78 |  | #define MIN(mm,nn) (((mm) < (nn)) ? (mm) : (nn)) | 
| 79 |  |  | 
| 80 |  | #if !defined(NDEBUG) && !defined(X_INT_MAX) | 
| 81 |  | #define  X_INT_MAX 2147483647 | 
| 82 |  | #endif | 
| 83 |  |  | 
| 84 |  | #if 0 /* !defined(NDEBUG) && !defined(X_ALIGN) */ | 
| 85 |  | #define  X_ALIGN 4 | 
| 86 |  | #else | 
| 87 |  | #undef X_ALIGN | 
| 88 |  | #endif | 
| 89 |  |  | 
| 90 |  | /* Private data for mmap */ | 
| 91 |  |  | 
| 92 |  | typedef struct NCMMAPIO { | 
| 93 |  |     int locked; /* => we cannot realloc */ | 
| 94 |  |     int persist; /* => save to a file; triggered by NC_PERSIST */ | 
| 95 |  |     char* memory; | 
| 96 |  |     size_t alloc; | 
| 97 |  |     off_t size; | 
| 98 |  |     off_t pos; | 
| 99 |  |     int mapfd; | 
| 100 |  | } NCMMAPIO; | 
| 101 |  |  | 
| 102 |  | /* Forward */ | 
| 103 |  | static int mmapio_rel(ncio *const nciop, off_t offset, int rflags); | 
| 104 |  | static int mmapio_get(ncio *const nciop, off_t offset, size_t extent, int rflags, void **const vpp); | 
| 105 |  | static int mmapio_move(ncio *const nciop, off_t to, off_t from, size_t nbytes, int rflags); | 
| 106 |  | static int mmapio_sync(ncio *const nciop); | 
| 107 |  | static int mmapio_filesize(ncio* nciop, off_t* filesizep); | 
| 108 |  | static int mmapio_pad_length(ncio* nciop, off_t length); | 
| 109 |  | static int mmapio_close(ncio* nciop, int); | 
| 110 |  |  | 
| 111 |  | /* Mnemonic */ | 
| 112 |  | #define DOOPEN 1 | 
| 113 |  |  | 
| 114 |  | static size_t pagesize = 0; | 
| 115 |  |  | 
| 116 |  | /* Create a new ncio struct to hold info about the file. */ | 
| 117 |  | static int | 
| 118 |  | mmapio_new(const char* path, int ioflags, size_t initialsize, ncio** nciopp, NCMMAPIO** mmapp) | 
| 119 | 0 | { | 
| 120 | 0 |     int status = NC_NOERR; | 
| 121 | 0 |     ncio* nciop = NULL; | 
| 122 | 0 |     NCMMAPIO* mmapio = NULL; | 
| 123 | 0 |     int openfd = -1; | 
| 124 |  | 
 | 
| 125 | 0 |     if(pagesize == 0) { | 
| 126 | 0 | #if defined HAVE_SYSCONF | 
| 127 | 0 |         pagesize = (size_t)sysconf(_SC_PAGE_SIZE); | 
| 128 |  | #elif defined HAVE_GETPAGESIZE | 
| 129 |  |         pagesize = (size_t)getpagesize(); | 
| 130 |  | #else | 
| 131 |  |         pagesize = 4096; /* good guess */ | 
| 132 |  | #endif | 
| 133 | 0 |     } | 
| 134 |  | 
 | 
| 135 | 0 |     errno = 0; | 
| 136 |  |  | 
| 137 |  |     /* Always force the allocated size to be a multiple of pagesize */ | 
| 138 | 0 |     if(initialsize == 0) initialsize = pagesize; | 
| 139 | 0 |     if((initialsize % pagesize) != 0) | 
| 140 | 0 |   initialsize += (pagesize - (initialsize % pagesize)); | 
| 141 |  | 
 | 
| 142 | 0 |     nciop = (ncio* )calloc(1,sizeof(ncio)); | 
| 143 | 0 |     if(nciop == NULL) {status = NC_ENOMEM; goto fail;} | 
| 144 |  |      | 
| 145 | 0 |     nciop->ioflags = ioflags; | 
| 146 | 0 |     *((int*)&nciop->fd) = -1; /* caller will fix */ | 
| 147 |  | 
 | 
| 148 | 0 |     *((char**)&nciop->path) = strdup(path); | 
| 149 | 0 |     if(nciop->path == NULL) {status = NC_ENOMEM; goto fail;} | 
| 150 |  |  | 
| 151 | 0 |     *((ncio_relfunc**)&nciop->rel) = mmapio_rel; | 
| 152 | 0 |     *((ncio_getfunc**)&nciop->get) = mmapio_get; | 
| 153 | 0 |     *((ncio_movefunc**)&nciop->move) = mmapio_move; | 
| 154 | 0 |     *((ncio_syncfunc**)&nciop->sync) = mmapio_sync; | 
| 155 | 0 |     *((ncio_filesizefunc**)&nciop->filesize) = mmapio_filesize; | 
| 156 | 0 |     *((ncio_pad_lengthfunc**)&nciop->pad_length) = mmapio_pad_length; | 
| 157 | 0 |     *((ncio_closefunc**)&nciop->close) = mmapio_close; | 
| 158 |  | 
 | 
| 159 | 0 |     mmapio = (NCMMAPIO*)calloc(1,sizeof(NCMMAPIO)); | 
| 160 | 0 |     if(mmapio == NULL) {status = NC_ENOMEM; goto fail;} | 
| 161 | 0 |     *((void* *)&nciop->pvt) = mmapio; | 
| 162 |  | 
 | 
| 163 | 0 |     mmapio->alloc = initialsize; | 
| 164 |  | 
 | 
| 165 | 0 |     mmapio->memory = NULL; | 
| 166 | 0 |     mmapio->size = 0; | 
| 167 | 0 |     mmapio->pos = 0; | 
| 168 | 0 |     mmapio->persist = fIsSet(ioflags,NC_PERSIST); | 
| 169 |  |  | 
| 170 |  |     /* See if ok to use mmap */ | 
| 171 | 0 |     if(sizeof(void*) < 8 && | 
| 172 | 0 |        (fIsSet(ioflags,NC_64BIT_OFFSET) || fIsSet(ioflags,NC_64BIT_DATA))) | 
| 173 | 0 |   return NC_DISKLESS; /* cannot support */ | 
| 174 | 0 |     mmapio->mapfd = -1; | 
| 175 |  | 
 | 
| 176 | 0 |     if(nciopp) *nciopp = nciop; | 
| 177 | 0 |     if(mmapp) *mmapp = mmapio; | 
| 178 |  | 
 | 
| 179 | 0 | done: | 
| 180 | 0 |     if(openfd >= 0) close(openfd); | 
| 181 | 0 |     return status; | 
| 182 |  |  | 
| 183 | 0 | fail: | 
| 184 | 0 |     if(nciop != NULL) { | 
| 185 | 0 |         if(nciop->path != NULL) free((char*)nciop->path); | 
| 186 | 0 |     } | 
| 187 | 0 |     goto done; | 
| 188 | 0 | } | 
| 189 |  |  | 
| 190 |  | /* Create a file, and the ncio struct to go with it. This function is | 
| 191 |  |    only called from nc__create_mp. | 
| 192 |  |  | 
| 193 |  |    path - path of file to create. | 
| 194 |  |    ioflags - flags from nc_create | 
| 195 |  |    initialsz - From the netcdf man page: "The argument | 
| 196 |  |    Iinitialsize sets the initial size of the file at creation time." | 
| 197 |  |    igeto -  | 
| 198 |  |    igetsz -  | 
| 199 |  |    sizehintp - the size of a page of data for buffered reads and writes. | 
| 200 |  |    nciopp - pointer to a pointer that will get location of newly | 
| 201 |  |    created and inited ncio struct. | 
| 202 |  |    mempp - pointer to pointer to the initial memory read. | 
| 203 |  | */ | 
| 204 |  | int | 
| 205 |  | mmapio_create(const char* path, int ioflags, | 
| 206 |  |     size_t initialsz, | 
| 207 |  |     off_t igeto, size_t igetsz, size_t* sizehintp, | 
| 208 |  |     void* parameters, | 
| 209 |  |     ncio* *nciopp, void** const mempp) | 
| 210 | 0 | { | 
| 211 | 0 |     ncio* nciop; | 
| 212 | 0 |     int fd; | 
| 213 | 0 |     int status; | 
| 214 | 0 |     NCMMAPIO* mmapio = NULL; | 
| 215 | 0 |     int persist = (ioflags & NC_PERSIST?1:0); | 
| 216 | 0 |     int oflags; | 
| 217 |  | 
 | 
| 218 | 0 |     if(path == NULL ||* path == 0) | 
| 219 | 0 |         return NC_EINVAL; | 
| 220 |  |  | 
| 221 |  |     /* For diskless open has, the file must be classic version 1 or 2.*/ | 
| 222 | 0 |     if(fIsSet(ioflags,NC_NETCDF4)) | 
| 223 | 0 |         return NC_EDISKLESS; /* violates constraints */ | 
| 224 |  |  | 
| 225 | 0 |     status = mmapio_new(path, ioflags, initialsz, &nciop, &mmapio); | 
| 226 | 0 |     if(status != NC_NOERR) | 
| 227 | 0 |         return status; | 
| 228 | 0 |     mmapio->size = 0; | 
| 229 |  | 
 | 
| 230 | 0 |     if(!persist) { | 
| 231 | 0 |         mmapio->mapfd = -1; | 
| 232 | 0 |   mmapio->memory = (char*)mmap(NULL,mmapio->alloc, | 
| 233 | 0 |                                     PROT_READ|PROT_WRITE, | 
| 234 | 0 |             MAP_PRIVATE|MAP_ANONYMOUS, | 
| 235 | 0 |                                     mmapio->mapfd,0); | 
| 236 | 0 |   {mmapio->memory[0] = 0;} /* test writing of the mmap'd memory */ | 
| 237 | 0 |     } else { /*persist */ | 
| 238 |  |         /* Open the file to get fd,  but make sure we can write it if needed */ | 
| 239 | 0 |         oflags = O_RDWR; | 
| 240 |  | #ifdef O_BINARY | 
| 241 |  |         fSet(oflags, O_BINARY); | 
| 242 |  | #endif | 
| 243 | 0 |       oflags |= (O_CREAT|O_TRUNC); | 
| 244 | 0 |         if(fIsSet(ioflags,NC_NOCLOBBER)) | 
| 245 | 0 |       oflags |= O_EXCL; | 
| 246 | 0 |         fd  = NCopen3(path, oflags, OPENMODE); | 
| 247 | 0 |         if(fd < 0) {status = errno; goto unwind_open;} | 
| 248 | 0 |   mmapio->mapfd = fd; | 
| 249 |  | 
 | 
| 250 | 0 |         { /* Cause the output file to have enough allocated space */ | 
| 251 | 0 |             lseek(fd,(off_t)mmapio->alloc-1,SEEK_SET); /* cause file to appear */ | 
| 252 | 0 |             write(fd,"",1); | 
| 253 | 0 |             lseek(fd,0,SEEK_SET); /* rewind */ | 
| 254 | 0 |         } | 
| 255 | 0 |         mmapio->memory = (char*)mmap(NULL,mmapio->alloc, | 
| 256 | 0 |                                     PROT_READ|PROT_WRITE, | 
| 257 | 0 |             MAP_SHARED, | 
| 258 | 0 |                                     mmapio->mapfd,0); | 
| 259 | 0 |   if(mmapio->memory == NULL) { | 
| 260 | 0 |       return NC_EDISKLESS; | 
| 261 | 0 |   } | 
| 262 | 0 |     } /*!persist*/ | 
| 263 |  |  | 
| 264 |  | #ifdef DEBUG | 
| 265 |  | fprintf(stderr,"mmap_create: initial memory: %lu/%lu\n",(unsigned long)mmapio->memory,(unsigned long)mmapio->alloc); | 
| 266 |  | #endif | 
| 267 |  |  | 
| 268 | 0 |     fd = nc__pseudofd(); | 
| 269 | 0 |     *((int* )&nciop->fd) = fd;  | 
| 270 |  | 
 | 
| 271 | 0 |     fSet(nciop->ioflags, NC_WRITE); | 
| 272 |  | 
 | 
| 273 | 0 |     if(igetsz != 0) | 
| 274 | 0 |     { | 
| 275 | 0 |         status = nciop->get(nciop, | 
| 276 | 0 |                 igeto, igetsz, | 
| 277 | 0 |                 RGN_WRITE, | 
| 278 | 0 |                 mempp); | 
| 279 | 0 |         if(status != NC_NOERR) | 
| 280 | 0 |             goto unwind_open; | 
| 281 | 0 |     } | 
| 282 |  |  | 
| 283 |  |     /* Pick a default sizehint */ | 
| 284 | 0 |     if(sizehintp) *sizehintp = pagesize; | 
| 285 |  | 
 | 
| 286 | 0 |     *nciopp = nciop; | 
| 287 | 0 |     return NC_NOERR; | 
| 288 |  |  | 
| 289 | 0 | unwind_open: | 
| 290 | 0 |     mmapio_close(nciop,1); | 
| 291 | 0 |     return status; | 
| 292 | 0 | } | 
| 293 |  |  | 
| 294 |  | /* This function opens the data file. It is only called from nc.c, | 
| 295 |  |    from nc__open_mp and nc_delete_mp. | 
| 296 |  |  | 
| 297 |  |    path - path of data file. | 
| 298 |  |    ioflags - flags passed into nc_open. | 
| 299 |  |    igeto - looks like this function can do an initial page get, and | 
| 300 |  |    igeto is going to be the offset for that. But it appears to be | 
| 301 |  |    unused  | 
| 302 |  |    igetsz - the size in bytes of initial page get (a.k.a. extent). Not | 
| 303 |  |    ever used in the library. | 
| 304 |  |    sizehintp - the size of a page of data for buffered reads and writes. | 
| 305 |  |    nciopp - pointer to pointer that will get address of newly created | 
| 306 |  |    and inited ncio struct. | 
| 307 |  |    mempp - pointer to pointer to the initial memory read. | 
| 308 |  | */ | 
| 309 |  | int | 
| 310 |  | mmapio_open(const char* path, | 
| 311 |  |     int ioflags, | 
| 312 |  |     off_t igeto, size_t igetsz, size_t* sizehintp, | 
| 313 |  |     void* parameters, | 
| 314 |  |     ncio* *nciopp, void** const mempp) | 
| 315 | 0 | { | 
| 316 | 0 |     ncio* nciop = NULL; | 
| 317 | 0 |     int fd; | 
| 318 | 0 |     int status; | 
| 319 | 0 |     int oflags; | 
| 320 | 0 |     NCMMAPIO* mmapio = NULL; | 
| 321 | 0 |     size_t sizehint; | 
| 322 | 0 |     off_t filesize; | 
| 323 | 0 |     int readwrite = (fIsSet(ioflags,NC_WRITE)?1:0); | 
| 324 |  | 
 | 
| 325 | 0 |     if(path == NULL ||* path == 0) | 
| 326 | 0 |         return EINVAL; | 
| 327 |  |  | 
| 328 | 0 |     assert(sizehintp != NULL); | 
| 329 | 0 |     sizehint = *sizehintp; | 
| 330 |  |  | 
| 331 |  |     /* Open the file, but make sure we can write it if needed */ | 
| 332 | 0 |     oflags = (readwrite ? O_RDWR : O_RDONLY);     | 
| 333 |  | #ifdef O_BINARY | 
| 334 |  |     fSet(oflags, O_BINARY); | 
| 335 |  | #endif | 
| 336 | 0 |     oflags |= O_EXCL; | 
| 337 | 0 |     fd  = NCopen3(path, oflags, OPENMODE); | 
| 338 | 0 |     if(fd < 0) {status = errno; goto unwind_open;} | 
| 339 |  |  | 
| 340 |  |     /* get current filesize  = max(|file|,initialize)*/ | 
| 341 | 0 |     filesize = lseek(fd,0,SEEK_END); | 
| 342 | 0 |     if(filesize < 0) {status = errno; goto unwind_open;} | 
| 343 |  |     /* move pointer back to beginning of file */ | 
| 344 | 0 |     (void)lseek(fd,0,SEEK_SET); | 
| 345 | 0 |     if(filesize < (off_t)sizehint) | 
| 346 | 0 |         filesize = (off_t)sizehint; | 
| 347 |  | 
 | 
| 348 | 0 |     status = mmapio_new(path, ioflags, (size_t)filesize, &nciop, &mmapio); | 
| 349 | 0 |     if(status != NC_NOERR) | 
| 350 | 0 |   return status; | 
| 351 | 0 |     mmapio->size = filesize; | 
| 352 |  | 
 | 
| 353 | 0 |     mmapio->mapfd = fd; | 
| 354 | 0 |     mmapio->memory = (char*)mmap(NULL,mmapio->alloc, | 
| 355 | 0 |                                     readwrite?(PROT_READ|PROT_WRITE):(PROT_READ), | 
| 356 | 0 |             MAP_SHARED, | 
| 357 | 0 |                                     mmapio->mapfd,0); | 
| 358 |  | #ifdef DEBUG | 
| 359 |  | fprintf(stderr,"mmapio_open: initial memory: %lu/%lu\n",(unsigned long)mmapio->memory,(unsigned long)mmapio->alloc); | 
| 360 |  | #endif | 
| 361 |  |  | 
| 362 |  |     /* Use half the filesize as the blocksize */ | 
| 363 | 0 |     sizehint = (size_t)filesize/2; | 
| 364 |  |  | 
| 365 |  |     /* sizehint must be multiple of 8 */ | 
| 366 | 0 |     sizehint = (sizehint / 8) * 8; | 
| 367 | 0 |     if(sizehint < 8) sizehint = 8; | 
| 368 |  | 
 | 
| 369 | 0 |     fd = nc__pseudofd(); | 
| 370 | 0 |     *((int* )&nciop->fd) = fd;  | 
| 371 |  | 
 | 
| 372 | 0 |     if(igetsz != 0) | 
| 373 | 0 |     { | 
| 374 | 0 |         status = nciop->get(nciop, | 
| 375 | 0 |                 igeto, igetsz, | 
| 376 | 0 |                 0, | 
| 377 | 0 |                 mempp); | 
| 378 | 0 |         if(status != NC_NOERR) | 
| 379 | 0 |             goto unwind_open; | 
| 380 | 0 |     } | 
| 381 |  |  | 
| 382 | 0 |     *sizehintp = sizehint; | 
| 383 | 0 |     *nciopp = nciop; | 
| 384 | 0 |     return NC_NOERR; | 
| 385 |  |  | 
| 386 | 0 | unwind_open: | 
| 387 | 0 |     mmapio_close(nciop,0); | 
| 388 | 0 |     return status; | 
| 389 | 0 | } | 
| 390 |  |  | 
| 391 |  |  | 
| 392 |  | /*  | 
| 393 |  |  *  Get file size in bytes. | 
| 394 |  |  */ | 
| 395 |  | static int | 
| 396 |  | mmapio_filesize(ncio* nciop, off_t* filesizep) | 
| 397 | 0 | { | 
| 398 | 0 |     NCMMAPIO* mmapio; | 
| 399 | 0 |     if(nciop == NULL || nciop->pvt == NULL) return NC_EINVAL; | 
| 400 | 0 |     mmapio = (NCMMAPIO*)nciop->pvt; | 
| 401 | 0 |     if(filesizep != NULL) *filesizep = mmapio->size; | 
| 402 | 0 |     return NC_NOERR; | 
| 403 | 0 | } | 
| 404 |  |  | 
| 405 |  | /* | 
| 406 |  |  *  Sync any changes to disk, then truncate or extend file so its size | 
| 407 |  |  *  is length.  This is only intended to be called before close, if the | 
| 408 |  |  *  file is open for writing and the actual size does not match the | 
| 409 |  |  *  calculated size, perhaps as the result of having been previously | 
| 410 |  |  *  written in NOFILL mode. | 
| 411 |  |  */ | 
| 412 |  | static int | 
| 413 |  | mmapio_pad_length(ncio* nciop, off_t length) | 
| 414 | 0 | { | 
| 415 | 0 |     NCMMAPIO* mmapio; | 
| 416 |  | 
 | 
| 417 | 0 |     if(nciop == NULL || nciop->pvt == NULL) return NC_EINVAL; | 
| 418 | 0 |     mmapio = (NCMMAPIO*)nciop->pvt; | 
| 419 |  | 
 | 
| 420 | 0 |     if(!fIsSet(nciop->ioflags, NC_WRITE)) | 
| 421 | 0 |         return EPERM; /* attempt to write readonly file*/ | 
| 422 |  |  | 
| 423 | 0 |     if(mmapio->locked > 0) | 
| 424 | 0 |   return NC_EDISKLESS; | 
| 425 |  |  | 
| 426 | 0 |     if(length > mmapio->alloc) { | 
| 427 |  |         /* Realloc the allocated memory to a multiple of the pagesize*/ | 
| 428 | 0 |   size_t newsize = (size_t)length; | 
| 429 | 0 |   void* newmem = NULL; | 
| 430 |  |   /* Round to a multiple of pagesize */ | 
| 431 | 0 |   if((newsize % pagesize) != 0) | 
| 432 | 0 |       newsize += (pagesize - (newsize % pagesize)); | 
| 433 |  |  | 
| 434 |  |   /* Force file size to be properly extended */ | 
| 435 | 0 |   { /* Cause the output file to have enough allocated space */ | 
| 436 | 0 |   off_t pos = lseek(mmapio->mapfd,0,SEEK_CUR); /* save current position*/ | 
| 437 |  |   /* cause file to be extended in size */ | 
| 438 | 0 |   lseek(mmapio->mapfd,(off_t)newsize-1,SEEK_SET); | 
| 439 | 0 |         write(mmapio->mapfd,"",mmapio->alloc); | 
| 440 | 0 |   lseek(mmapio->mapfd,pos,SEEK_SET); /* reset position */ | 
| 441 | 0 |   } | 
| 442 |  | 
 | 
| 443 | 0 | #ifdef HAVE_MREMAP | 
| 444 | 0 |   newmem = (char*)mremap(mmapio->memory,mmapio->alloc,newsize,MREMAP_MAYMOVE); | 
| 445 | 0 |   if(newmem == NULL) return NC_ENOMEM; | 
| 446 |  | #else | 
| 447 |  |         /* note: mmapio->mapfd >= 0 => persist */ | 
| 448 |  |         newmem = (char*)mmap(NULL,newsize, | 
| 449 |  |                                     mmapio->mapfd >= 0?(PROT_READ|PROT_WRITE):(PROT_READ), | 
| 450 |  |             MAP_SHARED, | 
| 451 |  |                                     mmapio->mapfd,0); | 
| 452 |  |   if(newmem == NULL) return NC_ENOMEM; | 
| 453 |  |   memcpy(newmem,mmapio->memory,mmapio->alloc); | 
| 454 |  |         munmap(mmapio->memory,mmapio->alloc); | 
| 455 |  | #endif | 
| 456 |  |  | 
| 457 |  | #ifdef DEBUG | 
| 458 |  | fprintf(stderr,"realloc: %lu/%lu -> %lu/%lu\n", | 
| 459 |  | (unsigned long)mmapio->memory,(unsigned long)mmapio->alloc, | 
| 460 |  | (unsigned long)newmem,(unsigned long)newsize); | 
| 461 |  | #endif | 
| 462 | 0 |   mmapio->memory = newmem; | 
| 463 | 0 |   mmapio->alloc = newsize; | 
| 464 | 0 |     }   | 
| 465 | 0 |     mmapio->size = length; | 
| 466 | 0 |     return NC_NOERR; | 
| 467 | 0 | } | 
| 468 |  |  | 
| 469 |  | /* Write out any dirty buffers to disk and | 
| 470 |  |    ensure that next read will get data from disk. | 
| 471 |  |    Sync any changes, then close the open file associated with the ncio | 
| 472 |  |    struct, and free its memory. | 
| 473 |  |    nciop - pointer to ncio to close. | 
| 474 |  |    doUnlink - if true, unlink file | 
| 475 |  | */ | 
| 476 |  |  | 
| 477 |  | static int  | 
| 478 |  | mmapio_close(ncio* nciop, int doUnlink) | 
| 479 | 0 | { | 
| 480 | 0 |     int status = NC_NOERR; | 
| 481 | 0 |     NCMMAPIO* mmapio; | 
| 482 | 0 |     if(nciop == NULL || nciop->pvt == NULL) return NC_NOERR; | 
| 483 |  |  | 
| 484 | 0 |     mmapio = (NCMMAPIO*)nciop->pvt; | 
| 485 | 0 |     assert(mmapio != NULL); | 
| 486 |  |  | 
| 487 |  |     /* Since we are using mmap, persisting to a file should be automatic */ | 
| 488 | 0 |     status = munmap(mmapio->memory,mmapio->alloc); | 
| 489 | 0 |     mmapio->memory = NULL; /* so we do not try to free it */ | 
| 490 |  |  | 
| 491 |  |     /* Close file if it was open */ | 
| 492 | 0 |     if(mmapio->mapfd >= 0) | 
| 493 | 0 |   close(mmapio->mapfd); | 
| 494 |  |  | 
| 495 |  |     /* do cleanup  */ | 
| 496 | 0 |     if(mmapio != NULL) free(mmapio); | 
| 497 | 0 |     if(nciop->path != NULL) free((char*)nciop->path); | 
| 498 | 0 |     free(nciop); | 
| 499 | 0 |     return status; | 
| 500 | 0 | } | 
| 501 |  |  | 
| 502 |  | static int | 
| 503 |  | guarantee(ncio* nciop, off_t endpoint) | 
| 504 | 0 | { | 
| 505 | 0 |     NCMMAPIO* mmapio = (NCMMAPIO*)nciop->pvt; | 
| 506 | 0 |     if(endpoint > mmapio->alloc) { | 
| 507 |  |   /* extend the allocated memory and size */ | 
| 508 | 0 |   int status = mmapio_pad_length(nciop,endpoint); | 
| 509 | 0 |   if(status != NC_NOERR) return status; | 
| 510 | 0 |     } | 
| 511 | 0 |     if(mmapio->size < endpoint) | 
| 512 | 0 |   mmapio->size = endpoint; | 
| 513 | 0 |     return NC_NOERR; | 
| 514 | 0 | } | 
| 515 |  |  | 
| 516 |  | /* | 
| 517 |  |  * Request that the region (offset, extent) | 
| 518 |  |  * be made available through *vpp. | 
| 519 |  |  */ | 
| 520 |  | static int | 
| 521 |  | mmapio_get(ncio* const nciop, off_t offset, size_t extent, int rflags, void** const vpp) | 
| 522 | 0 | { | 
| 523 | 0 |     int status = NC_NOERR; | 
| 524 | 0 |     NCMMAPIO* mmapio; | 
| 525 | 0 |     if(nciop == NULL || nciop->pvt == NULL) return NC_EINVAL; | 
| 526 | 0 |     mmapio = (NCMMAPIO*)nciop->pvt; | 
| 527 | 0 |     status = guarantee(nciop, offset+(off_t)extent); | 
| 528 | 0 |     mmapio->locked++; | 
| 529 | 0 |     if(status != NC_NOERR) return status; | 
| 530 | 0 |     if(vpp) *vpp = mmapio->memory+offset; | 
| 531 | 0 |     return NC_NOERR; | 
| 532 | 0 | } | 
| 533 |  |  | 
| 534 |  | /* | 
| 535 |  |  * Like memmove(), safely move possibly overlapping data. | 
| 536 |  |  */ | 
| 537 |  | static int | 
| 538 |  | mmapio_move(ncio* const nciop, off_t to, off_t from, size_t nbytes, int ignored) | 
| 539 | 0 | { | 
| 540 | 0 |     int status = NC_NOERR; | 
| 541 | 0 |     NCMMAPIO* mmapio; | 
| 542 |  | 
 | 
| 543 | 0 |     if(nciop == NULL || nciop->pvt == NULL) return NC_EINVAL; | 
| 544 | 0 |     mmapio = (NCMMAPIO*)nciop->pvt; | 
| 545 | 0 |     if(from < to) { | 
| 546 |  |        /* extend if "to" is not currently allocated */ | 
| 547 | 0 |        status = guarantee(nciop, to + (off_t)nbytes); | 
| 548 | 0 |        if(status != NC_NOERR) return status; | 
| 549 | 0 |     } | 
| 550 |  |     /* check for overlap */ | 
| 551 | 0 |     if((to + (off_t)nbytes) > from || (from + (off_t)nbytes) > to) { | 
| 552 |  |   /* Ranges overlap */ | 
| 553 | 0 | #ifdef HAVE_MEMMOVE | 
| 554 | 0 |         memmove((void*)(mmapio->memory+to),(void*)(mmapio->memory+from),nbytes); | 
| 555 |  | #else | 
| 556 |  |         off_t overlap; | 
| 557 |  |   off_t nbytes1; | 
| 558 |  |         if((from + nbytes) > to) { | 
| 559 |  |       overlap = ((from + nbytes) - to); /* # bytes of overlap */ | 
| 560 |  |       nbytes1 = (nbytes - overlap); /* # bytes of non-overlap */ | 
| 561 |  |       /* move the non-overlapping part */ | 
| 562 |  |             memcpy((void*)(mmapio->memory+(to+overlap)), | 
| 563 |  |                    (void*)(mmapio->memory+(from+overlap)), | 
| 564 |  |        nbytes1); | 
| 565 |  |       /* move the overlapping part */ | 
| 566 |  |       memcpy((void*)(mmapio->memory+to), | 
| 567 |  |                    (void*)(mmapio->memory+from), | 
| 568 |  |        overlap); | 
| 569 |  |   } else { /*((to + nbytes) > from) */ | 
| 570 |  |       overlap = ((to + nbytes) - from); /* # bytes of overlap */ | 
| 571 |  |       nbytes1 = (nbytes - overlap); /* # bytes of non-overlap */ | 
| 572 |  |       /* move the non-overlapping part */ | 
| 573 |  |             memcpy((void*)(mmapio->memory+to), | 
| 574 |  |                    (void*)(mmapio->memory+from), | 
| 575 |  |        nbytes1); | 
| 576 |  |       /* move the overlapping part */ | 
| 577 |  |       memcpy((void*)(mmapio->memory+(to+nbytes1)), | 
| 578 |  |                    (void*)(mmapio->memory+(from+nbytes1)), | 
| 579 |  |        overlap); | 
| 580 |  |   } | 
| 581 |  | #endif | 
| 582 | 0 |     } else {/* no overlap */ | 
| 583 | 0 |   memcpy((void*)(mmapio->memory+to),(void*)(mmapio->memory+from),nbytes); | 
| 584 | 0 |     } | 
| 585 | 0 |     return status; | 
| 586 | 0 | } | 
| 587 |  |  | 
| 588 |  | static int | 
| 589 |  | mmapio_rel(ncio* const nciop, off_t offset, int rflags) | 
| 590 | 0 | { | 
| 591 | 0 |     NCMMAPIO* mmapio; | 
| 592 | 0 |     if(nciop == NULL || nciop->pvt == NULL) return NC_EINVAL; | 
| 593 | 0 |     mmapio = (NCMMAPIO*)nciop->pvt; | 
| 594 | 0 |     mmapio->locked--; | 
| 595 | 0 |     return NC_NOERR; /* do nothing */ | 
| 596 | 0 | } | 
| 597 |  |  | 
| 598 |  | /* | 
| 599 |  |  * Write out any dirty buffers to disk and | 
| 600 |  |  * ensure that next read will get data from disk. | 
| 601 |  |  */ | 
| 602 |  | static int | 
| 603 |  | mmapio_sync(ncio* const nciop) | 
| 604 | 0 | { | 
| 605 | 0 |     return NC_NOERR; /* do nothing */ | 
| 606 | 0 | } |