1 /* CTF archive files.
2    Copyright (C) 2019-2020 Free Software Foundation, Inc.
3 
4    This file is part of libctf.
5 
6    libctf is free software; you can redistribute it and/or modify it under
7    the terms of the GNU General Public License as published by the Free
8    Software Foundation; either version 3, or (at your option) any later
9    version.
10 
11    This program is distributed in the hope that it will be useful, but
12    WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14    See the GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program; see the file COPYING.  If not see
18    <http://www.gnu.org/licenses/>.  */
19 
20 #include <ctf-impl.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <elf.h>
24 #include "ctf-endian.h"
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <unistd.h>
30 
31 #ifdef HAVE_MMAP
32 #include <sys/mman.h>
33 #endif
34 
35 static off_t arc_write_one_ctf (ctf_file_t * f, int fd, size_t threshold);
36 static ctf_file_t *ctf_arc_open_by_offset (const struct ctf_archive *arc,
37 					   const ctf_sect_t *symsect,
38 					   const ctf_sect_t *strsect,
39 					   size_t offset, int *errp);
40 static int sort_modent_by_name (const void *one, const void *two, void *n);
41 static void *arc_mmap_header (int fd, size_t headersz);
42 static void *arc_mmap_file (int fd, size_t size);
43 static int arc_mmap_writeout (int fd, void *header, size_t headersz,
44 			      const char **errmsg);
45 static int arc_mmap_unmap (void *header, size_t headersz, const char **errmsg);
46 
47 /* bsearch() internal state.  */
48 static __thread char *search_nametbl;
49 
50 /* Write out a CTF archive to the start of the file referenced by the passed-in
51    fd.  The entries in CTF_FILES are referenced by name: the names are passed in
52    the names array, which must have CTF_FILES entries.
53 
54    Returns 0 on success, or an errno, or an ECTF_* value.  */
55 int
56 ctf_arc_write_fd (int fd, ctf_file_t **ctf_files, size_t ctf_file_cnt,
57 		  const char **names, size_t threshold)
58 {
59   const char *errmsg;
60   struct ctf_archive *archdr;
61   size_t i;
62   char dummy = 0;
63   size_t headersz;
64   ssize_t namesz;
65   size_t ctf_startoffs;		/* Start of the section we are working over.  */
66   char *nametbl = NULL;		/* The name table.  */
67   char *np;
68   off_t nameoffs;
69   struct ctf_archive_modent *modent;
70 
71   ctf_dprintf ("Writing CTF archive with %lu files\n",
72 	       (unsigned long) ctf_file_cnt);
73 
74   /* Figure out the size of the mmap()ed header, including the
75      ctf_archive_modent array.  We assume that all of this needs no
76      padding: a likely assumption, given that it's all made up of
77      uint64_t's.  */
78   headersz = sizeof (struct ctf_archive)
79     + (ctf_file_cnt * sizeof (uint64_t) * 2);
80   ctf_dprintf ("headersz is %lu\n", (unsigned long) headersz);
81 
82   /* From now on we work in two pieces: an mmap()ed region from zero up to the
83      headersz, and a region updated via write() starting after that, containing
84      all the tables.  Platforms that do not support mmap() just use write().  */
85   ctf_startoffs = headersz;
86   if (lseek (fd, ctf_startoffs - 1, SEEK_SET) < 0)
87     {
88       errmsg = "ctf_arc_write(): cannot extend file while writing: %s\n";
89       goto err;
90     }
91 
92   if (write (fd, &dummy, 1) < 0)
93     {
94       errmsg = "ctf_arc_write(): cannot extend file while writing: %s\n";
95       goto err;
96     }
97 
98   if ((archdr = arc_mmap_header (fd, headersz)) == NULL)
99     {
100       errmsg = "ctf_arc_write(): Cannot mmap(): %s\n";
101       goto err;
102     }
103 
104   /* Fill in everything we can, which is everything other than the name
105      table offset.  */
106   archdr->ctfa_magic = htole64 (CTFA_MAGIC);
107   archdr->ctfa_nfiles = htole64 (ctf_file_cnt);
108   archdr->ctfa_ctfs = htole64 (ctf_startoffs);
109 
110   /* We could validate that all CTF files have the same data model, but
111      since any reasonable construction process will be building things of
112      only one bitness anyway, this is pretty pointless, so just use the
113      model of the first CTF file for all of them.  (It *is* valid to
114      create an empty archive: the value of ctfa_model is irrelevant in
115      this case, but we must be sure not to dereference uninitialized
116      memory.)  */
117 
118   if (ctf_file_cnt > 0)
119     archdr->ctfa_model = htole64 (ctf_getmodel (ctf_files[0]));
120 
121   /* Now write out the CTFs: ctf_archive_modent array via the mapping,
122      ctfs via write().  The names themselves have not been written yet: we
123      track them in a local strtab until the time is right, and sort the
124      modents array after construction.
125 
126     The name table is not sorted.  */
127 
128   for (i = 0, namesz = 0; i < le64toh (archdr->ctfa_nfiles); i++)
129     namesz += strlen (names[i]) + 1;
130 
131   nametbl = malloc (namesz);
132   if (nametbl == NULL)
133     {
134       errmsg = "Error writing named CTF to archive: %s\n";
135       goto err_unmap;
136     }
137 
138   for (i = 0, namesz = 0,
139        modent = (ctf_archive_modent_t *) ((char *) archdr
140 					  + sizeof (struct ctf_archive));
141        i < le64toh (archdr->ctfa_nfiles); i++)
142     {
143       off_t off;
144 
145       strcpy (&nametbl[namesz], names[i]);
146 
147       off = arc_write_one_ctf (ctf_files[i], fd, threshold);
148       if ((off < 0) && (off > -ECTF_BASE))
149 	{
150 	  errmsg = "ctf_arc_write(): Cannot determine file "
151 	    "position while writing to archive: %s";
152 	  goto err_free;
153 	}
154       if (off < 0)
155 	{
156 	  errmsg = "ctf_arc_write(): Cannot write CTF file to archive: %s\n";
157 	  errno = off * -1;
158 	  goto err_free;
159 	}
160 
161       modent->name_offset = htole64 (namesz);
162       modent->ctf_offset = htole64 (off - ctf_startoffs);
163       namesz += strlen (names[i]) + 1;
164       modent++;
165     }
166 
167   ctf_qsort_r ((ctf_archive_modent_t *) ((char *) archdr
168 					 + sizeof (struct ctf_archive)),
169 	       le64toh (archdr->ctfa_nfiles),
170 	       sizeof (struct ctf_archive_modent), sort_modent_by_name,
171 	       nametbl);
172 
173    /* Now the name table.  */
174 
175   if ((nameoffs = lseek (fd, 0, SEEK_CUR)) < 0)
176     {
177       errmsg = "ctf_arc_write(): Cannot get current file position "
178 	"in archive: %s\n";
179       goto err_free;
180     }
181   archdr->ctfa_names = htole64 (nameoffs);
182   np = nametbl;
183   while (namesz > 0)
184     {
185       ssize_t len;
186       if ((len = write (fd, np, namesz)) < 0)
187 	{
188 	  errmsg = "ctf_arc_write(): Cannot write name table to archive: %s\n";
189 	  goto err_free;
190 	}
191       namesz -= len;
192       np += len;
193     }
194   free (nametbl);
195 
196   if (arc_mmap_writeout (fd, archdr, headersz, &errmsg) < 0)
197     goto err_unmap;
198   if (arc_mmap_unmap (archdr, headersz, &errmsg) < 0)
199     goto err;
200   return 0;
201 
202 err_free:
203   free (nametbl);
204 err_unmap:
205   arc_mmap_unmap (archdr, headersz, NULL);
206 err:
207   ctf_dprintf (errmsg, errno < ECTF_BASE ? strerror (errno) :
208 	       ctf_errmsg (errno));
209   return errno;
210 }
211 
212 /* Write out a CTF archive.  The entries in CTF_FILES are referenced by name:
213    the names are passed in the names array, which must have CTF_FILES entries.
214 
215    If the filename is NULL, create a temporary file and return a pointer to it.
216 
217    Returns 0 on success, or an errno, or an ECTF_* value.  */
218 int
219 ctf_arc_write (const char *file, ctf_file_t ** ctf_files, size_t ctf_file_cnt,
220 	       const char **names, size_t threshold)
221 {
222   int err;
223   int fd;
224 
225   if ((fd = open (file, O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0666)) < 0)
226     {
227       ctf_dprintf ("ctf_arc_write(): cannot create %s: %s\n", file,
228 		   strerror (errno));
229       return errno;
230     }
231 
232   err = ctf_arc_write_fd (fd, ctf_files, ctf_file_cnt, names, threshold);
233   if (err)
234     goto err;
235 
236   if ((err = close (fd)) < 0)
237     {
238       ctf_dprintf ("ctf_arc_write(): Cannot close after writing to archive: "
239 		   "%s\n", strerror (errno));
240       goto err_close;
241     }
242 
243  err:
244   close (fd);
245   if (err < 0)
246     unlink (file);
247 
248   return err;
249 
250  err_close:
251   if (err < 0)
252     unlink (file);
253 
254   return err;
255 }
256 
257 /* Write one CTF file out.  Return the file position of the written file (or
258    rather, of the file-size uint64_t that precedes it): negative return is a
259    negative errno or ctf_errno value.  On error, the file position may no longer
260    be at the end of the file.  */
261 static off_t
262 arc_write_one_ctf (ctf_file_t * f, int fd, size_t threshold)
263 {
264   off_t off, end_off;
265   uint64_t ctfsz = 0;
266   char *ctfszp;
267   size_t ctfsz_len;
268   int (*writefn) (ctf_file_t * fp, int fd);
269 
270   if (ctf_serialize (f) < 0)
271     return f->ctf_errno * -1;
272 
273   if ((off = lseek (fd, 0, SEEK_CUR)) < 0)
274     return errno * -1;
275 
276   if (f->ctf_size > threshold)
277     writefn = ctf_compress_write;
278   else
279     writefn = ctf_write;
280 
281   /* This zero-write turns into the size in a moment. */
282   ctfsz_len = sizeof (ctfsz);
283   ctfszp = (char *) &ctfsz;
284   while (ctfsz_len > 0)
285     {
286       ssize_t writelen = write (fd, ctfszp, ctfsz_len);
287       if (writelen < 0)
288 	return errno * -1;
289       ctfsz_len -= writelen;
290       ctfszp += writelen;
291     }
292 
293   if (writefn (f, fd) != 0)
294     return f->ctf_errno * -1;
295 
296   if ((end_off = lseek (fd, 0, SEEK_CUR)) < 0)
297     return errno * -1;
298   ctfsz = htole64 (end_off - off);
299 
300   if ((lseek (fd, off, SEEK_SET)) < 0)
301     return errno * -1;
302 
303   /* ... here.  */
304   ctfsz_len = sizeof (ctfsz);
305   ctfszp = (char *) &ctfsz;
306   while (ctfsz_len > 0)
307     {
308       ssize_t writelen = write (fd, ctfszp, ctfsz_len);
309       if (writelen < 0)
310 	return errno * -1;
311       ctfsz_len -= writelen;
312       ctfszp += writelen;
313     }
314 
315   end_off = LCTF_ALIGN_OFFS (end_off, 8);
316   if ((lseek (fd, end_off, SEEK_SET)) < 0)
317     return errno * -1;
318 
319   return off;
320 }
321 
322 /* qsort() function to sort the array of struct ctf_archive_modents into
323    ascending name order.  */
324 static int
325 sort_modent_by_name (const void *one, const void *two, void *n)
326 {
327   const struct ctf_archive_modent *a = one;
328   const struct ctf_archive_modent *b = two;
329   char *nametbl = n;
330 
331   return strcmp (&nametbl[le64toh (a->name_offset)],
332 		 &nametbl[le64toh (b->name_offset)]);
333 }
334 
335 /* bsearch() function to search for a given name in the sorted array of struct
336    ctf_archive_modents.  */
337 static int
338 search_modent_by_name (const void *key, const void *ent)
339 {
340   const char *k = key;
341   const struct ctf_archive_modent *v = ent;
342 
343   return strcmp (k, &search_nametbl[le64toh (v->name_offset)]);
344 }
345 
346 /* A trivial wrapper: open a CTF archive, from data in a buffer (which the
347    caller must preserve until ctf_arc_close() time).  Returns the archive, or
348    NULL and an error in *err (if not NULL).  */
349 struct ctf_archive *
350 ctf_arc_bufopen (const void *buf, size_t size _libctf_unused_, int *errp)
351 {
352   struct ctf_archive *arc = (struct ctf_archive *) buf;
353 
354   if (le64toh (arc->ctfa_magic) != CTFA_MAGIC)
355     {
356       if (errp)
357 	*errp = ECTF_FMT;
358       return NULL;
359     }
360   return arc;
361 }
362 
363 /* Open a CTF archive.  Returns the archive, or NULL and an error in *err (if
364    not NULL).  */
365 struct ctf_archive *
366 ctf_arc_open_internal (const char *filename, int *errp)
367 {
368   const char *errmsg;
369   int fd;
370   struct stat s;
371   struct ctf_archive *arc;		/* (Actually the whole file.)  */
372 
373   libctf_init_debug();
374   if ((fd = open (filename, O_RDONLY)) < 0)
375     {
376       errmsg = "ctf_arc_open(): cannot open %s: %s\n";
377       goto err;
378     }
379   if (fstat (fd, &s) < 0)
380     {
381       errmsg = "ctf_arc_open(): cannot stat %s: %s\n";
382       goto err_close;
383     }
384 
385   if ((arc = arc_mmap_file (fd, s.st_size)) == NULL)
386     {
387       errmsg = "ctf_arc_open(): Cannot read in %s: %s\n";
388       goto err_close;
389     }
390 
391   if (le64toh (arc->ctfa_magic) != CTFA_MAGIC)
392     {
393       errmsg = "ctf_arc_open(): Invalid magic number";
394       errno = ECTF_FMT;
395       goto err_unmap;
396     }
397 
398   /* This horrible hack lets us know how much to unmap when the file is
399      closed.  (We no longer need the magic number, and the mapping
400      is private.)  */
401   arc->ctfa_magic = s.st_size;
402   close (fd);
403   return arc;
404 
405 err_unmap:
406   arc_mmap_unmap (arc, s.st_size, NULL);
407 err_close:
408   close (fd);
409 err:
410   if (errp)
411     *errp = errno;
412   ctf_dprintf (errmsg, filename, errno < ECTF_BASE ? strerror (errno) :
413 	       ctf_errmsg (errno));
414   return NULL;
415 }
416 
417 /* Close an archive.  */
418 void
419 ctf_arc_close_internal (struct ctf_archive *arc)
420 {
421   if (arc == NULL)
422     return;
423 
424   /* See the comment in ctf_arc_open().  */
425   arc_mmap_unmap (arc, arc->ctfa_magic, NULL);
426 }
427 
428 /* Public entry point: close an archive, or CTF file.  */
429 void
430 ctf_arc_close (ctf_archive_t *arc)
431 {
432   if (arc == NULL)
433     return;
434 
435   if (arc->ctfi_is_archive)
436     ctf_arc_close_internal (arc->ctfi_archive);
437   else
438     ctf_file_close (arc->ctfi_file);
439   free ((void *) arc->ctfi_symsect.cts_data);
440   /* Do not free the ctfi_strsect: it is bound to the bfd.  */
441   free (arc->ctfi_data);
442   if (arc->ctfi_bfd_close)
443     arc->ctfi_bfd_close (arc);
444   free (arc);
445 }
446 
447 /* Return the ctf_file_t with the given name, or NULL if none, setting 'err' if
448    non-NULL.  A name of NULL means to open the default file.  */
449 static ctf_file_t *
450 ctf_arc_open_by_name_internal (const struct ctf_archive *arc,
451 			       const ctf_sect_t *symsect,
452 			       const ctf_sect_t *strsect,
453 			       const char *name, int *errp)
454 {
455   struct ctf_archive_modent *modent;
456 
457   if (name == NULL)
458     name = _CTF_SECTION;		 /* The default name.  */
459 
460   ctf_dprintf ("ctf_arc_open_by_name(%s): opening\n", name);
461 
462   modent = (ctf_archive_modent_t *) ((char *) arc
463 				     + sizeof (struct ctf_archive));
464 
465   search_nametbl = (char *) arc + le64toh (arc->ctfa_names);
466   modent = bsearch (name, modent, le64toh (arc->ctfa_nfiles),
467 		    sizeof (struct ctf_archive_modent),
468 		    search_modent_by_name);
469 
470   /* This is actually a common case and normal operation: no error
471      debug output.  */
472   if (modent == NULL)
473     {
474       if (errp)
475 	*errp = ECTF_ARNNAME;
476       return NULL;
477     }
478 
479   return ctf_arc_open_by_offset (arc, symsect, strsect,
480 				 le64toh (modent->ctf_offset), errp);
481 }
482 
483 /* Return the ctf_file_t with the given name, or NULL if none, setting 'err' if
484    non-NULL.  A name of NULL means to open the default file.
485 
486    Use the specified string and symbol table sections.
487 
488    Public entry point.  */
489 ctf_file_t *
490 ctf_arc_open_by_name_sections (const ctf_archive_t *arc,
491 			       const ctf_sect_t *symsect,
492 			       const ctf_sect_t *strsect,
493 			       const char *name,
494 			       int *errp)
495 {
496   if (arc->ctfi_is_archive)
497     {
498       ctf_file_t *ret;
499       ret = ctf_arc_open_by_name_internal (arc->ctfi_archive, symsect, strsect,
500 					   name, errp);
501       if (ret)
502 	ret->ctf_archive = (ctf_archive_t *) arc;
503       return ret;
504     }
505 
506   if ((name != NULL) && (strcmp (name, _CTF_SECTION) != 0))
507     {
508       if (errp)
509 	*errp = ECTF_ARNNAME;
510       return NULL;
511     }
512   arc->ctfi_file->ctf_archive = (ctf_archive_t *) arc;
513 
514   /* Bump the refcount so that the user can ctf_file_close() it.  */
515   arc->ctfi_file->ctf_refcnt++;
516   return arc->ctfi_file;
517 }
518 
519 /* Return the ctf_file_t with the given name, or NULL if none, setting 'err' if
520    non-NULL.  A name of NULL means to open the default file.
521 
522    Public entry point.  */
523 ctf_file_t *
524 ctf_arc_open_by_name (const ctf_archive_t *arc, const char *name, int *errp)
525 {
526   const ctf_sect_t *symsect = &arc->ctfi_symsect;
527   const ctf_sect_t *strsect = &arc->ctfi_strsect;
528 
529   if (symsect->cts_name == NULL)
530     symsect = NULL;
531   if (strsect->cts_name == NULL)
532     strsect = NULL;
533 
534   return ctf_arc_open_by_name_sections (arc, symsect, strsect, name, errp);
535 }
536 
537 /* Return the ctf_file_t at the given ctfa_ctfs-relative offset, or NULL if
538    none, setting 'err' if non-NULL.  */
539 static ctf_file_t *
540 ctf_arc_open_by_offset (const struct ctf_archive *arc,
541 			const ctf_sect_t *symsect,
542 			const ctf_sect_t *strsect, size_t offset,
543 			int *errp)
544 {
545   ctf_sect_t ctfsect;
546   ctf_file_t *fp;
547 
548   ctf_dprintf ("ctf_arc_open_by_offset(%lu): opening\n", (unsigned long) offset);
549 
550   memset (&ctfsect, 0, sizeof (ctf_sect_t));
551 
552   offset += le64toh (arc->ctfa_ctfs);
553 
554   ctfsect.cts_name = _CTF_SECTION;
555   ctfsect.cts_size = le64toh (*((uint64_t *) ((char *) arc + offset)));
556   ctfsect.cts_entsize = 1;
557   ctfsect.cts_data = (void *) ((char *) arc + offset + sizeof (uint64_t));
558   fp = ctf_bufopen (&ctfsect, symsect, strsect, errp);
559   if (fp)
560     ctf_setmodel (fp, le64toh (arc->ctfa_model));
561   return fp;
562 }
563 
564 /* Raw iteration over all CTF files in an archive.  We pass the raw data for all
565    CTF files in turn to the specified callback function.  */
566 static int
567 ctf_archive_raw_iter_internal (const struct ctf_archive *arc,
568 			       ctf_archive_raw_member_f *func, void *data)
569 {
570   int rc;
571   size_t i;
572   struct ctf_archive_modent *modent;
573   const char *nametbl;
574 
575   modent = (ctf_archive_modent_t *) ((char *) arc
576 				     + sizeof (struct ctf_archive));
577   nametbl = (((const char *) arc) + le64toh (arc->ctfa_names));
578 
579   for (i = 0; i < le64toh (arc->ctfa_nfiles); i++)
580     {
581       const char *name;
582       char *fp;
583 
584       name = &nametbl[le64toh (modent[i].name_offset)];
585       fp = ((char *) arc + le64toh (arc->ctfa_ctfs)
586 	    + le64toh (modent[i].ctf_offset));
587 
588       if ((rc = func (name, (void *) (fp + sizeof (uint64_t)),
589 		      le64toh (*((uint64_t *) fp)), data)) != 0)
590 	return rc;
591     }
592   return 0;
593 }
594 
595 /* Raw iteration over all CTF files in an archive: public entry point.
596 
597    Returns -EINVAL if not supported for this sort of archive.  */
598 int
599 ctf_archive_raw_iter (const ctf_archive_t *arc,
600 		      ctf_archive_raw_member_f * func, void *data)
601 {
602   if (arc->ctfi_is_archive)
603     return ctf_archive_raw_iter_internal (arc->ctfi_archive, func, data);
604 
605   return -EINVAL;			 /* Not supported. */
606 }
607 
608 /* Iterate over all CTF files in an archive.  We pass all CTF files in turn to
609    the specified callback function.  */
610 static int
611 ctf_archive_iter_internal (const ctf_archive_t *wrapper,
612 			   const struct ctf_archive *arc,
613 			   const ctf_sect_t *symsect,
614 			   const ctf_sect_t *strsect,
615 			   ctf_archive_member_f *func, void *data)
616 {
617   int rc;
618   size_t i;
619   ctf_file_t *f;
620   struct ctf_archive_modent *modent;
621   const char *nametbl;
622 
623   modent = (ctf_archive_modent_t *) ((char *) arc
624 				     + sizeof (struct ctf_archive));
625   nametbl = (((const char *) arc) + le64toh (arc->ctfa_names));
626 
627   for (i = 0; i < le64toh (arc->ctfa_nfiles); i++)
628     {
629       const char *name;
630 
631       name = &nametbl[le64toh (modent[i].name_offset)];
632       if ((f = ctf_arc_open_by_name_internal (arc, symsect, strsect,
633 					      name, &rc)) == NULL)
634 	return rc;
635 
636       f->ctf_archive = (ctf_archive_t *) wrapper;
637       if ((rc = func (f, name, data)) != 0)
638 	{
639 	  ctf_file_close (f);
640 	  return rc;
641 	}
642 
643       ctf_file_close (f);
644     }
645   return 0;
646 }
647 
648 /* Iterate over all CTF files in an archive: public entry point.  We pass all
649    CTF files in turn to the specified callback function.  */
650 int
651 ctf_archive_iter (const ctf_archive_t *arc, ctf_archive_member_f *func,
652 		  void *data)
653 {
654   const ctf_sect_t *symsect = &arc->ctfi_symsect;
655   const ctf_sect_t *strsect = &arc->ctfi_strsect;
656 
657   if (symsect->cts_name == NULL)
658     symsect = NULL;
659   if (strsect->cts_name == NULL)
660     strsect = NULL;
661 
662   if (arc->ctfi_is_archive)
663     return ctf_archive_iter_internal (arc, arc->ctfi_archive, symsect, strsect,
664 				      func, data);
665 
666   return func (arc->ctfi_file, _CTF_SECTION, data);
667 }
668 
669 #ifdef HAVE_MMAP
670 /* Map the header in.  Only used on new, empty files.  */
671 static void *arc_mmap_header (int fd, size_t headersz)
672 {
673   void *hdr;
674   if ((hdr = mmap (NULL, headersz, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
675 		   0)) == MAP_FAILED)
676     return NULL;
677   return hdr;
678 }
679 
680 /* mmap() the whole file, for reading only.  (Map it writably, but privately: we
681    need to modify the region, but don't need anyone else to see the
682    modifications.)  */
683 static void *arc_mmap_file (int fd, size_t size)
684 {
685   void *arc;
686   if ((arc = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE,
687 		   fd, 0)) == MAP_FAILED)
688     return NULL;
689   return arc;
690 }
691 
692 /* Persist the header to disk.  */
693 static int arc_mmap_writeout (int fd _libctf_unused_, void *header,
694 			      size_t headersz, const char **errmsg)
695 {
696     if (msync (header, headersz, MS_ASYNC) < 0)
697     {
698       if (errmsg)
699 	*errmsg = "arc_mmap_writeout(): Cannot sync after writing to %s: %s\n";
700       return -1;
701     }
702     return 0;
703 }
704 
705 /* Unmap the region.  */
706 static int arc_mmap_unmap (void *header, size_t headersz, const char **errmsg)
707 {
708   if (munmap (header, headersz) < 0)
709     {
710       if (errmsg)
711 	*errmsg = "arc_mmap_munmap(): Cannot unmap after writing to %s: %s\n";
712       return -1;
713     }
714     return 0;
715 }
716 #else
717 /* Map the header in.  Only used on new, empty files.  */
718 static void *arc_mmap_header (int fd _libctf_unused_, size_t headersz)
719 {
720   void *hdr;
721   if ((hdr = malloc (headersz)) == NULL)
722     return NULL;
723   return hdr;
724 }
725 
726 /* Pull in the whole file, for reading only.  We assume the current file
727    position is at the start of the file.  */
728 static void *arc_mmap_file (int fd, size_t size)
729 {
730   char *data;
731 
732   if ((data = malloc (size)) == NULL)
733     return NULL;
734 
735   if (ctf_pread (fd, data, size, 0) < 0)
736     {
737       free (data);
738       return NULL;
739     }
740   return data;
741 }
742 
743 /* Persist the header to disk.  */
744 static int arc_mmap_writeout (int fd, void *header, size_t headersz,
745 			      const char **errmsg)
746 {
747   ssize_t len;
748   size_t acc = 0;
749   char *data = (char *) header;
750   ssize_t count = headersz;
751 
752   if ((lseek (fd, 0, SEEK_SET)) < 0)
753     {
754       if (errmsg)
755 	*errmsg = "arc_mmap_writeout(): Cannot seek while writing header to "
756 	  "%s: %s\n";
757       return -1;
758     }
759 
760   while (headersz > 0)
761     {
762       if ((len = write (fd, data, count)) < 0)
763 	{
764 	  if (errmsg)
765 	    *errmsg = "arc_mmap_writeout(): Cannot write header to %s: %s\n";
766 	  return len;
767 	}
768       if (len == EINTR)
769 	continue;
770 
771       acc += len;
772       if (len == 0)				/* EOF.  */
773 	break;
774 
775       count -= len;
776       data += len;
777     }
778   return 0;
779 }
780 
781 /* Unmap the region.  */
782 static int arc_mmap_unmap (void *header, size_t headersz _libctf_unused_,
783 			   const char **errmsg _libctf_unused_)
784 {
785   free (header);
786   return 0;
787 }
788 #endif
789