mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-22 07:03:38 +00:00
In the function ‘guestfs_int_make_temp_path’, allow an optional extension to be specified. For example: r = guestfs_int_make_temp_path (g, "ls", "txt"); will create paths like ‘<tmpdir>/ls123.txt’. NULL can also be passed for the extension, which means no extension.
162 lines
4.4 KiB
C
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", NULL);
|
|
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;
|
|
}
|