extern int ctf_arc_write (const char *, ctf_file_t **, size_t,
const char **, size_t);
+extern int ctf_arc_write_fd (int, ctf_file_t **, size_t, const char **,
+ size_t);
extern const char *ctf_cuname (ctf_file_t *);
extern void ctf_cuname_set (ctf_file_t *, const char *);
extern int ctf_rollback (ctf_file_t *, ctf_snapshot_id_t);
extern int ctf_discard (ctf_file_t *);
extern int ctf_write (ctf_file_t *, int);
-extern int ctf_gzwrite (ctf_file_t * fp, gzFile fd);
+extern int ctf_gzwrite (ctf_file_t *fp, gzFile fd);
extern int ctf_compress_write (ctf_file_t * fp, int fd);
+extern unsigned char *ctf_write_mem (ctf_file_t *, size_t *, size_t threshold);
extern void ctf_setdebug (int debug);
extern int ctf_getdebug (void);
/* bsearch() internal state. */
static __thread char *search_nametbl;
-/* Write out a CTF archive. The entries in CTF_FILES are referenced by name:
- the names are passed in the names array, which must have CTF_FILES entries.
+/* Write out a CTF archive to the start of the file referenced by the passed-in
+ fd. The entries in CTF_FILES are referenced by name: the names are passed in
+ the names array, which must have CTF_FILES entries.
Returns 0 on success, or an errno, or an ECTF_* value. */
int
-ctf_arc_write (const char *file, ctf_file_t ** ctf_files, size_t ctf_file_cnt,
- const char **names, size_t threshold)
+ctf_arc_write_fd (int fd, ctf_file_t **ctf_files, size_t ctf_file_cnt,
+ const char **names, size_t threshold)
{
const char *errmsg;
struct ctf_archive *archdr;
- int fd;
size_t i;
char dummy = 0;
size_t headersz;
off_t nameoffs;
struct ctf_archive_modent *modent;
- ctf_dprintf ("Writing archive %s with %lu files\n", file,
+ ctf_dprintf ("Writing CTF archive with %lu files\n",
(unsigned long) ctf_file_cnt);
- if ((fd = open (file, O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0666)) < 0)
- {
- errmsg = "ctf_arc_write(): cannot create %s: %s\n";
- goto err;
- }
-
/* Figure out the size of the mmap()ed header, including the
ctf_archive_modent array. We assume that all of this needs no
padding: a likely assumption, given that it's all made up of
ctf_startoffs = headersz;
if (lseek (fd, ctf_startoffs - 1, SEEK_SET) < 0)
{
- errmsg = "ctf_arc_write(): cannot extend file while writing %s: %s\n";
- goto err_close;
+ errmsg = "ctf_arc_write(): cannot extend file while writing: %s\n";
+ goto err;
}
if (write (fd, &dummy, 1) < 0)
{
- errmsg = "ctf_arc_write(): cannot extend file while writing %s: %s\n";
- goto err_close;
+ errmsg = "ctf_arc_write(): cannot extend file while writing: %s\n";
+ goto err;
}
if ((archdr = arc_mmap_header (fd, headersz)) == NULL)
{
- errmsg = "ctf_arc_write(): Cannot mmap() %s: %s\n";
- goto err_close;
+ errmsg = "ctf_arc_write(): Cannot mmap(): %s\n";
+ goto err;
}
/* Fill in everything we can, which is everything other than the name
nametbl = malloc (namesz);
if (nametbl == NULL)
{
- errmsg = "Error writing named CTF to %s: %s\n";
+ errmsg = "Error writing named CTF to archive: %s\n";
goto err_unmap;
}
if ((off < 0) && (off > -ECTF_BASE))
{
errmsg = "ctf_arc_write(): Cannot determine file "
- "position while writing %s: %s";
+ "position while writing to archive: %s";
goto err_free;
}
if (off < 0)
{
- errmsg = "ctf_arc_write(): Cannot write CTF file to %s: %s\n";
+ errmsg = "ctf_arc_write(): Cannot write CTF file to archive: %s\n";
errno = off * -1;
goto err_free;
}
if ((nameoffs = lseek (fd, 0, SEEK_CUR)) < 0)
{
errmsg = "ctf_arc_write(): Cannot get current file position "
- "in %s: %s\n";
+ "in archive: %s\n";
goto err_free;
}
archdr->ctfa_names = htole64 (nameoffs);
ssize_t len;
if ((len = write (fd, np, namesz)) < 0)
{
- errmsg = "ctf_arc_write(): Cannot write name table in %s: %s\n";
+ errmsg = "ctf_arc_write(): Cannot write name table to archive: %s\n";
goto err_free;
}
namesz -= len;
if (arc_mmap_writeout (fd, archdr, headersz, &errmsg) < 0)
goto err_unmap;
if (arc_mmap_unmap (archdr, headersz, &errmsg) < 0)
- goto err_unlink;
- if (close (fd) < 0)
- {
- errmsg = "ctf_arc_write(): Cannot close after writing to %s: %s\n";
- goto err_unlink;
- }
-
+ goto err;
return 0;
err_free:
free (nametbl);
err_unmap:
arc_mmap_unmap (archdr, headersz, NULL);
-err_close:
- close (fd);
-err_unlink:
- unlink (file);
err:
- ctf_dprintf (errmsg, file, errno < ECTF_BASE ? strerror (errno) :
+ ctf_dprintf (errmsg, errno < ECTF_BASE ? strerror (errno) :
ctf_errmsg (errno));
return errno;
}
+/* Write out a CTF archive. The entries in CTF_FILES are referenced by name:
+ the names are passed in the names array, which must have CTF_FILES entries.
+
+ If the filename is NULL, create a temporary file and return a pointer to it.
+
+ Returns 0 on success, or an errno, or an ECTF_* value. */
+int
+ctf_arc_write (const char *file, ctf_file_t ** ctf_files, size_t ctf_file_cnt,
+ const char **names, size_t threshold)
+{
+ int err;
+ int fd;
+
+ if ((fd = open (file, O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0666)) < 0)
+ {
+ ctf_dprintf ("ctf_arc_write(): cannot create %s: %s\n", file,
+ strerror (errno));
+ return errno;
+ }
+
+ err = ctf_arc_write_fd (fd, ctf_files, ctf_file_cnt, names, threshold);
+ if (err)
+ goto err;
+
+ if ((err = close (fd)) < 0)
+ {
+ ctf_dprintf ("ctf_arc_write(): Cannot close after writing to archive: "
+ "%s\n", strerror (errno));
+ goto err_close;
+ }
+
+ err:
+ close (fd);
+ if (err < 0)
+ unlink (file);
+
+ return err;
+
+ err_close:
+ if (err < 0)
+ unlink (file);
+
+ return err;
+}
+
/* Write one CTF file out. Return the file position of the written file (or
rather, of the file-size uint64_t that precedes it): negative return is a
negative errno or ctf_errno value. On error, the file position may no longer
return err;
}
+/* Optionally compress the specified CTF data stream and return it as a new
+ dynamically-allocated string. */
+unsigned char *
+ctf_write_mem (ctf_file_t *fp, size_t *size, size_t threshold)
+{
+ unsigned char *buf;
+ unsigned char *bp;
+ ctf_header_t *hp;
+ ssize_t header_len = sizeof (ctf_header_t);
+ ssize_t compress_len;
+ size_t max_compress_len = compressBound (fp->ctf_size);
+ int rc;
+
+ if (fp->ctf_size < threshold)
+ max_compress_len = fp->ctf_size;
+ if ((buf = malloc (max_compress_len
+ + sizeof (struct ctf_header))) == NULL)
+ {
+ ctf_set_errno (fp, ENOMEM);
+ return NULL;
+ }
+
+ hp = (ctf_header_t *) buf;
+ memcpy (hp, fp->ctf_header, header_len);
+ bp = buf + sizeof (struct ctf_header);
+ *size = sizeof (struct ctf_header);
+
+ compress_len = max_compress_len;
+
+ if (fp->ctf_size < threshold)
+ {
+ hp->cth_flags &= ~CTF_F_COMPRESS;
+ memcpy (bp, fp->ctf_buf, fp->ctf_size);
+ *size += fp->ctf_size;
+ }
+ else
+ {
+ hp->cth_flags |= CTF_F_COMPRESS;
+ if ((rc = compress (bp, (uLongf *) &compress_len,
+ fp->ctf_buf, fp->ctf_size)) != Z_OK)
+ {
+ ctf_dprintf ("zlib deflate err: %s\n", zError (rc));
+ ctf_set_errno (fp, ECTF_COMPRESS);
+ ctf_free (buf);
+ return NULL;
+ }
+ *size += compress_len;
+ }
+ return buf;
+}
+
/* Write the uncompressed CTF data stream to the specified file descriptor. */
int
ctf_write (ctf_file_t *fp, int fd)