mirror of
https://github.com/aaru-dps/libaaruformat.git
synced 2025-12-16 19:24:40 +00:00
Add write functionality for sectors and implement block closing logic
This commit is contained in:
@@ -121,7 +121,8 @@ add_library(aaruformat SHARED include/aaruformat/consts.h include/aaruformat/enu
|
|||||||
include/aaruformat/structs/options.h
|
include/aaruformat/structs/options.h
|
||||||
src/options.c
|
src/options.c
|
||||||
src/create.c
|
src/create.c
|
||||||
src/time.c)
|
src/time.c
|
||||||
|
src/write.c)
|
||||||
|
|
||||||
include_directories(include include/aaruformat)
|
include_directories(include include/aaruformat)
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#ifndef LIBAARUFORMAT_CONTEXT_H
|
#ifndef LIBAARUFORMAT_CONTEXT_H
|
||||||
#define LIBAARUFORMAT_CONTEXT_H
|
#define LIBAARUFORMAT_CONTEXT_H
|
||||||
|
|
||||||
|
#include "crc64.h"
|
||||||
#include "lru.h"
|
#include "lru.h"
|
||||||
#include "structs.h"
|
#include "structs.h"
|
||||||
|
|
||||||
@@ -116,6 +117,11 @@ typedef struct aaruformatContext
|
|||||||
uint16_t *cachedSecondaryDdtSmall;
|
uint16_t *cachedSecondaryDdtSmall;
|
||||||
uint32_t *cachedSecondaryDdtBig;
|
uint32_t *cachedSecondaryDdtBig;
|
||||||
bool isWriting;
|
bool isWriting;
|
||||||
|
BlockHeader currentBlockHeader;
|
||||||
|
uint8_t *writingBuffer;
|
||||||
|
int currentBlockOffset;
|
||||||
|
crc64_ctx *crc64Context;
|
||||||
|
int writingBufferPosition;
|
||||||
} aaruformatContext;
|
} aaruformatContext;
|
||||||
|
|
||||||
typedef struct DumpHardwareEntriesWithData
|
typedef struct DumpHardwareEntriesWithData
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#ifndef LIBAARUFORMAT_CRC64_H
|
#ifndef LIBAARUFORMAT_CRC64_H
|
||||||
#define LIBAARUFORMAT_CRC64_H
|
#define LIBAARUFORMAT_CRC64_H
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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,
|
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,
|
uint64_t userSectors, uint64_t negativeSectors, uint64_t overflowSectors,
|
||||||
const char *options, const uint8_t *applicationName,
|
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);
|
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,
|
AARU_EXPORT int32_t AARU_CALL aaruf_read_sector_long(void *context, uint64_t sectorAddress, uint8_t *data,
|
||||||
uint32_t *length);
|
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_verify_image(void *context);
|
||||||
|
|
||||||
AARU_EXPORT int32_t AARU_CALL aaruf_cst_transform(const uint8_t *interleaved, uint8_t *sequential, size_t length);
|
AARU_EXPORT int32_t AARU_CALL aaruf_cst_transform(const uint8_t *interleaved, uint8_t *sequential, size_t length);
|
||||||
|
|||||||
@@ -40,6 +40,9 @@
|
|||||||
#define AARUF_ERROR_CANNOT_CREATE_FILE -19
|
#define AARUF_ERROR_CANNOT_CREATE_FILE -19
|
||||||
#define AARUF_ERROR_INVALID_APP_NAME_LENGTH -20
|
#define AARUF_ERROR_INVALID_APP_NAME_LENGTH -20
|
||||||
#define AARUF_ERROR_CANNOT_WRITE_HEADER -21
|
#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_OK 0
|
||||||
#define AARUF_STATUS_SECTOR_NOT_DUMPED 1
|
#define AARUF_STATUS_SECTOR_NOT_DUMPED 1
|
||||||
|
|||||||
@@ -47,5 +47,6 @@ int32_t decode_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sectorAddre
|
|||||||
uint64_t *blockOffset, uint8_t *sectorStatus);
|
uint64_t *blockOffset, uint8_t *sectorStatus);
|
||||||
aaru_options parse_options(const char *options);
|
aaru_options parse_options(const char *options);
|
||||||
uint64_t get_filetime_uint64();
|
uint64_t get_filetime_uint64();
|
||||||
|
int32_t aaruf_close_current_block(aaruformatContext *ctx);
|
||||||
|
|
||||||
#endif // LIBAARUFORMAT_INTERNAL_H
|
#endif // LIBAARUFORMAT_INTERNAL_H
|
||||||
|
|||||||
10
src/close.c
10
src/close.c
@@ -26,6 +26,8 @@
|
|||||||
|
|
||||||
#include <aaruformat.h>
|
#include <aaruformat.h>
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
int aaruf_close(void *context)
|
int aaruf_close(void *context)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
@@ -58,6 +60,14 @@ int aaruf_close(void *context)
|
|||||||
errno = AARUF_ERROR_CANNOT_WRITE_HEADER;
|
errno = AARUF_ERROR_CANNOT_WRITE_HEADER;
|
||||||
return -1;
|
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
|
// This may do nothing if imageStream is NULL, but as the behaviour is undefined, better sure than sorry
|
||||||
|
|||||||
@@ -28,13 +28,13 @@
|
|||||||
void *aaruf_create(const char *filepath, uint32_t mediaType, uint32_t sectorSize, uint64_t userSectors,
|
void *aaruf_create(const char *filepath, uint32_t mediaType, uint32_t sectorSize, uint64_t userSectors,
|
||||||
uint64_t negativeSectors, uint64_t overflowSectors, const char *options,
|
uint64_t negativeSectors, uint64_t overflowSectors, const char *options,
|
||||||
const uint8_t *applicationName, uint8_t applicationNameLength, uint8_t applicationMajorVersion,
|
const uint8_t *applicationName, uint8_t applicationNameLength, uint8_t applicationMajorVersion,
|
||||||
uint8_t applicationMinorVersion);
|
uint8_t applicationMinorVersion)
|
||||||
{
|
{
|
||||||
// Parse the options
|
// Parse the options
|
||||||
aaru_options parsedOptions = parse_options(options);
|
aaru_options parsedOptions = parse_options(options);
|
||||||
|
|
||||||
// Allocate context
|
// Allocate context
|
||||||
aaruformatContext *ctx = (aaruformatContext *)malloc(sizeof(aaruformatContext));
|
aaruformatContext *ctx = malloc(sizeof(aaruformatContext));
|
||||||
if(ctx == NULL)
|
if(ctx == NULL)
|
||||||
{
|
{
|
||||||
errno = AARUF_ERROR_NOT_ENOUGH_MEMORY;
|
errno = AARUF_ERROR_NOT_ENOUGH_MEMORY;
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "aaruformat.h"
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
#include "structs/options.h"
|
#include "structs/options.h"
|
||||||
|
|
||||||
|
|||||||
133
src/write.c
Normal file
133
src/write.c
Normal file
@@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user