edouard@3940: 
edouard@3940: #include <stdlib.h>
edouard@3940: #include <errno.h>
edouard@3940: 
edouard@3940: #include "blob.hpp"
edouard@3940: #include <unistd.h>
edouard@3940: 
edouard@3940: Blob::Blob(uint8_t *seedData, size_t seedLength)
edouard@3940: {
edouard@3940:     // Create a temporary file to store blob data
edouard@3940:     // not using tmpfile() because we need to know the filename
edouard@3940:     // for later renaming and avoid deletion on close
edouard@3940:     
edouard@3940:     // Assume that a tmp directory exists in the current directory
edouard@3940:     uint8_t template_name[] = "tmp/blobXXXXXX";
edouard@3940:     int fd = mkstemp((char *)template_name);
edouard@3940:     if (fd == -1) {
edouard@3940:         throw errno;
edouard@3940:     }
edouard@3940: 
edouard@3940:     // Open file for stdlib I/O
edouard@3940:     m_file = fdopen(fd, "w+");
edouard@3940:     if (m_file == NULL) {
edouard@3940:         throw errno;
edouard@3940:     }
edouard@3940: 
edouard@3940:     // Save a copy of the filename
edouard@3940:     m_filename = (char *)template_name;
edouard@3940: 
edouard@3940:     // Seed the MD5 hash with the seed data
edouard@3940:     md5.update(seedData, seedLength);
edouard@3940: }
edouard@3940: 
edouard@3940: Blob::~Blob() {
edouard@3940:     if (m_file != NULL) {
edouard@3940:         std::fclose(m_file);
edouard@3940:         std::remove(m_filename.c_str());
edouard@3940:     }
edouard@3940: }
edouard@3940: 
edouard@3940: MD5::digest_t Blob::digest() {
edouard@3940:     return md5.digest();
edouard@3940: }
edouard@3940: 
edouard@3940: uint32_t Blob::appendChunk(uint8_t *data, size_t length) {
edouard@3940:     // Write data to file
edouard@3940:     if (std::fwrite(data, 1, length, m_file) != length) {
edouard@3940:         return errno;
edouard@3940:     }
edouard@3940: 
edouard@3940:     // Update MD5 hash
edouard@3940:     md5.update(data, length);
edouard@3940: 
edouard@3940:     return 0;
edouard@3940: }
edouard@3940: 
edouard@3940: uint32_t Blob::asFile(std::filesystem::path &filename)
edouard@3940: {
edouard@3940:     // Flush file
edouard@3940:     if (std::fflush(m_file) != 0) {
edouard@3940:         return errno;
edouard@3940:     }
edouard@3940: 
edouard@3940:     // Sync file to disk
edouard@3940:     if (fsync(fileno(m_file)) != 0) {
edouard@3940:         return errno;
edouard@3940:     }
edouard@3940: 
edouard@3940:     // Close file
edouard@3940:     if (std::fclose(m_file) != 0) {
edouard@3940:         return errno;
edouard@3940:     }
edouard@3940: 
edouard@3940:     m_file = NULL;
edouard@3940: 
edouard@3940:     // Rename temp file to final file
edouard@3940:     if (std::rename(m_filename.c_str(), filename.c_str()) != 0) {
edouard@3940:         return errno;
edouard@3940:     }
edouard@3940: 
edouard@3940:     return 0;
edouard@3940: }