C_runtime/blob.cpp
author Edouard Tisserant <edouard.tisserant@gmail.com>
Sat, 18 May 2024 23:59:32 +0200
changeset 3945 d303aab8f68b
parent 3940 934bd46a7500
permissions -rw-r--r--
C++ runtime: WIP. Continue PLCObject implementation.

#include <stdlib.h>
#include <errno.h>

#include "blob.hpp"
#include <unistd.h>

Blob::Blob(uint8_t *seedData, size_t seedLength)
{
    // Create a temporary file to store blob data
    // not using tmpfile() because we need to know the filename
    // for later renaming and avoid deletion on close
    
    // Assume that a tmp directory exists in the current directory
    uint8_t template_name[] = "tmp/blobXXXXXX";
    int fd = mkstemp((char *)template_name);
    if (fd == -1) {
        throw errno;
    }

    // Open file for stdlib I/O
    m_file = fdopen(fd, "w+");
    if (m_file == NULL) {
        throw errno;
    }

    // Save a copy of the filename
    m_filename = (char *)template_name;

    // Seed the MD5 hash with the seed data
    md5.update(seedData, seedLength);
}

Blob::~Blob() {
    if (m_file != NULL) {
        std::fclose(m_file);
        std::remove(m_filename.c_str());
    }
}

MD5::digest_t Blob::digest() {
    return md5.digest();
}

uint32_t Blob::appendChunk(uint8_t *data, size_t length) {
    // Write data to file
    if (std::fwrite(data, 1, length, m_file) != length) {
        return errno;
    }

    // Update MD5 hash
    md5.update(data, length);

    return 0;
}

uint32_t Blob::asFile(std::filesystem::path &filename)
{
    // Flush file
    if (std::fflush(m_file) != 0) {
        return errno;
    }

    // Sync file to disk
    if (fsync(fileno(m_file)) != 0) {
        return errno;
    }

    // Close file
    if (std::fclose(m_file) != 0) {
        return errno;
    }

    m_file = NULL;

    // Rename temp file to final file
    if (std::rename(m_filename.c_str(), filename.c_str()) != 0) {
        return errno;
    }

    return 0;
}