Add unit test validating seeking to last event of a trace
[babeltrace.git] / formats / ctf / ctf.c
index 786ba6fb120a9758570e74b1a0aa2ee50df06a4c..752b548e766d37bc60cf3fc21215f10eb894fc55 100644 (file)
@@ -33,7 +33,7 @@
 #include <babeltrace/ctf/events-internal.h>
 #include <babeltrace/trace-handle-internal.h>
 #include <babeltrace/context-internal.h>
-#include <babeltrace/uuid.h>
+#include <babeltrace/compat/uuid.h>
 #include <babeltrace/endian.h>
 #include <inttypes.h>
 #include <stdio.h>
@@ -51,7 +51,7 @@
 #include "metadata/ctf-parser.h"
 #include "metadata/ctf-ast.h"
 #include "events-private.h"
-#include "memstream.h"
+#include <babeltrace/compat/memstream.h>
 
 #define LOG2_CHAR_BIT  3
 
@@ -77,6 +77,7 @@ int opt_clock_cycles,
        opt_clock_gmt;
 
 uint64_t opt_clock_offset;
+uint64_t opt_clock_offset_ns;
 
 extern int yydebug;
 
@@ -321,6 +322,9 @@ void ctf_print_timestamp_real(FILE *fp,
 
        ts_nsec = timestamp;
 
+       /* Add command-line offset in ns*/
+        ts_nsec += opt_clock_offset_ns;
+
        /* Add command-line offset */
        ts_sec += opt_clock_offset;
 
@@ -426,9 +430,9 @@ void ctf_print_discarded(FILE *fp, struct ctf_stream_definition *stream,
        }
        fprintf(fp, "] in trace UUID ");
        print_uuid(fp, stream->stream_class->trace->uuid);
-       if (stream->stream_class->trace->path[0])
+       if (stream->stream_class->trace->parent.path[0])
                fprintf(fp, ", at path: \"%s\"",
-                       stream->stream_class->trace->path);
+                       stream->stream_class->trace->parent.path);
 
        fprintf(fp, ", within stream id %" PRIu64, stream->stream_id);
        if (stream->path[0])
@@ -606,7 +610,8 @@ error:
        return ret;
 }
 
-int ctf_init_pos(struct ctf_stream_pos *pos, int fd, int open_flags)
+int ctf_init_pos(struct ctf_stream_pos *pos, struct bt_trace_descriptor *trace,
+               int fd, int open_flags)
 {
        pos->fd = fd;
        if (fd >= 0) {
@@ -624,12 +629,14 @@ int ctf_init_pos(struct ctf_stream_pos *pos, int fd, int open_flags)
                pos->flags = MAP_PRIVATE;
                pos->parent.rw_table = read_dispatch_table;
                pos->parent.event_cb = ctf_read_event;
+               pos->parent.trace = trace;
                break;
        case O_RDWR:
                pos->prot = PROT_WRITE; /* Write has priority */
                pos->flags = MAP_SHARED;
                pos->parent.rw_table = write_dispatch_table;
                pos->parent.event_cb = ctf_write_event;
+               pos->parent.trace = trace;
                if (fd >= 0)
                        ctf_packet_seek(&pos->parent, 0, SEEK_SET);     /* position for write */
                break;
@@ -675,6 +682,14 @@ void ctf_packet_seek(struct bt_stream_pos *stream_pos, size_t index, int whence)
        off_t off;
        struct packet_index *packet_index;
 
+       switch (whence) {
+       case SEEK_CUR:
+       case SEEK_SET:  /* Fall-through */
+               break;  /* OK */
+       default:
+               assert(0);
+       }
+
        if (pos->prot == PROT_WRITE && pos->content_size_loc)
                *pos->content_size_loc = pos->offset;
 
@@ -722,6 +737,9 @@ void ctf_packet_seek(struct bt_stream_pos *stream_pos, size_t index, int whence)
                        if (pos->offset == EOF) {
                                return;
                        }
+                       assert(pos->cur_index < pos->packet_cycles_index->len);
+                       assert(pos->cur_index < pos->packet_real_index->len);
+
                        /* For printing discarded event count */
                        packet_index = &g_array_index(pos->packet_cycles_index,
                                        struct packet_index, pos->cur_index);
@@ -759,6 +777,10 @@ void ctf_packet_seek(struct bt_stream_pos *stream_pos, size_t index, int whence)
                        break;
                }
                case SEEK_SET:
+                       if (index >= pos->packet_cycles_index->len) {
+                               pos->offset = EOF;
+                               return;
+                       }
                        packet_index = &g_array_index(pos->packet_cycles_index,
                                        struct packet_index, index);
                        pos->last_events_discarded = packet_index->events_discarded;
@@ -778,7 +800,7 @@ void ctf_packet_seek(struct bt_stream_pos *stream_pos, size_t index, int whence)
                         * case, the collection is not there, so we
                         * cannot print the timestamps.
                         */
-                       if ((&file_stream->parent)->stream_class->trace->collection) {
+                       if ((&file_stream->parent)->stream_class->trace->parent.collection) {
                                /*
                                 * When a stream reaches the end of the
                                 * file, we need to show the number of
@@ -1037,7 +1059,7 @@ int ctf_open_trace_metadata_stream_read(struct ctf_trace *td, FILE **fp,
        buflen = strlen(*buf);
        if (!buflen) {
                *fp = NULL;
-               return -ENODATA;
+               return -ENOENT;
        }
        *fp = babeltrace_fmemopen(*buf, buflen, "rb");
        if (!*fp) {
@@ -1211,6 +1233,8 @@ error:
                bt_definition_unref(&stream_event->event_fields->p);
        if (stream_event->event_context)
                bt_definition_unref(&stream_event->event_context->p);
+       fprintf(stderr, "[error] Unable to create event definition for event \"%s\".\n",
+               g_quark_to_string(event->name));
        return NULL;
 }
 
@@ -1271,8 +1295,10 @@ int create_stream_definitions(struct ctf_trace *td, struct ctf_stream_definition
                if (!event)
                        continue;
                stream_event = create_event_definitions(td, stream, event);
-               if (!stream_event)
+               if (!stream_event) {
+                       ret = -EINVAL;
                        goto error_event;
+               }
                g_ptr_array_index(stream->events_by_id, i) = stream_event;
        }
        return 0;
@@ -1291,9 +1317,36 @@ error:
                bt_definition_unref(&stream->stream_event_header->p);
        if (stream->stream_packet_context)
                bt_definition_unref(&stream->stream_packet_context->p);
+       fprintf(stderr, "[error] Unable to create stream (%" PRIu64 ") definitions: %s\n",
+               stream_class->stream_id, strerror(-ret));
        return ret;
 }
 
+static
+int stream_assign_class(struct ctf_trace *td,
+               struct ctf_file_stream *file_stream,
+               uint64_t stream_id)
+{
+       struct ctf_stream_declaration *stream;
+       int ret;
+
+       file_stream->parent.stream_id = stream_id;
+       if (stream_id >= td->streams->len) {
+               fprintf(stderr, "[error] Stream %" PRIu64 " is not declared in metadata.\n", stream_id);
+               return -EINVAL;
+       }
+       stream = g_ptr_array_index(td->streams, stream_id);
+       if (!stream) {
+               fprintf(stderr, "[error] Stream %" PRIu64 " is not declared in metadata.\n", stream_id);
+               return -EINVAL;
+       }
+       file_stream->parent.stream_class = stream;
+       ret = create_stream_definitions(td, &file_stream->parent);
+       if (ret)
+               return ret;
+       return 0;
+}
+
 static
 int create_stream_one_packet_index(struct ctf_stream_pos *pos,
                        struct ctf_trace *td,
@@ -1301,11 +1354,10 @@ int create_stream_one_packet_index(struct ctf_stream_pos *pos,
                        size_t filesize)
 {
        struct packet_index packet_index;
-       struct ctf_stream_declaration *stream;
-       int len_index;
        uint64_t stream_id = 0;
+       uint64_t packet_map_len = DEFAULT_HEADER_LEN, tmp_map_len;
        int first_packet = 0;
-       size_t packet_map_len = DEFAULT_HEADER_LEN, tmp_map_len;
+       int len_index;
        int ret;
 
 begin:
@@ -1354,6 +1406,7 @@ begin:
                if (ret) {
                        if (ret == -EFAULT)
                                goto retry;
+                       fprintf(stderr, "[error] Unable to read packet header: %s\n", strerror(-ret));
                        return ret;
                }
                len_index = bt_struct_declaration_lookup_field_index(file_stream->parent.trace_packet_header->declaration, g_quark_from_static_string("magic"));
@@ -1414,18 +1467,7 @@ begin:
                return -EINVAL;
        }
        if (first_packet) {
-               file_stream->parent.stream_id = stream_id;
-               if (stream_id >= td->streams->len) {
-                       fprintf(stderr, "[error] Stream %" PRIu64 " is not declared in metadata.\n", stream_id);
-                       return -EINVAL;
-               }
-               stream = g_ptr_array_index(td->streams, stream_id);
-               if (!stream) {
-                       fprintf(stderr, "[error] Stream %" PRIu64 " is not declared in metadata.\n", stream_id);
-                       return -EINVAL;
-               }
-               file_stream->parent.stream_class = stream;
-               ret = create_stream_definitions(td, &file_stream->parent);
+               ret = stream_assign_class(td, file_stream, stream_id);
                if (ret)
                        return ret;
        }
@@ -1436,6 +1478,7 @@ begin:
                if (ret) {
                        if (ret == -EFAULT)
                                goto retry;
+                       fprintf(stderr, "[error] Unable to read packet context: %s\n", strerror(-ret));
                        return ret;
                }
                /* read content size from header */
@@ -1469,7 +1512,7 @@ begin:
 
                        field = bt_struct_definition_get_field_from_index(file_stream->parent.stream_packet_context, len_index);
                        packet_index.timestamp_begin = bt_get_unsigned_int(field);
-                       if (file_stream->parent.stream_class->trace->collection) {
+                       if (file_stream->parent.stream_class->trace->parent.collection) {
                                packet_index.timestamp_begin =
                                        ctf_get_real_timestamp(
                                                &file_stream->parent,
@@ -1484,7 +1527,7 @@ begin:
 
                        field = bt_struct_definition_get_field_from_index(file_stream->parent.stream_packet_context, len_index);
                        packet_index.timestamp_end = bt_get_unsigned_int(field);
-                       if (file_stream->parent.stream_class->trace->collection) {
+                       if (file_stream->parent.stream_class->trace->parent.collection) {
                                packet_index.timestamp_end =
                                        ctf_get_real_timestamp(
                                                &file_stream->parent,
@@ -1544,6 +1587,7 @@ retry:
        tmp_map_len = packet_map_len << 1;
        if (tmp_map_len >> 1 != packet_map_len) {
                /* Overflow */
+               fprintf(stderr, "[error] Packet mapping length overflow\n");
                return -EFAULT;
        }
        packet_map_len = tmp_map_len;
@@ -1564,6 +1608,30 @@ int create_stream_packet_index(struct ctf_trace *td,
        if (ret < 0)
                return ret;
 
+       /* Deal with empty files */
+       if (!filestats.st_size) {
+               if (file_stream->parent.trace_packet_header
+                               || file_stream->parent.stream_packet_context) {
+                       /*
+                        * We expect a trace packet header and/or stream packet
+                        * context. Since a trace needs to have at least one
+                        * packet, empty files are therefore not accepted.
+                        */
+                       fprintf(stderr, "[error] Encountered an empty file, but expecting a trace packet header.\n");
+                       return -EINVAL;
+               } else {
+                       /*
+                        * Without trace packet header nor stream packet
+                        * context, a one-packet trace can indeed be empty. This
+                        * is only valid if there is only one stream class: 0.
+                        */
+                       ret = stream_assign_class(td, file_stream, 0);
+                       if (ret)
+                               return ret;
+                       return 0;
+               }
+       }
+
        for (pos->mmap_offset = 0; pos->mmap_offset < filestats.st_size; ) {
                ret = create_stream_one_packet_index(pos, td, file_stream,
                        filestats.st_size);
@@ -1594,6 +1662,7 @@ int create_trace_definitions(struct ctf_trace *td, struct ctf_stream_definition
        return 0;
 
 error:
+       fprintf(stderr, "[error] Unable to create trace definitions: %s\n", strerror(-ret));
        return ret;
 }
 
@@ -1643,7 +1712,7 @@ int ctf_open_file_stream_read(struct ctf_trace *td, const char *path, int flags,
                goto error_def;
        }
 
-       ret = ctf_init_pos(&file_stream->pos, fd, flags);
+       ret = ctf_init_pos(&file_stream->pos, &td->parent, fd, flags);
        if (ret)
                goto error_def;
        ret = create_trace_definitions(td, &file_stream->parent);
@@ -1652,10 +1721,12 @@ int ctf_open_file_stream_read(struct ctf_trace *td, const char *path, int flags,
        /*
         * For now, only a single clock per trace is supported.
         */
-       file_stream->parent.current_clock = td->single_clock;
+       file_stream->parent.current_clock = td->parent.single_clock;
        ret = create_stream_packet_index(td, file_stream);
-       if (ret)
+       if (ret) {
+               fprintf(stderr, "[error] Stream index creation error.\n");
                goto error_index;
+       }
        /* Add stream file to stream class */
        g_ptr_array_add(file_stream->parent.stream_class->streams,
                        &file_stream->parent);
@@ -1708,8 +1779,8 @@ int ctf_open_trace_read(struct ctf_trace *td,
                ret = -errno;
                goto error_dirfd;
        }
-       strncpy(td->path, path, sizeof(td->path));
-       td->path[sizeof(td->path) - 1] = '\0';
+       strncpy(td->parent.path, path, sizeof(td->parent.path));
+       td->parent.path[sizeof(td->parent.path) - 1] = '\0';
 
        /*
         * Keep the metadata file separate.
@@ -1893,7 +1964,7 @@ int ctf_open_mmap_stream_read(struct ctf_trace *td,
        /*
         * For now, only a single clock per trace is supported.
         */
-       file_stream->parent.current_clock = td->single_clock;
+       file_stream->parent.current_clock = td->parent.single_clock;
 
        /* Add stream file to stream class */
        g_ptr_array_add(file_stream->parent.stream_class->streams,
@@ -2090,7 +2161,7 @@ void ctf_set_context(struct bt_trace_descriptor *descriptor,
        struct ctf_trace *td = container_of(descriptor, struct ctf_trace,
                        parent);
 
-       td->ctx = ctx;
+       td->parent.ctx = ctx;
 }
 
 static
@@ -2100,7 +2171,7 @@ void ctf_set_handle(struct bt_trace_descriptor *descriptor,
        struct ctf_trace *td = container_of(descriptor, struct ctf_trace,
                        parent);
 
-       td->handle = handle;
+       td->parent.handle = handle;
 }
 
 static
This page took 0.028271 seconds and 4 git commands to generate.