xref: /freebsd/contrib/ntp/sntp/libopts/text_mmap.c (revision a466cc55373fc3cf86837f09da729535b57e69a1)
12b15cb3dSCy Schubert /**
22b15cb3dSCy Schubert  * @file text_mmap.c
3ea906c41SOllivier Robert  *
42b15cb3dSCy Schubert  * Map a text file, ensuring the text always has an ending NUL byte.
52b15cb3dSCy Schubert  *
62b15cb3dSCy Schubert  * @addtogroup autoopts
72b15cb3dSCy Schubert  * @{
8ea906c41SOllivier Robert  */
92b15cb3dSCy Schubert /*
102b15cb3dSCy Schubert  *  This file is part of AutoOpts, a companion to AutoGen.
112b15cb3dSCy Schubert  *  AutoOpts is free software.
12*a466cc55SCy Schubert  *  AutoOpts is Copyright (C) 1992-2018 by Bruce Korb - all rights reserved
132b15cb3dSCy Schubert  *
142b15cb3dSCy Schubert  *  AutoOpts is available under any one of two licenses.  The license
152b15cb3dSCy Schubert  *  in use must be one of these two and the choice is under the control
162b15cb3dSCy Schubert  *  of the user of the license.
172b15cb3dSCy Schubert  *
182b15cb3dSCy Schubert  *   The GNU Lesser General Public License, version 3 or later
192b15cb3dSCy Schubert  *      See the files "COPYING.lgplv3" and "COPYING.gplv3"
202b15cb3dSCy Schubert  *
212b15cb3dSCy Schubert  *   The Modified Berkeley Software Distribution License
222b15cb3dSCy Schubert  *      See the file "COPYING.mbsd"
232b15cb3dSCy Schubert  *
242b15cb3dSCy Schubert  *  These files have the following sha256 sums:
252b15cb3dSCy Schubert  *
262b15cb3dSCy Schubert  *  8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95  COPYING.gplv3
272b15cb3dSCy Schubert  *  4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b  COPYING.lgplv3
282b15cb3dSCy Schubert  *  13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239  COPYING.mbsd
292b15cb3dSCy Schubert  */
302b15cb3dSCy Schubert #if defined(HAVE_MMAP)
31ea906c41SOllivier Robert #  ifndef      MAP_ANONYMOUS
32ea906c41SOllivier Robert #    ifdef     MAP_ANON
33ea906c41SOllivier Robert #      define  MAP_ANONYMOUS   MAP_ANON
34ea906c41SOllivier Robert #    endif
35ea906c41SOllivier Robert #  endif
36ea906c41SOllivier Robert 
372b15cb3dSCy Schubert #  if ! defined(MAP_ANONYMOUS) && ! defined(HAVE_DEV_ZERO)
382b15cb3dSCy Schubert      /*
392b15cb3dSCy Schubert       * We must have either /dev/zero or anonymous mapping for
402b15cb3dSCy Schubert       * this to work.
412b15cb3dSCy Schubert       */
422b15cb3dSCy Schubert #    undef HAVE_MMAP
432b15cb3dSCy Schubert 
442b15cb3dSCy Schubert #  else
452b15cb3dSCy Schubert #    ifdef _SC_PAGESIZE
462b15cb3dSCy Schubert #      define GETPAGESIZE() sysconf(_SC_PAGESIZE)
472b15cb3dSCy Schubert #    else
482b15cb3dSCy Schubert #      define GETPAGESIZE() getpagesize()
492b15cb3dSCy Schubert #    endif
502b15cb3dSCy Schubert #  endif
512b15cb3dSCy Schubert #endif
522b15cb3dSCy Schubert 
53ea906c41SOllivier Robert /*
54ea906c41SOllivier Robert  *  Some weird systems require that a specifically invalid FD number
55ea906c41SOllivier Robert  *  get passed in as an argument value.  Which value is that?  Well,
56ea906c41SOllivier Robert  *  as everybody knows, if open(2) fails, it returns -1, so that must
57ea906c41SOllivier Robert  *  be the value.  :)
58ea906c41SOllivier Robert  */
59ea906c41SOllivier Robert #define AO_INVALID_FD  -1
60ea906c41SOllivier Robert 
61ea906c41SOllivier Robert #define FILE_WRITABLE(_prt,_flg) \
62ea906c41SOllivier Robert         (   (_prt & PROT_WRITE) \
63ea906c41SOllivier Robert          && ((_flg & (MAP_SHARED|MAP_PRIVATE)) == MAP_SHARED))
64276da39aSCy Schubert #define MAP_FAILED_PTR (VOIDP(MAP_FAILED))
65ea906c41SOllivier Robert 
662b15cb3dSCy Schubert /**
672b15cb3dSCy Schubert  * Load the contents of a text file.  There are two separate implementations,
682b15cb3dSCy Schubert  * depending up on whether mmap(3) is available.
692b15cb3dSCy Schubert  *
702b15cb3dSCy Schubert  *  If not available, malloc the file length plus one byte.  Read it in
712b15cb3dSCy Schubert  *  and NUL terminate.
722b15cb3dSCy Schubert  *
732b15cb3dSCy Schubert  *  If available, first check to see if the text file size is a multiple of a
742b15cb3dSCy Schubert  *  page size.  If it is, map the file size plus an extra page from either
752b15cb3dSCy Schubert  *  anonymous memory or from /dev/zero.  Then map the file text on top of the
762b15cb3dSCy Schubert  *  first pages of the anonymous/zero pages.  Otherwise, just map the file
772b15cb3dSCy Schubert  *  because there will be NUL bytes provided at the end.
782b15cb3dSCy Schubert  *
792b15cb3dSCy Schubert  * @param mapinfo a structure holding everything we need to know
802b15cb3dSCy Schubert  *        about the mapping.
812b15cb3dSCy Schubert  *
822b15cb3dSCy Schubert  * @param pzFile name of the file, for error reporting.
832b15cb3dSCy Schubert  */
842b15cb3dSCy Schubert static void
load_text_file(tmap_info_t * mapinfo,char const * pzFile)852b15cb3dSCy Schubert load_text_file(tmap_info_t * mapinfo, char const * pzFile)
862b15cb3dSCy Schubert {
872b15cb3dSCy Schubert #if ! defined(HAVE_MMAP)
882b15cb3dSCy Schubert     mapinfo->txt_data = AGALOC(mapinfo->txt_size+1, "file text");
892b15cb3dSCy Schubert     if (mapinfo->txt_data == NULL) {
902b15cb3dSCy Schubert         mapinfo->txt_errno = ENOMEM;
912b15cb3dSCy Schubert         return;
922b15cb3dSCy Schubert     }
932b15cb3dSCy Schubert 
942b15cb3dSCy Schubert     {
952b15cb3dSCy Schubert         size_t sz = mapinfo->txt_size;
962b15cb3dSCy Schubert         char * pz = mapinfo->txt_data;
972b15cb3dSCy Schubert 
982b15cb3dSCy Schubert         while (sz > 0) {
992b15cb3dSCy Schubert             ssize_t rdct = read(mapinfo->txt_fd, pz, sz);
1002b15cb3dSCy Schubert             if (rdct <= 0) {
1012b15cb3dSCy Schubert                 mapinfo->txt_errno = errno;
1022b15cb3dSCy Schubert                 fserr_warn("libopts", "read", pzFile);
1032b15cb3dSCy Schubert                 free(mapinfo->txt_data);
1042b15cb3dSCy Schubert                 return;
1052b15cb3dSCy Schubert             }
1062b15cb3dSCy Schubert 
1072b15cb3dSCy Schubert             pz += rdct;
1082b15cb3dSCy Schubert             sz -= rdct;
1092b15cb3dSCy Schubert         }
1102b15cb3dSCy Schubert 
1112b15cb3dSCy Schubert         *pz = NUL;
1122b15cb3dSCy Schubert     }
1132b15cb3dSCy Schubert 
1142b15cb3dSCy Schubert     mapinfo->txt_errno   = 0;
1152b15cb3dSCy Schubert 
1162b15cb3dSCy Schubert #else /* HAVE mmap */
1172b15cb3dSCy Schubert     size_t const pgsz = (size_t)GETPAGESIZE();
1182b15cb3dSCy Schubert     void * map_addr   = NULL;
1192b15cb3dSCy Schubert 
1202b15cb3dSCy Schubert     (void)pzFile;
1212b15cb3dSCy Schubert 
1222b15cb3dSCy Schubert     mapinfo->txt_full_size = (mapinfo->txt_size + pgsz) & ~(pgsz - 1);
1232b15cb3dSCy Schubert     if (mapinfo->txt_full_size == (mapinfo->txt_size + pgsz)) {
1242b15cb3dSCy Schubert         /*
1252b15cb3dSCy Schubert          * The text is a multiple of a page boundary.  We must map an
1262b15cb3dSCy Schubert          * extra page so the text ends with a NUL.
1272b15cb3dSCy Schubert          */
1282b15cb3dSCy Schubert #if defined(MAP_ANONYMOUS)
1292b15cb3dSCy Schubert         map_addr = mmap(NULL, mapinfo->txt_full_size, PROT_READ|PROT_WRITE,
1302b15cb3dSCy Schubert                         MAP_ANONYMOUS|MAP_PRIVATE, AO_INVALID_FD, 0);
1312b15cb3dSCy Schubert #else
1322b15cb3dSCy Schubert         mapinfo->txt_zero_fd = open("/dev/zero", O_RDONLY);
1332b15cb3dSCy Schubert 
1342b15cb3dSCy Schubert         if (mapinfo->txt_zero_fd == AO_INVALID_FD) {
1352b15cb3dSCy Schubert             mapinfo->txt_errno = errno;
1362b15cb3dSCy Schubert             return;
1372b15cb3dSCy Schubert         }
1382b15cb3dSCy Schubert         map_addr = mmap(NULL, mapinfo->txt_full_size, PROT_READ|PROT_WRITE,
1392b15cb3dSCy Schubert                         MAP_PRIVATE, mapinfo->txt_zero_fd, 0);
1402b15cb3dSCy Schubert #endif
1412b15cb3dSCy Schubert         if (map_addr == MAP_FAILED_PTR) {
1422b15cb3dSCy Schubert             mapinfo->txt_errno = errno;
1432b15cb3dSCy Schubert             return;
1442b15cb3dSCy Schubert         }
1452b15cb3dSCy Schubert         mapinfo->txt_flags |= MAP_FIXED;
1462b15cb3dSCy Schubert     }
1472b15cb3dSCy Schubert 
1482b15cb3dSCy Schubert     mapinfo->txt_data =
1492b15cb3dSCy Schubert         mmap(map_addr, mapinfo->txt_size, mapinfo->txt_prot,
1502b15cb3dSCy Schubert              mapinfo->txt_flags, mapinfo->txt_fd, 0);
1512b15cb3dSCy Schubert 
1522b15cb3dSCy Schubert     if (mapinfo->txt_data == MAP_FAILED_PTR)
1532b15cb3dSCy Schubert         mapinfo->txt_errno = errno;
1542b15cb3dSCy Schubert #endif /* HAVE_MMAP */
1552b15cb3dSCy Schubert }
1562b15cb3dSCy Schubert 
1572b15cb3dSCy Schubert /**
1582b15cb3dSCy Schubert  * Make sure all the parameters are correct:  we have a file name that
1592b15cb3dSCy Schubert  * is a text file that we can read.
1602b15cb3dSCy Schubert  *
1612b15cb3dSCy Schubert  * @param fname the text file to map
1622b15cb3dSCy Schubert  * @param prot  the memory protections requested (read/write/etc.)
1632b15cb3dSCy Schubert  * @param flags mmap flags
1642b15cb3dSCy Schubert  * @param mapinfo a structure holding everything we need to know
1652b15cb3dSCy Schubert  *        about the mapping.
1662b15cb3dSCy Schubert  */
1672b15cb3dSCy Schubert static void
validate_mmap(char const * fname,int prot,int flags,tmap_info_t * mapinfo)1682b15cb3dSCy Schubert validate_mmap(char const * fname, int prot, int flags, tmap_info_t * mapinfo)
1692b15cb3dSCy Schubert {
1702b15cb3dSCy Schubert     memset(mapinfo, 0, sizeof(*mapinfo));
1712b15cb3dSCy Schubert #if defined(HAVE_MMAP) && ! defined(MAP_ANONYMOUS)
1722b15cb3dSCy Schubert     mapinfo->txt_zero_fd = AO_INVALID_FD;
1732b15cb3dSCy Schubert #endif
1742b15cb3dSCy Schubert     mapinfo->txt_fd      = AO_INVALID_FD;
1752b15cb3dSCy Schubert     mapinfo->txt_prot    = prot;
1762b15cb3dSCy Schubert     mapinfo->txt_flags   = flags;
1772b15cb3dSCy Schubert 
1782b15cb3dSCy Schubert     /*
1792b15cb3dSCy Schubert      *  Map mmap flags and protections into open flags and do the open.
1802b15cb3dSCy Schubert      */
1812b15cb3dSCy Schubert     {
1822b15cb3dSCy Schubert         /*
1832b15cb3dSCy Schubert          *  See if we will be updating the file.  If we can alter the memory
1842b15cb3dSCy Schubert          *  and if we share the data and we are *not* copy-on-writing the data,
1852b15cb3dSCy Schubert          *  then our updates will show in the file, so we must open with
1862b15cb3dSCy Schubert          *  write access.
1872b15cb3dSCy Schubert          */
188*a466cc55SCy Schubert         int o_flag =
189*a466cc55SCy Schubert #ifdef _WIN32
190*a466cc55SCy Schubert             _O_BINARY |
191*a466cc55SCy Schubert #endif
192*a466cc55SCy Schubert             FILE_WRITABLE(prot, flags) ? O_RDWR : O_RDONLY;
1932b15cb3dSCy Schubert 
1942b15cb3dSCy Schubert         /*
1952b15cb3dSCy Schubert          *  If you're not sharing the file and you are writing to it,
1962b15cb3dSCy Schubert          *  then don't let anyone else have access to the file.
1972b15cb3dSCy Schubert          */
1982b15cb3dSCy Schubert         if (((flags & MAP_SHARED) == 0) && (prot & PROT_WRITE))
1992b15cb3dSCy Schubert             o_flag |= O_EXCL;
2002b15cb3dSCy Schubert 
2012b15cb3dSCy Schubert         mapinfo->txt_fd = open(fname, o_flag);
2022b15cb3dSCy Schubert         if (mapinfo->txt_fd < 0) {
2032b15cb3dSCy Schubert             mapinfo->txt_errno = errno;
2042b15cb3dSCy Schubert             mapinfo->txt_fd = AO_INVALID_FD;
2052b15cb3dSCy Schubert             return;
2062b15cb3dSCy Schubert         }
2072b15cb3dSCy Schubert     }
2082b15cb3dSCy Schubert 
2092b15cb3dSCy Schubert     /*
2102b15cb3dSCy Schubert      *  Make sure we can stat the regular file.  Save the file size.
2112b15cb3dSCy Schubert      */
2122b15cb3dSCy Schubert     {
2132b15cb3dSCy Schubert         struct stat sb;
2142b15cb3dSCy Schubert         if (fstat(mapinfo->txt_fd, &sb) != 0) {
2152b15cb3dSCy Schubert             mapinfo->txt_errno = errno;
2162b15cb3dSCy Schubert             close(mapinfo->txt_fd);
2172b15cb3dSCy Schubert             return;
2182b15cb3dSCy Schubert         }
2192b15cb3dSCy Schubert 
2202b15cb3dSCy Schubert         if (! S_ISREG(sb.st_mode)) {
2212b15cb3dSCy Schubert             mapinfo->txt_errno = errno = EINVAL;
2222b15cb3dSCy Schubert             close(mapinfo->txt_fd);
2232b15cb3dSCy Schubert             return;
2242b15cb3dSCy Schubert         }
2252b15cb3dSCy Schubert 
2262b15cb3dSCy Schubert         mapinfo->txt_size = (size_t)sb.st_size;
2272b15cb3dSCy Schubert     }
2282b15cb3dSCy Schubert 
2292b15cb3dSCy Schubert     if (mapinfo->txt_fd == AO_INVALID_FD)
2302b15cb3dSCy Schubert         mapinfo->txt_errno = errno;
2312b15cb3dSCy Schubert }
2322b15cb3dSCy Schubert 
2332b15cb3dSCy Schubert /**
2342b15cb3dSCy Schubert  * Close any files opened by the mapping.
2352b15cb3dSCy Schubert  *
2362b15cb3dSCy Schubert  * @param mi a structure holding everything we need to know about the map.
2372b15cb3dSCy Schubert  */
2382b15cb3dSCy Schubert static void
close_mmap_files(tmap_info_t * mi)2392b15cb3dSCy Schubert close_mmap_files(tmap_info_t * mi)
2402b15cb3dSCy Schubert {
2412b15cb3dSCy Schubert     if (mi->txt_fd == AO_INVALID_FD)
2422b15cb3dSCy Schubert         return;
2432b15cb3dSCy Schubert 
2442b15cb3dSCy Schubert     close(mi->txt_fd);
2452b15cb3dSCy Schubert     mi->txt_fd = AO_INVALID_FD;
2462b15cb3dSCy Schubert 
2472b15cb3dSCy Schubert #if defined(HAVE_MMAP) && ! defined(MAP_ANONYMOUS)
2482b15cb3dSCy Schubert     if (mi->txt_zero_fd == AO_INVALID_FD)
2492b15cb3dSCy Schubert         return;
2502b15cb3dSCy Schubert 
2512b15cb3dSCy Schubert     close(mi->txt_zero_fd);
2522b15cb3dSCy Schubert     mi->txt_zero_fd = AO_INVALID_FD;
2532b15cb3dSCy Schubert #endif
2542b15cb3dSCy Schubert }
2552b15cb3dSCy Schubert 
256ea906c41SOllivier Robert /*=export_func  text_mmap
257ea906c41SOllivier Robert  * private:
258ea906c41SOllivier Robert  *
259ea906c41SOllivier Robert  * what:  map a text file with terminating NUL
260ea906c41SOllivier Robert  *
261ea906c41SOllivier Robert  * arg:   char const *,  pzFile,  name of the file to map
262ea906c41SOllivier Robert  * arg:   int,           prot,    mmap protections (see mmap(2))
263ea906c41SOllivier Robert  * arg:   int,           flags,   mmap flags (see mmap(2))
264ea906c41SOllivier Robert  * arg:   tmap_info_t *, mapinfo, returned info about the mapping
265ea906c41SOllivier Robert  *
266ea906c41SOllivier Robert  * ret-type:   void *
267ea906c41SOllivier Robert  * ret-desc:   The mmaped data address
268ea906c41SOllivier Robert  *
269ea906c41SOllivier Robert  * doc:
270ea906c41SOllivier Robert  *
271ea906c41SOllivier Robert  * This routine will mmap a file into memory ensuring that there is at least
272ea906c41SOllivier Robert  * one @file{NUL} character following the file data.  It will return the
273ea906c41SOllivier Robert  * address where the file contents have been mapped into memory.  If there is a
2742b15cb3dSCy Schubert  * problem, then it will return @code{MAP_FAILED} and set @code{errno}
275ea906c41SOllivier Robert  * appropriately.
276ea906c41SOllivier Robert  *
2772b15cb3dSCy Schubert  * The named file does not exist, @code{stat(2)} will set @code{errno} as it
2782b15cb3dSCy Schubert  * will.  If the file is not a regular file, @code{errno} will be
279ea906c41SOllivier Robert  * @code{EINVAL}.  At that point, @code{open(2)} is attempted with the access
280ea906c41SOllivier Robert  * bits set appropriately for the requested @code{mmap(2)} protections and flag
2812b15cb3dSCy Schubert  * bits.  On failure, @code{errno} will be set according to the documentation
2822b15cb3dSCy Schubert  * for @code{open(2)}.  If @code{mmap(2)} fails, @code{errno} will be set as
283ea906c41SOllivier Robert  * that routine sets it.  If @code{text_mmap} works to this point, a valid
284ea906c41SOllivier Robert  * address will be returned, but there may still be ``issues''.
285ea906c41SOllivier Robert  *
286ea906c41SOllivier Robert  * If the file size is not an even multiple of the system page size, then
2872b15cb3dSCy Schubert  * @code{text_map} will return at this point and @code{errno} will be zero.
288ea906c41SOllivier Robert  * Otherwise, an anonymous map is attempted.  If not available, then an attempt
289ea906c41SOllivier Robert  * is made to @code{mmap(2)} @file{/dev/zero}.  If any of these fail, the
290ea906c41SOllivier Robert  * address of the file's data is returned, bug @code{no} @file{NUL} characters
291ea906c41SOllivier Robert  * are mapped after the end of the data.
292ea906c41SOllivier Robert  *
293ea906c41SOllivier Robert  * see: mmap(2), open(2), stat(2)
294ea906c41SOllivier Robert  *
295ea906c41SOllivier Robert  * err: Any error code issued by mmap(2), open(2), stat(2) is possible.
296ea906c41SOllivier Robert  *      Additionally, if the specified file is not a regular file, then
297ea906c41SOllivier Robert  *      errno will be set to @code{EINVAL}.
298ea906c41SOllivier Robert  *
299ea906c41SOllivier Robert  * example:
300ea906c41SOllivier Robert  * #include <mylib.h>
301ea906c41SOllivier Robert  * tmap_info_t mi;
302ea906c41SOllivier Robert  * int no_nul;
303ea906c41SOllivier Robert  * void * data = text_mmap("file", PROT_WRITE, MAP_PRIVATE, &mi);
304ea906c41SOllivier Robert  * if (data == MAP_FAILED) return;
305ea906c41SOllivier Robert  * no_nul = (mi.txt_size == mi.txt_full_size);
306ea906c41SOllivier Robert  * << use the data >>
307ea906c41SOllivier Robert  * text_munmap(&mi);
308ea906c41SOllivier Robert =*/
309ea906c41SOllivier Robert void *
text_mmap(char const * pzFile,int prot,int flags,tmap_info_t * mi)3102b15cb3dSCy Schubert text_mmap(char const * pzFile, int prot, int flags, tmap_info_t * mi)
311ea906c41SOllivier Robert {
3122b15cb3dSCy Schubert     validate_mmap(pzFile, prot, flags, mi);
3132b15cb3dSCy Schubert     if (mi->txt_errno != 0)
314ea906c41SOllivier Robert         return MAP_FAILED_PTR;
315ea906c41SOllivier Robert 
3162b15cb3dSCy Schubert     load_text_file(mi, pzFile);
317ea906c41SOllivier Robert 
3182b15cb3dSCy Schubert     if (mi->txt_errno == 0)
3192b15cb3dSCy Schubert         return mi->txt_data;
320ea906c41SOllivier Robert 
3212b15cb3dSCy Schubert     close_mmap_files(mi);
322ea906c41SOllivier Robert 
3232b15cb3dSCy Schubert     errno = mi->txt_errno;
3242b15cb3dSCy Schubert     mi->txt_data = MAP_FAILED_PTR;
3252b15cb3dSCy Schubert     return mi->txt_data;
326ea906c41SOllivier Robert }
327ea906c41SOllivier Robert 
328ea906c41SOllivier Robert 
329ea906c41SOllivier Robert /*=export_func  text_munmap
330ea906c41SOllivier Robert  * private:
331ea906c41SOllivier Robert  *
332ea906c41SOllivier Robert  * what:  unmap the data mapped in by text_mmap
333ea906c41SOllivier Robert  *
334ea906c41SOllivier Robert  * arg:   tmap_info_t *, mapinfo, info about the mapping
335ea906c41SOllivier Robert  *
336ea906c41SOllivier Robert  * ret-type:   int
3372b15cb3dSCy Schubert  * ret-desc:   -1 or 0.  @code{errno} will have the error code.
338ea906c41SOllivier Robert  *
339ea906c41SOllivier Robert  * doc:
340ea906c41SOllivier Robert  *
341ea906c41SOllivier Robert  * This routine will unmap the data mapped in with @code{text_mmap} and close
342ea906c41SOllivier Robert  * the associated file descriptors opened by that function.
343ea906c41SOllivier Robert  *
344ea906c41SOllivier Robert  * see: munmap(2), close(2)
345ea906c41SOllivier Robert  *
346ea906c41SOllivier Robert  * err: Any error code issued by munmap(2) or close(2) is possible.
347ea906c41SOllivier Robert =*/
348ea906c41SOllivier Robert int
text_munmap(tmap_info_t * mi)3492b15cb3dSCy Schubert text_munmap(tmap_info_t * mi)
350ea906c41SOllivier Robert {
3512b15cb3dSCy Schubert     errno = 0;
3522b15cb3dSCy Schubert 
353ea906c41SOllivier Robert #ifdef HAVE_MMAP
3542b15cb3dSCy Schubert     (void)munmap(mi->txt_data, mi->txt_full_size);
355ea906c41SOllivier Robert 
356*a466cc55SCy Schubert #else // don't HAVE_MMAP
357ea906c41SOllivier Robert     /*
358ea906c41SOllivier Robert      *  IF the memory is writable *AND* it is not private (copy-on-write)
359ea906c41SOllivier Robert      *     *AND* the memory is "sharable" (seen by other processes)
3602b15cb3dSCy Schubert      *  THEN rewrite the data.  Emulate mmap visibility.
361ea906c41SOllivier Robert      */
3622b15cb3dSCy Schubert     if (  FILE_WRITABLE(mi->txt_prot, mi->txt_flags)
363*a466cc55SCy Schubert        && (lseek(mi->txt_fd, 0, SEEK_SET) >= 0) )
3642b15cb3dSCy Schubert         write(mi->txt_fd, mi->txt_data, mi->txt_size);
365ea906c41SOllivier Robert 
3662b15cb3dSCy Schubert     free(mi->txt_data);
367ea906c41SOllivier Robert #endif /* HAVE_MMAP */
3682b15cb3dSCy Schubert 
3692b15cb3dSCy Schubert     mi->txt_errno = errno;
3702b15cb3dSCy Schubert     close_mmap_files(mi);
3712b15cb3dSCy Schubert 
3722b15cb3dSCy Schubert     return mi->txt_errno;
373ea906c41SOllivier Robert }
374ea906c41SOllivier Robert 
3752b15cb3dSCy Schubert /** @}
3762b15cb3dSCy Schubert  *
377ea906c41SOllivier Robert  * Local Variables:
378ea906c41SOllivier Robert  * mode: C
379ea906c41SOllivier Robert  * c-file-style: "stroustrup"
380ea906c41SOllivier Robert  * indent-tabs-mode: nil
381ea906c41SOllivier Robert  * End:
382ea906c41SOllivier Robert  * end of autoopts/text_mmap.c */
383