/*
 * 伪造 sysfs 视图。
 *
 * 本应用域允许 open /dev/bus/usb 节点,但禁止枚举 /sys/bus/usb/devices,
 * 而 libusb/fastboot/adb 的 usb_linux 后端都靠枚举 sysfs 发现设备。
 * 这里把该前缀重写到 ArkTS 侧生成的替身树(FakeSysAdapter),
 * 并把 statfs("/sys") 伪装成 SYSFS_MAGIC——libusb 用这个魔数决定用不用 sysfs 后端,
 * 不伪装它会整体退回 usbfs(于是 speed=UNKNOWN、port_number=0、adb 拼出 usb:0-0)。
 */
#include "compat.h"

int ohb_rewrite(const char *path, char *out, size_t outsz) {
    if (!path) {
        return 0;
    }
    size_t plen = strlen(OHB_SYS_PREFIX);
    if (strncmp(path, OHB_SYS_PREFIX, plen) != 0) {
        return 0;
    }
    if (path[plen] != '\0' && path[plen] != '/') {
        return 0;
    }
    snprintf(out, outsz, "%s%s", OHB_FAKE_DEVICES, path + plen);
    return 1;
}

DIR *opendir(const char *path) {
    ohb_real_init();
    char np[512];
    if (ohb_rewrite(path, np, sizeof(np))) {
        ohb_trace("opendir %s -> %s", path, np);
        return g_real_opendir(np);
    }
    if (path && strstr(path, "usb") != NULL) {
        ohb_trace("opendir %s (passthrough)", path);
    }
    return g_real_opendir(path);
}

int stat(const char *path, struct stat *buf) {
    ohb_real_init();
    char np[512];
    if (ohb_rewrite(path, np, sizeof(np))) {
        return g_real_stat(np, buf);
    }
    return g_real_stat(path, buf);
}

int lstat(const char *path, struct stat *buf) {
    ohb_real_init();
    char np[512];
    if (ohb_rewrite(path, np, sizeof(np))) {
        return g_real_lstat(np, buf);
    }
    return g_real_lstat(path, buf);
}

int access(const char *path, int mode) {
    ohb_real_init();
    char np[512];
    if (ohb_rewrite(path, np, sizeof(np))) {
        return g_real_access(np, mode);
    }
    return g_real_access(path, mode);
}

FILE *fopen(const char *path, const char *mode) {
    ohb_real_init();
    char np[512];
    if (ohb_rewrite(path, np, sizeof(np))) {
        return g_real_fopen(np, mode);
    }
    return g_real_fopen(path, mode);
}

/*
 * 真实的 /sys/bus/usb/devices/<bus>-<port> 是符号链接,部分调用方靠 readlink
 * 推路径。伪造条目是普通目录,这里造一个指向"重写前缀下同一路径"的目标,
 * 后续对该路径的读取仍会命中伪造树。
 */
ssize_t readlink(const char *path, char *buf, size_t bufsiz) {
    ohb_real_init();
    char np[512];
    /* /sys/dev/char/MAJ:MIN → 伪造设备目录(末尾就是 "1-3" 这种 devpath,
     * adb 取 basename 拼成 "usb:1-3") */
    unsigned int maj = 0, min = 0;
    if (path && sscanf(path, "/sys/dev/char/%u:%u", &maj, &min) == 2) {
        int bus = 0, addr = 0;
        if (ohb_acq_lookup_rdev(maj, min, &bus, &addr)) {
            snprintf(np, sizeof(np), "%s/%d-%d", OHB_FAKE_DEVICES, bus, addr);
            size_t n = strlen(np);
            if (n > bufsiz) {
                n = bufsiz;
            }
            memcpy(buf, np, n);
            return (ssize_t)n;
        }
    }
    if (ohb_rewrite(path, np, sizeof(np))) {
        size_t n = strlen(np);
        if (bufsiz == 0) {
            return -1;
        }
        if (n > bufsiz) {
            n = bufsiz;         /* 与真实 readlink 一致:截断、不补 '\0' */
        }
        memcpy(buf, np, n);
        return (ssize_t)n;
    }
    return g_real_readlink(path, buf, bufsiz);
}

ssize_t readlinkat(int dirfd, const char *path, char *buf, size_t bufsiz) {
    ohb_real_init();
    char np[512];
    if (dirfd == AT_FDCWD && ohb_rewrite(path, np, sizeof(np))) {
        return readlink(path, buf, bufsiz);
    }
    return g_real_readlinkat(dirfd, path, buf, bufsiz);
}

char *realpath(const char *path, char *resolved) {
    ohb_real_init();
    char np[512];
    if (ohb_rewrite(path, np, sizeof(np))) {
        size_t n = strlen(np);
        if (!resolved) {
            resolved = malloc(n + 1);
            if (!resolved) {
                return NULL;
            }
        }
        memcpy(resolved, np, n + 1);
        return resolved;
    }
    return g_real_realpath(path, resolved);
}

/* libusb 的 linux_usbfs 后端在 op_init 里 sscanf(uname().release, "%d.%d.%d")
 * 判定内核能力,而鸿蒙的 release 是 "HongMeng Kernel 1.13.0",解析失败 → op_init
 * 返回 LIBUSB_ERROR_OTHER → libusb_init 失败 → 上层看到 "ctxUSB is nullptr,
 * recompile please"(hdc 的 USB 通道整体不可用)。这里只改 sysname/release,
 * 其余字段保持真实值。 */
int uname(struct utsname *buf) {
    ohb_real_init();
    if (!g_real_uname) {
        errno = ENOSYS;
        return -1;
    }
    int r = g_real_uname(buf);
    if (r == 0 && buf) {
        snprintf(buf->sysname, sizeof(buf->sysname), "%s", "Linux");
        snprintf(buf->release, sizeof(buf->release), "%s", OHB_FAKE_KERNEL_RELEASE);
    }
    return r;
}

/* libusb 的 linux_usbfs 后端是"poll 驱动"的:它 poll 设备 fd,被唤醒后才发
 * USBDEVFS_REAPURBNDELAY 去取完成事件。真实 usbfs 里内核会在 URB 完成时把 fd
 * 标成可读;而我们的 URB 完成事件放在**用户态队列**里(urb.c 的 g_done),
 * 真实 fd 永远不会变得可读 —— libusb 因此从不来 reap:
 *   SUBMITURB → 干等 → 超时 → DISCARDURB → 完成事件没人取 → event loop 挂死。
 * hdc 实测就是卡在这一步(WatchUsbNodeChange 连续 30s+ busy,之后再无任何 ioctl)。
 *
 * 对策:把我们的 usbfs fd 在 poll 里当作"有工作就绪":
 *   - 队列里有活:立刻标 POLLIN,libusb 马上回来 reap;
 *   - 队列空:把超时压到 10ms,让它周期性回来推进挂起的 IN URB 和处理定时器。
 * 只对登记过的 fake fd 生效,其它 fd 原样透传。 */
int poll(struct pollfd *fds, nfds_t nfds, int timeout) {
    ohb_real_init();
    if (!g_real_poll || !fds || nfds == 0) {
        return g_real_poll ? g_real_poll(fds, nfds, timeout) : -1;
    }
    // 排障开关:OHB_NO_POLL=1 时完全透传(用于定位"兼容层锁死 Electron 子进程")。
    {
        static int s_off = -1;
        if (s_off < 0) {
            const char *v = getenv("OHB_NO_POLL");
            s_off = (v && v[0] == '1') ? 1 : 0;
        }
        if (s_off) {
            return g_real_poll(fds, nfds, timeout);
        }
    }
    int has_fake = 0;
    int has_work = 0;
    for (nfds_t i = 0; i < nfds; i++) {
        if (fds[i].fd < 0 || !ohb_dev_known(fds[i].fd)) {
            continue;
        }
        has_fake = 1;
        if (ohb_urb_has_work(fds[i].fd)) {
            has_work = 1;
        }
    }
    if (!has_fake) {
        return g_real_poll(fds, nfds, timeout);
    }
    int wait = has_work ? 0 : (timeout < 0 || timeout > 10 ? 10 : timeout);
    int r = g_real_poll(fds, nfds, wait);
    if (has_work) {
        for (nfds_t i = 0; i < nfds; i++) {
            if (fds[i].fd >= 0 && ohb_dev_known(fds[i].fd)) {
                fds[i].revents |= POLLIN;
                if (r <= 0) {
                    r = 1;
                }
            }
        }
    }
    return r;
}

/* GET_DESCRIPTOR(STRING) 本地作答。
 *
 * 理由:设备在调试态下对字符串描述符的应答并不可靠——实测桥接回来的 langid 是
 * `30 00 00 00`(不是合法的 `04 03 09 04`),libusb 直接判
 * "invalid language ID string descriptor",hdc 的 CheckDescriptor 随即失败、
 * DetectMyNeed 返回 -1,于是 `hdc list targets` 永远为空。
 * 而这些东西伪造树里本来就有(manufacturer / product / serial,且配置描述符里
 * iManufacturer=1 / iProduct=2 / iSerialNumber=3 与之一一对应)。
 * fastboot 当初也是靠本地应答过掉的,这里把同一招做成通用的。
 *
 * index 0 = langid 列表(固定 en-US);1/2/3 = 厂商/产品/序列号。
 * 返回写入的字节数;0 表示不处理(交回桥接)。 */
int ohb_string_desc_local(int bus, int addr, unsigned int index, unsigned char *buf, int len) {
    if (!buf || len <= 0) {
        return 0;
    }
    unsigned char tmp[256];
    unsigned char text[128];
    if (index == 0) {
        static const unsigned char langid[] = { 4, 3, 0x09, 0x04 };
        int n = (int)sizeof(langid);
        if (n > len) {
            n = len;
        }
        memcpy(buf, langid, (size_t)n);
        return n;
    }
    const char *name = index == 1 ? "manufacturer" : (index == 2 ? "product" : (index == 3 ? "serial" : NULL));
    if (!name) {
        return 0;
    }
    char path[512];
    snprintf(path, sizeof(path), "%s/%d-%d/%s", OHB_FAKE_DEVICES, bus, addr, name);
    FILE *fp = g_real_fopen ? g_real_fopen(path, "r") : NULL;
    if (!fp) {
        return 0;
    }
    size_t got = fread(text, 1, sizeof(text), fp);
    fclose(fp);
    while (got > 0 && (text[got - 1] == '\n' || text[got - 1] == '\r' || text[got - 1] == ' ')) {
        got--;
    }
    if (got == 0) {
        return 0;
    }
    /* UTF-16LE:bLength = 2 + 2*字符数,bDescriptorType = 3 */
    int n = 2;
    for (size_t i = 0; i < got && n + 2 <= (int)sizeof(tmp); i++) {
        tmp[n++] = text[i];
        tmp[n++] = 0;
    }
    if (n > 2) {
        tmp[0] = (unsigned char)n;
        tmp[1] = 3;
    }
    if (n > len) {
        n = len;
    }
    memcpy(buf, tmp, (size_t)n);
    return n;
}

static int is_sys_root(const char *path) {
    return path && (strcmp(path, "/sys") == 0 || strcmp(path, "/sys/") == 0);
}

/* libusb 的 linux 后端在 op_init 里用 statfs(SYSFS_MOUNT_PATH).f_type == SYSFS_MAGIC
 * 判定后端;应用域里这一步可能失败。只改 f_type,其余字段保持真实值。 */
int statfs(const char *path, struct statfs *buf) {
    ohb_real_init();
    int r = g_real_statfs ? g_real_statfs(path, buf) : -1;
    if (is_sys_root(path)) {
        if (r != 0 && buf) {
            memset(buf, 0, sizeof(*buf));
            buf->f_bsize = 4096;
            r = 0;
        }
        if (buf) {
            buf->f_type = OHB_SYSFS_MAGIC;
        }
        return 0;
    }
    return r;
}