diff options
author | Jakob Kaivo <jkk@ung.org> | 2019-11-20 15:44:44 -0500 |
---|---|---|
committer | Jakob Kaivo <jkk@ung.org> | 2019-11-20 15:44:44 -0500 |
commit | ad7a406b3d6fa0c14d3b8efc341db4e7b1b297e0 (patch) | |
tree | 69ae7e9858c54242ce375b89e8c31d3a064a06ee |
initial commit
-rw-r--r-- | .gitignore | 4 | ||||
-rw-r--r-- | Makefile | 8 | ||||
-rw-r--r-- | cpio.c | 114 | ||||
-rw-r--r-- | pax.c | 269 | ||||
-rw-r--r-- | pax.h | 73 | ||||
-rw-r--r-- | tar.c | 113 |
6 files changed, 581 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d524b77 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +pax +tar +cpio +*.o diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..c6bbc04 --- /dev/null +++ b/Makefile @@ -0,0 +1,8 @@ +.POSIX: + +CFLAGS=-Wall -Wextra -Wpedantic + +pax: pax.o tar.o cpio.o + +clean: + rm -f $$(cat .gitignore) @@ -0,0 +1,114 @@ +/* + * UNG's Not GNU + * + * Copyright (c) 2011-2019, Jakob Kaivo <jkk@ung.org> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#define _XOPEN_SOURCE 700 +#include <cpio.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> + +#include "pax.h" + +struct cpio_header { + char magic[6]; + char dev[6]; + char ino[6]; + char mode[6]; + char uid[6]; + char gid[6]; + char nlink[6]; + char rdev[6]; + char mtime[11]; + char namesize[6]; + char filesize[11]; +}; + +struct cpio_entry { + struct stat st; + uintmax_t namesize; +}; + +const size_t cpio_header_size = sizeof(struct cpio_header); + +static mode_t cpio_convert_mode(unsigned long mode) +{ + mode_t m = 0; + m |= (mode & C_IRUSR) ? S_IRUSR : 0; + m |= (mode & C_IWUSR) ? S_IWUSR : 0; + m |= (mode & C_IXUSR) ? S_IXUSR : 0; + + m |= (mode & C_IRGRP) ? S_IRGRP : 0; + m |= (mode & C_IWGRP) ? S_IWGRP : 0; + m |= (mode & C_IXGRP) ? S_IXGRP : 0; + + m |= (mode & C_IROTH) ? S_IROTH : 0; + m |= (mode & C_IWOTH) ? S_IWOTH : 0; + m |= (mode & C_IXOTH) ? S_IXOTH : 0; + + m |= (mode & C_ISUID) ? S_ISUID : 0; + m |= (mode & C_ISGID) ? S_ISGID : 0; + m |= (mode & C_ISVTX) ? S_ISVTX : 0; + + m |= (mode & C_ISDIR) ? S_IFDIR : 0; + m |= (mode & C_ISFIFO) ? S_IFIFO : 0; + m |= (mode & C_ISREG) ? S_IFREG : 0; + m |= (mode & C_ISBLK) ? S_IFBLK : 0; + m |= (mode & C_ISCHR) ? S_IFCHR : 0; + //m |= (mode & C_ISCTG) ? S_IFCTG : 0; + m |= (mode & C_ISLNK) ? S_IFLNK : 0; + m |= (mode & C_ISSOCK) ? S_IFSOCK : 0; + + return m; +} + +static struct cpio_entry cpio_deserialize(struct cpio_header *dh) +{ + struct cpio_entry e = { 0 }; + e.st.st_dev = pax_atoi(sizeof(dh->dev), dh->dev, 8); + e.st.st_ino = pax_atoi(sizeof(dh->ino), dh->ino, 8); + e.st.st_mode = cpio_convert_mode(pax_atoi(sizeof(dh->mode), dh->mode, 8)); + e.st.st_uid = pax_atoi(sizeof(dh->uid), dh->uid, 8); + e.st.st_gid = pax_atoi(sizeof(dh->gid), dh->gid, 8); + e.st.st_nlink = pax_atoi(sizeof(dh->nlink), dh->nlink, 8); + e.st.st_rdev = pax_atoi(sizeof(dh->rdev), dh->rdev, 8); + e.st.st_mtim.tv_sec = pax_atoi(sizeof(dh->mtime), dh->mtime, 8); + e.st.st_size = pax_atoi(sizeof(dh->filesize), dh->filesize, 8); + + e.namesize = pax_atoi(sizeof(dh->namesize), dh->namesize, 8); + + return e; +} + +int cpio_list(FILE *input, size_t firstlen, void *firstblock) +{ + struct cpio_header *dh = firstblock; + + //for (;;) { + struct cpio_entry e = cpio_deserialize(dh); + pax_list_file(&e.st, (char*)firstblock + sizeof(*dh)); + //} + + return 0; +} @@ -0,0 +1,269 @@ +/* + * UNG's Not GNU + * + * Copyright (c) 2011-2019, Jakob Kaivo <jkk@ung.org> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#define _XOPEN_SOURCE 700 +#include <cpio.h> +#include <errno.h> +#include <locale.h> +#include <inttypes.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <tar.h> +#include <unistd.h> + +#include "pax.h" + +enum pax_format pax_identify(size_t n, void *header) +{ + if (n < sizeof(MAGIC)) { + return PAX_FORMAT_UNKNOWN; + } + + if (n >= cpio_header_size) { + if (memcmp(header, MAGIC, sizeof(MAGIC) - 1) == 0) { + return PAX_FORMAT_CPIO; + } + } + + /* TODO: differentiate between tar and pax format */ + if (n >= TAR_HEADER_SIZE) { + struct tar_header *th = header; + if (memcmp(th->magic, TMAGIC, TMAGLEN) == 0) { + return PAX_FORMAT_TAR; + } + } + + fprintf(stderr, "pax: unknown archive format\n"); + return PAX_FORMAT_UNKNOWN; +} + +int pax_list(FILE *input) +{ + char header[TAR_HEADER_SIZE]; + int nread = fread(header, 1, sizeof(header), input); + + switch (pax_identify(nread, header)) { + case PAX_FORMAT_CPIO: + return cpio_list(input, nread, header); + break; + + case PAX_FORMAT_TAR: + return tar_list(input, nread, header); + break; + + default: + break; + } + + fprintf(stderr, "pax: unknown file format\n"); + return 1; +} + +int main(int argc, char *argv[]) +{ + unsigned int flags = 0; + //unsigned int blocksize = 0; + enum { PAX_LIST, PAX_READ, PAX_WRITE, PAX_COPY } mode = PAX_LIST; + //enum { PAX_EXCLUDE, PAX_INCLUDE } match = -1; + //enum { FOLLOW, NOFOLLOW } symlinks = -1; + //char *format = NULL; + //char *options = NULL; + //char *replace = NULL; + //char *archive = NULL; + //char *preserve = NULL; + + setlocale(LC_ALL, ""); + + int c; + while ((c = getopt(argc, argv, "rwab:cdf:HikLno:p:s:tuvx:X")) != -1) { + switch (c) { + case 'r': + if (mode == PAX_WRITE || mode == PAX_COPY) { + mode = PAX_COPY; + } else { + mode = PAX_READ; + } + break; + + case 'w': + if (mode == PAX_READ || mode == PAX_COPY) { + mode = PAX_COPY; + } else { + mode = PAX_WRITE; + } + break; + + case 'a': + flags |= PAX_APPEND; + break; + + case 'b': + //blocksize = atoi(optarg); + break; + + case 'c': + //match = PAX_EXCLUDE; + break; + + case 'd': + flags |= PAX_DIRECTORY; + break; + + case 'f': + //archive = optarg; + break; + + case 'H': + //symlinks = FOLLOW; + break; + + case 'i': + flags |= PAX_INTERACTIVE; + break; + + case 'k': + flags |= PAX_KEEP; + break; + + case 'l': + flags |= PAX_LINK; + break; + + case 'L': + //symlinks = NOFOLLOW; + break; + + case 'n': + //match = PAX_INCLUDE; + break; + + case 'o': + //options = optarg; + break; + + case 'p': + //preserve = optarg; + break; + + case 's': + //replace = optarg; + break; + + case 't': + flags |= PAX_TIMESTAMP; + break; + + case 'u': + flags |= PAX_UPDATE; + break; + + case 'v': + flags |= PAX_VERBOSE; + break; + + case 'x': + //format = optarg; + break; + + case 'X': + flags |= PAX_SAMEDEVICE; + break; + + default: + return 1; + } + } + + if (mode == PAX_LIST) { + return pax_list(stdin); + } +} + +void pax_list_file(struct stat *st, const char *name) +{ + if (S_ISDIR(st->st_mode)) { + putchar('d'); + } else if (S_ISFIFO(st->st_mode)) { + putchar('f'); + } else if (S_ISLNK(st->st_mode)) { + putchar('l'); + } else if (S_ISBLK(st->st_mode)) { + putchar('b'); + } else if (S_ISCHR(st->st_mode)) { + putchar('c'); + //} else if (S_ISSOCK(st->st_mode)) { + //putchar('S'); + //} else if (S_ISCTG(st->st_mode)) { + //putchar('?'); + } else /* if (S_ISREG(st->st_mode)) */ { + putchar('-'); + } + + putchar(st->st_mode & S_IRUSR ? 'r' : '-'); + putchar(st->st_mode & S_IWUSR ? 'w' : '-'); + if (st->st_mode & S_ISUID) { + putchar(st->st_mode & S_IXUSR ? 's' : 'S'); + } else { + putchar(st->st_mode & S_IXUSR ? 'x' : '-'); + } + + putchar(st->st_mode & S_IRGRP ? 'r' : '-'); + putchar(st->st_mode & S_IWGRP ? 'w' : '-'); + if (st->st_mode & S_ISGID) { + putchar(st->st_mode & S_IXGRP ? 's' : 'S'); + } else { + putchar(st->st_mode & S_IXGRP ? 'x' : '-'); + } + + putchar(st->st_mode & S_IROTH ? 'r' : '-'); + putchar(st->st_mode & S_IWOTH ? 'w' : '-'); + if (st->st_mode & S_ISVTX) { + putchar(st->st_mode & S_IXOTH ? 's' : 'S'); + } else { + putchar(st->st_mode & S_IXOTH ? 'x' : '-'); + } + + printf(" %ju", (uintmax_t)st->st_nlink); + printf(" %ju", (uintmax_t)st->st_uid); + printf("/%ju", (uintmax_t)st->st_gid); + + if (S_ISBLK(st->st_mode) || S_ISCHR(st->st_mode)) { + printf(" %jx", (uintmax_t)st->st_rdev); + } else { + printf(" %ju", (uintmax_t)st->st_size); + } + + printf(" mtime"); /* TODO */ + + printf(" %s\n", name); +} + +uintmax_t pax_atoi(size_t n, const char _s[static n], int base) +{ + char s[64] = { 0 }; + strncpy(s, _s, n); + return strtoumax(s, NULL, base); +} @@ -0,0 +1,73 @@ +/* + * UNG's Not GNU + * + * Copyright (c) 2011-2019, Jakob Kaivo <jkk@ung.org> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <stdint.h> + +#define TAR_HEADER_SIZE 512 + +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[1]; + char linkname[100]; + char magic[6]; + char version[2]; + char uname[32]; + char gname[32]; + char devmajor[8]; + char devminor[8]; + char prefix[155]; +}; + +enum { + PAX_APPEND = 1<<0, + PAX_DIRECTORY = 1<<1, + PAX_INTERACTIVE = 1<<2, + PAX_KEEP = 1<<3, + PAX_LINK = 1<<4, + PAX_TIMESTAMP = 1<<5, + PAX_UPDATE = 1<<6, + PAX_VERBOSE = 1<<7, + PAX_SAMEDEVICE = 1<<8, +}; + +enum pax_format { + PAX_FORMAT_UNKNOWN, + PAX_FORMAT_PAX, + PAX_FORMAT_CPIO, + PAX_FORMAT_TAR, +}; + +int cpio_list(FILE *input, size_t firstlen, void *firstblock); +int tar_list(FILE *input, size_t firstlen, void *firstblock); + +void pax_list_file(struct stat *st, const char *filename); +uintmax_t pax_atoi(size_t n, const char s[static n], int base); + +extern const size_t cpio_header_size; @@ -0,0 +1,113 @@ +/* + * UNG's Not GNU + * + * Copyright (c) 2011-2019, Jakob Kaivo <jkk@ung.org> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#define _XOPEN_SOURCE 700 +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <tar.h> + +#include "pax.h" + +static mode_t tar_mode_to_st_mode(char typeflag, const char tm[static 8]) +{ + uintmax_t mode = pax_atoi(8, tm, 8); + mode_t m = 0; + + switch (typeflag) { + case REGTYPE: + case AREGTYPE: + case LNKTYPE: + m = S_IFREG; + break; + + case SYMTYPE: + m = S_IFLNK; + break; + + case CHRTYPE: + m = S_IFCHR; + break; + + case BLKTYPE: + m = S_IFBLK; + break; + + case DIRTYPE: + m = S_IFDIR; + break; + + case FIFOTYPE: + m = S_IFIFO; + break; + + case CONTTYPE: + //m = S_IFCONT; + break; + + default: + fprintf(stderr, "pax: unknown file type '%c' (%hhx)\n", + typeflag, typeflag); + break; + } + + m |= (mode & TSUID) ? S_ISUID : 0; + m |= (mode & TSGID) ? S_ISGID : 0; + m |= (mode & TSVTX) ? S_ISVTX : 0; + + m |= (mode & TUREAD) ? S_IRUSR : 0; + m |= (mode & TUWRITE) ? S_IWUSR : 0; + m |= (mode & TUEXEC) ? S_IXUSR : 0; + + m |= (mode & TGREAD) ? S_IRGRP : 0; + m |= (mode & TGWRITE) ? S_IWGRP : 0; + m |= (mode & TGEXEC) ? S_IXGRP : 0; + + m |= (mode & TOREAD) ? S_IROTH : 0; + m |= (mode & TOWRITE) ? S_IWOTH : 0; + m |= (mode & TOEXEC) ? S_IXOTH : 0; + + return m; +} + +static struct stat tar_header_to_stat(struct tar_header *th) +{ + struct stat st = { 0 }; + st.st_mode = tar_mode_to_st_mode(th->typeflag[0], th->mode); + st.st_nlink = 1; + st.st_uid = pax_atoi(sizeof(th->uid), th->uid, 8); + st.st_gid = pax_atoi(sizeof(th->gid), th->gid, 8); + st.st_size = pax_atoi(sizeof(th->size), th->size, 8); + st.st_mtim.tv_sec = pax_atoi(sizeof(th->mtime), th->mtime, 8); + return st; +} + +int tar_list(FILE *input, size_t firstlen, void *firstblock) +{ + struct tar_header *th = firstblock; + struct stat st = tar_header_to_stat(th); + pax_list_file(&st, th->name); + return 0; +} |