refactor(fileio): move compression destination policy to Rust
Move the single-file compression destination lifecycle into the Rust file-I/O policy layer while keeping C responsible for private resources, file handles, diagnostics, metadata operations, and codec dispatch callbacks. Preserve the original shared-destination fast path, temporary permissions, handler timing, metadata-before-close ordering, close-error propagation, stdout cleanup guard, and failed-artifact removal. Test Plan: - cargo fmt --manifest-path rust/Cargo.toml --all -- --check - git diff --check - Full capped Rust, native, CLI, and upstream test suites to follow
This commit is contained in:
+206
-54
@@ -1545,6 +1545,81 @@ int FIO_rust_compressFilenameInternal(
|
||||
U64 fileSize, int compressionLevel,
|
||||
const FIO_rust_compress_callbacks_t* callbacks);
|
||||
|
||||
enum {
|
||||
FIO_RUST_COMPRESS_DST_OPEN_OK = 0,
|
||||
};
|
||||
typedef int (*FIO_rust_compress_dst_open_fn)(void* opaque,
|
||||
const char* srcFileName,
|
||||
const char* dstFileName,
|
||||
int transferStat, int* dstFd);
|
||||
typedef void (*FIO_rust_compress_dst_handler_fn)(void* opaque);
|
||||
typedef int (*FIO_rust_compress_dst_file_fn)(void* opaque,
|
||||
const char* dstFileName,
|
||||
const char* srcFileName,
|
||||
int compressionLevel);
|
||||
typedef void (*FIO_rust_compress_dst_stat_fn)(void* opaque, int dstFd,
|
||||
const char* dstFileName);
|
||||
typedef int (*FIO_rust_compress_dst_close_fn)(void* opaque);
|
||||
typedef void (*FIO_rust_compress_dst_remove_fn)(void* opaque,
|
||||
const char* dstFileName);
|
||||
|
||||
/* Rust owns the per-file destination lifecycle; C retains private resource
|
||||
* handles, diagnostics, metadata operations, and format dispatch in opaque
|
||||
* callbacks. */
|
||||
typedef struct {
|
||||
void* opaque;
|
||||
const char* dstFileName;
|
||||
const char* srcFileName;
|
||||
int compressionLevel;
|
||||
int destinationAlreadyOpen;
|
||||
int sourceIsStdin;
|
||||
int destinationIsStdout;
|
||||
int sourceIsRegular;
|
||||
FIO_rust_compress_dst_open_fn openDestination;
|
||||
FIO_rust_compress_dst_handler_fn attachDestination;
|
||||
FIO_rust_compress_dst_handler_fn addHandler;
|
||||
FIO_rust_compress_dst_file_fn compress;
|
||||
FIO_rust_compress_dst_handler_fn clearHandler;
|
||||
FIO_rust_compress_dst_stat_fn setFDStat;
|
||||
FIO_rust_compress_dst_close_fn closeDestination;
|
||||
FIO_rust_compress_dst_handler_fn utimeDestination;
|
||||
FIO_rust_compress_dst_remove_fn removeDestination;
|
||||
} FIO_rust_compress_dst_projection_t;
|
||||
typedef char FIO_rust_compress_dst_opaque_offset[
|
||||
(offsetof(FIO_rust_compress_dst_projection_t, opaque) == 0) ? 1 : -1];
|
||||
typedef char FIO_rust_compress_dst_dst_name_offset[
|
||||
(offsetof(FIO_rust_compress_dst_projection_t, dstFileName)
|
||||
== sizeof(void*)) ? 1 : -1];
|
||||
typedef char FIO_rust_compress_dst_src_name_offset[
|
||||
(offsetof(FIO_rust_compress_dst_projection_t, srcFileName)
|
||||
== 2 * sizeof(void*)) ? 1 : -1];
|
||||
typedef char FIO_rust_compress_dst_level_offset[
|
||||
(offsetof(FIO_rust_compress_dst_projection_t, compressionLevel)
|
||||
== 3 * sizeof(void*)) ? 1 : -1];
|
||||
typedef char FIO_rust_compress_dst_opened_offset[
|
||||
(offsetof(FIO_rust_compress_dst_projection_t, destinationAlreadyOpen)
|
||||
== 3 * sizeof(void*) + sizeof(int)) ? 1 : -1];
|
||||
typedef char FIO_rust_compress_dst_stdin_offset[
|
||||
(offsetof(FIO_rust_compress_dst_projection_t, sourceIsStdin)
|
||||
== 3 * sizeof(void*) + 2 * sizeof(int)) ? 1 : -1];
|
||||
typedef char FIO_rust_compress_dst_stdout_offset[
|
||||
(offsetof(FIO_rust_compress_dst_projection_t, destinationIsStdout)
|
||||
== 3 * sizeof(void*) + 3 * sizeof(int)) ? 1 : -1];
|
||||
typedef char FIO_rust_compress_dst_regular_offset[
|
||||
(offsetof(FIO_rust_compress_dst_projection_t, sourceIsRegular)
|
||||
== 3 * sizeof(void*) + 4 * sizeof(int)) ? 1 : -1];
|
||||
typedef char FIO_rust_compress_dst_callback_offset[
|
||||
(offsetof(FIO_rust_compress_dst_projection_t, openDestination)
|
||||
== ((3 * sizeof(void*) + 5 * sizeof(int) + sizeof(void*) - 1)
|
||||
/ sizeof(void*)) * sizeof(void*)) ? 1 : -1];
|
||||
typedef char FIO_rust_compress_dst_projection_size[
|
||||
(sizeof(FIO_rust_compress_dst_projection_t)
|
||||
== ((3 * sizeof(void*) + 5 * sizeof(int) + sizeof(void*) - 1)
|
||||
/ sizeof(void*)) * sizeof(void*)
|
||||
+ 9 * sizeof(FIO_rust_compress_dst_open_fn)) ? 1 : -1];
|
||||
int FIO_rust_compressFilenameDstFile(
|
||||
const FIO_rust_compress_dst_projection_t* projection);
|
||||
|
||||
enum {
|
||||
FIO_RUST_COMPRESS_SRC_STAT_FAILED = 0,
|
||||
FIO_RUST_COMPRESS_SRC_STAT_OK = 1,
|
||||
@@ -2851,11 +2926,109 @@ FIO_compressFilename_internal(FIO_ctx_t* const fCtx,
|
||||
}
|
||||
|
||||
|
||||
typedef struct {
|
||||
FIO_ctx_t* fCtx;
|
||||
FIO_prefs_t* prefs;
|
||||
cRess_t* ress;
|
||||
const char* dstFileName;
|
||||
const stat_t* srcFileStat;
|
||||
FILE* dstFile;
|
||||
} FIO_rust_compress_dst_context_t;
|
||||
|
||||
static int FIO_rust_compressDestinationOpen(void* opaque,
|
||||
const char* srcFileName,
|
||||
const char* dstFileName,
|
||||
int transferStat, int* dstFd)
|
||||
{
|
||||
FIO_rust_compress_dst_context_t* const context =
|
||||
(FIO_rust_compress_dst_context_t*)opaque;
|
||||
int const permissions = transferStat
|
||||
? TEMPORARY_FILE_PERMISSIONS
|
||||
: DEFAULT_FILE_PERMISSIONS;
|
||||
|
||||
DISPLAYLEVEL(6, "FIO_compressFilename_dstFile: opening dst: %s \n", dstFileName);
|
||||
context->dstFile = FIO_openDstFile(
|
||||
context->fCtx, context->prefs, srcFileName, dstFileName, permissions);
|
||||
if (context->dstFile == NULL)
|
||||
return 1;
|
||||
*dstFd = fileno(context->dstFile);
|
||||
return FIO_RUST_COMPRESS_DST_OPEN_OK;
|
||||
}
|
||||
|
||||
static void FIO_rust_compressDestinationAttach(void* opaque)
|
||||
{
|
||||
FIO_rust_compress_dst_context_t* const context =
|
||||
(FIO_rust_compress_dst_context_t*)opaque;
|
||||
AIO_WritePool_setFile(context->ress->writeCtx, context->dstFile);
|
||||
}
|
||||
|
||||
static void FIO_rust_compressAddHandler(void* opaque)
|
||||
{
|
||||
FIO_rust_compress_dst_context_t* const context =
|
||||
(FIO_rust_compress_dst_context_t*)opaque;
|
||||
/* Add the handler only after FIO_openDstFile() succeeds. */
|
||||
addHandler(context->dstFileName);
|
||||
}
|
||||
|
||||
static int FIO_rust_compressDestinationFile(void* opaque,
|
||||
const char* dstFileName,
|
||||
const char* srcFileName,
|
||||
int compressionLevel)
|
||||
{
|
||||
FIO_rust_compress_dst_context_t* const context =
|
||||
(FIO_rust_compress_dst_context_t*)opaque;
|
||||
return FIO_compressFilename_internal(
|
||||
context->fCtx, context->prefs, *context->ress,
|
||||
dstFileName, srcFileName, compressionLevel);
|
||||
}
|
||||
|
||||
static void FIO_rust_compressClearHandler(void* opaque)
|
||||
{
|
||||
(void)opaque;
|
||||
clearHandler();
|
||||
}
|
||||
|
||||
static void FIO_rust_compressSetFDStat(void* opaque, int dstFd,
|
||||
const char* dstFileName)
|
||||
{
|
||||
FIO_rust_compress_dst_context_t* const context =
|
||||
(FIO_rust_compress_dst_context_t*)opaque;
|
||||
UTIL_setFDStat(dstFd, dstFileName, context->srcFileStat);
|
||||
}
|
||||
|
||||
static int FIO_rust_compressDestinationClose(void* opaque)
|
||||
{
|
||||
FIO_rust_compress_dst_context_t* const context =
|
||||
(FIO_rust_compress_dst_context_t*)opaque;
|
||||
int const result = AIO_WritePool_closeFile(context->ress->writeCtx);
|
||||
context->dstFile = NULL;
|
||||
if (result) {
|
||||
DISPLAYLEVEL(1, "zstd: %s: %s \n", context->dstFileName, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void FIO_rust_compressDestinationUtime(void* opaque)
|
||||
{
|
||||
FIO_rust_compress_dst_context_t* const context =
|
||||
(FIO_rust_compress_dst_context_t*)opaque;
|
||||
UTIL_utime(context->dstFileName, context->srcFileStat);
|
||||
}
|
||||
|
||||
static void FIO_rust_compressDestinationRemove(void* opaque,
|
||||
const char* dstFileName)
|
||||
{
|
||||
(void)opaque;
|
||||
(void)FIO_removeFile(dstFileName);
|
||||
}
|
||||
|
||||
/*! FIO_compressFilename_dstFile() :
|
||||
* open dstFileName, or pass-through if ress.file != NULL,
|
||||
* open the destination, or pass through if the write pool already owns it,
|
||||
* then start compression with FIO_compressFilename_internal().
|
||||
* Manages source removal (--rm) and file permissions transfer.
|
||||
* note : ress.srcFile must be != NULL,
|
||||
* Rust owns the lifecycle ordering; C retains opaque resources, diagnostics,
|
||||
* metadata operations, and format-specific compression callbacks.
|
||||
* note : ress.readCtx must already have a source file attached,
|
||||
* so reach this function through FIO_compressFilename_srcFile().
|
||||
* @return : 0 : compression completed correctly,
|
||||
* 1 : pb
|
||||
@@ -2868,62 +3041,41 @@ static int FIO_compressFilename_dstFile(FIO_ctx_t* const fCtx,
|
||||
const stat_t* srcFileStat,
|
||||
int compressionLevel)
|
||||
{
|
||||
int closeDstFile = 0;
|
||||
int result;
|
||||
int transferStat = 0;
|
||||
int dstFd = -1;
|
||||
FIO_rust_compress_dst_context_t context;
|
||||
FIO_rust_compress_dst_projection_t projection;
|
||||
|
||||
assert(AIO_ReadPool_getFile(ress.readCtx) != NULL);
|
||||
if (AIO_WritePool_getFile(ress.writeCtx) == NULL) {
|
||||
int dstFileInitialPermissions = DEFAULT_FILE_PERMISSIONS;
|
||||
if ( strcmp (srcFileName, stdinmark)
|
||||
&& strcmp (dstFileName, stdoutmark)
|
||||
&& UTIL_isRegularFileStat(srcFileStat) ) {
|
||||
transferStat = 1;
|
||||
dstFileInitialPermissions = TEMPORARY_FILE_PERMISSIONS;
|
||||
}
|
||||
|
||||
closeDstFile = 1;
|
||||
DISPLAYLEVEL(6, "FIO_compressFilename_dstFile: opening dst: %s \n", dstFileName);
|
||||
{ FILE *dstFile = FIO_openDstFile(fCtx, prefs, srcFileName, dstFileName, dstFileInitialPermissions);
|
||||
if (dstFile==NULL) return 1; /* could not open dstFileName */
|
||||
dstFd = fileno(dstFile);
|
||||
AIO_WritePool_setFile(ress.writeCtx, dstFile);
|
||||
}
|
||||
/* Must only be added after FIO_openDstFile() succeeds.
|
||||
* Otherwise we may delete the destination file if it already exists,
|
||||
* and the user presses Ctrl-C when asked if they wish to overwrite.
|
||||
*/
|
||||
addHandler(dstFileName);
|
||||
}
|
||||
memset(&context, 0, sizeof(context));
|
||||
context.fCtx = fCtx;
|
||||
context.prefs = prefs;
|
||||
context.ress = &ress;
|
||||
context.dstFileName = dstFileName;
|
||||
context.srcFileStat = srcFileStat;
|
||||
|
||||
result = FIO_compressFilename_internal(fCtx, prefs, ress, dstFileName, srcFileName, compressionLevel);
|
||||
memset(&projection, 0, sizeof(projection));
|
||||
projection.opaque = &context;
|
||||
projection.dstFileName = dstFileName;
|
||||
projection.srcFileName = srcFileName;
|
||||
projection.compressionLevel = compressionLevel;
|
||||
projection.destinationAlreadyOpen = AIO_WritePool_getFile(ress.writeCtx) != NULL;
|
||||
projection.sourceIsStdin = !strcmp(srcFileName, stdinmark);
|
||||
projection.destinationIsStdout = !strcmp(dstFileName, stdoutmark);
|
||||
projection.sourceIsRegular = (projection.sourceIsStdin
|
||||
|| projection.destinationIsStdout)
|
||||
? 0
|
||||
: UTIL_isRegularFileStat(srcFileStat);
|
||||
projection.openDestination = FIO_rust_compressDestinationOpen;
|
||||
projection.attachDestination = FIO_rust_compressDestinationAttach;
|
||||
projection.addHandler = FIO_rust_compressAddHandler;
|
||||
projection.compress = FIO_rust_compressDestinationFile;
|
||||
projection.clearHandler = FIO_rust_compressClearHandler;
|
||||
projection.setFDStat = FIO_rust_compressSetFDStat;
|
||||
projection.closeDestination = FIO_rust_compressDestinationClose;
|
||||
projection.utimeDestination = FIO_rust_compressDestinationUtime;
|
||||
projection.removeDestination = FIO_rust_compressDestinationRemove;
|
||||
|
||||
if (closeDstFile) {
|
||||
clearHandler();
|
||||
|
||||
if (transferStat) {
|
||||
UTIL_setFDStat(dstFd, dstFileName, srcFileStat);
|
||||
}
|
||||
|
||||
DISPLAYLEVEL(6, "FIO_compressFilename_dstFile: closing dst: %s \n", dstFileName);
|
||||
if (AIO_WritePool_closeFile(ress.writeCtx)) { /* error closing file */
|
||||
DISPLAYLEVEL(1, "zstd: %s: %s \n", dstFileName, strerror(errno));
|
||||
result=1;
|
||||
}
|
||||
|
||||
if (transferStat) {
|
||||
UTIL_utime(dstFileName, srcFileStat);
|
||||
}
|
||||
|
||||
if ( (result != 0) /* operation failure */
|
||||
&& strcmp(dstFileName, stdoutmark) /* special case : don't remove() stdout */
|
||||
) {
|
||||
FIO_removeFile(dstFileName); /* remove compression artefact; note don't do anything special if remove() fails */
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return FIO_rust_compressFilenameDstFile(&projection);
|
||||
}
|
||||
|
||||
/* List used to compare file extensions (used with --exclude-compressed flag)
|
||||
|
||||
Reference in New Issue
Block a user