diff --git a/docs/API.md b/docs/API.md index a9050c5..9e6ce78 100644 --- a/docs/API.md +++ b/docs/API.md @@ -77,7 +77,9 @@ This enum lists all supported file types: `MTAR_SYMLINK`: Symbolic links -Other file types supported in tar archives, such as block/character devices, FIFOs, or hard links, are not supported and minitar will throw an error when encountering one of them. This behavior can be controlled by passing `-DMINITAR_IGNORE_UNSUPPORTED_TYPES=ON` to CMake when configuring, which will make minitar silently ignore such entries instead of panicking. +`MTAR_HARDLINK`: Hard links + +Other file types supported in tar archives, such as block/character devices or FIFOs, are not supported and minitar will throw an error when encountering one of them. This behavior can be controlled by passing `-DMINITAR_IGNORE_UNSUPPORTED_TYPES=ON` to CMake when configuring, which will make minitar silently ignore such entries instead of panicking. ### minitar_entry_metadata `struct minitar_entry_metadata` @@ -88,7 +90,7 @@ This structure represents an entry's metadata, with the following fields: `name`: A string representing the base name of the entry (the last component of its path). (`char[]`) -`link`: A string representing the file being linked to. (Only applies to symlinks) (`char[]`) +`link`: A string representing the file being linked to. (Only applies to symlinks/hard links) (`char[]`) `mode`: An integer representing the permissions of the entry. (`mode_t`) diff --git a/examples/untar.c b/examples/untar.c index e1b23d9..67c0c86 100644 --- a/examples/untar.c +++ b/examples/untar.c @@ -98,6 +98,18 @@ int main(int argc, char** argv) printf("symlink %s -> %s\n", entry.metadata.path, entry.metadata.link); } + else if (entry.metadata.type == MTAR_HARDLINK) + { + int status = link(entry.metadata.link, entry.metadata.path); + + if (status != 0) + { + fprintf(stderr, "Failed to create hard link %s: %s\n", entry.metadata.path, strerror(errno)); + break; + } + + printf("link %s -> %s\n", entry.metadata.path, entry.metadata.link); + } } else break; diff --git a/minitar.h b/minitar.h index 6f673ab..455725e 100644 --- a/minitar.h +++ b/minitar.h @@ -21,7 +21,8 @@ enum minitar_file_type { MTAR_REGULAR, MTAR_DIRECTORY, - MTAR_SYMLINK + MTAR_SYMLINK, + MTAR_HARDLINK, }; struct minitar_entry_internal diff --git a/src/util.c b/src/util.c index 703b4dd..cea552f 100644 --- a/src/util.c +++ b/src/util.c @@ -174,6 +174,8 @@ void minitar_parse_metadata_from_tar_header(const struct tar_header* hdr, struct metadata->uid = (uid_t)minitar_parse_octal(hdr->uid); metadata->gid = (gid_t)minitar_parse_octal(hdr->gid); + // These two fields aren't null-terminated. + char* sizeptr = minitar_static_dup(hdr->size, 12); metadata->size = (size_t)minitar_parse_octal(sizeptr); @@ -186,12 +188,13 @@ void minitar_parse_metadata_from_tar_header(const struct tar_header* hdr, struct { case '\0': case '0': metadata->type = MTAR_REGULAR; break; - case '1': minitar_handle_panic("Links to other files within a tar archive are unsupported"); + 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 '5': metadata->type = MTAR_DIRECTORY; break; case '6': minitar_handle_panic("FIFOs are unsupported"); + // This case should have been previously handled by minitar_validate_header(). default: minitar_handle_panic("Unknown entry type in tar header"); } @@ -228,7 +231,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 != '2' && hdr->typeflag != '5') return 0; + 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')