]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
journal: Introduce journal_file_data_payload()
authorDaan De Meyer <daan.j.demeyer@gmail.com>
Thu, 29 Sep 2022 10:09:09 +0000 (12:09 +0200)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Fri, 7 Oct 2022 10:28:05 +0000 (12:28 +0200)
journal_file_data_payload() retrieves the payload of a Data object,
optionally decompressing it and checking to see if matches a given
field. This function replaces all the decompression code in the sd-journal
codebase with a single function.

This commit should not introduce any changes in sd-journal behavior.

src/libsystemd/sd-journal/journal-file.c
src/libsystemd/sd-journal/journal-file.h
src/libsystemd/sd-journal/sd-journal.c

index 33a285faa4514a09e2425baf5434927a1625a4ef..67bd2305adb0b5bc10d65c9cdf31511ce0a72fba 100644 (file)
@@ -1369,7 +1369,7 @@ int journal_file_find_data_object_with_hash(
                 const void *data, uint64_t size, uint64_t hash,
                 Object **ret, uint64_t *ret_offset) {
 
-        uint64_t p, osize, h, m, depth = 0;
+        uint64_t p, h, m, depth = 0;
         int r;
 
         assert(f);
@@ -1385,8 +1385,6 @@ int journal_file_find_data_object_with_hash(
         if (r < 0)
                 return r;
 
-        osize = offsetof(Object, data.payload) + size;
-
         m = le64toh(READ_NOW(f->header->data_hash_table_size)) / sizeof(HashItem);
         if (m <= 0)
                 return -EBADMSG;
@@ -1395,8 +1393,9 @@ int journal_file_find_data_object_with_hash(
         p = le64toh(f->data_hash_table[h].head_hash_offset);
 
         while (p > 0) {
-                Compression c;
                 Object *o;
+                void *d;
+                size_t rsize;
 
                 r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
                 if (r < 0)
@@ -1405,42 +1404,13 @@ int journal_file_find_data_object_with_hash(
                 if (le64toh(o->data.hash) != hash)
                         goto next;
 
-                c = COMPRESSION_FROM_OBJECT(o);
-                if (c < 0)
-                        return -EPROTONOSUPPORT;
-                if (c != COMPRESSION_NONE) {
-#if HAVE_COMPRESSION
-                        uint64_t l;
-                        size_t rsize = 0;
-
-                        l = le64toh(READ_NOW(o->object.size));
-                        if (l <= offsetof(Object, data.payload))
-                                return -EBADMSG;
-
-                        l -= offsetof(Object, data.payload);
-
-                        r = decompress_blob(c, o->data.payload, l, &f->compress_buffer, &rsize, 0);
-                        if (r < 0)
-                                return r;
-
-                        if (rsize == size &&
-                            memcmp(f->compress_buffer, data, size) == 0) {
-
-                                if (ret)
-                                        *ret = o;
-
-                                if (ret_offset)
-                                        *ret_offset = p;
-
-                                return 1;
-                        }
-#else
-                        return -EPROTONOSUPPORT;
-#endif
-                } else if (le64toh(o->object.size) == osize &&
-                           memcmp(o->data.payload, data, size) == 0) {
+                r = journal_file_data_payload(f, o, p, NULL, 0, 0, &d, &rsize);
+                if (r < 0)
+                        return r;
+                assert(r > 0); /* journal_file_data_payload() always returns > 0 if no field is provided. */
 
-                        if (ret)
+                if (memcmp_nn(data, size, d, rsize) == 0) {
+                         if (ret)
                                 *ret = o;
 
                         if (ret_offset)
@@ -1658,6 +1628,106 @@ static int journal_file_append_data(
         return 0;
 }
 
+static int maybe_decompress_payload(
+                JournalFile *f,
+                uint8_t *payload,
+                uint64_t size,
+                Compression compression,
+                const char *field,
+                size_t field_length,
+                size_t data_threshold,
+                void **ret_data,
+                size_t *ret_size) {
+
+        /* We can't read objects larger than 4G on a 32bit machine */
+        if ((uint64_t) (size_t) size != size)
+                return -E2BIG;
+
+        if (compression != COMPRESSION_NONE) {
+#if HAVE_COMPRESSION
+                size_t rsize;
+                int r;
+
+                if (field) {
+                        r = decompress_startswith(compression, payload, size, &f->compress_buffer, field,
+                                                  field_length, '=');
+                        if (r < 0)
+                                return log_debug_errno(r,
+                                                       "Cannot decompress %s object of length %" PRIu64 ": %m",
+                                                       compression_to_string(compression),
+                                                       size);
+                        if (r == 0) {
+                                *ret_data = NULL;
+                                *ret_size = 0;
+                                return 0;
+                        }
+                }
+
+                r = decompress_blob(compression, payload, size, &f->compress_buffer, &rsize, 0);
+                if (r < 0)
+                        return r;
+
+                if (ret_data)
+                        *ret_data = f->compress_buffer;
+                if (ret_size)
+                        *ret_size = rsize;
+#else
+                return -EPROTONOSUPPORT;
+#endif
+        } else {
+                if (field && (size < field_length + 1 || memcmp(payload, field, field_length) != 0 || payload[field_length] != '=')) {
+                        *ret_data = NULL;
+                        *ret_size = 0;
+                        return 0;
+                }
+
+                if (ret_data)
+                        *ret_data = payload;
+                if (ret_size)
+                        *ret_size = (size_t) size;
+        }
+
+        return 1;
+}
+
+int journal_file_data_payload(
+                JournalFile *f,
+                Object *o,
+                uint64_t offset,
+                const char *field,
+                size_t field_length,
+                size_t data_threshold,
+                void **ret_data,
+                size_t *ret_size) {
+
+        uint64_t size;
+        Compression c;
+        int r;
+
+        assert(!field == (field_length == 0)); /* These must be specified together. */
+        assert(ret_data);
+        assert(ret_size);
+
+        if (!o) {
+                r = journal_file_move_to_object(f, OBJECT_DATA, offset, &o);
+                if (r < 0)
+                        return r;
+        }
+
+        size = le64toh(READ_NOW(o->object.size));
+        if (size < offsetof(Object, data.payload))
+                return -EBADMSG;
+
+        size -= offsetof(Object, data.payload);
+
+        c = COMPRESSION_FROM_OBJECT(o);
+        if (c < 0)
+                return -EPROTONOSUPPORT;
+
+        return maybe_decompress_payload(f, o->data.payload, size, c, field, field_length, data_threshold,
+                                        ret_data, ret_size);
+}
+
 uint64_t journal_file_entry_n_items(JournalFile *f, Object *o) {
         uint64_t sz;
 
@@ -3807,51 +3877,20 @@ int journal_file_copy_entry(JournalFile *from, JournalFile *to, Object *o, uint6
         items = newa(EntryItem, n);
 
         for (uint64_t i = 0; i < n; i++) {
-                Compression c;
-                uint64_t l, h;
-                size_t t;
+                uint64_t h;
                 void *data;
+                size_t l;
                 Object *u;
 
                 q = journal_file_entry_item_object_offset(from, o, i);
-
-                r = journal_file_move_to_object(from, OBJECT_DATA, q, &o);
+                r = journal_file_data_payload(from, NULL, q, NULL, 0, 0, &data, &l);
+                if (IN_SET(r, -EADDRNOTAVAIL, -EBADMSG)) {
+                        log_debug_errno(r, "Entry item %"PRIu64" data object is bad, skipping over it: %m", i);
+                        continue;
+                }
                 if (r < 0)
                         return r;
-
-                l = le64toh(READ_NOW(o->object.size));
-                if (l < offsetof(Object, data.payload))
-                        return -EBADMSG;
-
-                l -= offsetof(Object, data.payload);
-                t = (size_t) l;
-
-                /* We hit the limit on 32bit machines */
-                if ((uint64_t) t != l)
-                        return -E2BIG;
-
-                c = COMPRESSION_FROM_OBJECT(o);
-                if (c < 0)
-                        return -EPROTONOSUPPORT;
-                if (c != COMPRESSION_NONE) {
-#if HAVE_COMPRESSION
-                        size_t rsize = 0;
-
-                        r = decompress_blob(
-                                        c,
-                                        o->data.payload, l,
-                                        &from->compress_buffer, &rsize,
-                                        0);
-                        if (r < 0)
-                                return r;
-
-                        data = from->compress_buffer;
-                        l = rsize;
-#else
-                        return -EPROTONOSUPPORT;
-#endif
-                } else
-                        data = o->data.payload;
+                assert(r > 0);
 
                 if (l == 0)
                         return -EBADMSG;
@@ -3869,10 +3908,6 @@ int journal_file_copy_entry(JournalFile *from, JournalFile *to, Object *o, uint6
                         .object_offset = h,
                         .hash = le64toh(u->data.hash),
                 };
-
-                r = journal_file_move_to_object(from, OBJECT_ENTRY, p, &o);
-                if (r < 0)
-                        return r;
         }
 
         r = journal_file_append_entry_internal(to, &ts, boot_id, xor_hash, items, n, NULL, NULL, NULL);
index 086b44088839c55f35b496840d526b4b714dd153..79769537937c7753db01419bbaee655ffba0aefe 100644 (file)
@@ -212,6 +212,17 @@ static inline size_t journal_file_entry_item_size(JournalFile *f) {
 }
 
 uint64_t journal_file_entry_n_items(JournalFile *f, Object *o) _pure_;
+
+int journal_file_data_payload(
+                JournalFile *f,
+                Object *o,
+                uint64_t offset,
+                const char *field,
+                size_t field_length,
+                size_t data_threshold,
+                void **ret_data,
+                size_t *ret_size);
+
 uint64_t journal_file_entry_array_n_items(JournalFile *f, Object *o) _pure_;
 
 static inline uint64_t journal_file_entry_array_item(JournalFile *f, Object *o, size_t i) {
index 8c94f02f3e88d99aca72bb6d33f34a36decb8436..5a75994d1594d016e8dcae097cda819b906f5495 100644 (file)
@@ -2289,13 +2289,14 @@ _public_ int sd_journal_get_data(sd_journal *j, const char *field, const void **
 
         uint64_t n = journal_file_entry_n_items(f, o);
         for (uint64_t i = 0; i < n; i++) {
-                Object *d;
-                uint64_t p, l;
-                size_t t;
-                Compression c;
+                uint64_t p;
+                void *d;
+                size_t l;
 
                 p = journal_file_entry_item_object_offset(f, o, i);
-                r = journal_file_move_to_object(f, OBJECT_DATA, p, &d);
+                r = journal_file_data_payload(f, NULL, p, field, field_length, j->data_threshold, &d, &l);
+                if (r == 0)
+                        continue;
                 if (IN_SET(r, -EADDRNOTAVAIL, -EBADMSG)) {
                         log_debug_errno(r, "Entry item %"PRIu64" data object is bad, skipping over it: %m", i);
                         continue;
@@ -2303,117 +2304,15 @@ _public_ int sd_journal_get_data(sd_journal *j, const char *field, const void **
                 if (r < 0)
                         return r;
 
-                l = le64toh(d->object.size) - offsetof(Object, data.payload);
-
-                c = COMPRESSION_FROM_OBJECT(d);
-                if (c < 0)
-                        return -EPROTONOSUPPORT;
-                if (c != COMPRESSION_NONE) {
-#if HAVE_COMPRESSION
-                        r = decompress_startswith(
-                                        c,
-                                        d->data.payload, l,
-                                        &f->compress_buffer,
-                                        field, field_length, '=');
-                        if (r < 0)
-                                log_debug_errno(r, "Cannot decompress %s object of length %"PRIu64" at offset "OFSfmt": %m",
-                                                compression_to_string(c), l, p);
-                        else if (r > 0) {
-
-                                size_t rsize;
-
-                                r = decompress_blob(
-                                                c,
-                                                d->data.payload, l,
-                                                &f->compress_buffer, &rsize,
-                                                j->data_threshold);
-                                if (r < 0)
-                                        return r;
-
-                                *data = f->compress_buffer;
-                                *size = (size_t) rsize;
-
-                                return 0;
-                        }
-#else
-                        return -EPROTONOSUPPORT;
-#endif
-                } else if (l >= field_length+1 &&
-                           memcmp(d->data.payload, field, field_length) == 0 &&
-                           d->data.payload[field_length] == '=') {
-
-                        t = (size_t) l;
-
-                        if ((uint64_t) t != l)
-                                return -E2BIG;
+                *data = d;
+                *size = l;
 
-                        *data = d->data.payload;
-                        *size = t;
-
-                        return 0;
-                }
+                return 0;
         }
 
         return -ENOENT;
 }
 
-static int return_data(
-                sd_journal *j,
-                JournalFile *f,
-                Object *o,
-                const void **ret_data,
-                size_t *ret_size) {
-
-        Compression c;
-        uint64_t l;
-        size_t t;
-
-        assert(j);
-        assert(f);
-
-        l = le64toh(READ_NOW(o->object.size));
-        if (l < offsetof(Object, data.payload))
-                return -EBADMSG;
-        l -= offsetof(Object, data.payload);
-
-        /* We can't read objects larger than 4G on a 32bit machine */
-        t = (size_t) l;
-        if ((uint64_t) t != l)
-                return -E2BIG;
-
-        c = COMPRESSION_FROM_OBJECT(o);
-        if (c < 0)
-                return -EPROTONOSUPPORT;
-        if (c != COMPRESSION_NONE) {
-#if HAVE_COMPRESSION
-                size_t rsize;
-                int r;
-
-                r = decompress_blob(
-                                c,
-                                o->data.payload, l,
-                                &f->compress_buffer, &rsize,
-                                j->data_threshold);
-                if (r < 0)
-                        return r;
-
-                if (ret_data)
-                        *ret_data = f->compress_buffer;
-                if (ret_size)
-                        *ret_size = (size_t) rsize;
-#else
-                return -EPROTONOSUPPORT;
-#endif
-        } else {
-                if (ret_data)
-                        *ret_data = o->data.payload;
-                if (ret_size)
-                        *ret_size = t;
-        }
-
-        return 0;
-}
-
 _public_ int sd_journal_enumerate_data(sd_journal *j, const void **data, size_t *size) {
         JournalFile *f;
         Object *o;
@@ -2437,23 +2336,21 @@ _public_ int sd_journal_enumerate_data(sd_journal *j, const void **data, size_t
 
         for (uint64_t n = journal_file_entry_n_items(f, o); j->current_field < n; j->current_field++) {
                 uint64_t p;
+                void *d;
+                size_t l;
 
                 p = journal_file_entry_item_object_offset(f, o, j->current_field);
-                r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
+                r = journal_file_data_payload(f, NULL, p, NULL, 0, j->data_threshold, &d, &l);
                 if (IN_SET(r, -EADDRNOTAVAIL, -EBADMSG)) {
                         log_debug_errno(r, "Entry item %"PRIu64" data object is bad, skipping over it: %m", j->current_field);
                         continue;
                 }
                 if (r < 0)
                         return r;
+                assert(r > 0);
 
-                r = return_data(j, f, o, data, size);
-                if (r == -EBADMSG) {
-                        log_debug("Entry item %"PRIu64" data payload is bad, skipping over it.", j->current_field);
-                        continue;
-                }
-                if (r < 0)
-                        return r;
+                *data = d;
+                *size = l;
 
                 j->current_field++;
 
@@ -2925,7 +2822,7 @@ _public_ int sd_journal_enumerate_unique(
         for (;;) {
                 JournalFile *of;
                 Object *o;
-                const void *odata;
+                void *odata;
                 size_t ol;
                 bool found;
                 int r;
@@ -2969,7 +2866,8 @@ _public_ int sd_journal_enumerate_unique(
                                                j->unique_offset,
                                                o->object.type, OBJECT_DATA);
 
-                r = return_data(j, j->unique_file, o, &odata, &ol);
+                r = journal_file_data_payload(j->unique_file, o, j->unique_offset, NULL, 0,
+                                              j->data_threshold, &odata, &ol);
                 if (r < 0)
                         return r;
 
@@ -3016,9 +2914,8 @@ _public_ int sd_journal_enumerate_unique(
                 if (found)
                         continue;
 
-                r = return_data(j, j->unique_file, o, ret_data, ret_size);
-                if (r < 0)
-                        return r;
+                *ret_data = odata;
+                *ret_size = ol;
 
                 return 1;
         }