diff --git a/src/libsysprof-capture/sysprof-capture-reader.c b/src/libsysprof-capture/sysprof-capture-reader.c index b65fe67c..1819f3f2 100644 --- a/src/libsysprof-capture/sysprof-capture-reader.c +++ b/src/libsysprof-capture/sysprof-capture-reader.c @@ -1168,6 +1168,10 @@ sysprof_capture_reader_read_file (SysprofCaptureReader *self) if ((self->pos % SYSPROF_CAPTURE_ALIGN) != 0) return NULL; + /* Make sure len is < the extra frame data */ + if (file_chunk->len > (file_chunk->frame.len - sizeof *file_chunk)) + return NULL; + /* Ensure trailing \0 in .path */ file_chunk->path[sizeof file_chunk->path - 1] = 0; @@ -1209,3 +1213,64 @@ sysprof_capture_reader_list_files (SysprofCaptureReader *self) return (gchar **)g_ptr_array_free (g_steal_pointer (&ar), FALSE); } + +gboolean +sysprof_capture_reader_read_file_fd (SysprofCaptureReader *self, + const gchar *path, + gint fd) +{ + g_assert (self != NULL); + g_assert (path != NULL); + g_assert (fd > -1); + + for (;;) + { + SysprofCaptureFrameType type; + const SysprofCaptureFileChunk *file; + const guint8 *buf; + gsize to_write; + + if (!sysprof_capture_reader_peek_type (self, &type)) + return FALSE; + + if (type != SYSPROF_CAPTURE_FRAME_FILE_CHUNK) + goto skip; + + if (!(file = sysprof_capture_reader_read_file (self))) + return FALSE; + + if (g_strcmp0 (path, file->path) != 0) + goto skip; + + buf = file->data; + to_write = file->len; + + while (to_write > 0) + { + gssize written; + + written = _sysprof_write (fd, buf, to_write); + if (written < 0) + return FALSE; + + if (written == 0 && errno != EAGAIN) + return FALSE; + + g_assert (written <= (gssize)to_write); + + buf += written; + to_write -= written; + } + + if (!file->is_last) + continue; + + return TRUE; + + skip: + if (!sysprof_capture_reader_skip (self)) + return FALSE; + } + + g_return_val_if_reached (FALSE); +} diff --git a/src/libsysprof-capture/sysprof-capture-reader.h b/src/libsysprof-capture/sysprof-capture-reader.h index 32560037..8ee2ea2e 100644 --- a/src/libsysprof-capture/sysprof-capture-reader.h +++ b/src/libsysprof-capture/sysprof-capture-reader.h @@ -99,6 +99,10 @@ void sysprof_capture_reader_set_stat const SysprofCaptureStat *st_buf); SYSPROF_AVAILABLE_IN_ALL gchar **sysprof_capture_reader_list_files (SysprofCaptureReader *self); +SYSPROF_AVAILABLE_IN_ALL +gboolean sysprof_capture_reader_read_file_fd (SysprofCaptureReader *self, + const gchar *path, + gint fd); G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofCaptureReader, sysprof_capture_reader_unref) diff --git a/src/tests/test-capture.c b/src/tests/test-capture.c index 8c2b2a55..5c2bf2b8 100644 --- a/src/tests/test-capture.c +++ b/src/tests/test-capture.c @@ -27,6 +27,8 @@ #include #include +#include "sysprof-platform.h" + static void test_reader_basic (void) { @@ -725,6 +727,7 @@ test_reader_writer_file (void) gsize data_len; guint count = 0; gint fd; + gint new_fd; gint r; writer = sysprof_capture_writer_new ("file1.syscap", 0); @@ -779,6 +782,15 @@ test_reader_writer_file (void) g_assert_cmpstr (files[0], ==, "/proc/kallsyms"); g_assert_null (files[1]); + sysprof_capture_reader_reset (reader); + new_fd = sysprof_memfd_create ("[sysprof-capture-file]"); + g_assert_cmpint (new_fd, !=, -1); + + r = sysprof_capture_reader_read_file_fd (reader, "/proc/kallsyms", new_fd); + g_assert_true (r); + + close (new_fd); + g_clear_pointer (&reader, sysprof_capture_reader_unref); g_clear_pointer (&buf, g_byte_array_unref);