| 57 | static_assert(sizeof(header_posix_ustar) == 512); |
| 58 | |
| 59 | TarFile::TarFile(const std::filesystem::path& archivePath) |
| 60 | { |
| 61 | m_ArchivePath = archivePath.lexically_normal().generic_string(); |
| 62 | m_ArchiveFile = fopen(m_ArchivePath.c_str(), "rb"); |
| 63 | |
| 64 | if (m_ArchiveFile) |
| 65 | { |
| 66 | bool errors = false; |
| 67 | |
| 68 | fseek(m_ArchiveFile, 0, SEEK_END); |
| 69 | size_t archiveSize = ftello(m_ArchiveFile); |
| 70 | |
| 71 | size_t currentPosition = 0; |
| 72 | |
| 73 | while (currentPosition + sizeof(header_posix_ustar) <= archiveSize) |
| 74 | { |
| 75 | fseeko(m_ArchiveFile, currentPosition, SEEK_SET); |
| 76 | |
| 77 | header_posix_ustar header{}; |
| 78 | if (fread(&header, sizeof(header), 1, m_ArchiveFile) != 1) |
| 79 | break; |
| 80 | |
| 81 | currentPosition += sizeof(header); |
| 82 | |
| 83 | // check if this is a regular file |
| 84 | if (header.typeflag != '0' && header.typeflag != 0) |
| 85 | continue; |
| 86 | |
| 87 | // combine the file name from prefix and name |
| 88 | char fileName[sizeof(header.name) + sizeof(header.prefix) + 2]; |
| 89 | size_t prefixLength = strnlen(header.prefix, sizeof(header.prefix)); |
| 90 | size_t nameLength = strnlen(header.name, sizeof(header.name)); |
| 91 | if (prefixLength) |
| 92 | { |
| 93 | memcpy(fileName, header.prefix, prefixLength); |
| 94 | fileName[prefixLength] = '/'; |
| 95 | ++prefixLength; |
| 96 | } |
| 97 | if (nameLength) |
| 98 | { |
| 99 | memcpy(fileName + prefixLength, header.name, nameLength); |
| 100 | } |
| 101 | fileName[nameLength + prefixLength] = 0; |
| 102 | |
| 103 | if (fileName[0] == 0) |
| 104 | continue; |
| 105 | |
| 106 | // parse the octal size |
| 107 | size_t fileSize = 0; |
| 108 | for (char c : header.size) |
| 109 | { |
| 110 | if (c < '0' || c > '7') |
| 111 | break; |
| 112 | |
| 113 | fileSize = (fileSize << 3) | (c - '0'); |
| 114 | } |
| 115 | |
| 116 | if (fileSize == 0) |