/*
 * DF-0871 FIXED harness.
 *
 * Identical to harness.c but the do/while is bounded to j < 64 (== the
 * destination array length == the source array length, NTFS_ATTRNAME_MAXLEN)
 * and the destination is explicitly NUL-terminated.  This is exactly the fix
 * in fix.diff.  No guard fault, no overflow.
 *
 * Build:  cc -O2 -o harness_fixed harness_fixed.c
 * Run:    ./harness_fixed [num]
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>

typedef uint16_t wchar_nt;

struct ntvattrdef {
    char      ad_name[0x40];
    int       ad_namelen;
    uint32_t  ad_type;
};

#define SRCLEN 256
static wchar_nt src_buf[SRCLEN];
static void make_evil_source(void) {
    for (int i = 0; i < SRCLEN - 1; i++) src_buf[i] = 0x4141;
    src_buf[SRCLEN - 1] = 0;
}

/* FIXED transcription: EXACT mirror of fix.diff -- bound the do/while to the
 * destination array length and force NUL-termination.  This is the verbatim
 * patched ntfs_vfsops.c:457-464 logic. */
static void fixed_copy(struct ntvattrdef *arr, int i) {
    int j = 0;
    size_t dstlen = sizeof(arr[i].ad_name);   /* = 64 (char[0x40]) */
    do {
        arr[i].ad_name[j] = (char)src_buf[j];
    } while(src_buf[j++] &&
        j < (int)dstlen);
    /* Force NUL-termination within the fixed-size buffer. */
    arr[i].ad_name[dstlen - 1] = '\0';
    arr[i].ad_namelen = j - 1;
    arr[i].ad_type    = 0xFFFFFFFFu;
}

int main(int argc, char **argv) {
    int num = (argc > 1) ? atoi(argv[1]) : 1;
    if (num < 1) num = 1;
    make_evil_source();
    size_t allocsz = (size_t)num * sizeof(struct ntvattrdef);

    /* allocate a touch of padding so any stray write would be visible */
    unsigned char *block = calloc(1, allocsz + 64);
    struct ntvattrdef *arr = (struct ntvattrdef *)block;

    fixed_copy(arr, num - 1);

    printf("[harness_fixed] DF-0871 fixed (bounded do/while, NUL-terminated) -- mirrors fix.diff\n");
    printf("[harness_fixed] num=%d  allocsz=%zu  copy completed with NO overflow.\n",
           num, allocsz);
    printf("[harness_fixed] entry[%d].ad_namelen = %d (capped)\n", num-1, arr[num-1].ad_namelen);
    /* verify no byte past entry[num-1]'s object was touched */
    int leak = 0;
    size_t start = (size_t)(num - 1) * 72 + 72;
    for (size_t k = start; k < allocsz + 64; k++)
        if (block[k] != 0) leak++;
    printf("[harness_fixed] bytes written past the %zu-byte allocation = %d (expect 0)\n",
           allocsz, leak);
    free(block);
    return leak == 0 ? 0 : 1;
}
