Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package aws-c-common for openSUSE:Factory 
checked in at 2026-07-08 17:39:25
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/aws-c-common (Old)
 and      /work/SRC/openSUSE:Factory/.aws-c-common.new.1982 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "aws-c-common"

Wed Jul  8 17:39:25 2026 rev:32 rq:1364498 version:0.14.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/aws-c-common/aws-c-common.changes        
2026-06-15 19:53:13.424023743 +0200
+++ /work/SRC/openSUSE:Factory/.aws-c-common.new.1982/aws-c-common.changes      
2026-07-08 17:42:17.101488047 +0200
@@ -1,0 +2,7 @@
+Fri Jul  3 12:47:55 UTC 2026 - John Paul Adrian Glaubitz 
<[email protected]>
+
+- Update to 0.14.1
+  * odirect write support by @TingDaoK in (#1245)
+  * aws_cbor_decoder_get_unconsumed_length by @TingDaoK in (#1251)
+
+-------------------------------------------------------------------

Old:
----
  v0.14.0.tar.gz

New:
----
  v0.14.1.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ aws-c-common.spec ++++++
--- /var/tmp/diff_new_pack.rR5bYL/_old  2026-07-08 17:42:19.009554538 +0200
+++ /var/tmp/diff_new_pack.rR5bYL/_new  2026-07-08 17:42:19.037555514 +0200
@@ -19,7 +19,7 @@
 %define library_version 1.0.0
 %define library_soversion 1
 Name:           aws-c-common
-Version:        0.14.0
+Version:        0.14.1
 Release:        0
 Summary:        Core C99 package for AWS SDK for C
 License:        Apache-2.0

++++++ v0.14.0.tar.gz -> v0.14.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/aws-c-common-0.14.0/include/aws/common/cbor.h 
new/aws-c-common-0.14.1/include/aws/common/cbor.h
--- old/aws-c-common-0.14.0/include/aws/common/cbor.h   2026-05-28 
00:02:05.000000000 +0200
+++ new/aws-c-common-0.14.1/include/aws/common/cbor.h   2026-06-24 
19:58:50.000000000 +0200
@@ -305,6 +305,8 @@
 /**
  * @brief  Get the length of the remaining bytes of the source. Once the 
source was decoded, it will be consumed,
  * and result in decrease of the remaining length of bytes.
+ * Note: aws_cbor_decoder_peek_type will also decrease the remaining length, 
as it decodes the next element
+ * internally.
  *
  * @param decoder
  * @return The length of bytes remaining of the decoder source.
@@ -313,6 +315,17 @@
 size_t aws_cbor_decoder_get_remaining_length(const struct aws_cbor_decoder 
*decoder);
 
 /**
+ * @brief  Get the number of bytes that have not yet been consumed (popped) by 
the caller.
+ * Unlike aws_cbor_decoder_get_remaining_length, aws_cbor_decoder_peek_type 
does NOT affect this value.
+ * Only pop/consume operations reduce the unconsumed length.
+ *
+ * @param decoder
+ * @return The number of bytes not yet consumed from the decoder source.
+ */
+AWS_COMMON_API
+size_t aws_cbor_decoder_get_unconsumed_length(const struct aws_cbor_decoder 
*decoder);
+
+/**
  * @brief  Reset the decoder source to a new src.
  * The previous src will be discarded regardless of the unconsumed bytes.
  * The decoder will clear its cache if any.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/aws-c-common-0.14.0/include/aws/common/file.h 
new/aws-c-common-0.14.1/include/aws/common/file.h
--- old/aws-c-common-0.14.0/include/aws/common/file.h   2026-05-28 
00:02:05.000000000 +0200
+++ new/aws-c-common-0.14.1/include/aws/common/file.h   2026-06-24 
19:58:50.000000000 +0200
@@ -267,6 +267,47 @@
     struct aws_byte_buf *output_buf,
     size_t *out_actual_read);
 
+/*
+ * Write to a file using DIRECT I/O at the given offset.
+ * Using direct IO to bypass the OS cache. Helpful when the disk I/O 
outperform the kernel cache.
+ * If O_DIRECT is not supported, returns AWS_ERROR_UNSUPPORTED_OPERATION.
+ *
+ * The file must already exist; the caller is responsible for creating it.
+ *
+ * For aligned writes (offset and length both aligned to page size), O_DIRECT 
is used for the
+ * entire write.
+ *
+ * Notes:
+ * - ONLY supports linux for now and raises AWS_ERROR_UNSUPPORTED_OPERATION on 
all other platforms.
+ * - The offset, data.len, and data.ptr all need to be aligned with the page 
size (a multiple of page size).
+ *      Otherwise, AWS_ERROR_INVALID_ARGUMENT will be raised.
+ * - check the NOTES for O_DIRECT in 
https://man7.org/linux/man-pages/man2/openat.2.html
+ *
+ * @param file_path         The file path to write to.
+ * @param offset            The offset in the file to start writing at.
+ * @param data              The buffer to write from (data.len bytes will be 
written).
+ *
+ * Returns AWS_OP_SUCCESS, or AWS_OP_ERR (after an error has been raised).
+ */
+AWS_COMMON_API
+int aws_file_path_write_to_offset_direct_io(
+    const struct aws_string *file_path,
+    uint64_t offset,
+    struct aws_byte_cursor data);
+
+/**
+ * Returns true if direct I/O (O_DIRECT) is supported on the current platform.
+ *
+ * Currently only Linux supports direct I/O. On unsupported platforms,
+ * aws_file_path_read_from_offset_direct_io() and 
aws_file_path_write_to_offset_direct_io()
+ * will raise AWS_ERROR_UNSUPPORTED_OPERATION.
+ *
+ * Use this to check at init time whether direct I/O is viable, rather than 
calling the
+ * read/write functions and handling the error reactively.
+ */
+AWS_COMMON_API
+bool aws_file_direct_io_is_supported(void);
+
 AWS_EXTERN_C_END AWS_POP_SANE_WARNING_LEVEL
 
 #endif /* AWS_COMMON_FILE_H */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/aws-c-common-0.14.0/source/cbor.c 
new/aws-c-common-0.14.1/source/cbor.c
--- old/aws-c-common-0.14.0/source/cbor.c       2026-05-28 00:02:05.000000000 
+0200
+++ new/aws-c-common-0.14.1/source/cbor.c       2026-06-24 19:58:50.000000000 
+0200
@@ -302,6 +302,9 @@
 
     struct aws_cbor_decoder_context cached_context;
 
+    /* Number of bytes from src consumed by peek (cached but not yet popped) */
+    size_t cached_bytes_consumed;
+
     /* Error code during decoding. Fail the decoding process without 
recovering, */
     int error_code;
 
@@ -327,6 +330,15 @@
     return decoder->src.len;
 }
 
+size_t aws_cbor_decoder_get_unconsumed_length(const struct aws_cbor_decoder 
*decoder) {
+    if (decoder->cached_context.type != AWS_CBOR_TYPE_UNKNOWN) {
+        /* peek_type decodes the next element and advances src, but from the 
caller's perspective
+         * those bytes haven't been consumed yet (the item hasn't been 
popped). Add them back. */
+        return decoder->src.len + decoder->cached_bytes_consumed;
+    }
+    return decoder->src.len;
+}
+
 void aws_cbor_decoder_reset_src(struct aws_cbor_decoder *decoder, struct 
aws_byte_cursor src) {
     decoder->src = src;
     /* Reset all cached state */
@@ -506,6 +518,7 @@
     }
 
     aws_byte_cursor_advance(&decoder->src, result.read);
+    decoder->cached_bytes_consumed = result.read;
 
     return AWS_OP_SUCCESS;
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/aws-c-common-0.14.0/source/linux/file_direct_io.c 
new/aws-c-common-0.14.1/source/linux/file_direct_io.c
--- old/aws-c-common-0.14.0/source/linux/file_direct_io.c       2026-05-28 
00:02:05.000000000 +0200
+++ new/aws-c-common-0.14.1/source/linux/file_direct_io.c       2026-06-24 
19:58:50.000000000 +0200
@@ -9,9 +9,11 @@
 #include <aws/common/file.h>
 #include <aws/common/logging.h>
 #include <aws/common/string.h>
+#include <aws/common/system_info.h>
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <inttypes.h>
 #include <pwd.h>
 #include <stdio.h>
 #include <sys/stat.h>
@@ -52,6 +54,24 @@
         return AWS_OP_SUCCESS; /* Nothing to do. */
     }
 
+    size_t page_size = aws_system_info_page_size();
+
+    /* Per open(2), O_DIRECT may impose alignment restrictions on the file 
offset, buffer
+     * pointer, and transfer length. Misaligned I/Os can either fail with 
EINVAL or silently
+     * fall back to buffered I/O depending on the filesystem and kernel 
version. We enforce
+     * alignment here to guarantee consistent, predictable behavior. */
+    /* Length is not forced for the case of reading last part to end of stream 
cannot align. */
+    if (offset % page_size != 0 || (uintptr_t)(output_buf->buffer + 
output_buf->len) % page_size != 0) {
+        AWS_LOGF_ERROR(
+            AWS_LS_COMMON_GENERAL,
+            "aws_file_path_read_from_offset_direct_io: offset %" PRIu64
+            ", buffer pointer %p must all be aligned to page size %zu",
+            offset,
+            (void *)(output_buf->buffer + output_buf->len),
+            page_size);
+        return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
+    }
+
     int rt_code = AWS_OP_ERR;
     int fd = open(aws_string_c_str(file_path), O_RDONLY | O_DIRECT);
     if (fd == -1) {
@@ -139,3 +159,94 @@
     return aws_file_path_read_from_offset_direct_io_with_chunk_size(
         file_path, offset, max_read_length, AWS_FILE_MAX_READ_CHUNK, 
output_buf, out_actual_read);
 }
+
+int aws_file_path_write_to_offset_direct_io(
+    const struct aws_string *file_path,
+    uint64_t offset,
+    struct aws_byte_cursor data) {
+
+    if (O_DIRECT == 0) {
+        AWS_LOGF_ERROR(AWS_LS_COMMON_GENERAL, "O_DIRECT is not supported on 
this platform");
+        return aws_raise_error(AWS_ERROR_UNSUPPORTED_OPERATION);
+    }
+
+    if (data.len == 0) {
+        return AWS_OP_SUCCESS;
+    }
+
+    size_t page_size = aws_system_info_page_size();
+
+    /* Per open(2), O_DIRECT may impose alignment restrictions on the file 
offset, buffer
+     * pointer, and transfer length. Misaligned I/Os can either fail with 
EINVAL or silently
+     * fall back to buffered I/O depending on the filesystem and kernel 
version. We enforce
+     * alignment here to guarantee consistent, predictable behavior. */
+    if (offset % page_size != 0 || (uintptr_t)data.ptr % page_size != 0 || 
data.len % page_size != 0) {
+        AWS_LOGF_ERROR(
+            AWS_LS_COMMON_GENERAL,
+            "aws_file_path_write_to_offset_direct_io: offset %" PRIu64
+            ", buffer pointer %p, and data.len %zu must all be aligned to page 
size %zu",
+            offset,
+            (void *)data.ptr,
+            data.len,
+            page_size);
+        return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
+    }
+
+    int rt_code = AWS_OP_ERR;
+    int fd = open(aws_string_c_str(file_path), O_WRONLY | O_DIRECT);
+    if (fd == -1) {
+        int errno_value = errno;
+        AWS_LOGF_ERROR(
+            AWS_LS_COMMON_GENERAL,
+            "Failed to open file %s for writing with O_DIRECT, errno: %d",
+            aws_string_c_str(file_path),
+            errno_value);
+        aws_translate_and_raise_io_error(errno_value);
+        goto cleanup;
+    }
+
+    if (lseek(fd, (off_t)offset, SEEK_SET) == -1) {
+        int errno_value = errno;
+        AWS_LOGF_ERROR(
+            AWS_LS_COMMON_GENERAL,
+            "Failed to seek to position %llu in file %s, errno: %d",
+            (unsigned long long)offset,
+            aws_string_c_str(file_path),
+            errno_value);
+        aws_translate_and_raise_io_error(errno_value);
+        goto cleanup;
+    }
+
+    /* Write with O_DIRECT */
+    size_t total_written = 0;
+    while (total_written < data.len) {
+        size_t chunk_size = aws_min_size(data.len - total_written, 
AWS_FILE_MAX_READ_CHUNK);
+        ssize_t written = write(fd, data.ptr + total_written, chunk_size);
+        if (written == -1) {
+            int errno_value = errno;
+            AWS_LOGF_ERROR(
+                AWS_LS_COMMON_GENERAL,
+                "Failed to write %zu bytes to file %s with O_DIRECT, errno: 
%d",
+                chunk_size,
+                aws_string_c_str(file_path),
+                errno_value);
+            aws_translate_and_raise_io_error(errno_value);
+            goto cleanup;
+        }
+        total_written += (size_t)written;
+    }
+
+    rt_code = AWS_OP_SUCCESS;
+cleanup:
+    if (fd != -1) {
+        close(fd);
+    }
+    return rt_code;
+}
+
+bool aws_file_direct_io_is_supported(void) {
+    /* O_DIRECT may be defined as 0 in some Linux build environments (e.g. 
glibc that doesn't
+     * expose it). When that's the case, opening with O_DIRECT is a no-op and 
direct I/O is
+     * not actually available. */
+    return O_DIRECT != 0;
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/aws-c-common-0.14.0/source/platform_fallback_stubs/file_direct_io.c 
new/aws-c-common-0.14.1/source/platform_fallback_stubs/file_direct_io.c
--- old/aws-c-common-0.14.0/source/platform_fallback_stubs/file_direct_io.c     
2026-05-28 00:02:05.000000000 +0200
+++ new/aws-c-common-0.14.1/source/platform_fallback_stubs/file_direct_io.c     
2026-06-24 19:58:50.000000000 +0200
@@ -22,3 +22,18 @@
     AWS_LOGF_ERROR(AWS_LS_COMMON_GENERAL, "Direct file IO is not supported yet 
on platforms other than linux.");
     return aws_raise_error(AWS_ERROR_UNSUPPORTED_OPERATION);
 }
+
+int aws_file_path_write_to_offset_direct_io(
+    const struct aws_string *file_path,
+    uint64_t offset,
+    struct aws_byte_cursor data) {
+    (void)file_path;
+    (void)offset;
+    (void)data;
+    AWS_LOGF_ERROR(AWS_LS_COMMON_GENERAL, "Direct file IO is not supported yet 
on platforms other than linux.");
+    return aws_raise_error(AWS_ERROR_UNSUPPORTED_OPERATION);
+}
+
+bool aws_file_direct_io_is_supported(void) {
+    return false;
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/aws-c-common-0.14.0/tests/CMakeLists.txt 
new/aws-c-common-0.14.1/tests/CMakeLists.txt
--- old/aws-c-common-0.14.0/tests/CMakeLists.txt        2026-05-28 
00:02:05.000000000 +0200
+++ new/aws-c-common-0.14.1/tests/CMakeLists.txt        2026-06-24 
19:58:50.000000000 +0200
@@ -521,6 +521,7 @@
 add_test_case(test_file_path_read_from_offset_direct_io)
 add_test_case(test_file_path_read_from_offset)
 add_test_case(test_file_path_read_from_offset_direct_io_chunking)
+add_test_case(test_file_path_write_to_offset_direct_io)
 
 add_test_case(test_json_parse_from_string)
 add_test_case(test_json_parse_to_string)
@@ -569,6 +570,7 @@
 add_test_case(cbor_decode_error_handling_test)
 add_test_case(cbor_decode_resource_limit_container_size_test)
 add_test_case(cbor_decode_resource_limit_depth_test)
+add_test_case(cbor_decode_remaining_length_after_peek_test)
 
 generate_test_driver(${PROJECT_NAME}-tests)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/aws-c-common-0.14.0/tests/cbor_test.c 
new/aws-c-common-0.14.1/tests/cbor_test.c
--- old/aws-c-common-0.14.0/tests/cbor_test.c   2026-05-28 00:02:05.000000000 
+0200
+++ new/aws-c-common-0.14.1/tests/cbor_test.c   2026-06-24 19:58:50.000000000 
+0200
@@ -549,3 +549,49 @@
     aws_common_library_clean_up();
     return AWS_OP_SUCCESS;
 }
+
+CBOR_TEST_CASE(cbor_decode_remaining_length_after_peek_test) {
+    (void)allocator;
+    (void)ctx;
+    aws_common_library_init(allocator);
+
+    struct aws_cbor_encoder *encoder = aws_cbor_encoder_new(allocator);
+    aws_cbor_encoder_write_uint(encoder, 42);
+    aws_cbor_encoder_write_uint(encoder, 100);
+    struct aws_byte_cursor cursor = aws_cbor_encoder_get_encoded_data(encoder);
+    size_t total_len = cursor.len;
+
+    struct aws_cbor_decoder *decoder = aws_cbor_decoder_new(allocator, cursor);
+    ASSERT_UINT_EQUALS(total_len, 
aws_cbor_decoder_get_remaining_length(decoder));
+    ASSERT_UINT_EQUALS(total_len, 
aws_cbor_decoder_get_unconsumed_length(decoder));
+
+    /* peek_type: old API (remaining_length) DOES decrease, new API 
(unconsumed_length) does NOT */
+    enum aws_cbor_type out_type;
+    ASSERT_SUCCESS(aws_cbor_decoder_peek_type(decoder, &out_type));
+    ASSERT_TRUE(aws_cbor_decoder_get_remaining_length(decoder) < total_len);
+    ASSERT_UINT_EQUALS(total_len, 
aws_cbor_decoder_get_unconsumed_length(decoder));
+
+    /* after pop, both decrease */
+    uint64_t val;
+    ASSERT_SUCCESS(aws_cbor_decoder_pop_next_unsigned_int_val(decoder, &val));
+    ASSERT_UINT_EQUALS(42, val);
+    size_t after_first_pop = aws_cbor_decoder_get_unconsumed_length(decoder);
+    ASSERT_TRUE(after_first_pop < total_len);
+    ASSERT_UINT_EQUALS(after_first_pop, 
aws_cbor_decoder_get_remaining_length(decoder));
+
+    /* peek second element: unconsumed_length unchanged, remaining_length 
decreases */
+    ASSERT_SUCCESS(aws_cbor_decoder_peek_type(decoder, &out_type));
+    ASSERT_UINT_EQUALS(after_first_pop, 
aws_cbor_decoder_get_unconsumed_length(decoder));
+    ASSERT_TRUE(aws_cbor_decoder_get_remaining_length(decoder) < 
after_first_pop);
+
+    /* pop second, both should be 0 */
+    ASSERT_SUCCESS(aws_cbor_decoder_pop_next_unsigned_int_val(decoder, &val));
+    ASSERT_UINT_EQUALS(100, val);
+    ASSERT_UINT_EQUALS(0, aws_cbor_decoder_get_remaining_length(decoder));
+    ASSERT_UINT_EQUALS(0, aws_cbor_decoder_get_unconsumed_length(decoder));
+
+    aws_cbor_encoder_destroy(encoder);
+    aws_cbor_decoder_destroy(decoder);
+    aws_common_library_clean_up();
+    return AWS_OP_SUCCESS;
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/aws-c-common-0.14.0/tests/file_test.c 
new/aws-c-common-0.14.1/tests/file_test.c
--- old/aws-c-common-0.14.0/tests/file_test.c   2026-05-28 00:02:05.000000000 
+0200
+++ new/aws-c-common-0.14.1/tests/file_test.c   2026-06-24 19:58:50.000000000 
+0200
@@ -11,8 +11,6 @@
 
 #include <aws/testing/aws_test_harness.h>
 
-#include <fcntl.h>
-
 static int s_aws_fopen_test_helper(char *file_path, char *content) {
     char read_result[100];
     AWS_ZERO_ARRAY(read_result);
@@ -601,7 +599,7 @@
 static int s_test_file_path_read_from_offset_direct_io(struct aws_allocator 
*allocator, void *ctx) {
     (void)ctx;
 
-#if defined(__linux__)
+#if defined(AWS_OS_LINUX)
     struct aws_file_path_read_from_offset_tester tester;
     char file_path[] = "test_file_path_read_from_offset_direct_io.txt";
 
@@ -805,7 +803,7 @@
 static int s_test_file_path_read_from_offset_direct_io_chunking(struct 
aws_allocator *allocator, void *ctx) {
     (void)ctx;
 
-#if defined(__linux__)
+#if defined(AWS_OS_LINUX)
     struct aws_file_path_read_from_offset_tester tester;
     char file_path[] = "test_direct_io_chunking.txt";
     /* Instead of creating a 2GiB file to test, we use the separate API that 
allows us to pass in the chunk size. */
@@ -895,3 +893,148 @@
 }
 
 AWS_TEST_CASE(test_file_path_read_from_offset_direct_io_chunking, 
s_test_file_path_read_from_offset_direct_io_chunking)
+
+static int s_test_file_path_write_to_offset_direct_io(struct aws_allocator 
*allocator, void *ctx) {
+    (void)ctx;
+
+#if defined(AWS_OS_LINUX)
+    size_t page_size = aws_system_info_page_size();
+    struct aws_allocator *aligned_alloc = 
aws_explicit_aligned_allocator_new(page_size);
+    ASSERT_NOT_NULL(aligned_alloc);
+
+    char file_path_cstr[] = "test_file_path_write_to_offset_direct_io.txt";
+    struct aws_string *file_path = aws_string_new_from_c_str(allocator, 
file_path_cstr);
+
+    /* Create the file first (function requires it to exist) */
+    FILE *f = aws_fopen(file_path_cstr, "wb");
+    ASSERT_NOT_NULL(f);
+    fclose(f);
+
+    /* Test 1: Write 2 aligned pages of 'A' at offset 0 */
+    size_t two_pages = page_size * 2;
+    struct aws_byte_buf write_buf;
+    ASSERT_SUCCESS(aws_byte_buf_init(&write_buf, aligned_alloc, two_pages));
+    memset(write_buf.buffer, 'A', two_pages);
+    write_buf.len = two_pages;
+    struct aws_byte_cursor write_cursor = aws_byte_cursor_from_buf(&write_buf);
+    ASSERT_SUCCESS(aws_file_path_write_to_offset_direct_io(file_path, 0, 
write_cursor));
+
+    /* Read back and verify */
+    struct aws_byte_buf read_buf;
+    ASSERT_SUCCESS(aws_byte_buf_init(&read_buf, aligned_alloc, two_pages));
+    size_t actual_read = 0;
+    ASSERT_SUCCESS(aws_file_path_read_from_offset_direct_io(file_path, 0, 
two_pages, &read_buf, &actual_read));
+    ASSERT_UINT_EQUALS(two_pages, actual_read);
+    for (size_t i = 0; i < two_pages; i++) {
+        ASSERT_UINT_EQUALS('A', read_buf.buffer[i]);
+    }
+    aws_byte_buf_clean_up(&read_buf);
+
+    /* Test 2: Write 1 page of 'C' at page-aligned offset (second page) */
+    struct aws_byte_buf overwrite_buf;
+    ASSERT_SUCCESS(aws_byte_buf_init(&overwrite_buf, aligned_alloc, 
page_size));
+    memset(overwrite_buf.buffer, 'C', page_size);
+    overwrite_buf.len = page_size;
+    struct aws_byte_cursor overwrite_cursor = 
aws_byte_cursor_from_buf(&overwrite_buf);
+    ASSERT_SUCCESS(aws_file_path_write_to_offset_direct_io(file_path, 
(uint64_t)page_size, overwrite_cursor));
+
+    /* Read back and verify first page still 'A', second page now 'C' */
+    ASSERT_SUCCESS(aws_byte_buf_init(&read_buf, aligned_alloc, two_pages));
+    actual_read = 0;
+    ASSERT_SUCCESS(aws_file_path_read_from_offset_direct_io(file_path, 0, 
two_pages, &read_buf, &actual_read));
+    ASSERT_UINT_EQUALS(two_pages, actual_read);
+    for (size_t i = 0; i < page_size; i++) {
+        ASSERT_UINT_EQUALS('A', read_buf.buffer[i]);
+    }
+    for (size_t i = page_size; i < two_pages; i++) {
+        ASSERT_UINT_EQUALS('C', read_buf.buffer[i]);
+    }
+    aws_byte_buf_clean_up(&read_buf);
+    aws_byte_buf_clean_up(&overwrite_buf);
+
+    /* Test 3: Unaligned MUST fail */
+    struct aws_byte_buf unaligned_buf;
+    size_t unaligned_len = page_size + 37;
+    ASSERT_SUCCESS(aws_byte_buf_init(&unaligned_buf, aligned_alloc, 
unaligned_len));
+    memset(unaligned_buf.buffer, 'X', unaligned_len);
+    unaligned_buf.len = unaligned_len;
+    struct aws_byte_cursor unaligned_cursor = 
aws_byte_cursor_from_buf(&unaligned_buf);
+    ASSERT_FAILS(aws_file_path_write_to_offset_direct_io(file_path, 37, 
unaligned_cursor));
+    ASSERT_UINT_EQUALS(AWS_ERROR_INVALID_ARGUMENT, aws_last_error());
+    aws_byte_buf_clean_up(&unaligned_buf);
+
+    /* Test 4: File does not exist MUST fail */
+    struct aws_string *nonexistent = aws_string_new_from_c_str(allocator, 
"nonexistent_direct_io_file.txt");
+    struct aws_byte_cursor one_page_cursor = {.ptr = write_buf.buffer, .len = 
page_size};
+    ASSERT_FAILS(aws_file_path_write_to_offset_direct_io(nonexistent, 0, 
one_page_cursor));
+    aws_string_destroy(nonexistent);
+
+    /* Test 5: Mixed O_DIRECT + buffered writes at non-overlapping offsets, 
verify all data correct.
+     * Simulates the download pattern: O_DIRECT for aligned parts, buffered 
write for last part tail. */
+    remove(file_path_cstr);
+    f = aws_fopen(file_path_cstr, "wb");
+    ASSERT_NOT_NULL(f);
+    fclose(f);
+
+    /* Write 3 pages with O_DIRECT: page 0='D', page 1='E', page 2='F' */
+    memset(write_buf.buffer, 'D', page_size);
+    write_cursor = (struct aws_byte_cursor){.ptr = write_buf.buffer, .len = 
page_size};
+    ASSERT_SUCCESS(aws_file_path_write_to_offset_direct_io(file_path, 0, 
write_cursor));
+
+    memset(write_buf.buffer, 'E', page_size);
+    ASSERT_SUCCESS(aws_file_path_write_to_offset_direct_io(file_path, 
(uint64_t)page_size, write_cursor));
+
+    memset(write_buf.buffer, 'F', page_size);
+    ASSERT_SUCCESS(aws_file_path_write_to_offset_direct_io(file_path, 
(uint64_t)(page_size * 2), write_cursor));
+
+    /* Write unaligned tail (37 bytes of 'G') at offset page_size*3 using 
buffered write */
+    size_t tail_len = 37;
+    uint8_t tail_data[37];
+    memset(tail_data, 'G', tail_len);
+    FILE *tail_file = aws_fopen(file_path_cstr, "r+b");
+    ASSERT_NOT_NULL(tail_file);
+    ASSERT_TRUE(fseek(tail_file, (long)(page_size * 3), SEEK_SET) == 0);
+    size_t written = fwrite(tail_data, 1, tail_len, tail_file);
+    ASSERT_INT_EQUALS((int)tail_len, (int)written);
+    fclose(tail_file);
+
+    /* Read entire file back and verify all regions */
+    size_t total_size = page_size * 3 + tail_len;
+    FILE *verify_file = aws_fopen(file_path_cstr, "rb");
+    ASSERT_NOT_NULL(verify_file);
+    uint8_t *verify_buf = aws_mem_calloc(allocator, 1, total_size);
+    ASSERT_UINT_EQUALS(total_size, fread(verify_buf, 1, total_size, 
verify_file));
+    fclose(verify_file);
+
+    for (size_t i = 0; i < page_size; i++) {
+        ASSERT_UINT_EQUALS('D', verify_buf[i]);
+    }
+    for (size_t i = page_size; i < page_size * 2; i++) {
+        ASSERT_UINT_EQUALS('E', verify_buf[i]);
+    }
+    for (size_t i = page_size * 2; i < page_size * 3; i++) {
+        ASSERT_UINT_EQUALS('F', verify_buf[i]);
+    }
+    for (size_t i = page_size * 3; i < total_size; i++) {
+        ASSERT_UINT_EQUALS('G', verify_buf[i]);
+    }
+    aws_mem_release(allocator, verify_buf);
+
+    /* Cleanup */
+    aws_byte_buf_clean_up(&write_buf);
+    remove(file_path_cstr);
+    aws_string_destroy(file_path);
+    aws_explicit_aligned_allocator_destroy(aligned_alloc);
+#else
+    (void)allocator;
+    struct aws_string *file_path = aws_string_new_from_c_str(allocator, 
"dummy.txt");
+    struct aws_byte_cursor empty = {.ptr = NULL, .len = 0};
+    ASSERT_FAILS(aws_file_path_write_to_offset_direct_io(file_path, 0, empty));
+    ASSERT_UINT_EQUALS(AWS_ERROR_UNSUPPORTED_OPERATION, aws_last_error());
+    aws_string_destroy(file_path);
+#endif
+
+    return AWS_OP_SUCCESS;
+}
+
+AWS_TEST_CASE(test_file_path_write_to_offset_direct_io, 
s_test_file_path_write_to_offset_direct_io)

Reply via email to