Skip to content

Commit 56dd680

Browse files
committed
fix: properly handle tar extended header entries size
1 parent 647f407 commit 56dd680

File tree

2 files changed

+56
-23
lines changed

2 files changed

+56
-23
lines changed

bzlreg/tar_view.cc

Lines changed: 52 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -140,14 +140,21 @@ auto bzlreg::tar_view::iterator::operator++() -> iterator& {
140140
assert(!_data.empty());
141141
auto file_size = operator*().size();
142142
auto header_size = operator*().header_byte_size();
143-
_data = _data.subspan(header_size + round_up_to_multiple(file_size, 512));
144-
if(is_all0(_data.subspan(0, TAR_HEADER_SIZE))) {
145-
_data = _data.subspan(TAR_HEADER_SIZE);
143+
auto file_size_rounded = round_up_to_multiple(file_size, 512);
146144

145+
if(header_size + file_size_rounded < _data.size()) {
146+
_data = _data.subspan(header_size + file_size_rounded);
147147
if(is_all0(_data.subspan(0, TAR_HEADER_SIZE))) {
148-
_data = {};
148+
_data = _data.subspan(TAR_HEADER_SIZE);
149+
150+
if(is_all0(_data.subspan(0, TAR_HEADER_SIZE))) {
151+
_data = {};
152+
}
149153
}
154+
} else {
155+
_data = {};
150156
}
157+
151158
return *this;
152159
}
153160

@@ -236,12 +243,12 @@ bzlreg::tar_view_file::tar_view_file( //
236243
}
237244

238245
auto key = extended_header.substr(
239-
length_sep_index,
240-
key_value_sep_index - length_sep_index
246+
length_sep_index + 1,
247+
key_value_sep_index - length_sep_index - 1
241248
);
242249
auto value = extended_header.substr(
243-
key_value_sep_index,
244-
length - (length_sep_index - key.size() - 2)
250+
key_value_sep_index + 1,
251+
length - key_value_sep_index - 2
245252
);
246253

247254
auto value_span = std::span{
@@ -256,6 +263,8 @@ bzlreg::tar_view_file::tar_view_file( //
256263
} else if(key == "size") {
257264
_extended_header_size = value_span;
258265
}
266+
267+
extended_header = extended_header.substr(length);
259268
}
260269
}
261270
}
@@ -274,7 +283,8 @@ auto bzlreg::tar_view_file::header_byte_size() const -> size_t {
274283

275284
if(typeflag == typeflag_enum::extended_header) {
276285
return TAR_HEADER_SIZE +
277-
round_up_to_multiple(get_tar_header_file_size(_data), 512);
286+
round_up_to_multiple(get_tar_header_file_size(_data), 512) +
287+
TAR_HEADER_SIZE;
278288
} else {
279289
return TAR_HEADER_SIZE;
280290
}
@@ -325,25 +335,44 @@ auto bzlreg::tar_view_file::size() const noexcept -> size_t {
325335
assert(*this);
326336

327337
const auto typeflag = get_typeflag(_data);
338+
auto file_size = std::size_t{};
328339

329340
if(typeflag == typeflag_enum::extended_header) {
330-
auto file_size = std::size_t{};
331-
auto [_, ec] = std::from_chars(
332-
reinterpret_cast<const char*>(_extended_header_size.data()),
333-
reinterpret_cast<const char*>(_extended_header_size.data()) +
334-
_extended_header_size.size(),
335-
file_size
336-
);
337-
if(ec != std::errc{}) {
338-
std::cerr << "ERROR: extended header file size: "
339-
<< std::make_error_code(ec).message() << std::endl;
340-
std::abort();
341+
if(!_extended_header_size.empty()) {
342+
auto [_, ec] = std::from_chars(
343+
reinterpret_cast<const char*>(_extended_header_size.data()),
344+
reinterpret_cast<const char*>(_extended_header_size.data()) +
345+
_extended_header_size.size(),
346+
file_size
347+
);
348+
if(ec != std::errc{}) {
349+
std::cerr << "ERROR: extended header file size: "
350+
<< std::make_error_code(ec).message() << std::endl;
351+
std::abort();
352+
}
353+
} else {
354+
auto next_entry = _data.subspan(
355+
TAR_HEADER_SIZE +
356+
round_up_to_multiple(get_tar_header_file_size(_data), 512)
357+
);
358+
auto next_typeflag = get_typeflag(next_entry);
359+
switch(next_typeflag) {
360+
case typeflag_enum::extended_header:
361+
case typeflag_enum::global_extended_header:
362+
std::cerr << "ERROR: unexpected typeflag: "
363+
<< static_cast<char>(next_typeflag) << "\n";
364+
std::abort();
365+
break;
366+
default:
367+
break;
368+
}
369+
file_size = get_tar_header_file_size(next_entry);
341370
}
342-
343-
return file_size;
344371
} else {
345-
return get_tar_header_file_size(_data);
372+
file_size = get_tar_header_file_size(_data);
346373
}
374+
375+
return file_size;
347376
}
348377

349378
auto bzlreg::tar_view_file::contents() const noexcept -> std::span<std::byte> {

bzlreg/tar_view.hh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ class tar_view_file {
1818

1919
tar_view_file(std::span<std::byte> data) noexcept;
2020

21+
/**
22+
* As small as 1 tar header (512 bytes) and as large as 1 tar header + PAX
23+
* header + the following tar header.
24+
*/
2125
auto header_byte_size() const -> size_t;
2226

2327
public:

0 commit comments

Comments
 (0)