#include "io.hpp"
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <fcntl.h>


static bool file_read(int fd, char*& buf, size_t& len) {
    struct stat ss;
    if (fstat(fd, &ss) == -1) {
        LOG_ERRNO("fstat()");
        close(fd);
        return false;
    }
    len = ss.st_size;

    buf = (char*)malloc(len + 1);
    if (read(fd, buf, len) != (ssize_t)len) {
        LOG("read()");
        close(fd);
        free(buf);
        return false;
    }
    buf[len] = '\0';

    return true;
}


bool file_read(const char* fn, char*& buf, size_t& len) {
    int fd = open(fn, O_RDONLY);
    if (fd == -1) {
        LOG_ERRNO("open(%s)", fn);
        return false;
    }
    bool rv = file_read(fd, buf, len);
    close(fd);
    return rv;
}


bool file_read_at(const char* dn, unsigned pos, char*& buf, size_t& len) {
    DIR* dirp = opendir(dn);
    if (!dirp) {
        LOG_ERRNO("opendir(%s)", dn);
        return false;
    }

    unsigned num = 0;
    struct dirent* dp;
    while ((dp = readdir(dirp)) != NULL) {
        if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) continue;
        ++num;
    }
    rewinddir(dirp);
    if (!num) return false;
    num = pos % num;

    while ((dp = readdir(dirp)) != NULL) {
        if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) continue;
        if (!num) {
            int fd = openat(dirfd(dirp), dp->d_name, O_RDONLY);
            if (fd == -1) {
                LOG_ERRNO("openat(%s, %s)", dn, dp->d_name);
                closedir(dirp);
                return false;
            }
            closedir(dirp);
            bool rv = file_read(fd, buf, len);
            close(fd);
            return rv;
        }
        --num;
    }

    closedir(dirp);
    return false;
}