TAR COMPATIBILITYYYYYYYYYYYY

This commit is contained in:
Gu://em_ 2026-04-08 19:57:58 +02:00
parent 589117ae1a
commit d71848194f
4 changed files with 76 additions and 23 deletions

View file

@ -1,8 +1,11 @@
#include "archive.h"
#include <grp.h>
#include <pwd.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include "../utils/filesystem.h"
#include "tar.h"
@ -32,31 +35,55 @@ static struct ustar_header create_header(FILE *file_stream, char *file_path)
// Versions
memcpy(header.version, TVERSION, TVERSLEN);
// TODO handle uid, gid, mtime, and links
// uid, gid, mtime and mode
struct stat st;
if (stat(file_path, &st) == -1)
{
printf("Could not stat file %s\n", file_path);
return header;
}
// TODO links
// UID
snprintf(header.uid, sizeof(header.uid), "%07o", st.st_uid);
// GID
snprintf(header.gid, sizeof(header.gid), "%07o", st.st_gid);
// Mtime
snprintf(header.mtime, sizeof(header.mtime), "%011lo", st.st_mtime);
// Mode
snprintf(header.mode, sizeof(header.mode), "%07o", st.st_mode & 0777);
// User name
struct passwd *pw = getpwuid(st.st_uid);
if (pw != NULL)
strncpy(header.uname, pw->pw_name, 32);
// Group name
struct group *gr = getgrgid(st.st_gid);
if (gr != NULL)
strncpy(header.gname, gr->gr_name, 32);
// File or directory
if (file_stream == NULL)
{
// === Directory
header.name[strlen(header.name)] = '/';
// Type
header.typeflag = DIRTYPE;
// Size
snprintf(header.size, 12, "%011o", 0);
}
else
{
// === File
// Length
size_t file_size = getfilesize(file_stream);
snprintf(header.size, TSIZELEN, "%lu", file_size);
// Size
snprintf(header.size, 12, "%011lo", st.st_size);
// Type
header.typeflag = REGTYPE;
}
// Checksum
union tar_header header_union = { .ustar = header };
size_t chksum = compute_checksum(&header_union);
snprintf(header.chksum, TCHKSUMLEN, "%lu", chksum);
return header;
compute_checksum(&header_union);
return header_union.ustar;
}
/**
@ -118,7 +145,7 @@ static enum error_code archivedir(FILE *archive, char *dir_path, bool verbose)
{
// Add the directory itself
if (verbose)
puts(dir_path);
printf("%s/\n", dir_path);
// Header
struct ustar_header header = create_header(NULL, dir_path);

View file

@ -1,6 +1,6 @@
#include "tar.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
struct unixtar_header *get_unixtar_header(union tar_header *header)
@ -26,34 +26,58 @@ bool check_checksum(union tar_header *header)
{
struct ustar_header *ustar_header;
struct unixtar_header *unixtar_header;
int actual_checksum;
char actual_checksum[TCHKSUMLEN];
// USTAR
if ((ustar_header = get_ustar_header(header)) != NULL)
{
actual_checksum = atoi(ustar_header->chksum);
strcpy(actual_checksum, ustar_header->chksum);
return strcmp(actual_checksum, header->ustar.chksum) == 0;
}
// UNIXTAR
else if ((unixtar_header = get_unixtar_header(header)) != NULL)
{
actual_checksum = atoi(unixtar_header->chksum);
strcpy(actual_checksum, unixtar_header->chksum);
return strcmp(actual_checksum, header->unixtar.chksum) == 0;
}
// Unsupported format
else
{
return false;
}
int computed_checksum = compute_checksum(header);
return computed_checksum == actual_checksum;
}
int compute_checksum(union tar_header *header)
void compute_checksum(union tar_header *header)
{
char *block = header->raw_block;
int sum = 0;
// Set to spaces
struct unixtar_header *unixtar_header = get_unixtar_header(header);
struct ustar_header *ustar_header = get_ustar_header(header);
if (ustar_header)
{
memset(ustar_header->chksum, ' ', TCHKSUMLEN);
}
else if (unixtar_header)
{
memset(unixtar_header->chksum, ' ', TCHKSUMLEN);
}
// Compute
unsigned char *block = header->raw_block;
unsigned int sum = 0;
for (int i = 0; i < BLOCK_SIZE; i++)
sum += block[i];
return sum;
// Update checksum
if (ustar_header)
{
snprintf(ustar_header->chksum, TCHKSUMLEN - 1, "%06o", sum);
ustar_header->chksum[TCHKSUMLEN - 2] = '\0';
ustar_header->chksum[TCHKSUMLEN - 1] = ' ';
}
else if (unixtar_header)
{
snprintf(unixtar_header->chksum, TCHKSUMLEN - 1, "%06o", sum);
unixtar_header->chksum[TCHKSUMLEN - 2] = '\0';
unixtar_header->chksum[TCHKSUMLEN - 1] = ' ';
}
}

View file

@ -86,7 +86,7 @@ union tar_header
{
struct unixtar_header unixtar;
struct ustar_header ustar;
char raw_block[BLOCK_SIZE];
unsigned char raw_block[BLOCK_SIZE];
};
// === Functions
@ -103,13 +103,14 @@ struct unixtar_header *get_unixtar_header(union tar_header *header);
struct ustar_header *get_ustar_header(union tar_header *header);
/* @brief checks if file has not been corrupted via checksum
* @warn Alters header checksum with the new one
* @return true if member file is valid, false otherwise
*/
bool check_checksum(union tar_header *header);
/* @brief computes the checksum of the given file
/* @brief computes the checksum of the given header and updates it
* @return the checksum
*/
int compute_checksum(union tar_header *header);
void compute_checksum(union tar_header *header);
#endif // TAR_H

View file

@ -14,6 +14,7 @@ enum error_code
TARGET_ALREADY_EXISTS,
NO_TARGET_PROVIDED,
EMPTY_ARCHIVE,
CANNOT_STAT,
NOT_IMPLEMENTED
};