Move remaining protorectoral files to ctf fs plugin
authorJérémie Galarneau <jeremie.galarneau@efficios.com>
Wed, 31 Aug 2016 19:16:06 +0000 (15:16 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Sat, 27 May 2017 18:09:05 +0000 (14:09 -0400)
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
22 files changed:
converter/babeltrace.c
ctf-reader-proto/ctf-fs-data-stream.c [deleted file]
ctf-reader-proto/ctf-fs-data-stream.h [deleted file]
ctf-reader-proto/ctf-fs-file.c [deleted file]
ctf-reader-proto/ctf-fs-file.h [deleted file]
ctf-reader-proto/ctf-fs-metadata.c [deleted file]
ctf-reader-proto/ctf-fs-metadata.h [deleted file]
ctf-reader-proto/print.h [deleted file]
lib/plugin-system/source.c
plugins/ctf/fs/Makefile.am
plugins/ctf/fs/data-stream.c [new file with mode: 0644]
plugins/ctf/fs/data-stream.h [new file with mode: 0644]
plugins/ctf/fs/file.c [new file with mode: 0644]
plugins/ctf/fs/file.h [new file with mode: 0644]
plugins/ctf/fs/fs-internal.h [deleted file]
plugins/ctf/fs/fs.c
plugins/ctf/fs/fs.h [new file with mode: 0644]
plugins/ctf/fs/metadata.c [new file with mode: 0644]
plugins/ctf/fs/metadata.h [new file with mode: 0644]
plugins/ctf/fs/print.h [new file with mode: 0644]
plugins/ctf/plugin.c
plugins/text/text.c

index 035c4a250badf04c0fe683671dd16cb35afb3d07..cd7bd7c48b3cd0746ce03cbb9b36435c55580cf5 100644 (file)
 
 
 static char *opt_plugin_path;
+static char *opt_input_path;
 
 enum {
        OPT_NONE = 0,
        OPT_PLUGIN_PATH,
+       OPT_INPUT_PATH,
        OPT_VERBOSE,
        OPT_DEBUG,
        OPT_HELP,
@@ -60,6 +62,7 @@ enum {
 static struct poptOption long_options[] = {
        /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
        { "plugin-path", 0, POPT_ARG_STRING, NULL, OPT_PLUGIN_PATH, NULL, NULL },
+       { "input-path", 0, POPT_ARG_STRING, NULL, OPT_INPUT_PATH, NULL, NULL },
        { "verbose", 'v', POPT_ARG_NONE, NULL, OPT_VERBOSE, NULL, NULL },
        { "debug", 'd', POPT_ARG_NONE, NULL, OPT_DEBUG, NULL, NULL },
        { NULL, 0, 0, NULL, 0, NULL, NULL },
@@ -95,7 +98,7 @@ static int parse_options(int argc, char **argv)
                        if (!opt_plugin_path) {
                                ret = -EINVAL;
                                goto end;
-                       }                       ;
+                       }
                        break;
                case OPT_VERBOSE:
                        babeltrace_verbose = 1;
@@ -103,6 +106,13 @@ static int parse_options(int argc, char **argv)
                case OPT_DEBUG:
                        babeltrace_debug = 1;
                        break;
+               case OPT_INPUT_PATH:
+                       opt_input_path = (char *) poptGetOptArg(pc);
+                       if (!opt_input_path) {
+                               ret = -EINVAL;
+                               goto end;
+                       }
+                       break;
                default:
                        ret = -EINVAL;
                        goto end;
@@ -133,7 +143,7 @@ const char *component_type_str(enum bt_component_type type)
 }
 
 static
-void print_detected_component_classes(struct bt_component_factory *factory)
+void print_found_component_classes(struct bt_component_factory *factory)
 {
        int count, i;
 
@@ -183,18 +193,12 @@ void print_detected_component_classes(struct bt_component_factory *factory)
        }
 }
 
-static
-void test_sink_notifications(struct bt_component *sink)
-{
-       return;
-}
-
 int main(int argc, char **argv)
 {
        int ret;
+       enum bt_value_status value_status;
        struct bt_component_factory *component_factory = NULL;
-       struct bt_component_class *source_class = NULL;
-       struct bt_component_class *sink_class = NULL;
+       struct bt_component_class *source_class = NULL, *sink_class = NULL;
        struct bt_component *source = NULL, *sink = NULL;
        struct bt_value *source_params = NULL, *sink_params = NULL;
 
@@ -206,6 +210,20 @@ int main(int argc, char **argv)
                exit(EXIT_SUCCESS);
        }
 
+       source_params = bt_value_map_create();
+       if (!source_params) {
+               fprintf(stderr, "Failed to create source parameters map, aborting...\n");
+               ret = -1;
+               goto end;
+       }
+
+       value_status = bt_value_map_insert_string(source_params, "path",
+                       opt_input_path);
+       if (value_status != BT_VALUE_STATUS_OK) {
+               ret = -1;
+               goto end;
+       }
+
        printf_verbose("Verbose mode active.\n");
        printf_debug("Debug mode active.\n");
 
@@ -229,25 +247,39 @@ int main(int argc, char **argv)
                goto end;
        }
 
-       print_detected_component_classes(component_factory);
+       print_found_component_classes(component_factory);
+
+       source_class = bt_component_factory_get_component_class(
+                       component_factory, "ctf", BT_COMPONENT_TYPE_SOURCE,
+                       "fs");
+       if (!source_class) {
+               fprintf(stderr, "Could not find ctf-fs output component class. Aborting...\n");
+               ret = -1;
+               goto end;
+       }
 
        sink_class = bt_component_factory_get_component_class(component_factory,
-                       NULL, BT_COMPONENT_TYPE_SINK, "text");
+                       "text", BT_COMPONENT_TYPE_SINK, "text");
        if (!sink_class) {
                fprintf(stderr, "Could not find text output component class. Aborting...\n");
                ret = -1;
                goto end;
        }
 
+       source = bt_component_create(source_class, "ctf-fs", source_params);
+       if (!source) {
+               fprintf(stderr, "Failed to instantiate source component. Aborting...\n");
+               ret = -1;
+               goto end;
+       }
+
        sink = bt_component_create(sink_class, "bt_text_output", sink_params);
        if (!sink) {
-               fprintf(stderr, "Failed to instanciate text output. Aborting...\n");
+               fprintf(stderr, "Failed to instantiate output component. Aborting...\n");
                ret = -1;
                goto end;
        }
 
-       test_sink_notifications(sink);
-
        /* teardown and exit */
 end:
        BT_PUT(component_factory);
diff --git a/ctf-reader-proto/ctf-fs-data-stream.c b/ctf-reader-proto/ctf-fs-data-stream.c
deleted file mode 100644 (file)
index c696927..0000000
+++ /dev/null
@@ -1,362 +0,0 @@
-/*
- * Copyright 2016 - Philippe Proulx <pproulx@efficios.com>
- * Copyright 2010-2011 - EfficiOS Inc. and Linux Foundation
- *
- * Some functions are based on older functions written by Mathieu Desnoyers.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include <glib.h>
-#include <inttypes.h>
-#include <sys/mman.h>
-#include <babeltrace/ctf-ir/stream.h>
-
-#define PRINT_ERR_STREAM       ctf_fs->error_fp
-#define PRINT_PREFIX           "ctf-fs-data-stream"
-#include "print.h"
-
-#include "ctf-fs.h"
-#include "ctf-fs-file.h"
-#include "ctf-fs-metadata.h"
-#include "ctf-notif-iter/ctf-notif-iter.h"
-
-static void ctf_fs_stream_destroy(struct ctf_fs_stream *stream)
-{
-       if (stream->file) {
-               ctf_fs_file_destroy(stream->file);
-       }
-
-       if (stream->stream) {
-               BT_PUT(stream->stream);
-       }
-
-       if (stream->notif_iter) {
-               bt_ctf_notif_iter_destroy(stream->notif_iter);
-       }
-
-       g_free(stream);
-}
-
-static size_t remaining_mmap_bytes(struct ctf_fs_stream *stream)
-{
-       return stream->mmap_offset + stream->mmap_len -
-               stream->request_offset;
-}
-
-static int stream_munmap(struct ctf_fs_stream *stream)
-{
-       struct ctf_fs *ctf_fs = stream->file->ctf_fs;
-
-       if (munmap(stream->mmap_addr, stream->mmap_len)) {
-               PERR("Cannot memory-unmap address %p (size %zu) of file \"%s\" (%p): %s\n",
-                       stream->mmap_addr, stream->mmap_len,
-                       stream->file->path->str, stream->file->fp,
-                       strerror(errno));
-               return -1;
-       }
-
-       return 0;
-}
-
-static int mmap_next(struct ctf_fs_stream *stream)
-{
-       struct ctf_fs *ctf_fs = stream->file->ctf_fs;
-       int ret = 0;
-
-       /* Unmap old region */
-       if (stream->mmap_addr) {
-               if (stream_munmap(stream)) {
-                       goto error;
-               }
-
-               stream->mmap_offset += stream->mmap_len;
-               stream->request_offset = stream->mmap_offset;
-       }
-
-       /* Map new region */
-       stream->mmap_addr = mmap((void *) 0, stream->mmap_len,
-               PROT_READ, MAP_PRIVATE, fileno(stream->file->fp),
-               stream->mmap_offset);
-       if (stream->mmap_addr == MAP_FAILED) {
-               PERR("Cannot memory-map address (size %zu) of file \"%s\" (%p) at offset %zu: %s\n",
-                       stream->mmap_len, stream->file->path->str,
-                       stream->file->fp, stream->mmap_offset,
-                       strerror(errno));
-               goto error;
-       }
-
-       goto end;
-
-error:
-       stream_munmap(stream);
-       ret = -1;
-
-end:
-       return ret;
-}
-
-static enum bt_ctf_notif_iter_medium_status medop_request_bytes(
-               size_t request_sz, uint8_t **buffer_addr,
-               size_t *buffer_sz, void *data)
-{
-       enum bt_ctf_notif_iter_medium_status status =
-               BT_CTF_NOTIF_ITER_MEDIUM_STATUS_OK;
-       struct ctf_fs_stream *stream = data;
-       struct ctf_fs *ctf_fs = stream->file->ctf_fs;
-
-       if (request_sz == 0) {
-               goto end;
-       }
-
-       /* Check if we need an initial memory map */
-       if (!stream->mmap_addr) {
-               if (mmap_next(stream)) {
-                       PERR("Cannot memory-map initial region of file \"%s\" (%p)\n",
-                               stream->file->path->str, stream->file->fp);
-                       goto error;
-               }
-       }
-
-       /* Check if we have at least one memory-mapped byte left */
-       if (remaining_mmap_bytes(stream) == 0) {
-               /* Are we at the end of the file? */
-               if (stream->request_offset == stream->file->size) {
-                       PDBG("Reached end of file \"%s\" (%p)\n",
-                               stream->file->path->str, stream->file->fp);
-                       status = BT_CTF_NOTIF_ITER_MEDIUM_STATUS_EOF;
-                       goto end;
-               }
-
-               if (mmap_next(stream)) {
-                       PERR("Cannot memory-map next region of file \"%s\" (%p)\n",
-                               stream->file->path->str, stream->file->fp);
-                       goto error;
-               }
-       }
-
-       *buffer_sz = MIN(remaining_mmap_bytes(stream), request_sz);
-       *buffer_addr = ((uint8_t *) stream->mmap_addr) +
-               stream->request_offset - stream->mmap_offset;
-       stream->request_offset += *buffer_sz;
-       goto end;
-
-error:
-       status = BT_CTF_NOTIF_ITER_MEDIUM_STATUS_ERROR;
-
-end:
-       return status;
-}
-
-static struct bt_ctf_stream *medop_get_stream(
-               struct bt_ctf_stream_class *stream_class, void *data)
-{
-       struct ctf_fs_stream *fs_stream = data;
-       struct ctf_fs *ctf_fs = fs_stream->file->ctf_fs;
-
-       if (!fs_stream->stream) {
-               int64_t id = bt_ctf_stream_class_get_id(stream_class);
-
-               PDBG("Creating stream out of stream class %" PRId64 "\n", id);
-               fs_stream->stream = bt_ctf_stream_create(stream_class,
-                       fs_stream->file->path->str);
-               if (!fs_stream->stream) {
-                       PERR("Cannot create stream (stream class %" PRId64 ")\n",
-                               id);
-               }
-       }
-
-       return fs_stream->stream;
-}
-
-static struct bt_ctf_notif_iter_medium_ops medops = {
-       .request_bytes = medop_request_bytes,
-       .get_stream = medop_get_stream,
-};
-
-static struct ctf_fs_stream *ctf_fs_stream_create(struct ctf_fs *ctf_fs,
-               struct ctf_fs_file *file)
-{
-       struct ctf_fs_stream *stream = g_new0(struct ctf_fs_stream, 1);
-
-       if (!stream) {
-               goto error;
-       }
-
-       stream->file = file;
-       stream->notif_iter = bt_ctf_notif_iter_create(ctf_fs->metadata.trace,
-               12, medops, stream, ctf_fs->error_fp);
-       if (!stream->notif_iter) {
-               goto error;
-       }
-       stream->mmap_len = ctf_fs->page_size;
-
-       goto end;
-
-error:
-       /* Do not touch borrowed file */
-       stream->file = NULL;
-       ctf_fs_stream_destroy(stream);
-       stream = NULL;
-
-end:
-       return stream;
-}
-
-int ctf_fs_data_stream_open_streams(struct ctf_fs *ctf_fs)
-{
-       int ret = 0;
-       GError *error = NULL;
-       GDir *dir = g_dir_open(ctf_fs->trace_path->str, 0, &error);
-       const char *name;
-
-       if (!dir) {
-               PERR("Cannot open directory \"%s\": %s (code %d)\n",
-                       ctf_fs->trace_path->str, error->message,
-                       error->code);
-               goto error;
-       }
-
-       while ((name = g_dir_read_name(dir))) {
-               struct ctf_fs_file *file = NULL;
-               struct ctf_fs_stream *stream = NULL;
-
-               if (strcmp(name, CTF_FS_METADATA_FILENAME) == 0) {
-                       /* Ignore the metadata stream */
-                       PDBG("Ignoring metadata file \"%s\"\n",
-                               name);
-                       continue;
-               }
-
-               if (name[0] == '.') {
-                       PDBG("Ignoring hidden file \"%s\"\n",
-                               name);
-                       continue;
-               }
-
-               /* Create the file */
-               file = ctf_fs_file_create(ctf_fs);
-               if (!file) {
-                       PERR("Cannot create stream file object\n");
-                       goto error;
-               }
-
-               /* Create full path string */
-               g_string_append(file->path, ctf_fs->trace_path->str);
-               g_string_append(file->path, "/");
-               g_string_append(file->path, name);
-
-               if (!g_file_test(file->path->str, G_FILE_TEST_IS_REGULAR)) {
-                       PDBG("Ignoring non-regular file \"%s\"\n", name);
-                       ctf_fs_file_destroy(file);
-                       continue;
-               }
-
-               /* Open the file */
-               if (ctf_fs_file_open(ctf_fs, file, "rb")) {
-                       ctf_fs_file_destroy(file);
-                       goto error;
-               }
-
-               /* Create a private stream */
-               stream = ctf_fs_stream_create(ctf_fs, file);
-               if (!stream) {
-                       ctf_fs_file_destroy(file);
-                       goto error;
-               }
-
-               /* Append file to the array of files */
-               g_ptr_array_add(ctf_fs->data_stream.streams, stream);
-       }
-
-       goto end;
-
-error:
-       ret = -1;
-
-end:
-       if (dir) {
-               g_dir_close(dir);
-               dir = NULL;
-       }
-
-       if (error) {
-               g_error_free(error);
-       }
-
-       return ret;
-}
-
-int ctf_fs_data_stream_init(struct ctf_fs *ctf_fs,
-               struct ctf_fs_data_stream *data_stream)
-{
-       int ret = 0;
-
-       data_stream->streams = g_ptr_array_new_with_free_func(
-               (GDestroyNotify) ctf_fs_stream_destroy);
-       if (!data_stream->streams) {
-               PERR("Cannot allocate array of streams\n");
-               goto error;
-       }
-
-       goto end;
-
-error:
-       ret = -1;
-
-end:
-       return ret;
-}
-
-void ctf_fs_data_stream_deinit(struct ctf_fs_data_stream *data_stream)
-{
-       g_ptr_array_free(data_stream->streams, TRUE);
-}
-
-int ctf_fs_data_stream_get_next_notification(
-               struct ctf_fs *ctf_fs,
-               struct bt_ctf_notif_iter_notif **notification)
-{
-       int ret = 0;
-       struct ctf_fs_stream *stream = g_ptr_array_index(
-               ctf_fs->data_stream.streams, 0);
-       enum bt_ctf_notif_iter_status status;
-
-       status = bt_ctf_notif_iter_get_next_notification(
-               stream->notif_iter, notification);
-       if (status != BT_CTF_NOTIF_ITER_STATUS_OK &&
-                       status != BT_CTF_NOTIF_ITER_STATUS_EOF) {
-               goto error;
-       }
-       if (status == BT_CTF_NOTIF_ITER_STATUS_EOF) {
-               *notification = NULL;
-       }
-
-       goto end;
-
-error:
-       ret = -1;
-
-end:
-       return ret;
-}
diff --git a/ctf-reader-proto/ctf-fs-data-stream.h b/ctf-reader-proto/ctf-fs-data-stream.h
deleted file mode 100644 (file)
index d8f6746..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-#ifndef CTF_FS_DATA_STREAM_H
-#define CTF_FS_DATA_STREAM_H
-
-/*
- * Copyright 2016 - Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdio.h>
-#include <glib.h>
-#include <babeltrace/babeltrace-internal.h>
-#include <babeltrace/ctf-ir/trace.h>
-
-#include "ctf-notif-iter/ctf-notif-iter.h"
-
-struct ctf_fs_stream {
-       struct ctf_fs_file *file;
-       struct bt_ctf_stream *stream;
-       struct bt_ctf_notif_iter *notif_iter;
-       void *mmap_addr;
-       size_t mmap_len;
-       off_t mmap_offset;
-       off_t request_offset;
-};
-
-struct ctf_fs_data_stream {
-       GPtrArray *streams;
-};
-
-BT_HIDDEN
-int ctf_fs_data_stream_init(struct ctf_fs *ctf_fs,
-               struct ctf_fs_data_stream *data_stream);
-
-BT_HIDDEN
-void ctf_fs_data_stream_deinit(struct ctf_fs_data_stream *data_stream);
-
-BT_HIDDEN
-int ctf_fs_data_stream_open_streams(struct ctf_fs *ctf_fs);
-
-BT_HIDDEN
-int ctf_fs_data_stream_get_next_notification(
-               struct ctf_fs *ctf_fs,
-               struct bt_ctf_notif_iter_notif **notification);
-
-#endif /* CTF_FS_DATA_STREAM_H */
diff --git a/ctf-reader-proto/ctf-fs-file.c b/ctf-reader-proto/ctf-fs-file.c
deleted file mode 100644 (file)
index 45819ef..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright 2016 - Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <glib.h>
-
-#define PRINT_ERR_STREAM       ctf_fs->error_fp
-#define PRINT_PREFIX           "ctf-fs-file"
-#include "print.h"
-
-#include "ctf-fs-file.h"
-
-void ctf_fs_file_destroy(struct ctf_fs_file *file)
-{
-       struct ctf_fs *ctf_fs = file->ctf_fs;
-
-       if (!file) {
-               return;
-       }
-
-       if (file->fp) {
-               PDBG("Closing file \"%s\" (%p)\n", file->path->str, file->fp);
-
-               if (fclose(file->fp)) {
-                       PERR("Cannot close file \"%s\": %s\n", file->path->str,
-                               strerror(errno));
-               }
-       }
-
-       if (file->path) {
-               g_string_free(file->path, TRUE);
-       }
-
-       g_free(file);
-}
-
-struct ctf_fs_file *ctf_fs_file_create(struct ctf_fs *ctf_fs)
-{
-       struct ctf_fs_file *file = g_new0(struct ctf_fs_file, 1);
-
-       if (!file) {
-               goto error;
-       }
-
-       file->ctf_fs = ctf_fs;
-       file->path = g_string_new(NULL);
-       if (!file->path) {
-               goto error;
-       }
-
-       goto end;
-
-error:
-       ctf_fs_file_destroy(file);
-       file = NULL;
-
-end:
-       return file;
-}
-
-int ctf_fs_file_open(struct ctf_fs *ctf_fs, struct ctf_fs_file *file,
-               const char *mode)
-{
-       int ret = 0;
-       struct stat stat;
-
-       PDBG("Opening file \"%s\" with mode \"%s\"\n", file->path->str, mode);
-       file->fp = fopen(file->path->str, mode);
-       if (!file->fp) {
-               PERR("Cannot open file \"%s\" with mode \"%s\": %s",
-                       file->path->str, mode, strerror(errno));
-               goto error;
-       }
-
-       PDBG("Opened file: %p\n", file->fp);
-
-       if (fstat(fileno(file->fp), &stat)) {
-               PERR("Cannot get file informations: %s\n", strerror(errno));
-               goto error;
-       }
-
-       file->size = stat.st_size;
-       PDBG("  File is %zu bytes\n", file->size);
-       goto end;
-
-error:
-       ret = -1;
-
-       if (file->fp) {
-               if (fclose(file->fp)) {
-                       PERR("Cannot close file \"%s\": %s\n", file->path->str,
-                               strerror(errno));
-               }
-       }
-
-end:
-       return ret;
-}
diff --git a/ctf-reader-proto/ctf-fs-file.h b/ctf-reader-proto/ctf-fs-file.h
deleted file mode 100644 (file)
index 5da082e..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-#ifndef CTF_FS_FILE_H
-#define CTF_FS_FILE_H
-
-/*
- * Copyright 2016 - Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdio.h>
-#include <glib.h>
-#include <babeltrace/babeltrace-internal.h>
-
-#include "ctf-fs.h"
-
-struct ctf_fs_file {
-       struct ctf_fs *ctf_fs;
-       GString *path;
-       FILE *fp;
-       off_t size;
-};
-
-BT_HIDDEN
-void ctf_fs_file_destroy(struct ctf_fs_file *file);
-
-BT_HIDDEN
-struct ctf_fs_file *ctf_fs_file_create(struct ctf_fs *ctf_fs);
-
-BT_HIDDEN
-int ctf_fs_file_open(struct ctf_fs *ctf_fs, struct ctf_fs_file *file,
-               const char *mode);
-
-#endif /* CTF_FS_FILE_H */
diff --git a/ctf-reader-proto/ctf-fs-metadata.c b/ctf-reader-proto/ctf-fs-metadata.c
deleted file mode 100644 (file)
index bfe2472..0000000
+++ /dev/null
@@ -1,404 +0,0 @@
-/*
- * Copyright 2016 - Philippe Proulx <pproulx@efficios.com>
- * Copyright 2010-2011 - EfficiOS Inc. and Linux Foundation
- *
- * Some functions are based on older functions written by Mathieu Desnoyers.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include <glib.h>
-#include <babeltrace/compat/uuid.h>
-#include <babeltrace/compat/memstream.h>
-
-#define PRINT_ERR_STREAM       ctf_fs->error_fp
-#define PRINT_PREFIX           "ctf-fs-metadata"
-#include "print.h"
-
-#include "ctf-fs.h"
-#include "ctf-fs-file.h"
-#include "metadata-parsing/ctf-ast.h"
-#include "metadata-parsing/ctf-scanner.h"
-
-#define TSDL_MAGIC     0x75d11d57
-
-struct packet_header {
-       uint32_t magic;
-       uint8_t  uuid[16];
-       uint32_t checksum;
-       uint32_t content_size;
-       uint32_t packet_size;
-       uint8_t  compression_scheme;
-       uint8_t  encryption_scheme;
-       uint8_t  checksum_scheme;
-       uint8_t  major;
-       uint8_t  minor;
-} __attribute__((__packed__));
-
-static struct ctf_fs_file *get_file(struct ctf_fs *ctf_fs,
-               const char *trace_path)
-{
-       struct ctf_fs_file *file = ctf_fs_file_create(ctf_fs);
-
-       if (!file) {
-               goto error;
-       }
-
-       g_string_append(file->path, trace_path);
-       g_string_append(file->path, "/" CTF_FS_METADATA_FILENAME);
-
-       if (ctf_fs_file_open(ctf_fs, file, "rb")) {
-               goto error;
-       }
-
-       goto end;
-
-error:
-       if (file) {
-               ctf_fs_file_destroy(file);
-               file = NULL;
-       }
-
-end:
-       return file;
-}
-
-static
-bool is_packetized(struct ctf_fs *ctf_fs, struct ctf_fs_file *file)
-{
-       uint32_t magic;
-       size_t len;
-       int ret = 0;
-
-       len = fread(&magic, sizeof(magic), 1, file->fp);
-       if (len != 1) {
-               goto end;
-       }
-
-       if (magic == TSDL_MAGIC) {
-               ret = 1;
-               ctf_fs->metadata.bo = BYTE_ORDER;
-       } else if (magic == GUINT32_SWAP_LE_BE(TSDL_MAGIC)) {
-               ret = 1;
-               ctf_fs->metadata.bo = BYTE_ORDER == BIG_ENDIAN ?
-                       LITTLE_ENDIAN : BIG_ENDIAN;
-       }
-
-end:
-       rewind(file->fp);
-
-       return ret;
-}
-
-static
-bool is_version_valid(unsigned int major, unsigned int minor)
-{
-       return major == 1 && minor == 8;
-}
-
-static
-int decode_packet(struct ctf_fs *ctf_fs, FILE *in_fp, FILE *out_fp)
-{
-       struct packet_header header;
-       size_t readlen, writelen, toread;
-       uint8_t buf[512 + 1];   /* + 1 for debug-mode \0 */
-       int ret = 0;
-
-       readlen = fread(&header, sizeof(header), 1, in_fp);
-       if (feof(in_fp) != 0) {
-               goto end;
-       }
-       if (readlen < 1) {
-               goto error;
-       }
-
-       if (ctf_fs->metadata.bo != BYTE_ORDER) {
-               header.magic = GUINT32_SWAP_LE_BE(header.magic);
-               header.checksum = GUINT32_SWAP_LE_BE(header.checksum);
-               header.content_size = GUINT32_SWAP_LE_BE(header.content_size);
-               header.packet_size = GUINT32_SWAP_LE_BE(header.packet_size);
-       }
-
-       if (header.compression_scheme) {
-               PERR("Metadata packet compression not supported yet\n");
-               goto error;
-       }
-
-       if (header.encryption_scheme) {
-               PERR("Metadata packet encryption not supported yet\n");
-               goto error;
-       }
-
-       if (header.checksum || header.checksum_scheme) {
-               PERR("Metadata packet checksum verification not supported yet\n");
-               goto error;
-       }
-
-       if (!is_version_valid(header.major, header.minor)) {
-               PERR("Invalid metadata version: %u.%u\n", header.major,
-                       header.minor);
-               goto error;
-       }
-
-       /* Set expected trace UUID if not set; otherwise validate it */
-       if (!ctf_fs->metadata.is_uuid_set) {
-               memcpy(ctf_fs->metadata.uuid, header.uuid, sizeof(header.uuid));
-               ctf_fs->metadata.is_uuid_set = true;
-       } else if (bt_uuid_compare(header.uuid, ctf_fs->metadata.uuid)) {
-               PERR("Metadata UUID mismatch between packets of the same file\n");
-               goto error;
-       }
-
-       if ((header.content_size / CHAR_BIT) < sizeof(header)) {
-               PERR("Bad metadata packet content size: %u\n",
-                       header.content_size);
-               goto error;
-       }
-
-       toread = header.content_size / CHAR_BIT - sizeof(header);
-
-       for (;;) {
-               readlen = fread(buf, sizeof(uint8_t),
-                       MIN(sizeof(buf) - 1, toread), in_fp);
-               if (ferror(in_fp)) {
-                       PERR("Cannot read metadata packet buffer (at position %ld)\n",
-                               ftell(in_fp));
-                       goto error;
-               }
-
-               writelen = fwrite(buf, sizeof(uint8_t), readlen, out_fp);
-               if (writelen < readlen || ferror(out_fp)) {
-                       PERR("Cannot write decoded metadata text to buffer\n");
-                       goto error;
-               }
-
-               toread -= readlen;
-               if (toread == 0) {
-                       int fseek_ret;
-
-                       /* Read leftover padding */
-                       toread = (header.packet_size - header.content_size) /
-                               CHAR_BIT;
-                       fseek_ret = fseek(in_fp, toread, SEEK_CUR);
-                       if (fseek_ret < 0) {
-                               PWARN("Missing padding at the end of the metadata file\n");
-                       }
-
-                       break;
-               }
-       }
-
-       goto end;
-
-error:
-       ret = -1;
-
-end:
-       return ret;
-}
-
-static
-int packetized_file_to_buf(struct ctf_fs *ctf_fs, struct ctf_fs_file *file,
-               uint8_t **buf)
-{
-       FILE *out_fp;
-       size_t size;
-       int ret = 0;
-       int tret;
-       size_t packet_index = 0;
-
-       out_fp = babeltrace_open_memstream((char **) buf, &size);
-       if (out_fp == NULL) {
-               PERR("Cannot open memory stream: %s\n", strerror(errno));
-               goto error;
-       }
-
-       for (;;) {
-               if (feof(file->fp) != 0) {
-                       break;
-               }
-
-               tret = decode_packet(ctf_fs, file->fp, out_fp);
-               if (tret) {
-                       PERR("Cannot decode packet #%zu\n", packet_index);
-                       goto error;
-               }
-
-               packet_index++;
-       }
-
-       /* Make sure the whole string ends with a null character */
-       tret = fputc('\0', out_fp);
-       if (tret == EOF) {
-               PERR("Cannot append '\\0' to the decoded metadata buffer\n");
-               goto error;
-       }
-
-       /* Close stream, which also flushes the buffer */
-       ret = babeltrace_close_memstream((char **) buf, &size, out_fp);
-       if (ret < 0) {
-               PERR("Cannot close memory stream: %s\n", strerror(errno));
-               goto error;
-       }
-
-       goto end;
-
-error:
-       ret = -1;
-
-       if (out_fp) {
-               babeltrace_close_memstream((char **) buf, &size, out_fp);
-       }
-
-       if (*buf) {
-               free(*buf);
-       }
-
-end:
-       return ret;
-}
-
-void ctf_fs_metadata_set_trace(struct ctf_fs *ctf_fs)
-{
-       int ret = 0;
-       struct ctf_fs_file *file = get_file(ctf_fs, ctf_fs->trace_path->str);
-       struct ctf_scanner *scanner = NULL;
-       uint8_t *buf = NULL;
-       char *cbuf;
-
-       if (!file) {
-               PERR("Cannot create metadata file object\n");
-               goto error;
-       }
-
-       if (babeltrace_debug) {
-               // yydebug = 1;
-       }
-
-       if (is_packetized(ctf_fs, file)) {
-               PDBG("Metadata file \"%s\" is packetized\n", file->path->str);
-               ret = packetized_file_to_buf(ctf_fs, file, &buf);
-               if (ret) {
-                       // log: details
-                       goto error;
-               }
-
-               cbuf = (char *) buf;
-               ctf_fs->metadata.text = (char *) cbuf;
-
-               /* Convert the real file pointer to a memory file pointer */
-               ret = fclose(file->fp);
-               file->fp = NULL;
-               if (ret) {
-                       PERR("Cannot close file \"%s\": %s\n", file->path->str,
-                               strerror(errno));
-                       goto error;
-               }
-
-               file->fp = babeltrace_fmemopen(cbuf, strlen(cbuf), "rb");
-               if (!file->fp) {
-                       PERR("Cannot memory-open metadata buffer: %s\n",
-                               strerror(errno));
-                       goto error;
-               }
-       } else {
-               unsigned int major, minor;
-               ssize_t nr_items;
-
-               PDBG("Metadata file \"%s\" is plain text\n", file->path->str);
-
-               /* Check text-only metadata header and version */
-               nr_items = fscanf(file->fp, "/* CTF %10u.%10u", &major, &minor);
-               if (nr_items < 2) {
-                       PWARN("Ill-shapen or missing \"/* CTF major.minor\" header in plain text metadata file\n");
-               }
-               PDBG("Metadata version: %u.%u\n", major, minor);
-
-               if (!is_version_valid(major, minor)) {
-                       PERR("Invalid metadata version: %u.%u\n", major, minor);
-                       goto error;
-               }
-
-               rewind(file->fp);
-       }
-
-       /* Allocate a scanner and append the metadata text content */
-       scanner = ctf_scanner_alloc();
-       if (!scanner) {
-               PERR("Cannot allocate a metadata lexical scanner\n");
-               goto error;
-       }
-
-       ret = ctf_scanner_append_ast(scanner, file->fp);
-       if (ret) {
-               PERR("Cannot create the metadata AST\n");
-               goto error;
-       }
-
-       ret = ctf_visitor_semantic_check(stderr, 0, &scanner->ast->root);
-       if (ret) {
-               PERR("Metadata semantic validation failed\n");
-               goto error;
-       }
-
-       ret = ctf_visitor_generate_ir(ctf_fs->error_fp, &scanner->ast->root,
-               &ctf_fs->metadata.trace);
-       if (ret) {
-               PERR("Cannot create trace object from metadata AST\n");
-               goto error;
-       }
-
-       goto end;
-
-error:
-       if (ctf_fs->metadata.text) {
-               free(ctf_fs->metadata.text);
-               ctf_fs->metadata.text = NULL;
-       }
-
-end:
-       if (file) {
-               ctf_fs_file_destroy(file);
-       }
-
-       if (scanner) {
-               ctf_scanner_free(scanner);
-       }
-}
-
-int ctf_fs_metadata_init(struct ctf_fs_metadata *metadata)
-{
-       /* Nothing to initialize for the moment */
-       return 0;
-}
-
-void ctf_fs_metadata_deinit(struct ctf_fs_metadata *metadata)
-{
-       if (metadata->text) {
-               free(metadata->text);
-       }
-
-       if (metadata->trace) {
-               BT_PUT(metadata->trace);
-       }
-}
diff --git a/ctf-reader-proto/ctf-fs-metadata.h b/ctf-reader-proto/ctf-fs-metadata.h
deleted file mode 100644 (file)
index ed9b785..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-#ifndef CTF_FS_METADATA_H
-#define CTF_FS_METADATA_H
-
-/*
- * Copyright 2016 - Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdio.h>
-#include <glib.h>
-#include <babeltrace/babeltrace-internal.h>
-#include <babeltrace/ctf-ir/trace.h>
-
-#define CTF_FS_METADATA_FILENAME       "metadata"
-
-struct ctf_fs;
-
-struct ctf_fs_metadata {
-       struct bt_ctf_trace *trace;
-       uint8_t uuid[16];
-       bool is_uuid_set;
-       int bo;
-       char *text;
-};
-
-BT_HIDDEN
-int ctf_fs_metadata_init(struct ctf_fs_metadata *metadata);
-
-BT_HIDDEN
-void ctf_fs_metadata_deinit(struct ctf_fs_metadata *metadata);
-
-BT_HIDDEN
-void ctf_fs_metadata_set_trace(struct ctf_fs *ctf_fs);
-
-#endif /* CTF_FS_METADATA_H */
diff --git a/ctf-reader-proto/print.h b/ctf-reader-proto/print.h
deleted file mode 100644 (file)
index 4c47f62..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-#ifndef CTF_FS_PRINT_H
-#define CTF_FS_PRINT_H
-
-/*
- * Define PRINT_PREFIX and PRINT_ERR_STREAM, then include this file.
- *
- * Copyright (c) 2016 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdio.h>
-
-#include "ctf-fs.h"
-
-#define PERR(fmt, ...)                                                 \
-       do {                                                            \
-               if (PRINT_ERR_STREAM) {                                 \
-                       fprintf(PRINT_ERR_STREAM,                       \
-                               "Error: " PRINT_PREFIX ": " fmt,        \
-                               ##__VA_ARGS__);                         \
-               }                                                       \
-       } while (0)
-
-#define PWARN(fmt, ...)                                                        \
-       do {                                                            \
-               if (PRINT_ERR_STREAM) {                                 \
-                       fprintf(PRINT_ERR_STREAM,                       \
-                               "Warning: " PRINT_PREFIX ": " fmt,      \
-                               ##__VA_ARGS__);                         \
-               }                                                       \
-       } while (0)
-
-#define PDBG(fmt, ...)                                                 \
-       do {                                                            \
-               if (ctf_fs_debug) {                                     \
-                       fprintf(stderr,                                 \
-                               "Debug: " PRINT_PREFIX ": " fmt,        \
-                               ##__VA_ARGS__);                         \
-               }                                                       \
-       } while (0)
-
-#endif /* CTF_FS_PRINT_H */
index e7c4c9af1b0220c304d3c78e7a1d361ec990047f..333139f51f17e6c5f74ad35b228325aa9c7af9d6 100644 (file)
@@ -56,7 +56,7 @@ enum bt_component_status bt_component_source_validate(
        }
 
        source = container_of(component, struct bt_component_source, parent);
-       if (source->init_iterator) {
+       if (!source->init_iterator) {
                ret = BT_COMPONENT_STATUS_INVALID;
                goto end;
        }
index 953ca337386c13ac2c865f250767a55d5009f890..c08c1aa9e3464c454536e62e0218d814bd7ff102 100644 (file)
@@ -1,7 +1,17 @@
 AM_CFLAGS = $(PACKAGE_CFLAGS) -I$(top_srcdir)/include
 
-noinst_HEADERS = fs-internal.h
+noinst_HEADERS = \
+       fs.h \
+       data-stream.h \
+       file.h \
+       metadata.h \
+       print.h
 noinst_LTLIBRARIES = libbabeltrace-plugin-ctf-fs.la
 
-# Plug-in system library
-libbabeltrace_plugin_ctf_fs_la_SOURCES = fs.c
+libbabeltrace_plugin_ctf_fs_la_LIBADD = \
+       $(builddir)/../common/libbabeltrace-plugin-ctf-common.la
+libbabeltrace_plugin_ctf_fs_la_SOURCES = \
+       fs.c \
+       data-stream.c \
+       metadata.c \
+       file.c
diff --git a/plugins/ctf/fs/data-stream.c b/plugins/ctf/fs/data-stream.c
new file mode 100644 (file)
index 0000000..6fba603
--- /dev/null
@@ -0,0 +1,361 @@
+/*
+ * Copyright 2016 - Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2010-2011 - EfficiOS Inc. and Linux Foundation
+ *
+ * Some functions are based on older functions written by Mathieu Desnoyers.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <glib.h>
+#include <inttypes.h>
+#include <sys/mman.h>
+#include <babeltrace/ctf-ir/stream.h>
+
+#define PRINT_ERR_STREAM       ctf_fs->error_fp
+#define PRINT_PREFIX           "ctf-fs-data-stream"
+#include "print.h"
+
+#include "file.h"
+#include "metadata.h"
+#include "../common/notif-iter/notif-iter.h"
+
+static void ctf_fs_stream_destroy(struct ctf_fs_stream *stream)
+{
+       if (stream->file) {
+               ctf_fs_file_destroy(stream->file);
+       }
+
+       if (stream->stream) {
+               BT_PUT(stream->stream);
+       }
+
+       if (stream->notif_iter) {
+               bt_ctf_notif_iter_destroy(stream->notif_iter);
+       }
+
+       g_free(stream);
+}
+
+static size_t remaining_mmap_bytes(struct ctf_fs_stream *stream)
+{
+       return stream->mmap_offset + stream->mmap_len -
+               stream->request_offset;
+}
+
+static int stream_munmap(struct ctf_fs_stream *stream)
+{
+       struct ctf_fs_component *ctf_fs = stream->file->ctf_fs;
+
+       if (munmap(stream->mmap_addr, stream->mmap_len)) {
+               PERR("Cannot memory-unmap address %p (size %zu) of file \"%s\" (%p): %s\n",
+                       stream->mmap_addr, stream->mmap_len,
+                       stream->file->path->str, stream->file->fp,
+                       strerror(errno));
+               return -1;
+       }
+
+       return 0;
+}
+
+static int mmap_next(struct ctf_fs_stream *stream)
+{
+       struct ctf_fs_component *ctf_fs = stream->file->ctf_fs;
+       int ret = 0;
+
+       /* Unmap old region */
+       if (stream->mmap_addr) {
+               if (stream_munmap(stream)) {
+                       goto error;
+               }
+
+               stream->mmap_offset += stream->mmap_len;
+               stream->request_offset = stream->mmap_offset;
+       }
+
+       /* Map new region */
+       stream->mmap_addr = mmap((void *) 0, stream->mmap_len,
+               PROT_READ, MAP_PRIVATE, fileno(stream->file->fp),
+               stream->mmap_offset);
+       if (stream->mmap_addr == MAP_FAILED) {
+               PERR("Cannot memory-map address (size %zu) of file \"%s\" (%p) at offset %zu: %s\n",
+                       stream->mmap_len, stream->file->path->str,
+                       stream->file->fp, stream->mmap_offset,
+                       strerror(errno));
+               goto error;
+       }
+
+       goto end;
+
+error:
+       stream_munmap(stream);
+       ret = -1;
+
+end:
+       return ret;
+}
+
+static enum bt_ctf_notif_iter_medium_status medop_request_bytes(
+               size_t request_sz, uint8_t **buffer_addr,
+               size_t *buffer_sz, void *data)
+{
+       enum bt_ctf_notif_iter_medium_status status =
+               BT_CTF_NOTIF_ITER_MEDIUM_STATUS_OK;
+       struct ctf_fs_stream *stream = data;
+       struct ctf_fs_component *ctf_fs = stream->file->ctf_fs;
+
+       if (request_sz == 0) {
+               goto end;
+       }
+
+       /* Check if we need an initial memory map */
+       if (!stream->mmap_addr) {
+               if (mmap_next(stream)) {
+                       PERR("Cannot memory-map initial region of file \"%s\" (%p)\n",
+                               stream->file->path->str, stream->file->fp);
+                       goto error;
+               }
+       }
+
+       /* Check if we have at least one memory-mapped byte left */
+       if (remaining_mmap_bytes(stream) == 0) {
+               /* Are we at the end of the file? */
+               if (stream->request_offset == stream->file->size) {
+                       PDBG("Reached end of file \"%s\" (%p)\n",
+                               stream->file->path->str, stream->file->fp);
+                       status = BT_CTF_NOTIF_ITER_MEDIUM_STATUS_EOF;
+                       goto end;
+               }
+
+               if (mmap_next(stream)) {
+                       PERR("Cannot memory-map next region of file \"%s\" (%p)\n",
+                               stream->file->path->str, stream->file->fp);
+                       goto error;
+               }
+       }
+
+       *buffer_sz = MIN(remaining_mmap_bytes(stream), request_sz);
+       *buffer_addr = ((uint8_t *) stream->mmap_addr) +
+               stream->request_offset - stream->mmap_offset;
+       stream->request_offset += *buffer_sz;
+       goto end;
+
+error:
+       status = BT_CTF_NOTIF_ITER_MEDIUM_STATUS_ERROR;
+
+end:
+       return status;
+}
+
+static struct bt_ctf_stream *medop_get_stream(
+               struct bt_ctf_stream_class *stream_class, void *data)
+{
+       struct ctf_fs_stream *fs_stream = data;
+       struct ctf_fs_component *ctf_fs = fs_stream->file->ctf_fs;
+
+       if (!fs_stream->stream) {
+               int64_t id = bt_ctf_stream_class_get_id(stream_class);
+
+               PDBG("Creating stream out of stream class %" PRId64 "\n", id);
+               fs_stream->stream = bt_ctf_stream_create(stream_class,
+                       fs_stream->file->path->str);
+               if (!fs_stream->stream) {
+                       PERR("Cannot create stream (stream class %" PRId64 ")\n",
+                               id);
+               }
+       }
+
+       return fs_stream->stream;
+}
+
+static struct bt_ctf_notif_iter_medium_ops medops = {
+       .request_bytes = medop_request_bytes,
+       .get_stream = medop_get_stream,
+};
+
+static struct ctf_fs_stream *ctf_fs_stream_create(
+               struct ctf_fs_component *ctf_fs, struct ctf_fs_file *file)
+{
+       struct ctf_fs_stream *stream = g_new0(struct ctf_fs_stream, 1);
+
+       if (!stream) {
+               goto error;
+       }
+
+       stream->file = file;
+       stream->notif_iter = bt_ctf_notif_iter_create(ctf_fs->metadata.trace,
+               12, medops, stream, ctf_fs->error_fp);
+       if (!stream->notif_iter) {
+               goto error;
+       }
+       stream->mmap_len = ctf_fs->page_size;
+
+       goto end;
+
+error:
+       /* Do not touch borrowed file */
+       stream->file = NULL;
+       ctf_fs_stream_destroy(stream);
+       stream = NULL;
+
+end:
+       return stream;
+}
+
+int ctf_fs_data_stream_open_streams(struct ctf_fs_component *ctf_fs)
+{
+       int ret = 0;
+       GError *error = NULL;
+       GDir *dir = g_dir_open(ctf_fs->trace_path->str, 0, &error);
+       const char *name;
+
+       if (!dir) {
+               PERR("Cannot open directory \"%s\": %s (code %d)\n",
+                       ctf_fs->trace_path->str, error->message,
+                       error->code);
+               goto error;
+       }
+
+       while ((name = g_dir_read_name(dir))) {
+               struct ctf_fs_file *file = NULL;
+               struct ctf_fs_stream *stream = NULL;
+
+               if (strcmp(name, CTF_FS_METADATA_FILENAME) == 0) {
+                       /* Ignore the metadata stream */
+                       PDBG("Ignoring metadata file \"%s\"\n",
+                               name);
+                       continue;
+               }
+
+               if (name[0] == '.') {
+                       PDBG("Ignoring hidden file \"%s\"\n",
+                               name);
+                       continue;
+               }
+
+               /* Create the file */
+               file = ctf_fs_file_create(ctf_fs);
+               if (!file) {
+                       PERR("Cannot create stream file object\n");
+                       goto error;
+               }
+
+               /* Create full path string */
+               g_string_append(file->path, ctf_fs->trace_path->str);
+               g_string_append(file->path, "/");
+               g_string_append(file->path, name);
+
+               if (!g_file_test(file->path->str, G_FILE_TEST_IS_REGULAR)) {
+                       PDBG("Ignoring non-regular file \"%s\"\n", name);
+                       ctf_fs_file_destroy(file);
+                       continue;
+               }
+
+               /* Open the file */
+               if (ctf_fs_file_open(ctf_fs, file, "rb")) {
+                       ctf_fs_file_destroy(file);
+                       goto error;
+               }
+
+               /* Create a private stream */
+               stream = ctf_fs_stream_create(ctf_fs, file);
+               if (!stream) {
+                       ctf_fs_file_destroy(file);
+                       goto error;
+               }
+
+               /* Append file to the array of files */
+               g_ptr_array_add(ctf_fs->data_stream.streams, stream);
+       }
+
+       goto end;
+
+error:
+       ret = -1;
+
+end:
+       if (dir) {
+               g_dir_close(dir);
+               dir = NULL;
+       }
+
+       if (error) {
+               g_error_free(error);
+       }
+
+       return ret;
+}
+
+int ctf_fs_data_stream_init(struct ctf_fs_component *ctf_fs,
+               struct ctf_fs_data_stream *data_stream)
+{
+       int ret = 0;
+
+       data_stream->streams = g_ptr_array_new_with_free_func(
+               (GDestroyNotify) ctf_fs_stream_destroy);
+       if (!data_stream->streams) {
+               PERR("Cannot allocate array of streams\n");
+               goto error;
+       }
+
+       goto end;
+
+error:
+       ret = -1;
+
+end:
+       return ret;
+}
+
+void ctf_fs_data_stream_deinit(struct ctf_fs_data_stream *data_stream)
+{
+       g_ptr_array_free(data_stream->streams, TRUE);
+}
+
+int ctf_fs_data_stream_get_next_notification(
+               struct ctf_fs_component *ctf_fs,
+               struct bt_ctf_notif_iter_notif **notification)
+{
+       int ret = 0;
+       struct ctf_fs_stream *stream = g_ptr_array_index(
+               ctf_fs->data_stream.streams, 0);
+       enum bt_ctf_notif_iter_status status;
+
+       status = bt_ctf_notif_iter_get_next_notification(
+               stream->notif_iter, notification);
+       if (status != BT_CTF_NOTIF_ITER_STATUS_OK &&
+                       status != BT_CTF_NOTIF_ITER_STATUS_EOF) {
+               goto error;
+       }
+       if (status == BT_CTF_NOTIF_ITER_STATUS_EOF) {
+               *notification = NULL;
+       }
+
+       goto end;
+
+error:
+       ret = -1;
+
+end:
+       return ret;
+}
diff --git a/plugins/ctf/fs/data-stream.h b/plugins/ctf/fs/data-stream.h
new file mode 100644 (file)
index 0000000..d8f6746
--- /dev/null
@@ -0,0 +1,62 @@
+#ifndef CTF_FS_DATA_STREAM_H
+#define CTF_FS_DATA_STREAM_H
+
+/*
+ * Copyright 2016 - Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <glib.h>
+#include <babeltrace/babeltrace-internal.h>
+#include <babeltrace/ctf-ir/trace.h>
+
+#include "ctf-notif-iter/ctf-notif-iter.h"
+
+struct ctf_fs_stream {
+       struct ctf_fs_file *file;
+       struct bt_ctf_stream *stream;
+       struct bt_ctf_notif_iter *notif_iter;
+       void *mmap_addr;
+       size_t mmap_len;
+       off_t mmap_offset;
+       off_t request_offset;
+};
+
+struct ctf_fs_data_stream {
+       GPtrArray *streams;
+};
+
+BT_HIDDEN
+int ctf_fs_data_stream_init(struct ctf_fs *ctf_fs,
+               struct ctf_fs_data_stream *data_stream);
+
+BT_HIDDEN
+void ctf_fs_data_stream_deinit(struct ctf_fs_data_stream *data_stream);
+
+BT_HIDDEN
+int ctf_fs_data_stream_open_streams(struct ctf_fs *ctf_fs);
+
+BT_HIDDEN
+int ctf_fs_data_stream_get_next_notification(
+               struct ctf_fs *ctf_fs,
+               struct bt_ctf_notif_iter_notif **notification);
+
+#endif /* CTF_FS_DATA_STREAM_H */
diff --git a/plugins/ctf/fs/file.c b/plugins/ctf/fs/file.c
new file mode 100644 (file)
index 0000000..1d31bcf
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2016 - Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <glib.h>
+
+#define PRINT_ERR_STREAM       ctf_fs->error_fp
+#define PRINT_PREFIX           "ctf-fs-file"
+#include "print.h"
+
+#include "file.h"
+
+void ctf_fs_file_destroy(struct ctf_fs_file *file)
+{
+       struct ctf_fs_component *ctf_fs = file->ctf_fs;
+
+       if (!file) {
+               return;
+       }
+
+       if (file->fp) {
+               PDBG("Closing file \"%s\" (%p)\n", file->path->str, file->fp);
+
+               if (fclose(file->fp)) {
+                       PERR("Cannot close file \"%s\": %s\n", file->path->str,
+                               strerror(errno));
+               }
+       }
+
+       if (file->path) {
+               g_string_free(file->path, TRUE);
+       }
+
+       g_free(file);
+}
+
+struct ctf_fs_file *ctf_fs_file_create(struct ctf_fs_component *ctf_fs)
+{
+       struct ctf_fs_file *file = g_new0(struct ctf_fs_file, 1);
+
+       if (!file) {
+               goto error;
+       }
+
+       file->ctf_fs = ctf_fs;
+       file->path = g_string_new(NULL);
+       if (!file->path) {
+               goto error;
+       }
+
+       goto end;
+
+error:
+       ctf_fs_file_destroy(file);
+       file = NULL;
+
+end:
+       return file;
+}
+
+int ctf_fs_file_open(struct ctf_fs_component *ctf_fs, struct ctf_fs_file *file,
+               const char *mode)
+{
+       int ret = 0;
+       struct stat stat;
+
+       PDBG("Opening file \"%s\" with mode \"%s\"\n", file->path->str, mode);
+       file->fp = fopen(file->path->str, mode);
+       if (!file->fp) {
+               PERR("Cannot open file \"%s\" with mode \"%s\": %s",
+                       file->path->str, mode, strerror(errno));
+               goto error;
+       }
+
+       PDBG("Opened file: %p\n", file->fp);
+
+       if (fstat(fileno(file->fp), &stat)) {
+               PERR("Cannot get file informations: %s\n", strerror(errno));
+               goto error;
+       }
+
+       file->size = stat.st_size;
+       PDBG("  File is %zu bytes\n", file->size);
+       goto end;
+
+error:
+       ret = -1;
+
+       if (file->fp) {
+               if (fclose(file->fp)) {
+                       PERR("Cannot close file \"%s\": %s\n", file->path->str,
+                               strerror(errno));
+               }
+       }
+
+end:
+       return ret;
+}
diff --git a/plugins/ctf/fs/file.h b/plugins/ctf/fs/file.h
new file mode 100644 (file)
index 0000000..59f3d0e
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef CTF_FS_FILE_H
+#define CTF_FS_FILE_H
+
+/*
+ * Copyright 2016 - Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <glib.h>
+#include <babeltrace/babeltrace-internal.h>
+#include "fs.h"
+
+BT_HIDDEN
+void ctf_fs_file_destroy(struct ctf_fs_file *file);
+
+BT_HIDDEN
+struct ctf_fs_file *ctf_fs_file_create(struct ctf_fs_component *ctf_fs);
+
+BT_HIDDEN
+int ctf_fs_file_open(struct ctf_fs_component *ctf_fs, struct ctf_fs_file *file,
+               const char *mode);
+
+#endif /* CTF_FS_FILE_H */
diff --git a/plugins/ctf/fs/fs-internal.h b/plugins/ctf/fs/fs-internal.h
deleted file mode 100644 (file)
index d0a9f76..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-#ifndef BABELTRACE_PLUGIN_CTF_FS_INTERNAL_H
-#define BABELTRACE_PLUGIN_CTF_FS_INTERNAL_H
-
-/*
- * BabelTrace - CTF on File System Component
- *
- * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace/babeltrace-internal.h>
-#include <babeltrace/plugin/component.h>
-
-#define CTF_FS_COMPONENT_NAME "ctf"
-#define CTF_FS_COMPONENT_DESCRIPTION \
-       "Component used to read a CTF trace located on a file system."
-
-struct ctf_fs_iterator {
-       int dummy;
-};
-
-struct ctf_fs_component_options {
-       bool opt_dummy : 1;
-};
-
-struct ctf_fs_component {
-       struct ctf_fs_component_options options;
-};
-
-BT_HIDDEN
-enum bt_component_status ctf_fs_init(struct bt_component *source,
-               struct bt_value *params);
-
-#endif /* BABELTRACE_PLUGIN_CTF_FS_INTERNAL_H */
index cd58753aea240a5032a271e17cf57bf8900896e4..9019543eea6595268e81f0183eccd93b114bced4 100644 (file)
@@ -30,7 +30,8 @@
 #include <babeltrace/plugin/notification/iterator.h>
 #include <glib.h>
 #include <assert.h>
-#include "fs-internal.h"
+#include <unistd.h>
+#include "fs.h"
 
 static bool ctf_fs_debug;
 
@@ -104,15 +105,15 @@ error:
        return ret;
 }
 
-static
-struct ctf_fs_component *ctf_fs_create(struct bt_value *params)
-{
-       return g_new0(struct ctf_fs_component, 1);
-}
-
 static
 void ctf_fs_destroy_data(struct ctf_fs_component *component)
 {
+       if (component->trace_path) {
+               g_string_free(component->trace_path, TRUE);
+       }
+
+//     ctf_fs_metadata_fini(&component->metadata);
+//     ctf_fs_data_stream_fini(&component->data_stream);
        g_free(component);
 }
 
@@ -124,6 +125,45 @@ void ctf_fs_destroy(struct bt_component *component)
        ctf_fs_destroy_data(data);
 }
 
+static
+struct ctf_fs_component *ctf_fs_create(struct bt_value *params)
+{
+       struct ctf_fs_component *ctf_fs;
+       struct bt_value *value;
+       const char *path;
+       enum bt_value_status ret;
+
+       ctf_fs = g_new0(struct ctf_fs_component, 1);
+       if (!ctf_fs) {
+               goto end;
+       }
+
+       /* FIXME: should probably look for a source URI */
+       value = bt_value_map_get(params, "path");
+       if (!value || bt_value_is_null(value) || !bt_value_is_string(value)) {
+               goto error;
+       }
+
+       ret = bt_value_string_get(value, &path);
+       if (ret != BT_VALUE_STATUS_OK) {
+               goto error;
+       }
+
+       ctf_fs->trace_path = g_string_new(path);
+       if (!ctf_fs->trace_path) {
+               goto error;
+       }
+
+       ctf_fs->error_fp = stderr;
+       ctf_fs->page_size = (size_t) getpagesize();
+
+end:
+       return ctf_fs;
+error:
+       ctf_fs_destroy_data(ctf_fs);
+       return ctf_fs;
+}
+
 BT_HIDDEN
 enum bt_component_status ctf_fs_init(struct bt_component *source,
                struct bt_value *params)
diff --git a/plugins/ctf/fs/fs.h b/plugins/ctf/fs/fs.h
new file mode 100644 (file)
index 0000000..ff97b7a
--- /dev/null
@@ -0,0 +1,90 @@
+#ifndef BABELTRACE_PLUGIN_CTF_FS_INTERNAL_H
+#define BABELTRACE_PLUGIN_CTF_FS_INTERNAL_H
+
+/*
+ * BabelTrace - CTF on File System Component
+ *
+ * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ * Copyright 2016 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <babeltrace/babeltrace-internal.h>
+#include <babeltrace/plugin/component.h>
+
+#define CTF_FS_COMPONENT_NAME "fs"
+#define CTF_FS_COMPONENT_DESCRIPTION \
+       "Component used to read a CTF trace located on a file system."
+
+static bool ctf_fs_debug;
+
+struct ctf_fs_file {
+       struct ctf_fs_component *ctf_fs;
+       GString *path;
+       FILE *fp;
+       off_t size;
+};
+
+struct ctf_fs_metadata {
+       struct bt_ctf_trace *trace;
+       uint8_t uuid[16];
+       bool is_uuid_set;
+       int bo;
+       char *text;
+};
+
+struct ctf_fs_stream {
+       struct ctf_fs_file *file;
+       struct bt_ctf_stream *stream;
+       struct bt_ctf_notif_iter *notif_iter;
+       void *mmap_addr;
+       size_t mmap_len;
+       off_t mmap_offset;
+       off_t request_offset;
+};
+
+struct ctf_fs_data_stream {
+       GPtrArray *streams;
+};
+
+struct ctf_fs_iterator {
+       int dummy;
+};
+
+struct ctf_fs_component_options {
+       bool opt_dummy : 1;
+};
+
+struct ctf_fs_component {
+       GString *trace_path;
+       FILE *error_fp;
+       size_t page_size;
+       struct ctf_fs_metadata metadata;
+       struct ctf_fs_data_stream data_stream;
+       struct ctf_fs_component_options options;
+};
+
+BT_HIDDEN
+enum bt_component_status ctf_fs_init(struct bt_component *source,
+               struct bt_value *params);
+
+#endif /* BABELTRACE_PLUGIN_CTF_FS_INTERNAL_H */
diff --git a/plugins/ctf/fs/metadata.c b/plugins/ctf/fs/metadata.c
new file mode 100644 (file)
index 0000000..967452f
--- /dev/null
@@ -0,0 +1,405 @@
+/*
+ * Copyright 2016 - Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2010-2011 - EfficiOS Inc. and Linux Foundation
+ *
+ * Some functions are based on older functions written by Mathieu Desnoyers.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <glib.h>
+#include <babeltrace/compat/uuid.h>
+#include <babeltrace/compat/memstream.h>
+
+#define PRINT_ERR_STREAM       ctf_fs->error_fp
+#define PRINT_PREFIX           "ctf-fs-metadata"
+#include "print.h"
+
+#include "fs.h"
+#include "file.h"
+#include "metadata.h"
+#include "../common/metadata/ast.h"
+#include "../common/metadata/scanner.h"
+
+#define TSDL_MAGIC     0x75d11d57
+
+struct packet_header {
+       uint32_t magic;
+       uint8_t  uuid[16];
+       uint32_t checksum;
+       uint32_t content_size;
+       uint32_t packet_size;
+       uint8_t  compression_scheme;
+       uint8_t  encryption_scheme;
+       uint8_t  checksum_scheme;
+       uint8_t  major;
+       uint8_t  minor;
+} __attribute__((__packed__));
+
+static struct ctf_fs_file *get_file(struct ctf_fs_component *ctf_fs,
+               const char *trace_path)
+{
+       struct ctf_fs_file *file = ctf_fs_file_create(ctf_fs);
+
+       if (!file) {
+               goto error;
+       }
+
+       g_string_append(file->path, trace_path);
+       g_string_append(file->path, "/" CTF_FS_METADATA_FILENAME);
+
+       if (ctf_fs_file_open(ctf_fs, file, "rb")) {
+               goto error;
+       }
+
+       goto end;
+
+error:
+       if (file) {
+               ctf_fs_file_destroy(file);
+               file = NULL;
+       }
+
+end:
+       return file;
+}
+
+static
+bool is_packetized(struct ctf_fs_component *ctf_fs, struct ctf_fs_file *file)
+{
+       uint32_t magic;
+       size_t len;
+       int ret = 0;
+
+       len = fread(&magic, sizeof(magic), 1, file->fp);
+       if (len != 1) {
+               goto end;
+       }
+
+       if (magic == TSDL_MAGIC) {
+               ret = 1;
+               ctf_fs->metadata.bo = BYTE_ORDER;
+       } else if (magic == GUINT32_SWAP_LE_BE(TSDL_MAGIC)) {
+               ret = 1;
+               ctf_fs->metadata.bo = BYTE_ORDER == BIG_ENDIAN ?
+                       LITTLE_ENDIAN : BIG_ENDIAN;
+       }
+
+end:
+       rewind(file->fp);
+
+       return ret;
+}
+
+static
+bool is_version_valid(unsigned int major, unsigned int minor)
+{
+       return major == 1 && minor == 8;
+}
+
+static
+int decode_packet(struct ctf_fs_component *ctf_fs, FILE *in_fp, FILE *out_fp)
+{
+       struct packet_header header;
+       size_t readlen, writelen, toread;
+       uint8_t buf[512 + 1];   /* + 1 for debug-mode \0 */
+       int ret = 0;
+
+       readlen = fread(&header, sizeof(header), 1, in_fp);
+       if (feof(in_fp) != 0) {
+               goto end;
+       }
+       if (readlen < 1) {
+               goto error;
+       }
+
+       if (ctf_fs->metadata.bo != BYTE_ORDER) {
+               header.magic = GUINT32_SWAP_LE_BE(header.magic);
+               header.checksum = GUINT32_SWAP_LE_BE(header.checksum);
+               header.content_size = GUINT32_SWAP_LE_BE(header.content_size);
+               header.packet_size = GUINT32_SWAP_LE_BE(header.packet_size);
+       }
+
+       if (header.compression_scheme) {
+               PERR("Metadata packet compression not supported yet\n");
+               goto error;
+       }
+
+       if (header.encryption_scheme) {
+               PERR("Metadata packet encryption not supported yet\n");
+               goto error;
+       }
+
+       if (header.checksum || header.checksum_scheme) {
+               PERR("Metadata packet checksum verification not supported yet\n");
+               goto error;
+       }
+
+       if (!is_version_valid(header.major, header.minor)) {
+               PERR("Invalid metadata version: %u.%u\n", header.major,
+                       header.minor);
+               goto error;
+       }
+
+       /* Set expected trace UUID if not set; otherwise validate it */
+       if (!ctf_fs->metadata.is_uuid_set) {
+               memcpy(ctf_fs->metadata.uuid, header.uuid, sizeof(header.uuid));
+               ctf_fs->metadata.is_uuid_set = true;
+       } else if (bt_uuid_compare(header.uuid, ctf_fs->metadata.uuid)) {
+               PERR("Metadata UUID mismatch between packets of the same file\n");
+               goto error;
+       }
+
+       if ((header.content_size / CHAR_BIT) < sizeof(header)) {
+               PERR("Bad metadata packet content size: %u\n",
+                       header.content_size);
+               goto error;
+       }
+
+       toread = header.content_size / CHAR_BIT - sizeof(header);
+
+       for (;;) {
+               readlen = fread(buf, sizeof(uint8_t),
+                       MIN(sizeof(buf) - 1, toread), in_fp);
+               if (ferror(in_fp)) {
+                       PERR("Cannot read metadata packet buffer (at position %ld)\n",
+                               ftell(in_fp));
+                       goto error;
+               }
+
+               writelen = fwrite(buf, sizeof(uint8_t), readlen, out_fp);
+               if (writelen < readlen || ferror(out_fp)) {
+                       PERR("Cannot write decoded metadata text to buffer\n");
+                       goto error;
+               }
+
+               toread -= readlen;
+               if (toread == 0) {
+                       int fseek_ret;
+
+                       /* Read leftover padding */
+                       toread = (header.packet_size - header.content_size) /
+                               CHAR_BIT;
+                       fseek_ret = fseek(in_fp, toread, SEEK_CUR);
+                       if (fseek_ret < 0) {
+                               PWARN("Missing padding at the end of the metadata file\n");
+                       }
+
+                       break;
+               }
+       }
+
+       goto end;
+
+error:
+       ret = -1;
+
+end:
+       return ret;
+}
+
+static
+int packetized_file_to_buf(struct ctf_fs_component *ctf_fs, struct ctf_fs_file *file,
+               uint8_t **buf)
+{
+       FILE *out_fp;
+       size_t size;
+       int ret = 0;
+       int tret;
+       size_t packet_index = 0;
+
+       out_fp = babeltrace_open_memstream((char **) buf, &size);
+       if (out_fp == NULL) {
+               PERR("Cannot open memory stream: %s\n", strerror(errno));
+               goto error;
+       }
+
+       for (;;) {
+               if (feof(file->fp) != 0) {
+                       break;
+               }
+
+               tret = decode_packet(ctf_fs, file->fp, out_fp);
+               if (tret) {
+                       PERR("Cannot decode packet #%zu\n", packet_index);
+                       goto error;
+               }
+
+               packet_index++;
+       }
+
+       /* Make sure the whole string ends with a null character */
+       tret = fputc('\0', out_fp);
+       if (tret == EOF) {
+               PERR("Cannot append '\\0' to the decoded metadata buffer\n");
+               goto error;
+       }
+
+       /* Close stream, which also flushes the buffer */
+       ret = babeltrace_close_memstream((char **) buf, &size, out_fp);
+       if (ret < 0) {
+               PERR("Cannot close memory stream: %s\n", strerror(errno));
+               goto error;
+       }
+
+       goto end;
+
+error:
+       ret = -1;
+
+       if (out_fp) {
+               babeltrace_close_memstream((char **) buf, &size, out_fp);
+       }
+
+       if (*buf) {
+               free(*buf);
+       }
+
+end:
+       return ret;
+}
+
+void ctf_fs_metadata_set_trace(struct ctf_fs_component *ctf_fs)
+{
+       int ret = 0;
+       struct ctf_fs_file *file = get_file(ctf_fs, ctf_fs->trace_path->str);
+       struct ctf_scanner *scanner = NULL;
+       uint8_t *buf = NULL;
+       char *cbuf;
+
+       if (!file) {
+               PERR("Cannot create metadata file object\n");
+               goto error;
+       }
+
+       if (babeltrace_debug) {
+               // yydebug = 1;
+       }
+
+       if (is_packetized(ctf_fs, file)) {
+               PDBG("Metadata file \"%s\" is packetized\n", file->path->str);
+               ret = packetized_file_to_buf(ctf_fs, file, &buf);
+               if (ret) {
+                       // log: details
+                       goto error;
+               }
+
+               cbuf = (char *) buf;
+               ctf_fs->metadata.text = (char *) cbuf;
+
+               /* Convert the real file pointer to a memory file pointer */
+               ret = fclose(file->fp);
+               file->fp = NULL;
+               if (ret) {
+                       PERR("Cannot close file \"%s\": %s\n", file->path->str,
+                               strerror(errno));
+                       goto error;
+               }
+
+               file->fp = babeltrace_fmemopen(cbuf, strlen(cbuf), "rb");
+               if (!file->fp) {
+                       PERR("Cannot memory-open metadata buffer: %s\n",
+                               strerror(errno));
+                       goto error;
+               }
+       } else {
+               unsigned int major, minor;
+               ssize_t nr_items;
+
+               PDBG("Metadata file \"%s\" is plain text\n", file->path->str);
+
+               /* Check text-only metadata header and version */
+               nr_items = fscanf(file->fp, "/* CTF %10u.%10u", &major, &minor);
+               if (nr_items < 2) {
+                       PWARN("Ill-shapen or missing \"/* CTF major.minor\" header in plain text metadata file\n");
+               }
+               PDBG("Metadata version: %u.%u\n", major, minor);
+
+               if (!is_version_valid(major, minor)) {
+                       PERR("Invalid metadata version: %u.%u\n", major, minor);
+                       goto error;
+               }
+
+               rewind(file->fp);
+       }
+
+       /* Allocate a scanner and append the metadata text content */
+       scanner = ctf_scanner_alloc();
+       if (!scanner) {
+               PERR("Cannot allocate a metadata lexical scanner\n");
+               goto error;
+       }
+
+       ret = ctf_scanner_append_ast(scanner, file->fp);
+       if (ret) {
+               PERR("Cannot create the metadata AST\n");
+               goto error;
+       }
+
+       ret = ctf_visitor_semantic_check(stderr, 0, &scanner->ast->root);
+       if (ret) {
+               PERR("Metadata semantic validation failed\n");
+               goto error;
+       }
+
+       ret = ctf_visitor_generate_ir(ctf_fs->error_fp, &scanner->ast->root,
+               &ctf_fs->metadata.trace);
+       if (ret) {
+               PERR("Cannot create trace object from metadata AST\n");
+               goto error;
+       }
+
+       goto end;
+
+error:
+       if (ctf_fs->metadata.text) {
+               free(ctf_fs->metadata.text);
+               ctf_fs->metadata.text = NULL;
+       }
+
+end:
+       if (file) {
+               ctf_fs_file_destroy(file);
+       }
+
+       if (scanner) {
+               ctf_scanner_free(scanner);
+       }
+}
+
+int ctf_fs_metadata_init(struct ctf_fs_metadata *metadata)
+{
+       /* Nothing to initialize for the moment */
+       return 0;
+}
+
+void ctf_fs_metadata_deinit(struct ctf_fs_metadata *metadata)
+{
+       if (metadata->text) {
+               free(metadata->text);
+       }
+
+       if (metadata->trace) {
+               BT_PUT(metadata->trace);
+       }
+}
diff --git a/plugins/ctf/fs/metadata.h b/plugins/ctf/fs/metadata.h
new file mode 100644 (file)
index 0000000..eeccf84
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef CTF_FS_METADATA_H
+#define CTF_FS_METADATA_H
+
+/*
+ * Copyright 2016 - Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <glib.h>
+#include <babeltrace/babeltrace-internal.h>
+#include <babeltrace/ctf-ir/trace.h>
+#include "fs.h"
+
+#define CTF_FS_METADATA_FILENAME       "metadata"
+
+BT_HIDDEN
+int ctf_fs_metadata_init(struct ctf_fs_metadata *metadata);
+
+BT_HIDDEN
+void ctf_fs_metadata_deinit(struct ctf_fs_metadata *metadata);
+
+BT_HIDDEN
+void ctf_fs_metadata_set_trace(struct ctf_fs_component *ctf_fs);
+
+#endif /* CTF_FS_METADATA_H */
diff --git a/plugins/ctf/fs/print.h b/plugins/ctf/fs/print.h
new file mode 100644 (file)
index 0000000..9daf7ea
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef CTF_FS_PRINT_H
+#define CTF_FS_PRINT_H
+
+/*
+ * Define PRINT_PREFIX and PRINT_ERR_STREAM, then include this file.
+ *
+ * Copyright (c) 2016 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+
+#define PERR(fmt, ...)                                                 \
+       do {                                                            \
+               if (PRINT_ERR_STREAM) {                                 \
+                       fprintf(PRINT_ERR_STREAM,                       \
+                               "Error: " PRINT_PREFIX ": " fmt,        \
+                               ##__VA_ARGS__);                         \
+               }                                                       \
+       } while (0)
+
+#define PWARN(fmt, ...)                                                        \
+       do {                                                            \
+               if (PRINT_ERR_STREAM) {                                 \
+                       fprintf(PRINT_ERR_STREAM,                       \
+                               "Warning: " PRINT_PREFIX ": " fmt,      \
+                               ##__VA_ARGS__);                         \
+               }                                                       \
+       } while (0)
+
+#define PDBG(fmt, ...)                                                 \
+       do {                                                            \
+               if (ctf_fs_debug) {                                     \
+                       fprintf(stderr,                                 \
+                               "Debug: " PRINT_PREFIX ": " fmt,        \
+                               ##__VA_ARGS__);                         \
+               }                                                       \
+       } while (0)
+
+#endif /* CTF_FS_PRINT_H */
index ef6ed2fd9c42f3fac3adb39fc463d22ee7a67ae4..f84f9ce04ce30e8bcba67a593a5775a2be92420f 100644 (file)
  */
 
 #include <babeltrace/plugin/plugin-macros.h>
-#include "fs/fs-internal.h"
+#include "fs/fs.h"
 #include "lttng-live/lttng-live-internal.h"
 
-/* Initialize plug-in entry points. */
+/* Initialize plug-in description. */
 BT_PLUGIN_NAME("ctf");
-BT_PLUGIN_DESCRIPTION("Babeltrace CTF plug-in.");
+BT_PLUGIN_DESCRIPTION("Built-in Babeltrace plug-in providing CTF read support.");
 BT_PLUGIN_AUTHOR("Jérémie Galarneau");
 BT_PLUGIN_LICENSE("MIT");
 
+/* Declare component classes implemented by this plug-in. */
 BT_PLUGIN_COMPONENT_CLASSES_BEGIN
 BT_PLUGIN_SOURCE_COMPONENT_CLASS_ENTRY(CTF_FS_COMPONENT_NAME,
                CTF_FS_COMPONENT_DESCRIPTION, ctf_fs_init);
 BT_PLUGIN_SOURCE_COMPONENT_CLASS_ENTRY(LTTNG_LIVE_COMPONENT_NAME,
                LTTNG_LIVE_COMPONENT_DESCRIPTION, lttng_live_init);
 BT_PLUGIN_COMPONENT_CLASSES_END
-
index a269fe160742c1cfa49a435a258f50c662f365ee..9a31041e0d0e2746de86ab29d871df7e8d92110c 100644 (file)
@@ -155,7 +155,7 @@ error:
 }
 
 /* Initialize plug-in entry points. */
-BT_PLUGIN_NAME("ctf-text");
+BT_PLUGIN_NAME("text");
 BT_PLUGIN_DESCRIPTION("Babeltrace text output plug-in.");
 BT_PLUGIN_AUTHOR("Jérémie Galarneau");
 BT_PLUGIN_LICENSE("MIT");
This page took 0.054894 seconds and 4 git commands to generate.