Compare commits
3 Commits
6e0b65aaa8
...
c05a8e1b07
Author | SHA1 | Date | |
---|---|---|---|
c05a8e1b07 | |||
6bb0fecdc4 | |||
6c916ad861 |
12
.clang-format
Normal file
12
.clang-format
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
---
|
||||||
|
BasedOnStyle: Microsoft
|
||||||
|
CompactNamespaces: 'false'
|
||||||
|
FixNamespaceComments: 'false'
|
||||||
|
NamespaceIndentation: All
|
||||||
|
AllowShortBlocksOnASingleLine: 'true'
|
||||||
|
AllowShortCaseLabelsOnASingleLine: 'true'
|
||||||
|
AllowShortFunctionsOnASingleLine: None
|
||||||
|
AllowShortIfStatementsOnASingleLine: Always
|
||||||
|
AllowShortLambdasOnASingleLine: All
|
||||||
|
AllowShortLoopsOnASingleLine: 'true'
|
||||||
|
PointerAlignment: Left
|
2
Makefile
2
Makefile
@ -6,7 +6,7 @@ SRC := src
|
|||||||
CC ?= gcc
|
CC ?= gcc
|
||||||
AR ?= ar
|
AR ?= ar
|
||||||
CFLAGS ?= -O2 -Wall -Wextra
|
CFLAGS ?= -O2 -Wall -Wextra
|
||||||
CFLAGS := ${CFLAGS} -I.
|
CFLAGS := ${CFLAGS} -I. -D_IN_MINITAR
|
||||||
DESTDIR ?= /usr/local
|
DESTDIR ?= /usr/local
|
||||||
|
|
||||||
OBJS := $(OBJ)/tar.o \
|
OBJS := $(OBJ)/tar.o \
|
||||||
|
31
README.md
31
README.md
@ -34,3 +34,34 @@ int main(int argc, char** argv)
|
|||||||
```
|
```
|
||||||
|
|
||||||
This program will list out the files in a tar archive :)
|
This program will list out the files in a tar archive :)
|
||||||
|
|
||||||
|
## API
|
||||||
|
### minitar_open
|
||||||
|
`struct minitar* minitar_open(const char* filename)`
|
||||||
|
|
||||||
|
Opens a tar archive for reading, and returns a heap-allocated `struct minitar` which must be freed with `minitar_close()` after using it. If opening the file or allocating the struct fails, returns NULL.
|
||||||
|
|
||||||
|
A `struct minitar` is opaque, and should only be passed to other minitar functions. You should not care about its contents.
|
||||||
|
|
||||||
|
### minitar_read_entry
|
||||||
|
`struct minitar_entry* minitar_read_entry(struct minitar* mp)`
|
||||||
|
|
||||||
|
Reads the next entry from a `struct minitar` which should be the return value of a previous call to `minitar_open()`. The return value is a heap-allocated `struct minitar_entry`, which should be freed with `minitar_free_entry()` when no longer needed.
|
||||||
|
|
||||||
|
This structure consists of the file metadata (in the `metadata` field), and a heap-allocated pointer to the file's contents (the `ptr` field), of size metadata.size + a NULL character, for convenience. This means you can use normal C string functions if you're expecting an ASCII file. Other kinds of files may have NULL characters before the end of the file, so you should assume the length of `ptr` is `metadata.size` and not `strlen(ptr)`.
|
||||||
|
|
||||||
|
This pointer will be freed when calling `minitar_free_entry()`, so if you're intending to use it later, copy its contents somewhere else.
|
||||||
|
|
||||||
|
This function returns NULL on end-of-file (when all entries have been read).
|
||||||
|
|
||||||
|
### minitar_free_entry
|
||||||
|
`void minitar_free_entry(struct minitar_entry* entry)`
|
||||||
|
|
||||||
|
Frees the heap-allocated `struct minitar_entry` and the file contents stored inside it. The pointer passed to `minitar_free_entry()` should be the return value of a previous call to `minitar_read_entry()`.
|
||||||
|
|
||||||
|
### minitar_close
|
||||||
|
`int minitar_close(struct minitar* mp)`
|
||||||
|
|
||||||
|
Closes the tar archive file `mp` points to and frees the heap memory it was using. The pointer passed to `minitar_close()` should be the return value of a previous call to `minitar_open()`.
|
||||||
|
|
||||||
|
Returns 0 on success, everything else is failure and you should check `errno`.
|
@ -3,10 +3,14 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#ifdef _IN_MINITAR
|
||||||
struct minitar
|
struct minitar
|
||||||
{
|
{
|
||||||
FILE* stream;
|
FILE* stream;
|
||||||
};
|
};
|
||||||
|
#else
|
||||||
|
struct minitar;
|
||||||
|
#endif
|
||||||
|
|
||||||
enum minitar_file_type
|
enum minitar_file_type
|
||||||
{
|
{
|
||||||
|
22
src/tar.c
22
src/tar.c
@ -1,6 +1,6 @@
|
|||||||
#include <stdlib.h>
|
|
||||||
#include "minitar.h"
|
|
||||||
#include "tar.h"
|
#include "tar.h"
|
||||||
|
#include "minitar.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
int minitar_read_header(struct minitar* mp, struct tar_header* hdr);
|
int minitar_read_header(struct minitar* mp, struct tar_header* hdr);
|
||||||
int minitar_validate_header(struct tar_header* hdr);
|
int minitar_validate_header(struct tar_header* hdr);
|
||||||
@ -11,9 +11,13 @@ char* minitar_read_file(struct minitar_entry_metadata* metadata, struct minitar*
|
|||||||
struct minitar* minitar_open(const char* path)
|
struct minitar* minitar_open(const char* path)
|
||||||
{
|
{
|
||||||
FILE* fp = fopen(path, "rb"); // On some systems, this might be necessary to read the file properly.
|
FILE* fp = fopen(path, "rb"); // On some systems, this might be necessary to read the file properly.
|
||||||
if(!fp) return NULL;
|
if (!fp) return NULL;
|
||||||
struct minitar* mp = malloc(sizeof(struct minitar));
|
struct minitar* mp = malloc(sizeof(struct minitar));
|
||||||
if(!mp) { fclose(fp); return NULL; }
|
if (!mp)
|
||||||
|
{
|
||||||
|
fclose(fp);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
mp->stream = fp;
|
mp->stream = fp;
|
||||||
return mp;
|
return mp;
|
||||||
}
|
}
|
||||||
@ -22,7 +26,7 @@ int minitar_close(struct minitar* mp)
|
|||||||
{
|
{
|
||||||
int rc = fclose(mp->stream);
|
int rc = fclose(mp->stream);
|
||||||
free(mp);
|
free(mp);
|
||||||
if(rc) return rc;
|
if (rc) return rc;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,12 +34,12 @@ static struct minitar_entry* minitar_attempt_read_entry(struct minitar* mp, int*
|
|||||||
{
|
{
|
||||||
struct minitar_entry entry;
|
struct minitar_entry entry;
|
||||||
struct tar_header hdr;
|
struct tar_header hdr;
|
||||||
if(!minitar_read_header(mp, &hdr))
|
if (!minitar_read_header(mp, &hdr))
|
||||||
{
|
{
|
||||||
*valid = 1; // we are at end-of-file
|
*valid = 1; // we are at end-of-file
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if(!minitar_validate_header(&hdr))
|
if (!minitar_validate_header(&hdr))
|
||||||
{
|
{
|
||||||
*valid = 0;
|
*valid = 0;
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -43,7 +47,7 @@ static struct minitar_entry* minitar_attempt_read_entry(struct minitar* mp, int*
|
|||||||
*valid = 1;
|
*valid = 1;
|
||||||
minitar_parse_tar_header(&hdr, &entry.metadata);
|
minitar_parse_tar_header(&hdr, &entry.metadata);
|
||||||
char* buf = minitar_read_file(&entry.metadata, mp);
|
char* buf = minitar_read_file(&entry.metadata, mp);
|
||||||
if(!buf) return NULL;
|
if (!buf) return NULL;
|
||||||
entry.ptr = buf;
|
entry.ptr = buf;
|
||||||
return minitar_dup_entry(&entry);
|
return minitar_dup_entry(&entry);
|
||||||
}
|
}
|
||||||
@ -54,7 +58,7 @@ struct minitar_entry* minitar_read_entry(struct minitar* mp)
|
|||||||
struct minitar_entry* result;
|
struct minitar_entry* result;
|
||||||
do {
|
do {
|
||||||
result = minitar_attempt_read_entry(mp, &valid);
|
result = minitar_attempt_read_entry(mp, &valid);
|
||||||
} while(!valid);
|
} while (!valid);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
#ifndef MINITAR_TAR_H
|
#ifndef MINITAR_TAR_H
|
||||||
#define MINITAR_TAR_H
|
#define MINITAR_TAR_H
|
||||||
|
|
||||||
struct tar_header {
|
struct tar_header
|
||||||
|
{
|
||||||
char name[100];
|
char name[100];
|
||||||
char mode[8];
|
char mode[8];
|
||||||
char uid[8];
|
char uid[8];
|
||||||
|
58
src/util.c
58
src/util.c
@ -1,11 +1,11 @@
|
|||||||
#define _POSIX_C_SOURCE 200809L
|
#define _POSIX_C_SOURCE 200809L
|
||||||
|
#include "minitar.h"
|
||||||
|
#include "tar.h"
|
||||||
|
#include <stdarg.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdnoreturn.h>
|
#include <stdnoreturn.h>
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "minitar.h"
|
|
||||||
#include "tar.h"
|
|
||||||
|
|
||||||
noreturn void minitar_panic(const char* message)
|
noreturn void minitar_panic(const char* message)
|
||||||
{
|
{
|
||||||
@ -15,11 +15,13 @@ noreturn void minitar_panic(const char* message)
|
|||||||
|
|
||||||
void minitar_parse_tar_header(struct tar_header* hdr, struct minitar_entry_metadata* metadata)
|
void minitar_parse_tar_header(struct tar_header* hdr, struct minitar_entry_metadata* metadata)
|
||||||
{
|
{
|
||||||
if(!strlen(hdr->prefix))
|
if (!strlen(hdr->prefix))
|
||||||
{
|
{
|
||||||
strncpy(metadata->name, hdr->name, 100);
|
strncpy(metadata->name, hdr->name, 100);
|
||||||
metadata->name[100] = '\0';
|
metadata->name[100] = '\0';
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
strcpy(metadata->name, hdr->prefix);
|
strcpy(metadata->name, hdr->prefix);
|
||||||
strcat(metadata->name, "/");
|
strcat(metadata->name, "/");
|
||||||
strncat(metadata->name, hdr->name, 100);
|
strncat(metadata->name, hdr->name, 100);
|
||||||
@ -31,38 +33,26 @@ void minitar_parse_tar_header(struct tar_header* hdr, struct minitar_entry_metad
|
|||||||
metadata->gid = (gid_t)strtoul(hdr->gid, NULL, 8);
|
metadata->gid = (gid_t)strtoul(hdr->gid, NULL, 8);
|
||||||
|
|
||||||
char* sizeptr = strndup(hdr->size, 12);
|
char* sizeptr = strndup(hdr->size, 12);
|
||||||
if(!sizeptr) minitar_panic("Failed to allocate memory to duplicate a tar header's size field");
|
if (!sizeptr) minitar_panic("Failed to allocate memory to duplicate a tar header's size field");
|
||||||
metadata->size = (size_t)strtoull(sizeptr, NULL, 8);
|
metadata->size = (size_t)strtoull(sizeptr, NULL, 8);
|
||||||
free(sizeptr);
|
free(sizeptr);
|
||||||
|
|
||||||
char* timeptr = strndup(hdr->mtime, 12);
|
char* timeptr = strndup(hdr->mtime, 12);
|
||||||
if(!timeptr) minitar_panic("Failed to allocate memory to duplicate a tar header's mtime field");
|
if (!timeptr) minitar_panic("Failed to allocate memory to duplicate a tar header's mtime field");
|
||||||
metadata->mtime = (time_t)strtol(timeptr, NULL, 8);
|
metadata->mtime = (time_t)strtol(timeptr, NULL, 8);
|
||||||
free(timeptr);
|
free(timeptr);
|
||||||
|
|
||||||
switch(hdr->typeflag)
|
switch (hdr->typeflag)
|
||||||
{
|
{
|
||||||
case '\0':
|
case '\0':
|
||||||
case '0':
|
case '0': metadata->type = MTAR_REGULAR; break;
|
||||||
metadata->type = MTAR_REGULAR;
|
case '1': minitar_panic("Links to other files within a tar archive are unsupported");
|
||||||
break;
|
case '2': minitar_panic("Symbolic links are unsupported");
|
||||||
case '1':
|
case '3': metadata->type = MTAR_CHRDEV; break;
|
||||||
minitar_panic("Links to other files within a tar archive are unsupported");
|
case '4': metadata->type = MTAR_BLKDEV; break;
|
||||||
case '2':
|
case '5': metadata->type = MTAR_DIRECTORY; break;
|
||||||
minitar_panic("Symbolic links are unsupported");
|
case '6': minitar_panic("FIFOs are unsupported");
|
||||||
case '3':
|
default: minitar_panic("Unknown entry type in tar header");
|
||||||
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->uname, hdr->uname);
|
||||||
@ -77,14 +67,14 @@ int minitar_validate_header(struct tar_header* hdr)
|
|||||||
int minitar_read_header(struct minitar* mp, struct tar_header* hdr)
|
int minitar_read_header(struct minitar* mp, struct tar_header* hdr)
|
||||||
{
|
{
|
||||||
size_t rc = fread(hdr, sizeof *hdr, 1, mp->stream);
|
size_t rc = fread(hdr, sizeof *hdr, 1, mp->stream);
|
||||||
if(rc == 0 && feof(mp->stream)) return 0;
|
if (rc == 0 && feof(mp->stream)) return 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct minitar_entry* minitar_dup_entry(struct minitar_entry* original)
|
struct minitar_entry* minitar_dup_entry(struct minitar_entry* original)
|
||||||
{
|
{
|
||||||
struct minitar_entry* new = malloc(sizeof *original);
|
struct minitar_entry* new = malloc(sizeof *original);
|
||||||
if(!new) return NULL;
|
if (!new) return NULL;
|
||||||
memcpy(new, original, sizeof *new);
|
memcpy(new, original, sizeof *new);
|
||||||
return new;
|
return new;
|
||||||
}
|
}
|
||||||
@ -92,14 +82,14 @@ struct minitar_entry* minitar_dup_entry(struct minitar_entry* original)
|
|||||||
char* minitar_read_file(struct minitar_entry_metadata* metadata, struct minitar* mp)
|
char* minitar_read_file(struct minitar_entry_metadata* metadata, struct minitar* mp)
|
||||||
{
|
{
|
||||||
char* buf = malloc(metadata->size + 1);
|
char* buf = malloc(metadata->size + 1);
|
||||||
if(!buf) return NULL;
|
if (!buf) return NULL;
|
||||||
|
|
||||||
size_t nread = fread(buf, 1, metadata->size, mp->stream);
|
size_t nread = fread(buf, 1, metadata->size, mp->stream);
|
||||||
if(!nread)
|
if (!nread)
|
||||||
{
|
{
|
||||||
free(buf);
|
free(buf);
|
||||||
if(feof(mp->stream)) return NULL;
|
if (feof(mp->stream)) return NULL;
|
||||||
if(ferror(mp->stream)) minitar_panic("Error while reading file data from tar archive");
|
if (ferror(mp->stream)) minitar_panic("Error while reading file data from tar archive");
|
||||||
__builtin_unreachable();
|
__builtin_unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user