Basic file listing :)

This commit is contained in:
apio 2022-11-05 20:10:48 +01:00
parent e233ca00eb
commit 0952af15b4
6 changed files with 221 additions and 2 deletions

View File

@ -9,7 +9,8 @@ CFLAGS ?= -O2 -Wall -Wextra
CFLAGS := ${CFLAGS} -I.
DESTDIR ?= /usr/local
OBJS := $(OBJ)/tar.o
OBJS := $(OBJ)/tar.o \
$(OBJ)/util.o
build: $(OBJS)
@echo -- Creating $(LIBNAME).a

View File

@ -1,3 +1,36 @@
# minitar
Tiny C library to interact with tar archives
Tiny C library to interact with tar archives
## Example
```
#include <stdio.h>
#include <minitar.h>
int main(int argc, char** argv)
{
if(argc == 1)
{
fprintf(stderr, "Usage: %s [file]\n", argv[0]);
return 1;
}
struct minitar* mp = minitar_open(argv[1]);
if(!mp)
{
perror(argv[1]);
return 1;
}
struct minitar_entry* entry;
do {
entry = minitar_read_entry(mp);
if(entry) {
printf("Found file %s\n", entry->metadata.name);
minitar_free_entry(entry);
}
} while(entry);
minitar_close(mp);
}
```
This program will list out the files in a tar archive :)

View File

@ -1,13 +1,43 @@
#ifndef MINITAR_H
#define MINITAR_H
#include <stdio.h>
#include <sys/types.h>
struct minitar
{
FILE* stream;
};
enum minitar_file_type
{
MTAR_REGULAR,
MTAR_CHRDEV,
MTAR_BLKDEV,
MTAR_DIRECTORY
};
struct minitar_entry_metadata
{
char name[257];
mode_t mode;
uid_t uid;
gid_t gid;
size_t size;
time_t mtime;
enum minitar_file_type type;
char uname[32];
char gname[32];
};
struct minitar_entry
{
struct minitar_entry_metadata metadata;
char* ptr;
};
struct minitar* minitar_open(const char* pathname);
struct minitar_entry* minitar_read_entry(struct minitar* mp);
void minitar_free_entry(struct minitar_entry* entry);
int minitar_close(struct minitar* mp);
#endif

View File

@ -1,5 +1,11 @@
#include <stdlib.h>
#include "minitar.h"
#include "tar.h"
int minitar_read_header(struct minitar* mp, struct tar_header* hdr);
int minitar_validate_header(struct tar_header* hdr);
void minitar_parse_tar_header(struct tar_header* hdr, struct minitar_entry_metadata* metadata);
struct minitar_entry* minitar_dup_entry(struct minitar_entry* original);
struct minitar* minitar_open(const char* path)
{
@ -17,4 +23,39 @@ int minitar_close(struct minitar* mp)
free(mp);
if(rc) return rc;
return 0;
}
static struct minitar_entry* minitar_attempt_read_entry(struct minitar* mp, int* valid)
{
struct minitar_entry entry;
struct tar_header hdr;
if(!minitar_read_header(mp, &hdr))
{
*valid = 1; // we are at end-of-file
return NULL;
}
if(!minitar_validate_header(&hdr))
{
*valid = 0;
return NULL;
}
*valid = 1;
minitar_parse_tar_header(&hdr, &entry.metadata);
// FIXME: Actually read the file and place it in buf.
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);
} while(!valid);
return result;
}
void minitar_free_entry(struct minitar_entry* entry)
{
free(entry); // FIXME: Also free the file's content, when it's placed in buf.
}

24
src/tar.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef MINITAR_TAR_H
#define MINITAR_TAR_H
struct tar_header {
char name[100];
char mode[8];
char uid[8];
char gid[8];
char size[12];
char mtime[12];
char chksum[8];
char typeflag;
char linkname[100];
char magic[6];
char version[2];
char uname[32];
char gname[32];
char devmajor[8];
char devminor[8];
char prefix[155];
char padding[12];
} __attribute__((packed));
#endif

90
src/util.c Normal file
View File

@ -0,0 +1,90 @@
#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <stdlib.h>
#include <stdnoreturn.h>
#include <stdarg.h>
#include <string.h>
#include "minitar.h"
#include "tar.h"
noreturn void minitar_panic(const char* message)
{
fprintf(stderr, "minitar: %s\n", message);
abort();
}
void minitar_parse_tar_header(struct tar_header* hdr, struct minitar_entry_metadata* metadata)
{
if(!strlen(hdr->prefix))
{
strncpy(metadata->name, hdr->name, 100);
metadata->name[100] = '\0';
} else {
strcpy(metadata->name, hdr->prefix);
strcat(metadata->name, "/");
strncat(metadata->name, hdr->name, 100);
metadata->name[256] = '\0';
}
metadata->mode = (mode_t)strtol(hdr->mode, NULL, 8);
metadata->uid = (uid_t)strtoul(hdr->uid, NULL, 8);
metadata->gid = (gid_t)strtoul(hdr->gid, NULL, 8);
char* sizeptr = strndup(hdr->size, 12);
if(!sizeptr) minitar_panic("Failed to allocate memory to duplicate a tar header's size field");
metadata->size = (size_t)strtoull(sizeptr, NULL, 8);
free(sizeptr);
char* timeptr = strndup(hdr->mtime, 12);
if(!timeptr) minitar_panic("Failed to allocate memory to duplicate a tar header's mtime field");
metadata->mtime = (time_t)strtol(timeptr, NULL, 8);
free(timeptr);
switch(hdr->typeflag)
{
case '\0':
case '0':
metadata->type = MTAR_REGULAR;
break;
case '1':
minitar_panic("Links to other files within a tar archive are unsupported");
case '2':
minitar_panic("Symbolic links are unsupported");
case '3':
metadata->type = MTAR_CHRDEV;
break;
case '4':
metadata->type = MTAR_BLKDEV;
break;
case '5':
metadata->type = MTAR_DIRECTORY;
break;
case '6':
minitar_panic("FIFOs are unsupported");
default:
minitar_panic("Unknown entry type in tar header");
}
strcpy(metadata->uname, hdr->uname);
strcpy(metadata->gname, hdr->gname);
}
int minitar_validate_header(struct tar_header* hdr)
{
return !strncmp(hdr->magic, "ustar", 5);
}
int minitar_read_header(struct minitar* mp, struct tar_header* hdr)
{
size_t rc = fread(hdr, sizeof *hdr, 1, mp->stream);
if(rc == 0 && feof(mp->stream)) return 0;
return 1;
}
struct minitar_entry* minitar_dup_entry(struct minitar_entry* original)
{
struct minitar_entry* new = malloc(sizeof *original);
if(!new) return NULL;
memcpy(new, original, sizeof *new);
return new;
}