]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph-client.git/commitdiff
des code
authorAlex Markuze <amarkuze@redhat.com>
Wed, 13 Aug 2025 15:02:23 +0000 (15:02 +0000)
committerAlex Markuze <amarkuze@redhat.com>
Wed, 13 Aug 2025 15:02:23 +0000 (15:02 +0000)
lib/blog/blog_des.c

index 3ff84d53d388162cc972c164a78c6afe408fe241..266ec240a4d959cd18787ecbf8e227e77d315bd1 100644 (file)
 // SPDX-License-Identifier: GPL-2.0
 /*
- * Binary Logging Deserialization - Stub Implementation
+ * Binary Logging Deserialization
+ * 
+ * Migrated from ceph_san_des.c with all algorithms preserved
  */
 
-#include <linux/module.h>
-#include <linux/blog/blog.h>
 #include <linux/blog/blog_des.h>
+#include <linux/blog/blog.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/printk.h>
+#include <linux/align.h>
 
 /**
  * blog_des_reconstruct - Reconstructs a formatted string from serialized values
+ * @fmt: Format string containing % specifiers
+ * @buffer: Buffer containing serialized values
+ * @nr_args: Number of arguments to process (not used yet, for future)
+ * @size: Size of the buffer in bytes
+ * @out: Buffer to store the reconstructed string
+ * @out_size: Size of the output buffer
+ *
+ * Return: Number of bytes written to out buffer, or negative error code on failure
  */
 int blog_des_reconstruct(const char *fmt, const void *buffer, size_t nr_args,
                           size_t size, char *out, size_t out_size)
 {
-       /* Stub implementation */
-       if (!fmt || !buffer || !out)
+       const char *buf_start = (const char *)buffer;
+       const char *buf_ptr = buf_start;
+       const char *buf_end = buf_start + size;
+       const char *fmt_ptr = fmt;
+       char *out_ptr = out;
+       size_t remaining = out_size - 1; /* Reserve space for null terminator */
+       size_t arg_count = 0;
+       int ret;
+
+       if (!fmt || !buffer || !out || !out_size) {
+               pr_err("blog_des_reconstruct: invalid parameters\n");
                return -EINVAL;
-       
-       /* For now, just return a placeholder string */
-       return snprintf(out, out_size, "[BLOG stub: fmt=%s]", fmt);
+       }
+
+       *out_ptr = '\0';
+
+       /* Process the format string */
+       while (*fmt_ptr && remaining > 0) {
+               if (*fmt_ptr != '%') {
+                       /* Copy literal character */
+                       *out_ptr++ = *fmt_ptr++;
+                       remaining--;
+                       continue;
+               }
+
+               /* Skip the '%' */
+               fmt_ptr++;
+
+               /* Handle %% */
+               if (*fmt_ptr == '%') {
+                       *out_ptr++ = '%';
+                       fmt_ptr++;
+                       remaining--;
+                       continue;
+               }
+
+               /* Skip flags (-+#0 space) */
+               while (*fmt_ptr && (*fmt_ptr == '-' || *fmt_ptr == '+' || *fmt_ptr == '#' || 
+                                  *fmt_ptr == '0' || *fmt_ptr == ' ')) {
+                       fmt_ptr++;
+               }
+
+               /* Skip field width (digits or *) */
+               while (*fmt_ptr && (*fmt_ptr >= '0' && *fmt_ptr <= '9')) {
+                       fmt_ptr++;
+               }
+               if (*fmt_ptr == '*') {
+                       fmt_ptr++;
+               }
+
+               /* Skip precision (.digits or .*) */
+               if (*fmt_ptr == '.') {
+                       fmt_ptr++;
+                       while (*fmt_ptr && (*fmt_ptr >= '0' && *fmt_ptr <= '9')) {
+                               fmt_ptr++;
+                       }
+                       if (*fmt_ptr == '*') {
+                               fmt_ptr++;
+                       }
+               }
+
+               /* Parse length modifiers (l, ll, h, hh, z) */
+               int is_long = 0;
+               int is_long_long = 0;
+               
+               if (*fmt_ptr == 'l') {
+                       fmt_ptr++;
+                       is_long = 1;
+                       if (*fmt_ptr == 'l') {
+                               fmt_ptr++;
+                               is_long_long = 1;
+                               is_long = 0;
+                       }
+               } else if (*fmt_ptr == 'h') {
+                       fmt_ptr++;
+                       if (*fmt_ptr == 'h') {
+                               fmt_ptr++;
+                       }
+               } else if (*fmt_ptr == 'z') {
+                       fmt_ptr++;
+               }
+
+               /* Parse and handle format specifier */
+               switch (*fmt_ptr) {
+               case 's': { /* String (inline) */
+                       const char *str;
+                       size_t str_len;
+                       size_t max_scan_len;
+
+                       /* Validate we have enough buffer space for at least a null terminator */
+                       if (buf_ptr >= buf_end) {
+                               pr_err("blog_des_reconstruct (%zu): buffer overrun at string argument\n", arg_count);
+                               return -EFAULT;
+                       }
+
+                       /* String is stored inline in buffer */
+                       str = buf_ptr;
+
+                       /* Calculate maximum safe length to scan for null terminator */
+                       max_scan_len = buf_end - buf_ptr;
+
+                       /* Find string length with bounds checking */
+                       str_len = strnlen(str, max_scan_len);
+                       if (str_len == max_scan_len && str[str_len - 1] != '\0') {
+                               pr_err("blog_des_reconstruct (%zu): unterminated string in buffer\n", arg_count);
+                               return -EFAULT;
+                       }
+
+                       /* Advance buffer pointer with proper alignment */
+                       buf_ptr += round_up(str_len + 1, 4);
+
+                       /* Check if buffer advance exceeds entry bounds */
+                       if (buf_ptr > buf_end) {
+                               pr_err("blog_des_reconstruct (%zu): string extends beyond buffer bounds\n", arg_count);
+                               return -EFAULT;
+                       }
+
+                       /* Copy string to output with bounds checking */
+                       if (str_len > remaining)
+                               str_len = remaining;
+                       memcpy(out_ptr, str, str_len);
+                       out_ptr += str_len;
+                       remaining -= str_len;
+                       break;
+               }
+
+               case 'd': case 'i': { /* Integer */
+                       if (is_long_long) {
+                               long long val;
+                               if (buf_ptr + sizeof(long long) > buf_end) {
+                                       pr_err("blog_des_reconstruct (%zu): buffer overrun reading long long\n", arg_count);
+                                       return -EFAULT;
+                               }
+                               val = *(long long *)buf_ptr;
+                               buf_ptr += sizeof(long long);
+                               ret = snprintf(out_ptr, remaining, "%lld", val);
+                       } else if (is_long) {
+                               long val;
+                               if (buf_ptr + sizeof(long) > buf_end) {
+                                       pr_err("blog_des_reconstruct (%zu): buffer overrun reading long\n", arg_count);
+                                       return -EFAULT;
+                               }
+                               val = *(long *)buf_ptr;
+                               buf_ptr += sizeof(long);
+                               ret = snprintf(out_ptr, remaining, "%ld", val);
+                       } else {
+                               int val;
+                               if (buf_ptr + sizeof(int) > buf_end) {
+                                       pr_err("blog_des_reconstruct (%zu): buffer overrun reading int\n", arg_count);
+                                       return -EFAULT;
+                               }
+                               val = *(int *)buf_ptr;
+                               buf_ptr += sizeof(int);
+                               ret = snprintf(out_ptr, remaining, "%d", val);
+                       }
+                       
+                       if (ret > 0) {
+                               if (ret > remaining)
+                                       ret = remaining;
+                               out_ptr += ret;
+                               remaining -= ret;
+                       }
+                       break;
+               }
+
+               case 'u': { /* Unsigned integer */
+                       if (is_long_long) {
+                               unsigned long long val;
+                               if (buf_ptr + sizeof(unsigned long long) > buf_end) {
+                                       pr_err("blog_des_reconstruct (%zu): buffer overrun reading unsigned long long\n", arg_count);
+                                       return -EFAULT;
+                               }
+                               val = *(unsigned long long *)buf_ptr;
+                               buf_ptr += sizeof(unsigned long long);
+                               ret = snprintf(out_ptr, remaining, "%llu", val);
+                       } else if (is_long) {
+                               unsigned long val;
+                               if (buf_ptr + sizeof(unsigned long) > buf_end) {
+                                       pr_err("blog_des_reconstruct (%zu): buffer overrun reading unsigned long\n", arg_count);
+                                       return -EFAULT;
+                               }
+                               val = *(unsigned long *)buf_ptr;
+                               buf_ptr += sizeof(unsigned long);
+                               ret = snprintf(out_ptr, remaining, "%lu", val);
+                       } else {
+                               unsigned int val;
+                               if (buf_ptr + sizeof(unsigned int) > buf_end) {
+                                       pr_err("blog_des_reconstruct (%zu): buffer overrun reading unsigned int\n", arg_count);
+                                       return -EFAULT;
+                               }
+                               val = *(unsigned int *)buf_ptr;
+                               buf_ptr += sizeof(unsigned int);
+                               ret = snprintf(out_ptr, remaining, "%u", val);
+                       }
+                       
+                       if (ret > 0) {
+                               if (ret > remaining)
+                                       ret = remaining;
+                               out_ptr += ret;
+                               remaining -= ret;
+                       }
+                       break;
+               }
+
+               case 'x': case 'X': { /* Hex integer */
+                       const char *hex_fmt;
+                       if (*fmt_ptr == 'x')
+                               hex_fmt = is_long_long ? "%llx" : is_long ? "%lx" : "%x";
+                       else
+                               hex_fmt = is_long_long ? "%llX" : is_long ? "%lX" : "%X";
+
+                       if (is_long_long) {
+                               unsigned long long val;
+                               if (buf_ptr + sizeof(unsigned long long) > buf_end) {
+                                       pr_err("blog_des_reconstruct (%zu): buffer overrun reading unsigned long long\n", arg_count);
+                                       return -EFAULT;
+                               }
+                               val = *(unsigned long long *)buf_ptr;
+                               buf_ptr += sizeof(unsigned long long);
+                               ret = snprintf(out_ptr, remaining, hex_fmt, val);
+                       } else if (is_long) {
+                               unsigned long val;
+                               if (buf_ptr + sizeof(unsigned long) > buf_end) {
+                                       pr_err("blog_des_reconstruct (%zu): buffer overrun reading unsigned long\n", arg_count);
+                                       return -EFAULT;
+                               }
+                               val = *(unsigned long *)buf_ptr;
+                               buf_ptr += sizeof(unsigned long);
+                               ret = snprintf(out_ptr, remaining, hex_fmt, val);
+                       } else {
+                               unsigned int val;
+                               if (buf_ptr + sizeof(unsigned int) > buf_end) {
+                                       pr_err("blog_des_reconstruct (%zu): buffer overrun reading unsigned int\n", arg_count);
+                                       return -EFAULT;
+                               }
+                               val = *(unsigned int *)buf_ptr;
+                               buf_ptr += sizeof(unsigned int);
+                               ret = snprintf(out_ptr, remaining, hex_fmt, val);
+                       }
+                       
+                       if (ret > 0) {
+                               if (ret > remaining)
+                                       ret = remaining;
+                               out_ptr += ret;
+                               remaining -= ret;
+                       }
+                       break;
+               }
+
+               case 'p': { /* Pointer */
+                       void *ptr;
+                       
+                       /* Check buffer bounds before reading */
+                       if (buf_ptr + sizeof(void *) > buf_end) {
+                               pr_err("blog_des_reconstruct (%zu): buffer overrun reading pointer\n", arg_count);
+                               return -EFAULT;
+                       }
+
+                       ptr = *(void **)buf_ptr;
+                       buf_ptr += sizeof(void *);
+
+                       ret = snprintf(out_ptr, remaining, "%p", ptr);
+                       if (ret > 0) {
+                               if (ret > remaining)
+                                       ret = remaining;
+                               out_ptr += ret;
+                               remaining -= ret;
+                       }
+                       break;
+               }
+
+               case 'c': { /* Character */
+                       char val;
+                       
+                       /* Check buffer bounds before reading */
+                       if (buf_ptr + sizeof(int) > buf_end) { /* chars are promoted to int */
+                               pr_err("blog_des_reconstruct (%zu): buffer overrun reading char\n", arg_count);
+                               return -EFAULT;
+                       }
+
+                       val = (char)(*(int *)buf_ptr);
+                       buf_ptr += sizeof(int);
+
+                       if (remaining > 0) {
+                               *out_ptr++ = val;
+                               remaining--;
+                       }
+                       break;
+               }
+
+               default:
+                       pr_err("blog_des_reconstruct (%zu): unsupported format specifier '%%%c'\n", 
+                              arg_count, *fmt_ptr);
+                       return -EINVAL;
+               }
+
+               fmt_ptr++;
+               arg_count++;
+       }
+
+       /* Null-terminate the output */
+       *out_ptr = '\0';
+
+       return out_ptr - out;
 }
 EXPORT_SYMBOL(blog_des_reconstruct);
 
 /**
  * blog_log_reconstruct - Reconstructs a formatted string from a log entry
+ * @entry: Log entry containing serialized data
+ * @output: Buffer to write the formatted string to
+ * @output_size: Size of the output buffer
+ *
+ * This reconstructs the log message but does NOT handle client_id.
+ * The caller should handle client_id separately using their module-specific callback.
+ *
+ * Return: Length of formatted string, or negative error code on failure
  */
 int blog_log_reconstruct(const struct blog_log_entry *entry, char *output, size_t output_size)
 {
-       /* Stub implementation */
+       struct blog_source_info *source;
+       
        if (!entry || !output)
                return -EINVAL;
        
-       /* For now, just return a placeholder string */
-       return snprintf(output, output_size, "[BLOG entry stub]");
+       /* Get source info */
+       source = blog_get_source_info(entry->source_id);
+       if (!source) {
+               return snprintf(output, output_size, "[unknown source %u]", entry->source_id);
+       }
+       
+       /* Reconstruct using the format string from source */
+       return blog_des_reconstruct(source->fmt, entry->buffer, 0, entry->len,
+                                  output, output_size);
 }
-EXPORT_SYMBOL(blog_log_reconstruct);
+EXPORT_SYMBOL(blog_log_reconstruct);
\ No newline at end of file