2025-08-06 22:04:36 +01:00
|
|
|
#include "tar.h"
|
|
|
|
|
|
|
|
|
|
#include <blue/compress/cstream.h>
|
2025-07-17 18:12:16 +01:00
|
|
|
#include <ropkg/writer.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
struct ropkg_writer {
|
2025-08-06 22:04:36 +01:00
|
|
|
b_cstream *w_fp;
|
2025-07-17 18:12:16 +01:00
|
|
|
|
|
|
|
|
struct ustar_header w_file_header;
|
|
|
|
|
size_t w_file_header_offset;
|
|
|
|
|
size_t w_file_nr_written;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const char zero_padding[512] = {0};
|
|
|
|
|
|
2025-08-06 22:04:36 +01:00
|
|
|
enum ropkg_status ropkg_writer_open(b_cstream *fp, struct ropkg_writer **out)
|
2025-07-17 18:12:16 +01:00
|
|
|
{
|
|
|
|
|
struct ropkg_writer *writer = malloc(sizeof *writer);
|
|
|
|
|
if (!writer) {
|
|
|
|
|
return ROPKG_ERR_NO_MEMORY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
memset(writer, 0x0, sizeof *writer);
|
|
|
|
|
|
|
|
|
|
writer->w_fp = fp;
|
|
|
|
|
|
|
|
|
|
*out = writer;
|
|
|
|
|
return ROPKG_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum ropkg_status ropkg_writer_close(struct ropkg_writer *pkg)
|
|
|
|
|
{
|
|
|
|
|
memset(&pkg->w_file_header, 0x0, sizeof pkg->w_file_header);
|
|
|
|
|
|
|
|
|
|
size_t nr_written;
|
2025-08-06 22:04:36 +01:00
|
|
|
b_status status = b_cstream_write(
|
2025-07-17 18:12:16 +01:00
|
|
|
pkg->w_fp,
|
|
|
|
|
&pkg->w_file_header,
|
|
|
|
|
sizeof pkg->w_file_header,
|
|
|
|
|
&nr_written);
|
|
|
|
|
|
2025-08-06 22:04:36 +01:00
|
|
|
if (!B_OK(status)) {
|
|
|
|
|
return ROPKG_ERR_IO_FAILURE;
|
2025-07-17 18:12:16 +01:00
|
|
|
}
|
|
|
|
|
|
2025-08-06 22:04:36 +01:00
|
|
|
status = b_cstream_write(
|
2025-07-17 18:12:16 +01:00
|
|
|
pkg->w_fp,
|
|
|
|
|
&pkg->w_file_header,
|
|
|
|
|
sizeof pkg->w_file_header,
|
|
|
|
|
&nr_written);
|
|
|
|
|
|
2025-08-06 22:04:36 +01:00
|
|
|
if (!B_OK(status)) {
|
|
|
|
|
return ROPKG_ERR_IO_FAILURE;
|
2025-07-17 18:12:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (nr_written != sizeof pkg->w_file_header) {
|
|
|
|
|
return ROPKG_ERR_IO_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
free(pkg);
|
|
|
|
|
|
|
|
|
|
return ROPKG_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void to_octal(size_t in, char *out, size_t field_size)
|
|
|
|
|
{
|
|
|
|
|
// char buf[64];
|
|
|
|
|
snprintf(out, field_size, "%0*zo", (int)(field_size - 1), in);
|
|
|
|
|
// memcpy(out, buf, field_size);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void refresh_header_checksum(struct ustar_header *header)
|
|
|
|
|
{
|
|
|
|
|
memset(header->tar_checksum, ' ', sizeof header->tar_checksum);
|
|
|
|
|
|
|
|
|
|
size_t checksum = 0;
|
|
|
|
|
unsigned char *v = (unsigned char *)header;
|
|
|
|
|
for (size_t i = 0; i < sizeof *header; i++) {
|
|
|
|
|
checksum += v[i];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
to_octal(checksum, header->tar_checksum, sizeof header->tar_checksum);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static enum ropkg_status encode_header(
|
|
|
|
|
struct ropkg_writer *pkg,
|
|
|
|
|
const char *path,
|
|
|
|
|
const struct ropkg_writer_file_info *info,
|
|
|
|
|
struct ustar_header *out)
|
|
|
|
|
{
|
|
|
|
|
memset(out, 0x0, sizeof *out);
|
|
|
|
|
snprintf(out->tar_filename, sizeof out->tar_filename, "%s", path);
|
|
|
|
|
|
|
|
|
|
to_octal(info->f_length, out->tar_filesize, sizeof out->tar_filesize);
|
|
|
|
|
to_octal(0755, out->tar_mode, sizeof out->tar_mode);
|
|
|
|
|
out->tar_type[0] = '0';
|
|
|
|
|
snprintf(out->tar_ustar_id, sizeof out->tar_ustar_id, "ustar");
|
|
|
|
|
out->tar_ustar_version[0] = out->tar_ustar_version[1] = '0';
|
|
|
|
|
|
|
|
|
|
refresh_header_checksum(out);
|
|
|
|
|
return ROPKG_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum ropkg_status ropkg_writer_begin_file(
|
|
|
|
|
struct ropkg_writer *pkg,
|
|
|
|
|
const char *path,
|
|
|
|
|
const struct ropkg_writer_file_info *info)
|
|
|
|
|
{
|
2025-08-06 22:04:36 +01:00
|
|
|
if (b_cstream_in_compressed_section(pkg->w_fp)) {
|
|
|
|
|
b_cstream_tx_bytes_uncompressed(
|
|
|
|
|
pkg->w_fp,
|
|
|
|
|
&pkg->w_file_header_offset);
|
2025-07-17 18:12:16 +01:00
|
|
|
} else {
|
2025-08-06 22:04:36 +01:00
|
|
|
b_cstream_tx_bytes(pkg->w_fp, &pkg->w_file_header_offset);
|
2025-07-17 18:12:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum ropkg_status status
|
|
|
|
|
= encode_header(pkg, path, info, &pkg->w_file_header);
|
|
|
|
|
if (status != ROPKG_SUCCESS) {
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t nr_written;
|
2025-08-06 22:04:36 +01:00
|
|
|
b_status status2 = b_cstream_write(
|
2025-07-17 18:12:16 +01:00
|
|
|
pkg->w_fp,
|
|
|
|
|
&pkg->w_file_header,
|
|
|
|
|
sizeof pkg->w_file_header,
|
|
|
|
|
&nr_written);
|
|
|
|
|
|
2025-08-06 22:04:36 +01:00
|
|
|
if (!B_OK(status2)) {
|
|
|
|
|
return ROPKG_ERR_IO_FAILURE;
|
2025-07-17 18:12:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (nr_written != sizeof pkg->w_file_header) {
|
|
|
|
|
return ROPKG_ERR_IO_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ROPKG_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum ropkg_status ropkg_writer_end_file(struct ropkg_writer *pkg)
|
|
|
|
|
{
|
2025-08-06 22:04:36 +01:00
|
|
|
b_status status;
|
2025-07-17 18:12:16 +01:00
|
|
|
size_t written, file_length, pos;
|
2025-08-06 22:04:36 +01:00
|
|
|
if (b_cstream_in_compressed_section(pkg->w_fp)) {
|
|
|
|
|
b_cstream_tx_bytes_uncompressed(pkg->w_fp, &pos);
|
2025-07-17 18:12:16 +01:00
|
|
|
} else {
|
2025-08-06 22:04:36 +01:00
|
|
|
b_cstream_tx_bytes(pkg->w_fp, &pos);
|
2025-07-17 18:12:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
file_length
|
|
|
|
|
= pos - pkg->w_file_header_offset - sizeof pkg->w_file_header;
|
|
|
|
|
|
|
|
|
|
size_t required_padding = 512 - (file_length % 512);
|
2025-08-06 22:04:36 +01:00
|
|
|
status = b_cstream_write(
|
2025-07-17 18:12:16 +01:00
|
|
|
pkg->w_fp,
|
|
|
|
|
zero_padding,
|
|
|
|
|
required_padding,
|
|
|
|
|
&written);
|
|
|
|
|
|
2025-08-06 22:04:36 +01:00
|
|
|
if (!B_OK(status)) {
|
|
|
|
|
return ROPKG_ERR_IO_FAILURE;
|
2025-07-17 18:12:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
to_octal(
|
|
|
|
|
file_length,
|
|
|
|
|
pkg->w_file_header.tar_filesize,
|
|
|
|
|
sizeof pkg->w_file_header.tar_filesize);
|
|
|
|
|
refresh_header_checksum(&pkg->w_file_header);
|
|
|
|
|
|
2025-08-06 22:04:36 +01:00
|
|
|
status = b_cstream_set_cursor_position(
|
2025-07-17 18:12:16 +01:00
|
|
|
pkg->w_fp,
|
|
|
|
|
pkg->w_file_header_offset);
|
2025-08-06 22:04:36 +01:00
|
|
|
if (B_OK(status)) {
|
|
|
|
|
b_cstream_write(
|
2025-07-17 18:12:16 +01:00
|
|
|
pkg->w_fp,
|
|
|
|
|
&pkg->w_file_header,
|
|
|
|
|
sizeof pkg->w_file_header,
|
|
|
|
|
&written);
|
2025-08-06 22:04:36 +01:00
|
|
|
b_cstream_restore_cursor_position(pkg->w_fp);
|
2025-07-17 18:12:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ROPKG_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum ropkg_status ropkg_writer_write(
|
|
|
|
|
struct ropkg_writer *pkg,
|
|
|
|
|
const void *p,
|
|
|
|
|
size_t len,
|
|
|
|
|
size_t *nr_written)
|
|
|
|
|
{
|
2025-08-06 22:04:36 +01:00
|
|
|
b_status status = b_cstream_write(pkg->w_fp, p, len, nr_written);
|
|
|
|
|
if (!B_OK(status)) {
|
|
|
|
|
return ROPKG_ERR_IO_FAILURE;
|
2025-07-17 18:12:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pkg->w_file_nr_written += len;
|
|
|
|
|
|
|
|
|
|
return ROPKG_SUCCESS;
|
|
|
|
|
}
|