From 64c58c0300f229986977c6abd7dacd64cc243389 Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Wed, 13 Aug 2025 16:17:45 +0100 Subject: [PATCH] Add write functionality for sectors and implement block closing logic --- CMakeLists.txt | 3 +- include/aaruformat/context.h | 6 ++ include/aaruformat/crc64.h | 1 + include/aaruformat/decls.h | 6 +- include/aaruformat/errors.h | 45 ++++++------ include/internal.h | 1 + src/close.c | 16 ++++- src/create.c | 4 +- src/options.c | 1 + src/write.c | 133 +++++++++++++++++++++++++++++++++++ 10 files changed, 188 insertions(+), 28 deletions(-) create mode 100644 src/write.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 6e65ecf..ea01c92 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -121,7 +121,8 @@ add_library(aaruformat SHARED include/aaruformat/consts.h include/aaruformat/enu include/aaruformat/structs/options.h src/options.c src/create.c - src/time.c) + src/time.c + src/write.c) include_directories(include include/aaruformat) diff --git a/include/aaruformat/context.h b/include/aaruformat/context.h index 70fd81e..3d0c2bc 100644 --- a/include/aaruformat/context.h +++ b/include/aaruformat/context.h @@ -19,6 +19,7 @@ #ifndef LIBAARUFORMAT_CONTEXT_H #define LIBAARUFORMAT_CONTEXT_H +#include "crc64.h" #include "lru.h" #include "structs.h" @@ -116,6 +117,11 @@ typedef struct aaruformatContext uint16_t *cachedSecondaryDdtSmall; uint32_t *cachedSecondaryDdtBig; bool isWriting; + BlockHeader currentBlockHeader; + uint8_t *writingBuffer; + int currentBlockOffset; + crc64_ctx *crc64Context; + int writingBufferPosition; } aaruformatContext; typedef struct DumpHardwareEntriesWithData diff --git a/include/aaruformat/crc64.h b/include/aaruformat/crc64.h index 599feba..2fbd050 100644 --- a/include/aaruformat/crc64.h +++ b/include/aaruformat/crc64.h @@ -18,6 +18,7 @@ #ifndef LIBAARUFORMAT_CRC64_H #define LIBAARUFORMAT_CRC64_H +#include typedef struct { diff --git a/include/aaruformat/decls.h b/include/aaruformat/decls.h index c49a29e..5339de9 100644 --- a/include/aaruformat/decls.h +++ b/include/aaruformat/decls.h @@ -65,7 +65,8 @@ AARU_EXPORT void *AARU_CALL aaruf_open(const char *filepath); AARU_EXPORT void *AARU_CALL aaruf_create(const char *filepath, uint32_t mediaType, uint32_t sectorSize, uint64_t userSectors, uint64_t negativeSectors, uint64_t overflowSectors, const char *options, const uint8_t *applicationName, - uint8_t applicationMajorVersion, uint8_t applicationMinorVersion); + uint8_t applicationNameLength, uint8_t applicationMajorVersion, + uint8_t applicationMinorVersion); AARU_EXPORT int AARU_CALL aaruf_close(void *context); @@ -82,6 +83,9 @@ AARU_EXPORT int32_t AARU_CALL aaruf_read_sector(void *context, uint64_t sectorAd AARU_EXPORT int32_t AARU_CALL aaruf_read_sector_long(void *context, uint64_t sectorAddress, uint8_t *data, uint32_t *length); +AARU_EXPORT int32_t AARU_CALL aaruf_write_sector(void *context, uint64_t sectorAddress, uint8_t *data, + uint8_t sectorStatus, uint32_t length); + AARU_EXPORT int32_t AARU_CALL aaruf_verify_image(void *context); AARU_EXPORT int32_t AARU_CALL aaruf_cst_transform(const uint8_t *interleaved, uint8_t *sequential, size_t length); diff --git a/include/aaruformat/errors.h b/include/aaruformat/errors.h index faca2ff..0fc3781 100644 --- a/include/aaruformat/errors.h +++ b/include/aaruformat/errors.h @@ -19,27 +19,30 @@ #ifndef LIBAARUFORMAT_ERRORS_H #define LIBAARUFORMAT_ERRORS_H -#define AARUF_ERROR_NOT_AARUFORMAT -1 -#define AARUF_ERROR_FILE_TOO_SMALL -2 -#define AARUF_ERROR_INCOMPATIBLE_VERSION -3 -#define AARUF_ERROR_CANNOT_READ_INDEX -4 -#define AARUF_ERROR_SECTOR_OUT_OF_BOUNDS -5 -#define AARUF_ERROR_CANNOT_READ_HEADER -6 -#define AARUF_ERROR_CANNOT_READ_BLOCK -7 -#define AARUF_ERROR_UNSUPPORTED_COMPRESSION -8 -#define AARUF_ERROR_NOT_ENOUGH_MEMORY -9 -#define AARUF_ERROR_BUFFER_TOO_SMALL -10 -#define AARUF_ERROR_MEDIA_TAG_NOT_PRESENT -11 -#define AARUF_ERROR_INCORRECT_MEDIA_TYPE -12 -#define AARUF_ERROR_TRACK_NOT_FOUND -13 -#define AARUF_ERROR_REACHED_UNREACHABLE_CODE -14 -#define AARUF_ERROR_INVALID_TRACK_FORMAT -15 -#define AARUF_ERROR_SECTOR_TAG_NOT_PRESENT -16 -#define AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK -17 -#define AARUF_ERROR_INVALID_BLOCK_CRC -18 -#define AARUF_ERROR_CANNOT_CREATE_FILE -19 -#define AARUF_ERROR_INVALID_APP_NAME_LENGTH -20 -#define AARUF_ERROR_CANNOT_WRITE_HEADER -21 +#define AARUF_ERROR_NOT_AARUFORMAT -1 +#define AARUF_ERROR_FILE_TOO_SMALL -2 +#define AARUF_ERROR_INCOMPATIBLE_VERSION -3 +#define AARUF_ERROR_CANNOT_READ_INDEX -4 +#define AARUF_ERROR_SECTOR_OUT_OF_BOUNDS -5 +#define AARUF_ERROR_CANNOT_READ_HEADER -6 +#define AARUF_ERROR_CANNOT_READ_BLOCK -7 +#define AARUF_ERROR_UNSUPPORTED_COMPRESSION -8 +#define AARUF_ERROR_NOT_ENOUGH_MEMORY -9 +#define AARUF_ERROR_BUFFER_TOO_SMALL -10 +#define AARUF_ERROR_MEDIA_TAG_NOT_PRESENT -11 +#define AARUF_ERROR_INCORRECT_MEDIA_TYPE -12 +#define AARUF_ERROR_TRACK_NOT_FOUND -13 +#define AARUF_ERROR_REACHED_UNREACHABLE_CODE -14 +#define AARUF_ERROR_INVALID_TRACK_FORMAT -15 +#define AARUF_ERROR_SECTOR_TAG_NOT_PRESENT -16 +#define AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK -17 +#define AARUF_ERROR_INVALID_BLOCK_CRC -18 +#define AARUF_ERROR_CANNOT_CREATE_FILE -19 +#define AARUF_ERROR_INVALID_APP_NAME_LENGTH -20 +#define AARUF_ERROR_CANNOT_WRITE_HEADER -21 +#define AARUF_READ_ONLY -22 +#define AARUF_ERROR_CANNOT_WRITE_BLOCK_HEADER -23 +#define AARUF_ERROR_CANNOT_WRITE_BLOCK_DATA -24 #define AARUF_STATUS_OK 0 #define AARUF_STATUS_SECTOR_NOT_DUMPED 1 diff --git a/include/internal.h b/include/internal.h index 5121fec..c253013 100644 --- a/include/internal.h +++ b/include/internal.h @@ -47,5 +47,6 @@ int32_t decode_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sectorAddre uint64_t *blockOffset, uint8_t *sectorStatus); aaru_options parse_options(const char *options); uint64_t get_filetime_uint64(); +int32_t aaruf_close_current_block(aaruformatContext *ctx); #endif // LIBAARUFORMAT_INTERNAL_H diff --git a/src/close.c b/src/close.c index a792dde..feb6d47 100644 --- a/src/close.c +++ b/src/close.c @@ -26,10 +26,12 @@ #include +#include "internal.h" + int aaruf_close(void *context) { - int i = 0; - mediaTagEntry *mediaTag = NULL; + int i = 0; + mediaTagEntry *mediaTag = NULL; mediaTagEntry *tmpMediaTag = NULL; if(context == NULL) @@ -55,9 +57,17 @@ int aaruf_close(void *context) { fclose(ctx->imageStream); ctx->imageStream = NULL; - errno = AARUF_ERROR_CANNOT_WRITE_HEADER; + errno = AARUF_ERROR_CANNOT_WRITE_HEADER; return -1; } + + // Close current block first + if(ctx->writingBuffer != NULL) + { + int error = aaruf_close_current_block(ctx); + + if(error != AARUF_STATUS_OK) return error; + } } // This may do nothing if imageStream is NULL, but as the behaviour is undefined, better sure than sorry diff --git a/src/create.c b/src/create.c index fd509c2..ef529f6 100644 --- a/src/create.c +++ b/src/create.c @@ -28,13 +28,13 @@ void *aaruf_create(const char *filepath, uint32_t mediaType, uint32_t sectorSize, uint64_t userSectors, uint64_t negativeSectors, uint64_t overflowSectors, const char *options, const uint8_t *applicationName, uint8_t applicationNameLength, uint8_t applicationMajorVersion, - uint8_t applicationMinorVersion); + uint8_t applicationMinorVersion) { // Parse the options aaru_options parsedOptions = parse_options(options); // Allocate context - aaruformatContext *ctx = (aaruformatContext *)malloc(sizeof(aaruformatContext)); + aaruformatContext *ctx = malloc(sizeof(aaruformatContext)); if(ctx == NULL) { errno = AARUF_ERROR_NOT_ENOUGH_MEMORY; diff --git a/src/options.c b/src/options.c index 9d00e11..b4c1aac 100644 --- a/src/options.c +++ b/src/options.c @@ -21,6 +21,7 @@ #include #include +#include "aaruformat.h" #include "internal.h" #include "structs/options.h" diff --git a/src/write.c b/src/write.c new file mode 100644 index 0000000..1861d74 --- /dev/null +++ b/src/write.c @@ -0,0 +1,133 @@ +/* + * This file is part of the Aaru Data Preservation Suite. + * Copyright (c) 2019-2025 Natalia Portillo. + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ +#include +#include +#include +#include +#include +#include + +#include "aaruformat.h" +#include "internal.h" + +int32_t aaruf_write_sector(void *context, uint64_t sectorAddress, uint8_t *data, uint8_t sectorStatus, uint32_t length) +{ + // Check context is correct AaruFormat context + if(context == NULL) return AARUF_ERROR_NOT_AARUFORMAT; + + aaruformatContext *ctx = context; + + // Not a libaaruformat context + if(ctx->magic != AARU_MAGIC) return AARUF_ERROR_NOT_AARUFORMAT; + + // Check we are writing + if(!ctx->isWriting) return AARUF_READ_ONLY; + + // TODO: Check not trying to write beyond media limits + + // TODO: Check rewinded for disabling checksums + + // TODO: If optical disc check track + + // Close current block first + if(ctx->writingBuffer != NULL && + // When sector size changes + (ctx->currentBlockHeader.sectorSize != length || ctx->currentBlockOffset == 1 << ctx->userDataDdtHeader.dataShift + // TODO: Implement compression + )) + { + int error = aaruf_close_current_block(ctx); + + if(error != AARUF_STATUS_OK) return error; + } + + // No block set + if(ctx->writingBufferPosition == 0) + { + ctx->currentBlockHeader.identifier = DataBlock; + ctx->currentBlockHeader.type = UserData; + ctx->currentBlockHeader.compression = None; // TODO: Compression + ctx->currentBlockHeader.sectorSize = length; + + // TODO: Optical discs + + uint32_t maxBufferSize = (1 << ctx->userDataDdtHeader.dataShift) * ctx->currentBlockHeader.sectorSize; + ctx->writingBuffer = (uint8_t *)malloc(maxBufferSize); + if(ctx->writingBuffer == NULL) return AARUF_ERROR_NOT_ENOUGH_MEMORY; + + ctx->crc64Context = aaruf_crc64_init(); + } + + // TODO: DDT entry + + memcpy(ctx->writingBuffer, data, length); + ctx->writingBufferPosition += length; + aaruf_crc64_update(ctx->crc64Context, data, length); + ctx->currentBlockOffset++; + + return AARUF_STATUS_OK; +} + +int32_t aaruf_close_current_block(aaruformatContext *ctx) +{ + // Not a libaaruformat context + if(ctx->magic != AARU_MAGIC) return AARUF_ERROR_NOT_AARUFORMAT; + + // Check we are writing + if(!ctx->isWriting) return AARUF_READ_ONLY; + + ctx->currentBlockHeader.length = ctx->currentBlockOffset * ctx->currentBlockHeader.sectorSize; + aaruf_crc64_final(ctx->crc64Context, &ctx->currentBlockHeader.crc64); + + switch(ctx->currentBlockHeader.compression) + { + case None: + ctx->currentBlockHeader.cmpCrc64 = ctx->currentBlockHeader.crc64; + ctx->currentBlockHeader.cmpLength = ctx->currentBlockHeader.length; + } + + // TODO: Add to index + + // Write block header to file + + // Get file position + long pos = ftell(ctx->imageStream); + + // Fill file with zeroes until next aligned position according to DDT's block alignment shift + long next_alignment = + pos / (1 << ctx->userDataDdtHeader.blockAlignmentShift) * (1 << ctx->userDataDdtHeader.blockAlignmentShift); + fwrite("\0", 1, next_alignment - pos, ctx->imageStream); + + // Write block header + if(fwrite(&ctx->currentBlockHeader, sizeof(BlockHeader), 1, ctx->imageStream) != 1) + return AARUF_ERROR_CANNOT_WRITE_BLOCK_HEADER; + + // Write block data + if(fwrite(ctx->writingBuffer, ctx->currentBlockHeader.length, 1, ctx->imageStream) != 1) + return AARUF_ERROR_CANNOT_WRITE_BLOCK_DATA; + + // Clear values + free(ctx->writingBuffer); + ctx->writingBuffer = NULL; + ctx->currentBlockOffset = 0; + memset(&ctx->currentBlockHeader, 0, sizeof(BlockHeader)); + aaruf_crc64_free(ctx->crc64Context); + ctx->writingBufferPosition = 0; + + return AARUF_STATUS_OK; +} \ No newline at end of file