blob: 644a19a5d7ed5e96aa7aba72ea1fbe9f1f5c1e55 [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fbl/unique_fd.h>
#include "src/lib/chunked-compression/chunked-compressor.h"
#include "src/lib/chunked-compression/status.h"
#include "src/storage/tools/blobfs-compression/blobfs-compression.h"
namespace {
using chunked_compression::ChunkedCompressor;
using chunked_compression::CompressionParams;
void usage(const char* fname) {
fprintf(stderr, "Usage: %s source_file destination_file\n", fname);
}
// Opens |file|, truncates to |write_size|, and mmaps the file for writing.
// Returns the mapped buffer in |out_write_buf|, and the managed FD in |out_fd|.
int OpenAndMapForWriting(const char* file, size_t write_size, uint8_t** out_write_buf,
fbl::unique_fd* out_fd) {
fbl::unique_fd fd(open(file, O_RDWR | O_CREAT | O_TRUNC, 0644));
if (!fd.is_valid()) {
fprintf(stderr, "Failed to open '%s': %s\n", file, strerror(errno));
return 1;
}
if (ftruncate(fd.get(), write_size)) {
fprintf(stderr, "Failed to truncate '%s': %s\n", file, strerror(errno));
return 1;
}
void* data = nullptr;
if (write_size > 0) {
data = mmap(NULL, write_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd.get(), 0);
if (data == MAP_FAILED) {
fprintf(stderr, "mmap failed: %s\n", strerror(errno));
return 1;
}
}
*out_write_buf = static_cast<uint8_t*>(data);
*out_fd = std::move(fd);
return 0;
}
// Opens |file| and mmaps the file for reading.
// Returns the mapped buffer in |out_buf|, the size of the file in |out_size|, and the managed FD in
// |out_fd|.
int OpenAndMapForReading(const char* file, fbl::unique_fd* out_fd, const uint8_t** out_buf,
size_t* out_size) {
fbl::unique_fd fd(open(file, O_RDONLY));
if (!fd.is_valid()) {
fprintf(stderr, "Failed to open '%s'.\n", file);
return 1;
}
size_t size;
struct stat info;
if (fstat(fd.get(), &info) < 0) {
fprintf(stderr, "stat(%s) failed: %s\n", file, strerror(errno));
return 1;
}
if (!S_ISREG(info.st_mode)) {
fprintf(stderr, "%s is not a regular file\n", file);
return 1;
}
size = info.st_size;
void* data = nullptr;
if (size > 0) {
data = mmap(NULL, size, PROT_READ, MAP_SHARED, fd.get(), 0);
if (data == MAP_FAILED) {
fprintf(stderr, "mmap failed: %s\n", strerror(errno));
return 1;
}
}
*out_fd = std::move(fd);
*out_buf = static_cast<uint8_t*>(data);
*out_size = size;
return 0;
}
} // namespace
int main(int argc, char* const* argv) {
if (argc < 3) {
usage(argv[0]);
return 1;
}
fbl::unique_fd src_fd;
const uint8_t* src_data;
size_t src_size;
if (OpenAndMapForReading(argv[1] /*src file*/, &src_fd, &src_data, &src_size)) {
return 1;
}
CompressionParams params = blobfs_compress::ComputeDefaultBlobfsCompressionParams(src_size);
fbl::unique_fd dst_fd;
uint8_t* dest_write_buf;
if (OpenAndMapForWriting(argv[2] /*destination file*/, params.ComputeOutputSizeLimit(src_size),
&dest_write_buf, &dst_fd)) {
return 1;
}
size_t compressed_size;
if (blobfs_compress::BlobfsCompress(src_data, src_size, dest_write_buf /*destination buffer*/,
&compressed_size, params)) {
return 1;
}
ftruncate(dst_fd.get(), compressed_size);
return 0;
}