Files
libguestfs/lib/journal.c
Richard W.M. Jones f161c9ea57 Rename src/ to lib/
2017-01-26 15:05:46 +00:00

162 lines
4.4 KiB
C

/* libguestfs
* Copyright (C) 2013 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifdef HAVE_ENDIAN_H
#include <endian.h>
#endif
#ifdef HAVE_SYS_ENDIAN_H
#include <sys/endian.h>
#endif
#if defined __APPLE__ && defined __MACH__
#include <libkern/OSByteOrder.h>
#define be64toh(x) OSSwapBigToHostInt64(x)
#endif
#include "full-read.h"
#include "guestfs.h"
#include "guestfs-internal.h"
#include "guestfs-internal-actions.h"
/* This is implemented library-side in order to get around potential
* protocol limits.
*
* A journal record can contain an arbitrarily large amount of data
* (stuff like core dumps in particular). To save the user from
* having to deal with it, the implementation uses an internal
* function that downloads to a FileOut, and we reconstruct the
* hashtable entries from that.
*/
struct guestfs_xattr_list *
guestfs_impl_journal_get (guestfs_h *g)
{
CLEANUP_UNLINK_FREE char *tmpfile = NULL;
CLEANUP_FREE char *buf = NULL;
struct stat statbuf;
struct guestfs_xattr_list *ret = NULL;
char *p, *eofield, *eobuf;
int fd = -1;
size_t i, j, size;
uint64_t len;
tmpfile = guestfs_int_make_temp_path (g, "journal");
if (tmpfile == NULL)
goto err;
if (guestfs_internal_journal_get (g, tmpfile) == -1)
goto err;
fd = open (tmpfile, O_RDONLY|O_CLOEXEC);
if (fd == -1) {
perrorf (g, "open: %s", tmpfile);
goto err;
}
/* Read the whole file into memory. */
if (fstat (fd, &statbuf) == -1) {
perrorf (g, "stat: %s", tmpfile);
goto err;
}
/* Don't use safe_malloc. Want to return an errno to the caller. */
size = statbuf.st_size;
buf = malloc (size+1);
if (!buf) {
perrorf (g, "malloc: %zu bytes", size);
goto err;
}
eobuf = &buf[size];
*eobuf = '\0'; /* Makes strchr etc safe. */
if (full_read (fd, buf, size) != size) {
perrorf (g, "full-read: %s: %zu bytes", tmpfile, size);
goto err;
}
if (close (fd) == -1) {
perrorf (g, "close: %s", tmpfile);
goto err;
}
fd = -1;
j = 0;
ret = safe_malloc (g, sizeof *ret);
ret->len = 0;
ret->val = NULL;
/* There is a simple, private protocol employed here (note: it may
* be changed at any time), where fields are sent using a big-endian
* 64 bit length field followed by N bytes of 'field=data' binary
* data.
*/
for (i = 0; i < size; ) {
if (i+8 > size) {
error (g, "invalid data from guestfs_internal_journal_get: "
"truncated: "
"size=%zu, i=%zu", size, i);
goto err;
}
memcpy(&len, &buf[i], sizeof(len));
len = be64toh (len);
i += 8;
eofield = &buf[i+len];
if (eofield > eobuf) {
error (g, "invalid data from guestfs_internal_journal_get: "
"length field is too large: "
"size=%zu, i=%zu, len=%" PRIu64, size, i, len);
goto err;
}
p = strchr (&buf[i], '=');
if (!p || p >= eofield) {
error (g, "invalid data from guestfs_internal_journal_get: "
"no '=' found separating field name and data: "
"size=%zu, i=%zu, p=%p", size, i, p);
goto err;
}
*p = '\0';
j++;
ret->val = safe_realloc (g, ret->val, j * sizeof (struct guestfs_xattr));
ret->val[j-1].attrname = safe_strdup (g, &buf[i]);
ret->val[j-1].attrval_len = eofield - (p+1);
ret->val[j-1].attrval = safe_memdup (g, p+1, eofield - (p+1));
ret->len = j;
i += len;
}
return ret; /* caller frees */
err:
guestfs_free_xattr_list (ret);
if (fd >= 0)
close (fd);
return NULL;
}