Tar.h 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. /*
  2. * Copyright (c) 2020, Peter Elliott <pelliott@serenityos.org>
  3. * Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org>
  4. * Copyright (c) 2022, the SerenityOS developers.
  5. *
  6. * SPDX-License-Identifier: BSD-2-Clause
  7. */
  8. #pragma once
  9. #include <AK/String.h>
  10. #include <AK/StringView.h>
  11. #include <string.h>
  12. #include <sys/types.h>
  13. namespace Archive {
  14. enum class TarFileType : char {
  15. NormalFile = '0',
  16. AlternateNormalFile = '\0',
  17. HardLink = '1',
  18. SymLink = '2',
  19. CharacterSpecialFile = '3',
  20. BlockSpecialFile = '4',
  21. Directory = '5',
  22. FIFO = '6',
  23. ContiguousFile = '7',
  24. GlobalExtendedHeader = 'g',
  25. ExtendedHeader = 'x'
  26. };
  27. constexpr size_t block_size = 512;
  28. constexpr StringView gnu_magic = "ustar "; // gnu format magic
  29. constexpr StringView gnu_version = " "; // gnu format version
  30. constexpr StringView ustar_magic = "ustar"; // ustar format magic
  31. constexpr StringView ustar_version = "00"; // ustar format version
  32. constexpr StringView posix1_tar_magic = ""; // POSIX.1-1988 format magic
  33. constexpr StringView posix1_tar_version = ""; // POSIX.1-1988 format version
  34. template<size_t N>
  35. static size_t get_field_as_integral(char const (&field)[N])
  36. {
  37. size_t value = 0;
  38. for (size_t i = 0; i < N; ++i) {
  39. if (field[i] == 0 || field[i] == ' ')
  40. break;
  41. VERIFY(field[i] >= '0' && field[i] <= '7');
  42. value *= 8;
  43. value += field[i] - '0';
  44. }
  45. return value;
  46. }
  47. template<size_t N>
  48. static StringView get_field_as_string_view(char const (&field)[N])
  49. {
  50. return { field, min(__builtin_strlen(field), N) };
  51. }
  52. template<size_t N, class TSource>
  53. static void set_field(char (&field)[N], TSource&& source)
  54. {
  55. if constexpr (requires { source.characters_without_null_termination(); }) {
  56. memcpy(field, source.characters_without_null_termination(), min(N, source.length()));
  57. } else {
  58. auto success = source.copy_characters_to_buffer(field, N);
  59. VERIFY(success);
  60. }
  61. }
  62. template<class TSource, size_t N>
  63. static void set_octal_field(char (&field)[N], TSource&& source)
  64. {
  65. set_field(field, String::formatted("{:o}", forward<TSource>(source)));
  66. }
  67. class [[gnu::packed]] TarFileHeader {
  68. public:
  69. StringView filename() const { return get_field_as_string_view(m_filename); }
  70. mode_t mode() const { return get_field_as_integral(m_mode); }
  71. uid_t uid() const { return get_field_as_integral(m_uid); }
  72. gid_t gid() const { return get_field_as_integral(m_gid); }
  73. // FIXME: support 2001-star size encoding
  74. size_t size() const { return get_field_as_integral(m_size); }
  75. time_t timestamp() const { return get_field_as_integral(m_timestamp); }
  76. unsigned checksum() const { return get_field_as_integral(m_checksum); }
  77. TarFileType type_flag() const { return TarFileType(m_type_flag); }
  78. StringView link_name() const { return m_link_name; }
  79. StringView magic() const { return get_field_as_string_view(m_magic); }
  80. StringView version() const { return get_field_as_string_view(m_version); }
  81. StringView owner_name() const { return get_field_as_string_view(m_owner_name); }
  82. StringView group_name() const { return get_field_as_string_view(m_group_name); }
  83. int major() const { return get_field_as_integral(m_major); }
  84. int minor() const { return get_field_as_integral(m_minor); }
  85. // FIXME: support ustar filename prefix
  86. StringView prefix() const { return get_field_as_string_view(m_prefix); }
  87. void set_filename(String const& filename) { set_field(m_filename, filename); }
  88. void set_mode(mode_t mode) { set_octal_field(m_mode, mode); }
  89. void set_uid(uid_t uid) { set_octal_field(m_uid, uid); }
  90. void set_gid(gid_t gid) { set_octal_field(m_gid, gid); }
  91. void set_size(size_t size) { set_octal_field(m_size, size); }
  92. void set_timestamp(time_t timestamp) { set_octal_field(m_timestamp, timestamp); }
  93. void set_type_flag(TarFileType type) { m_type_flag = to_underlying(type); }
  94. void set_link_name(String const& link_name) { set_field(m_link_name, link_name); }
  95. // magic doesn't necessarily include a null byte
  96. void set_magic(StringView magic) { set_field(m_magic, magic); }
  97. // version doesn't necessarily include a null byte
  98. void set_version(StringView version) { set_field(m_version, version); }
  99. void set_owner_name(String const& owner_name) { set_field(m_owner_name, owner_name); }
  100. void set_group_name(String const& group_name) { set_field(m_group_name, group_name); }
  101. void set_major(int major) { set_octal_field(m_major, major); }
  102. void set_minor(int minor) { set_octal_field(m_minor, minor); }
  103. void set_prefix(String const& prefix) { set_field(m_prefix, prefix); }
  104. unsigned expected_checksum() const;
  105. void calculate_checksum();
  106. bool content_is_like_extended_header() const;
  107. private:
  108. char m_filename[100] { 0 };
  109. char m_mode[8] { 0 };
  110. char m_uid[8] { 0 };
  111. char m_gid[8] { 0 };
  112. char m_size[12] { 0 };
  113. char m_timestamp[12] { 0 };
  114. char m_checksum[8] { 0 }; // an uninitialized header's checksum is filled with spaces
  115. char m_type_flag { 0 };
  116. char m_link_name[100] { 0 };
  117. char m_magic[6] { 0 };
  118. char m_version[2] { 0 };
  119. char m_owner_name[32] { 0 };
  120. char m_group_name[32] { 0 };
  121. char m_major[8] { 0 };
  122. char m_minor[8] { 0 };
  123. char m_prefix[155] { 0 }; // zero out the prefix for archiving
  124. };
  125. }