/** * Load the contents of a text file. There are two separate implementations, * depending up on whether mmap(3) is available. * * If not available, malloc the file length plus one byte. Read it in * and NUL terminate. * * If available, first check to see if the text file size is a multiple of a * page size. If it is, map the file size plus an extra page from either * anonymous memory or from /dev/zero. Then map the file text on top of the * first pages of the anonymous/zero pages. Otherwise, just map the file * because there will be NUL bytes provided at the end. * * @param mapinfo a structure holding everything we need to know * about the mapping. * * @param pzFile name of the file, for error reporting. */ static void load_text_file(tmap_info_t * mapinfo, char const * pzFile) { #if ! defined(HAVE_MMAP) mapinfo->txt_data = AGALOC(mapinfo->txt_size+1, "file text"); if (mapinfo->txt_data == NULL) { mapinfo->txt_errno = ENOMEM; return; } { size_t sz = mapinfo->txt_size; char* pz = mapinfo->txt_data; while (sz > 0) { ssize_t rdct = read(mapinfo->txt_fd, pz, sz); if (rdct <= 0) { mapinfo->txt_errno = errno; fserr_warn("libopts", "read", pzFile); free(mapinfo->txt_data); return; } pz += rdct; sz -= rdct; } *pz = NUL; } mapinfo->txt_errno = 0; #else /* HAVE mmap */ size_t const pgsz = (size_t)GETPAGESIZE(); void * map_addr = NULL; (void)pzFile; mapinfo->txt_full_size = (mapinfo->txt_size + pgsz) & ~(pgsz - 1); if (mapinfo->txt_full_size == (mapinfo->txt_size + pgsz)) { /* * The text is a multiple of a page boundary. We must map an * extra page so the text ends with a NUL. */ #if defined(MAP_ANONYMOUS) map_addr = mmap(NULL, mapinfo->txt_full_size, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, AO_INVALID_FD, 0); #else mapinfo->txt_zero_fd = open("/dev/zero", O_RDONLY); if (mapinfo->txt_zero_fd == AO_INVALID_FD) { mapinfo->txt_errno = errno; return; } map_addr = mmap(NULL, mapinfo->txt_full_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, mapinfo->txt_zero_fd, 0); #endif if (map_addr == MAP_FAILED_PTR) { mapinfo->txt_errno = errno; return; } mapinfo->txt_flags |= MAP_FIXED; } mapinfo->txt_data = mmap(map_addr, mapinfo->txt_size, mapinfo->txt_prot, mapinfo->txt_flags, mapinfo->txt_fd, 0); if (mapinfo->txt_data == MAP_FAILED_PTR) mapinfo->txt_errno = errno; #endif /* HAVE_MMAP */ }
LOCAL noreturn void fserr_exit(char const * prog, char const * op, char const * fname) { fserr_warn(prog, op, fname); option_exits(EXIT_FAILURE); }