nar

simple archives
git clone git://git.kocotian.pl/nar.git
Log | Files | Refs | LICENSE

commit 2eea68590658c4e57146eb27c9a9e1c4b4fd4828
parent 329695dd70ab47175849cd9b4c662e92ec3be982
Author: kocotian <kocotian@kocotian.pl>
Date:   Thu, 28 Jan 2021 20:31:29 +0100

extraction

Diffstat:
MSTRUCTURE.wiki | 2++
Mnar.c | 62+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 63 insertions(+), 1 deletion(-)

diff --git a/STRUCTURE.wiki b/STRUCTURE.wiki @@ -3,6 +3,7 @@ Typical NAR archive contains: - Archive header - File array (just files) +- Archive ending == NAR Archive header == @@ -20,6 +21,7 @@ File array structure: | 2 | File mode | | 4 | Owner ID | | 4 | Owner's Group ID | +| 4 | File name length | | *Length* + 1 | File name (NULL terminated) | | *File size* | File content | | 1 | End of file confirmation byte | diff --git a/nar.c b/nar.c @@ -5,6 +5,7 @@ #include <fcntl.h> #include <stdio.h> +#include <stdlib.h> #include <string.h> #include <sys/mman.h> #include <sys/stat.h> @@ -15,8 +16,10 @@ #include "util.h" static void create(char *fn, int fc, char *farr[]); +static void extract(char *fn); static void usage(void); +const char conbyte = 'c'; const char eofbyte = 'k'; char *argv0; int verbose; @@ -54,13 +57,14 @@ create(char *fn, int fc, char *farr[]) b16 = sb.st_mode; write(fd, &b16, 2); b32 = sb.st_uid; write(fd, &b32, 4); b32 = sb.st_gid; write(fd, &b32, 4); + b32 = strlen(farr[i]); write(fd, &b32, 4); write(fd, farr[i], strlen(farr[i]) + 1); if ((fdl = open(farr[i], O_RDONLY)) < 0) die("open: %s:", farr[i]); membuf = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fdl, 0); write(fd, membuf, sb.st_size); munmap(membuf, sb.st_size); - write(fd, &eofbyte, 1); + write(fd, (i < fc - 1 ? &conbyte : &eofbyte), 1); close(fdl); } @@ -70,6 +74,61 @@ create(char *fn, int fc, char *farr[]) } void +extract(char *fn) +{ + int fd, fdl; + struct stat sb; + void *membuf; + char *filename, eofb, magicval[4]; + + u_int64_t b64; + u_int32_t b32; + u_int16_t b16; + + /* opening a file */ + if (fn != NULL) { + if ((fd = open(fn, O_RDONLY)) < 0) + die("error while opening %s:", fn); + } + else + fd = 0; /* if no filename, default will be stdin */ + + /* check for magic value */ + if (read(fd, magicval, 4) < 4) + die("read error:"); + if (strncmp("NAR\n", magicval, 4)) + die("file is definitely not a nar."); + + do { + read(fd, &b64, 8); sb.st_size = b64; + read(fd, &b16, 2); sb.st_mode = b16; + read(fd, &b32, 4); sb.st_uid = b32; + read(fd, &b32, 4); sb.st_gid = b32; + read(fd, &b32, 4); /* file name length */ + filename = malloc(b32); + read(fd, filename, b32 + 1); + if (verbose) + printf("extracting %s\n", filename); + membuf = malloc(sb.st_size); + read(fd, membuf, sb.st_size); + if ((fdl = open(filename, O_CREAT | O_WRONLY, sb.st_mode)) < 0) + die("open: %s:", filename); + free(filename); + write(fdl, membuf, sb.st_size); + close(fdl); + free(membuf); + read(fd, &eofb, 1); + } while (eofb == conbyte); + + if (eofb != eofbyte) + die("archive is broken"); + + /* closing a file */ + if (fn != NULL) + close(fd); +} + +void usage(void) { die("usage: %s [-cx] [-v] [-f filename]", argv0); @@ -103,6 +162,7 @@ main(int argc, char *argv[]) switch (flag) { case 'c': create(filename, argc, argv); break; + case 'x': extract(filename); break; default: usage(); break; }