1 /*------------------------------------------------------------------------------
2 *
3 * Copyright (c) 2011-2021, EURid vzw. All rights reserved.
4 * The YADIFA TM software product is provided under the BSD 3-clause license:
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * * Neither the name of EURid nor the names of its contributors may be
16 * used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 *
31 *------------------------------------------------------------------------------
32 *
33 */
34
35 /** @defgroup streaming Streams
36 * @ingroup dnscore
37 * @brief
38 *
39 *
40 *
41 * @{
42 *
43 *----------------------------------------------------------------------------*/
44
45 #include "dnscore/dnscore-config.h"
46
47 #if HAS_MREMAP
48 #define _GNU_SOURCE 1
49 #endif
50
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <sys/types.h>
54 #include <sys/stat.h>
55 #include <fcntl.h>
56 #include <unistd.h>
57 #include <sys/mman.h>
58
59 #include "dnscore/mapped-file.h"
60 #include "dnscore/fdtools.h"
61 #include "dnscore/zalloc.h"
62 #include "dnscore/mutex.h"
63
64 //extern logger_handle *g_system_logger;
65 //#define MODULE_MSG_HANDLE g_system_logger
66
67 #define MAPPED_FILE_TAG 0x454c494650414d4d // MMAPFILE_TAG
68
69 ssize_t g_page_size = 0;
70 ssize_t g_page_mask = 0;
71
72 static void
mapped_file_update_system_consts()73 mapped_file_update_system_consts()
74 {
75 #ifndef WIN32
76 if(g_page_size == 0)
77 {
78 g_page_size = sysconf(_SC_PAGE_SIZE);
79 if(g_page_size < 0)
80 {
81 g_page_size = 4096;
82 }
83 g_page_mask = g_page_size - 1;
84 }
85 #else
86 g_page_size = 4096;
87 g_page_mask = g_page_size - 1;
88 #endif
89 }
90
91 struct mapped_file_t_ // matches the file_t_ signature, appends its own
92 {
93 const struct file_vtbl *vtbl;
94 u8 *address;
95 ssize_t size;
96 ssize_t real_size; // for non file-backed maps
97 off_t position;
98 group_mutex_t mtx;
99 int fd;
100 int prot;
101 int flags;
102 };
103
104 typedef struct mapped_file_t_* mapped_file_t;
105
106 static int
mapped_file_resize_internal(mapped_file_t mf,size_t required_new_size)107 mapped_file_resize_internal(mapped_file_t mf, size_t required_new_size)
108 {
109 u8 *address;
110
111 if((ssize_t)required_new_size <= mf->real_size)
112 {
113 mf->size = required_new_size;
114 return SUCCESS;
115 }
116
117 size_t new_real_size = MAX(mf->real_size * 2, 0x1000000);
118
119 #if HAS_MREMAP
120 if(mf->address != NULL)
121 {
122 address = mremap(mf->address, mf->real_size, new_real_size, MREMAP_MAYMOVE);
123
124 if(address == (u8*)MAP_FAILED)
125 {
126 return ERRNO_ERROR;
127 }
128 }
129 else
130 {
131 address = mmap(mf->address, new_real_size, mf->prot, mf->flags, mf->fd, 0);
132
133 if(address == (u8*)MAP_FAILED)
134 {
135 return ERRNO_ERROR;
136 }
137 }
138 #else
139 address = mmap(mf->address, new_real_size, mf->prot, mf->flags, mf->fd, 0);
140
141 if(address == (u8*)MAP_FAILED)
142 {
143 return ERRNO_ERROR;
144 }
145
146 if(mf->address != NULL)
147 {
148 memcpy(address, mf->address, MIN(mf->size, (ssize_t)required_new_size));
149 munmap(mf->address, mf->size);
150 }
151 #endif
152
153 mf->address = address;
154 mf->size = required_new_size;
155 mf->real_size = new_real_size;
156
157 return SUCCESS;
158 }
159
160 static ssize_t
mapped_file_read(file_t f,void * buffer,ssize_t size)161 mapped_file_read(file_t f, void *buffer, ssize_t size)
162 {
163 mapped_file_t mf = (mapped_file_t)f;
164
165 if((mf->prot & PROT_READ) == 0)
166 {
167 return INVALID_STATE_ERROR;
168 }
169
170 group_mutex_double_lock(&mf->mtx, GROUP_MUTEX_READ, GROUP_MUTEX_WRITE);
171 ssize_t avail = mf->size - mf->position;
172
173 if(avail < size)
174 {
175 size = avail;
176 }
177 memcpy(buffer, &mf->address[mf->position], size);
178
179 group_mutex_exchange_locks(&mf->mtx, GROUP_MUTEX_READ, GROUP_MUTEX_WRITE);
180 mf->position += size;
181 group_mutex_exchange_locks(&mf->mtx, GROUP_MUTEX_WRITE, GROUP_MUTEX_READ);
182
183 group_mutex_double_unlock(&mf->mtx, GROUP_MUTEX_READ, GROUP_MUTEX_WRITE);
184
185 return size;
186 }
187
188 static ssize_t
mapped_file_write(file_t f,const void * buffer,ssize_t size)189 mapped_file_write(file_t f, const void *buffer, ssize_t size)
190 {
191 mapped_file_t mf = (mapped_file_t)f;
192
193 if((mf->prot & PROT_WRITE) == 0)
194 {
195 return INVALID_STATE_ERROR;
196 }
197
198 group_mutex_lock(&mf->mtx, GROUP_MUTEX_WRITE);
199 ssize_t avail = mf->size - mf->position;
200
201 if(avail < size)
202 {
203 // grow the file
204 if(mf->fd >= 0)
205 {
206 ftruncate(mf->fd, mf->position + size);
207 }
208
209 ssize_t ret = mapped_file_resize_internal(mf, mf->position + size);
210
211 if(FAIL(ret))
212 {
213 group_mutex_unlock(&mf->mtx, GROUP_MUTEX_WRITE);
214
215 return ret;
216 }
217 }
218
219 memcpy(&mf->address[mf->position], buffer, size);
220
221 mf->position += size;
222
223 group_mutex_unlock(&mf->mtx, GROUP_MUTEX_WRITE);
224
225 return size;
226 }
227
228 static ssize_t
mapped_file_seek(file_t f,ssize_t position,int whence)229 mapped_file_seek(file_t f, ssize_t position, int whence)
230 {
231 mapped_file_t mf = (mapped_file_t)f;
232
233 if(mf->prot == PROT_NONE)
234 {
235 return INVALID_STATE_ERROR;
236 }
237
238 group_mutex_lock(&mf->mtx, GROUP_MUTEX_WRITE);
239
240 switch(whence)
241 {
242 case SEEK_SET:
243 {
244 mf->position = position;
245
246 group_mutex_unlock(&mf->mtx, GROUP_MUTEX_WRITE);
247
248 return position;
249 }
250 case SEEK_CUR:
251 {
252 if(mf->position + position >= 0)
253 {
254 position = (mf->position += position);
255
256 group_mutex_unlock(&mf->mtx, GROUP_MUTEX_WRITE);
257
258 return position;
259 }
260 else
261 {
262 mf->position = 0;
263
264 group_mutex_unlock(&mf->mtx, GROUP_MUTEX_WRITE);
265
266 return 0;
267 }
268 }
269 case SEEK_END:
270 {
271 if(mf->size + position >= 0)
272 {
273 position = mf->position = mf->size + position;
274 group_mutex_unlock(&mf->mtx, GROUP_MUTEX_WRITE);
275 return position;
276 }
277 else
278 {
279 mf->position = 0;
280 group_mutex_unlock(&mf->mtx, GROUP_MUTEX_WRITE);
281 return 0;
282 }
283 }
284 default:
285 {
286 group_mutex_unlock(&mf->mtx, GROUP_MUTEX_WRITE);
287 return ERROR;
288 }
289 }
290 }
291
292 static ssize_t
mapped_file_tell(file_t f)293 mapped_file_tell(file_t f)
294 {
295 mapped_file_t mf = (mapped_file_t)f;
296
297 if(mf->prot == PROT_NONE)
298 {
299 return INVALID_STATE_ERROR;
300 }
301
302 ssize_t ret;
303
304 group_mutex_lock(&mf->mtx, GROUP_MUTEX_READ);
305 ret = mf->position;
306 group_mutex_unlock(&mf->mtx, GROUP_MUTEX_READ);
307
308 return ret;
309 }
310
311 static ya_result
mapped_file_flush(file_t f)312 mapped_file_flush(file_t f)
313 {
314 mapped_file_t mf = (mapped_file_t)f;
315
316 if(mf->prot == PROT_NONE)
317 {
318 return INVALID_STATE_ERROR;
319 }
320
321 group_mutex_lock(&mf->mtx, GROUP_MUTEX_READ);
322
323 int ret = msync(mf->address, mf->size, MS_SYNC);
324
325 group_mutex_unlock(&mf->mtx, GROUP_MUTEX_READ);
326
327 if(FAIL(ret))
328 {
329 ret = ERRNO_ERROR;
330 }
331
332 return ret;
333 }
334
335 static int
mapped_file_close(file_t f)336 mapped_file_close(file_t f)
337 {
338 mapped_file_t mf = (mapped_file_t)f;
339
340 if(mf->prot == PROT_NONE)
341 {
342 return INVALID_STATE_ERROR;
343 }
344
345 group_mutex_lock(&mf->mtx, GROUP_MUTEX_WRITE);
346
347 if(mf->address != NULL)
348 {
349 munmap(mf->address, mf->real_size);
350 mf->address = NULL;
351 mf->size = 0;
352 }
353
354 group_mutex_unlock(&mf->mtx, GROUP_MUTEX_WRITE);
355
356 if(mf->fd >= 0)
357 {
358 close_ex(mf->fd);
359 mf->fd = -2;
360 }
361 mf->vtbl = NULL;
362 ZFREE_OBJECT(mf);
363
364 return SUCCESS;
365 }
366
367 static ssize_t
mapped_file_size(file_t f)368 mapped_file_size(file_t f)
369 {
370 mapped_file_t mf = (mapped_file_t)f;
371
372 if(mf->prot == PROT_NONE)
373 {
374 return INVALID_STATE_ERROR;
375 }
376
377 ssize_t ret;
378
379 group_mutex_lock(&mf->mtx, GROUP_MUTEX_READ);
380 ret = mf->size;
381 group_mutex_unlock(&mf->mtx, GROUP_MUTEX_READ);
382
383 return ret;
384 }
385
386 static int
mapped_file_resize(file_t f,ssize_t size)387 mapped_file_resize(file_t f, ssize_t size)
388 {
389 mapped_file_t mf = (mapped_file_t)f;
390
391 if(mf->prot == PROT_NONE)
392 {
393 return INVALID_STATE_ERROR;
394 }
395
396 ya_result ret = SUCCESS;
397
398 group_mutex_lock(&mf->mtx, GROUP_MUTEX_WRITE);
399
400 if(mf->size != size)
401 {
402 // grow the file
403 if(mf->fd >= 0)
404 {
405 if(ISOK(ret = ftruncate(mf->fd, size)))
406 {
407 ret = mapped_file_resize_internal(mf, size);
408 }
409 }
410 else
411 {
412 ret = mapped_file_resize_internal(mf, size);
413 }
414 }
415
416 group_mutex_unlock(&mf->mtx, GROUP_MUTEX_WRITE);
417
418 return ret;
419 }
420
421 static const struct file_vtbl mapped_file_vtbl =
422 {
423 mapped_file_read,
424 mapped_file_write,
425 mapped_file_seek,
426 mapped_file_tell,
427 mapped_file_flush,
428 mapped_file_close,
429 mapped_file_size,
430 mapped_file_resize
431 };
432
433 /*
434 file_t
435 mapped_file_open_ex(const char *filename, int flags, mode_t mode, ya_result *ret)
436 */
437
438 ya_result
mapped_file_open_ex(file_t * fp,const char * filename,int flags)439 mapped_file_open_ex(file_t *fp, const char *filename, int flags)
440 {
441 mapped_file_update_system_consts();
442
443 if(fp == NULL)
444 {
445 return UNEXPECTED_NULL_ARGUMENT_ERROR;
446 }
447
448 int fd = open_ex(filename, flags);
449 if(FAIL(fd))
450 {
451 return ERRNO_ERROR;
452 }
453
454 struct stat st;
455 if(fstat(fd, &st) < 0)
456 {
457 close_ex(fd);
458 return ERRNO_ERROR;
459 }
460
461 int prot;
462
463 if((flags & O_RDWR) == O_RDWR)
464 {
465 prot = PROT_READ|PROT_WRITE;
466 }
467 else if((flags & O_RDONLY) == O_RDONLY)
468 {
469 prot = PROT_READ;
470 }
471 else if((flags & O_WRONLY) == O_WRONLY)
472 {
473 prot = PROT_WRITE;
474 }
475 else
476 {
477 prot = PROT_NONE;
478 }
479
480 int mmap_flags = MAP_SHARED;
481
482 u8 *address = NULL;
483
484 ssize_t real_size = 0;
485
486 if(st.st_size > 0)
487 {
488 real_size = (st.st_size + 0xffffffLL) & ~0xffffffLL;
489 address = mmap(NULL, real_size, prot, mmap_flags, fd, 0);
490
491 if(address == (u8*)MAP_FAILED)
492 {
493 close_ex(fd);
494 return ERRNO_ERROR;
495 }
496 }
497
498 mapped_file_t mf;
499 ZALLOC_OBJECT_OR_DIE(mf,struct mapped_file_t_, MAPPED_FILE_TAG);
500 mf->vtbl = &mapped_file_vtbl;
501 mf->address = address;
502 mf->size = st.st_size;
503 mf->real_size = real_size;
504 mf->position = 0;
505 group_mutex_init(&mf->mtx);
506 mf->fd = fd;
507 mf->prot = prot;
508 mf->flags = mmap_flags;
509
510 *fp = (file_t)mf;
511
512 return SUCCESS;
513 }
514
515 ya_result
mapped_file_create_ex(file_t * fp,const char * filename,int flags,mode_t mode)516 mapped_file_create_ex(file_t *fp, const char *filename, int flags, mode_t mode)
517 {
518 mapped_file_update_system_consts();
519
520 if(fp == NULL)
521 {
522 return UNEXPECTED_NULL_ARGUMENT_ERROR;
523 }
524
525 int fd = open_create_ex(filename, flags, mode);
526
527 if(FAIL(fd))
528 {
529 return ERRNO_ERROR;
530 }
531
532 struct stat st;
533 if(fstat(fd, &st) < 0)
534 {
535 close_ex(fd);
536 return ERRNO_ERROR;
537 }
538
539 int prot;
540
541 if((flags & O_RDWR) == O_RDWR)
542 {
543 prot = PROT_READ|PROT_WRITE;
544 }
545 else if((flags & O_RDONLY) == O_RDONLY)
546 {
547 prot = PROT_READ;
548 }
549 else if((flags & O_WRONLY) == O_WRONLY)
550 {
551 prot = PROT_WRITE;
552 }
553 else
554 {
555 prot = PROT_NONE;
556 }
557
558 int mmap_flags = MAP_SHARED;
559
560 u8 *address = NULL;
561 size_t real_size = 0;
562
563 if(st.st_size > 0)
564 {
565 real_size = (st.st_size + 0xffffffLL) & ~0xffffffLL;
566 address = mmap(NULL, real_size, prot, mmap_flags, fd, 0);
567
568 if(address == (u8*)MAP_FAILED)
569 {
570 close_ex(fd);
571 return ERRNO_ERROR;
572 }
573 }
574
575 mapped_file_t mf;
576 ZALLOC_OBJECT_OR_DIE(mf,struct mapped_file_t_, MAPPED_FILE_TAG);
577 mf->vtbl = &mapped_file_vtbl;
578 mf->address = address;
579 mf->size = st.st_size;
580 mf->real_size = real_size;
581 mf->position = 0;
582 group_mutex_init(&mf->mtx);
583 mf->fd = fd;
584 mf->prot = prot;
585 mf->flags = mmap_flags;
586
587 *fp = (file_t)mf;
588
589 return SUCCESS;
590 }
591
592 ya_result
mapped_file_create_volatile(file_t * fp,const char * filename,size_t base_size)593 mapped_file_create_volatile(file_t *fp, const char *filename, size_t base_size)
594 {
595 (void)filename;
596
597 mapped_file_update_system_consts();
598
599 if(fp == NULL)
600 {
601 return UNEXPECTED_NULL_ARGUMENT_ERROR;
602 }
603
604 int fd = -1;
605
606 int prot = PROT_READ|PROT_WRITE;
607
608 int mmap_flags = MAP_ANONYMOUS|MAP_PRIVATE;
609
610 u8 *address = NULL;
611 size_t real_size = 0;
612
613 if(base_size > 0)
614 {
615 real_size = (base_size + 0xffffffLL) & ~0xffffffLL;
616
617 address = mmap(NULL, real_size, prot, mmap_flags, fd, 0);
618
619 if(address == (u8*)MAP_FAILED)
620 {
621 close_ex(fd);
622 return ERRNO_ERROR;
623 }
624 }
625
626 mapped_file_t mf;
627 ZALLOC_OBJECT_OR_DIE(mf,struct mapped_file_t_, MAPPED_FILE_TAG);
628 mf->vtbl = &mapped_file_vtbl;
629 mf->address = address;
630 mf->size = 0;
631 mf->real_size = real_size;
632 mf->position = 0;
633 group_mutex_init(&mf->mtx);
634 mf->fd = fd;
635 mf->prot = prot;
636 mf->flags = mmap_flags;
637
638 *fp = (file_t)mf;
639
640 return SUCCESS;
641 }
642
643 ya_result
mapped_file_get_buffer(file_t f,void ** address,ssize_t * size)644 mapped_file_get_buffer(file_t f, void **address, ssize_t *size)
645 {
646 mapped_file_t mf = (mapped_file_t)f;
647
648 if(f->vtbl == &mapped_file_vtbl)
649 {
650 if(address != NULL)
651 {
652 *address = mf->address;
653 }
654 if(size != NULL)
655 {
656 *size = mf->size;
657 }
658
659 return SUCCESS;
660 }
661 else
662 {
663 return INVALID_ARGUMENT_ERROR;
664 }
665 }
666
667 ya_result
mapped_file_get_buffer_const(file_t f,const void ** address,ssize_t * size)668 mapped_file_get_buffer_const(file_t f, const void **address, ssize_t *size)
669 {
670 mapped_file_t mf = (mapped_file_t)f;
671
672 if(f->vtbl == &mapped_file_vtbl)
673 {
674 if(address != NULL)
675 {
676 *address = mf->address;
677 }
678 if(size != NULL)
679 {
680 *size = mf->size;
681 }
682
683 return SUCCESS;
684 }
685 else
686 {
687 return INVALID_ARGUMENT_ERROR;
688 }
689 }
690
691 /** @} */
692