mirror of
https://github.com/linux-msm/tqftpserv.git
synced 2024-11-26 19:43:44 +08:00
0f7fd27524
Currently we pre-allocate around 128K of zstd state ahead of time, keeping if for the whole daemon lifetime... Even if we don't need to decompress any files. As mentioned by Dmitry: Granted that tqftpserv handles only few files during the whole lifetime and most of devices don't have swap, I think it's fine to use non-context versions of the functions. Let's free the memory for other software. Swap ZSTD_decompressDCtx() for ZSTD_decompress() which will allocate and free the state when needed. Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
97 lines
2.5 KiB
C
97 lines
2.5 KiB
C
// SPDX-License-Identifier: BSD-3-Clause
|
|
/*
|
|
* Copyright (c) 2024, Stefan Hansson
|
|
* Copyright (c) 2024, Emil Velikov
|
|
*/
|
|
|
|
/* For memfd_create */
|
|
#define _GNU_SOURCE
|
|
|
|
#include <sys/mman.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <zstd.h>
|
|
|
|
#include "zstd-decompress.h"
|
|
|
|
/**
|
|
* zstd_decompress_file() - decompress a zstd-compressed file
|
|
* @filename: path to a file to decompress
|
|
*
|
|
* Return: opened fd on success, -1 on error
|
|
*/
|
|
int zstd_decompress_file(const char *filename)
|
|
{
|
|
/* Figure out the size of the file. */
|
|
struct stat file_stat;
|
|
if (stat(filename, &file_stat) == -1) {
|
|
perror("stat failed");
|
|
return -1;
|
|
}
|
|
|
|
const size_t file_size = file_stat.st_size;
|
|
|
|
const int input_file_fd = open(filename, O_RDONLY);
|
|
if (input_file_fd == -1) {
|
|
perror("open failed");
|
|
return -1;
|
|
}
|
|
|
|
void* const compressed_buffer = mmap(NULL, file_size, PROT_READ, MAP_POPULATE | MAP_PRIVATE, input_file_fd, 0);
|
|
if (compressed_buffer == MAP_FAILED) {
|
|
perror("mmap failed");
|
|
close(input_file_fd);
|
|
return -1;
|
|
}
|
|
close(input_file_fd);
|
|
|
|
const unsigned long long decompressed_size = ZSTD_getFrameContentSize(compressed_buffer, file_size);
|
|
if (decompressed_size == ZSTD_CONTENTSIZE_UNKNOWN) {
|
|
fprintf(stderr, "Content size could not be determined for %s\n", filename);
|
|
munmap(compressed_buffer, file_size);
|
|
return -1;
|
|
}
|
|
if (decompressed_size == ZSTD_CONTENTSIZE_ERROR) {
|
|
fprintf(stderr, "Error getting content size for %s\n", filename);
|
|
munmap(compressed_buffer, file_size);
|
|
return -1;
|
|
}
|
|
|
|
void* const decompressed_buffer = malloc((size_t)decompressed_size);
|
|
if (decompressed_buffer == NULL) {
|
|
perror("malloc failed");
|
|
munmap(compressed_buffer, file_size);
|
|
return -1;
|
|
}
|
|
|
|
const size_t return_size = ZSTD_decompress(decompressed_buffer, decompressed_size, compressed_buffer, file_size);
|
|
if (ZSTD_isError(return_size)) {
|
|
fprintf(stderr, "ZSTD_decompress failed: %s\n", ZSTD_getErrorName(return_size));
|
|
free(decompressed_buffer);
|
|
munmap(compressed_buffer, file_size);
|
|
return -1;
|
|
}
|
|
|
|
const int output_file_fd = memfd_create(filename, 0);
|
|
if (output_file_fd == -1) {
|
|
perror("memfd_create failed");
|
|
free(decompressed_buffer);
|
|
munmap(compressed_buffer, file_size);
|
|
return -1;
|
|
}
|
|
|
|
if (write(output_file_fd, decompressed_buffer, decompressed_size) != decompressed_size) {
|
|
perror("write failed");
|
|
close(output_file_fd);
|
|
free(decompressed_buffer);
|
|
munmap(compressed_buffer, file_size);
|
|
return -1;
|
|
}
|
|
|
|
return output_file_fd;
|
|
}
|