From 5b0d597c095de80bcde7a737d46f2ea8332a1c7b Mon Sep 17 00:00:00 2001 From: apio Date: Sun, 29 Jan 2023 22:07:54 +0100 Subject: [PATCH] feat: Add support for block and character devices --- examples/untar.c | 43 +++++++++++++++++++++++++++++++++++++++++++ minitar.h | 4 ++++ src/util.c | 16 ++++++++-------- 3 files changed, 55 insertions(+), 8 deletions(-) diff --git a/examples/untar.c b/examples/untar.c index fa236d0..c9e5706 100644 --- a/examples/untar.c +++ b/examples/untar.c @@ -14,6 +14,7 @@ #include #include #include +#include #include static int untar_file(const struct minitar_entry* entry, const void* buf) @@ -48,6 +49,7 @@ int main(int argc, char** argv) perror(argv[1]); return 1; } + int exit_status = 0; struct minitar_entry entry; do { if (minitar_read_entry(&mp, &entry) == 0) @@ -58,6 +60,7 @@ int main(int argc, char** argv) if (status != 0) { fprintf(stderr, "Failed to create directory %s: %s\n", entry.metadata.path, strerror(errno)); + exit_status = 1; break; } @@ -69,6 +72,7 @@ int main(int argc, char** argv) if (!ptr) { perror("malloc"); + exit_status = 1; break; } @@ -81,6 +85,7 @@ int main(int argc, char** argv) if (status != 0) { fprintf(stderr, "Failed to extract file %s: %s\n", entry.metadata.path, strerror(errno)); + exit_status = 1; break; } @@ -93,6 +98,7 @@ int main(int argc, char** argv) if (status != 0) { fprintf(stderr, "Failed to create symlink %s: %s\n", entry.metadata.path, strerror(errno)); + exit_status = 1; break; } @@ -105,6 +111,7 @@ int main(int argc, char** argv) if (status != 0) { fprintf(stderr, "Failed to create hard link %s: %s\n", entry.metadata.path, strerror(errno)); + exit_status = 1; break; } @@ -117,14 +124,50 @@ int main(int argc, char** argv) if (status != 0) { fprintf(stderr, "Failed to create FIFO %s: %s\n", entry.metadata.path, strerror(errno)); + exit_status = 1; break; } printf("fifo %s\n", entry.metadata.path); } + else if (entry.metadata.type == MTAR_BLKDEV) + { + int status = mknod(entry.metadata.path, entry.metadata.mode | S_IFBLK, + makedev(entry.metadata.devmajor, entry.metadata.devminor)); + + if (status != 0) + { + fprintf(stderr, "Failed to create block device %s: %s\n", entry.metadata.path, strerror(errno)); + exit_status = 1; + break; + } + + printf("blkdev %s (%u:%u)\n", entry.metadata.path, entry.metadata.devmajor, entry.metadata.devminor); + } + else if (entry.metadata.type == MTAR_CHRDEV) + { + int status = mknod(entry.metadata.path, entry.metadata.mode | S_IFCHR, + makedev(entry.metadata.devmajor, entry.metadata.devminor)); + + if (status != 0) + { + fprintf(stderr, "Failed to create character device %s: %s\n", entry.metadata.path, strerror(errno)); + exit_status = 1; + break; + } + + printf("chrdev %s (%u:%u)\n", entry.metadata.path, entry.metadata.devmajor, entry.metadata.devminor); + } + else + { + fprintf(stderr, "error: unknown entry type: %d", entry.metadata.type); + exit_status = 1; + break; + } } else break; } while (1); minitar_close(&mp); + return exit_status; } \ No newline at end of file diff --git a/minitar.h b/minitar.h index ec78925..8a8aeee 100644 --- a/minitar.h +++ b/minitar.h @@ -24,6 +24,8 @@ enum minitar_file_type MTAR_SYMLINK, MTAR_HARDLINK, MTAR_FIFO, + MTAR_CHRDEV, + MTAR_BLKDEV }; struct minitar_entry_internal @@ -44,6 +46,8 @@ struct minitar_entry_metadata enum minitar_file_type type; char uname[32]; char gname[32]; + unsigned devminor; + unsigned devmajor; }; struct minitar_entry diff --git a/src/util.c b/src/util.c index bcf358e..84bf178 100644 --- a/src/util.c +++ b/src/util.c @@ -190,8 +190,8 @@ void minitar_parse_metadata_from_tar_header(const struct tar_header* hdr, struct case '0': metadata->type = MTAR_REGULAR; break; case '1': metadata->type = MTAR_HARDLINK; break; case '2': metadata->type = MTAR_SYMLINK; break; - case '3': minitar_handle_panic("Character devices are unsupported"); - case '4': minitar_handle_panic("Block devices 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': metadata->type = MTAR_FIFO; break; // This case should have been previously handled by minitar_validate_header(). @@ -200,6 +200,12 @@ void minitar_parse_metadata_from_tar_header(const struct tar_header* hdr, struct minitar_strlcpy(metadata->uname, hdr->uname, 32); minitar_strlcpy(metadata->gname, hdr->gname, 32); + + if (metadata->type == MTAR_CHRDEV || metadata->type == MTAR_BLKDEV) + { + metadata->devminor = minitar_parse_octal(hdr->devminor); + metadata->devmajor = minitar_parse_octal(hdr->devmajor); + } } uint32_t minitar_checksum_header(const struct tar_header* hdr) @@ -230,15 +236,9 @@ uint32_t minitar_checksum_header(const struct tar_header* hdr) int minitar_validate_header(const struct tar_header* hdr) { -#ifdef MINITAR_IGNORE_UNSUPPORTED_TYPES - if (hdr->typeflag != '\0' && hdr->typeflag != '0' && hdr->typeflag != '1' && hdr->typeflag != '2' && - hdr->typeflag != '5') - return 0; -#else if (hdr->typeflag != '\0' && hdr->typeflag != '0' && hdr->typeflag != '1' && hdr->typeflag != '2' && hdr->typeflag != '3' && hdr->typeflag != '4' && hdr->typeflag != '5' && hdr->typeflag != '6') return 0; -#endif // FIXME: Warn on checksum mismatch unless header is all blanks? if (minitar_checksum_header(hdr) != minitar_parse_octal(hdr->chksum)) return 0; return !strncmp(hdr->magic, "ustar", 5);