/src/netcdf-c/libsrc/mmapio.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 | | #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 | | off_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 long 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, off_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 = sysconf(_SC_PAGE_SIZE); |
128 | | #elif defined HAVE_GETPAGESIZE |
129 | | pagesize = 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,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; |
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, 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 = 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 | off_t newsize = 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,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+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+nbytes); |
548 | 0 | if(status != NC_NOERR) return status; |
549 | 0 | } |
550 | | /* check for overlap */ |
551 | 0 | if((to + nbytes) > from || (from + 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 | } |