2022-11-06 10:22:27 +00:00
|
|
|
#define _IN_MINITAR
|
2022-11-05 19:10:48 +00:00
|
|
|
#include "tar.h"
|
2022-11-06 10:02:26 +00:00
|
|
|
#include "minitar.h"
|
|
|
|
#include <stdlib.h>
|
2022-11-06 10:51:03 +00:00
|
|
|
#include <string.h>
|
2022-11-05 19:10:48 +00:00
|
|
|
|
2022-11-06 13:23:35 +00:00
|
|
|
// all of these are defined in util.c
|
2022-11-06 13:21:32 +00:00
|
|
|
int minitar_read_header(struct minitar*, struct tar_header*);
|
2022-11-21 16:38:08 +00:00
|
|
|
int minitar_validate_header(const struct tar_header*);
|
2022-11-22 16:28:15 +00:00
|
|
|
void minitar_parse_metadata_from_tar_header(const struct tar_header*, struct minitar_entry_metadata*);
|
2022-11-21 16:38:08 +00:00
|
|
|
struct minitar_entry* minitar_dup_entry(const struct minitar_entry*);
|
2022-11-06 13:23:35 +00:00
|
|
|
char* minitar_read_file_contents(struct minitar_entry_metadata*, struct minitar*);
|
2022-11-21 19:20:37 +00:00
|
|
|
size_t minitar_get_size_in_blocks(size_t);
|
2022-11-05 17:52:51 +00:00
|
|
|
|
2022-11-06 13:21:32 +00:00
|
|
|
struct minitar* minitar_open(const char* pathname)
|
2022-11-05 17:52:51 +00:00
|
|
|
{
|
2022-11-06 13:21:32 +00:00
|
|
|
FILE* fp = fopen(pathname, "rb"); // On some systems, this might be necessary to read the file properly.
|
2022-11-06 10:02:26 +00:00
|
|
|
if (!fp) return NULL;
|
2022-11-05 17:52:51 +00:00
|
|
|
struct minitar* mp = malloc(sizeof(struct minitar));
|
2022-11-06 10:02:26 +00:00
|
|
|
if (!mp)
|
|
|
|
{
|
|
|
|
fclose(fp);
|
|
|
|
return NULL;
|
|
|
|
}
|
2022-11-05 17:52:51 +00:00
|
|
|
mp->stream = fp;
|
|
|
|
return mp;
|
|
|
|
}
|
|
|
|
|
|
|
|
int minitar_close(struct minitar* mp)
|
|
|
|
{
|
|
|
|
int rc = fclose(mp->stream);
|
|
|
|
free(mp);
|
2022-11-22 16:25:17 +00:00
|
|
|
return rc;
|
2022-11-05 19:10:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct minitar_entry* minitar_attempt_read_entry(struct minitar* mp, int* valid)
|
|
|
|
{
|
|
|
|
struct minitar_entry entry;
|
|
|
|
struct tar_header hdr;
|
2022-11-22 16:28:34 +00:00
|
|
|
*valid = 1;
|
|
|
|
if (!minitar_read_header(mp, &hdr)) return NULL;
|
2022-11-06 10:02:26 +00:00
|
|
|
if (!minitar_validate_header(&hdr))
|
2022-11-05 19:10:48 +00:00
|
|
|
{
|
|
|
|
*valid = 0;
|
|
|
|
return NULL;
|
|
|
|
}
|
2022-11-21 19:20:37 +00:00
|
|
|
if (fgetpos(mp->stream, &entry.position)) return NULL;
|
2022-11-22 16:28:15 +00:00
|
|
|
minitar_parse_metadata_from_tar_header(&hdr, &entry.metadata);
|
2022-11-21 19:20:37 +00:00
|
|
|
if (entry.metadata.size)
|
|
|
|
{
|
|
|
|
size_t size_in_blocks = minitar_get_size_in_blocks(entry.metadata.size);
|
|
|
|
if (fseek(mp->stream, size_in_blocks,
|
|
|
|
SEEK_CUR)) // move over to the next block, skipping over the file contents
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
2022-11-05 19:10:48 +00:00
|
|
|
return minitar_dup_entry(&entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct minitar_entry* minitar_read_entry(struct minitar* mp)
|
|
|
|
{
|
|
|
|
int valid;
|
|
|
|
struct minitar_entry* result;
|
|
|
|
do {
|
|
|
|
result = minitar_attempt_read_entry(mp, &valid);
|
2022-11-22 16:28:34 +00:00
|
|
|
} while (!valid); // Skip over invalid entries
|
2022-11-05 19:10:48 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2022-11-06 10:22:27 +00:00
|
|
|
void minitar_rewind(struct minitar* mp)
|
|
|
|
{
|
|
|
|
rewind(mp->stream);
|
|
|
|
}
|
|
|
|
|
2022-11-05 19:10:48 +00:00
|
|
|
void minitar_free_entry(struct minitar_entry* entry)
|
|
|
|
{
|
2022-11-06 09:33:37 +00:00
|
|
|
free(entry);
|
2022-11-06 10:51:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
struct minitar_entry* minitar_find_by_name(struct minitar* mp, const char* name)
|
|
|
|
{
|
|
|
|
struct minitar_entry* entry;
|
|
|
|
do {
|
|
|
|
entry = minitar_read_entry(mp);
|
|
|
|
if (entry)
|
|
|
|
{
|
|
|
|
if (!strcmp(entry->metadata.name, name)) return entry;
|
|
|
|
minitar_free_entry(entry);
|
|
|
|
}
|
|
|
|
} while (entry);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct minitar_entry* minitar_find_any_of(struct minitar* mp, enum minitar_file_type type)
|
|
|
|
{
|
|
|
|
struct minitar_entry* entry;
|
|
|
|
do {
|
|
|
|
entry = minitar_read_entry(mp);
|
|
|
|
if (entry)
|
|
|
|
{
|
|
|
|
if (entry->metadata.type == type) return entry;
|
|
|
|
minitar_free_entry(entry);
|
|
|
|
}
|
|
|
|
} while (entry);
|
|
|
|
return NULL;
|
2022-11-21 19:20:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
size_t minitar_read_contents(struct minitar* mp, struct minitar_entry* entry, char* buf, size_t max)
|
|
|
|
{
|
|
|
|
if (!max) return 0;
|
|
|
|
fpos_t current_position;
|
|
|
|
if (fgetpos(mp->stream, ¤t_position)) return 0;
|
|
|
|
if (fsetpos(mp->stream, &entry->position)) return 0;
|
|
|
|
size_t nread = fread(buf, 1, max > entry->metadata.size ? entry->metadata.size : max, mp->stream);
|
|
|
|
if (ferror(mp->stream)) return 0;
|
|
|
|
if (fsetpos(mp->stream, ¤t_position)) return 0;
|
|
|
|
return nread;
|
2022-11-05 17:52:51 +00:00
|
|
|
}
|