+ if (!iter_pos)
+ return;
+
+ if (iter_pos->type == BT_SEEK_RESTORE && iter_pos->u.restore) {
+ if (iter_pos->u.restore->stream_saved_pos) {
+ g_array_free(
+ iter_pos->u.restore->stream_saved_pos,
+ TRUE);
+ }
+ g_free(iter_pos->u.restore);
+ }
+ g_free(iter_pos);
+}
+
+/*
+ * seek_file_stream_by_timestamp
+ *
+ * Browse a filestream by index, if an index contains the timestamp passed in
+ * argument, seek inside the corresponding packet it until we find the event we
+ * are looking for (either the exact timestamp or the event just after the
+ * timestamp).
+ *
+ * Return 0 if the seek succeded, EOF if we didn't find any packet
+ * containing the timestamp, or a positive integer for error.
+ *
+ * TODO: this should be turned into a binary search! It is currently
+ * doing a linear search in the packets. This is a O(n) operation on a
+ * very frequent code path.
+ */
+static int seek_file_stream_by_timestamp(struct ctf_file_stream *cfs,
+ uint64_t timestamp)
+{
+ struct ctf_stream_pos *stream_pos;
+ struct packet_index *index;
+ int i, ret;
+
+ stream_pos = &cfs->pos;
+ for (i = 0; i < stream_pos->packet_index->len; i++) {
+ index = &g_array_index(stream_pos->packet_index,
+ struct packet_index, i);
+ if (index->ts_real.timestamp_end < timestamp)
+ continue;
+
+ stream_pos->packet_seek(&stream_pos->parent, i, SEEK_SET);
+ do {
+ ret = stream_read_event(cfs);
+ } while (cfs->parent.real_timestamp < timestamp && ret == 0);
+
+ /* Can return either EOF, 0, or error (> 0). */
+ return ret;
+ }
+ /*
+ * Cannot find the timestamp within the stream packets, return
+ * EOF.
+ */
+ return EOF;
+}
+
+/*
+ * seek_ctf_trace_by_timestamp : for each file stream, seek to the event with
+ * the corresponding timestamp
+ *
+ * Return 0 on success.
+ * If the timestamp is not part of any file stream, return EOF to inform the
+ * user the timestamp is out of the scope.
+ * On other errors, return positive value.
+ */
+static int seek_ctf_trace_by_timestamp(struct ctf_trace *tin,
+ uint64_t timestamp, struct ptr_heap *stream_heap)
+{
+ int i, j, ret;
+ int found = 0;
+ struct bt_trace_descriptor *td = &tin->parent;
+
+ if (td->interval_set) {
+ /*
+ * If this trace has an interval selected, don't allow seeks
+ * before the selected interval. We seek to the start of the
+ * interval, thereby presenting a shorter "virtual" trace.
+ */
+ timestamp = max(timestamp, td->interval_real.timestamp_begin);
+ }
+
+ /* for each stream_class */
+ for (i = 0; i < tin->streams->len; i++) {
+ struct ctf_stream_declaration *stream_class;
+
+ stream_class = g_ptr_array_index(tin->streams, i);
+ if (!stream_class)
+ continue;
+ /* for each file_stream */
+ for (j = 0; j < stream_class->streams->len; j++) {
+ struct ctf_stream_definition *stream;
+ struct ctf_file_stream *cfs;
+
+ stream = g_ptr_array_index(stream_class->streams, j);
+ if (!stream)
+ continue;
+ cfs = container_of(stream, struct ctf_file_stream,
+ parent);
+ ret = seek_file_stream_by_timestamp(cfs, timestamp);
+ if (ret == 0) {
+ /* Add to heap */
+ ret = bt_heap_insert(stream_heap, cfs);
+ if (ret) {
+ /* Return positive error. */
+ return -ret;
+ }
+ found = 1;
+ } else if (ret > 0) {
+ /*
+ * Error in seek (not EOF), failure.
+ */
+ return ret;