Skip to content

Commit 1a871f2

Browse files
committed
Fix tar extraction bug
1 parent df8b50e commit 1a871f2

1 file changed

Lines changed: 69 additions & 14 deletions

File tree

Source/Heavy/Toolchain.h

Lines changed: 69 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -309,31 +309,86 @@ class ToolchainInstaller final : public Component
309309
// TODO: we do this a few times inline, move it into a helper function along with the xz decompression
310310
auto extractTar = [](const uint8_t* data, size_t size, const File& destRoot) -> bool {
311311
size_t offset = 0;
312+
std::string longLinkName; // For GNU tar @@LongLink entries
313+
312314
while (offset + 512 <= size) {
313315
const uint8_t* header = data + offset;
314316
if (header[0] == '\0') break; // End of archive
315-
316-
// Get file name
317-
std::string name(reinterpret_cast<const char*>(header), 100);
317+
318+
// Get file name - handle both name and prefix fields for long paths
319+
std::string name;
320+
321+
if (!longLinkName.empty()) {
322+
// Use the long name from previous @@LongLink entry
323+
name = longLinkName;
324+
longLinkName.clear();
325+
} else {
326+
// Extract name from header (100 bytes at offset 0)
327+
char nameField[101] = {0};
328+
std::memcpy(nameField, header, 100);
329+
name = std::string(nameField);
330+
331+
// Check if there's a prefix field (155 bytes at offset 345)
332+
char prefixField[156] = {0};
333+
std::memcpy(prefixField, header + 345, 155);
334+
std::string prefix(prefixField);
335+
336+
if (!prefix.empty()) {
337+
name = prefix + "/" + name;
338+
}
339+
}
340+
318341
if (name.empty()) break;
319342

320-
#if !JUCE_WINDOWS
343+
// Clean up the path
344+
name.erase(name.find_last_not_of(" \t\n\r\f\v\0") + 1);
345+
346+
#if !JUCE_WINDOWS
321347
mode_t mode = static_cast<mode_t>(
322348
std::strtoul(reinterpret_cast<const char*>(header + 100), nullptr, 8)
323349
);
324350
bool executable = (mode & 0100) || (mode & 0010) || (mode & 0001);
325-
#endif
351+
#endif
352+
326353
// Get file size (octal)
327354
size_t fileSize = std::strtoull(reinterpret_cast<const char*>(header + 124), nullptr, 8);
328-
File outFile = destRoot.getChildFile(String(name));
329-
355+
330356
// Determine type
331357
char typeFlag = header[156];
358+
359+
// Handle GNU tar long link entries
360+
if (typeFlag == 'L') {
361+
// This is a @@LongLink entry - read the long filename
362+
size_t fileOffset = offset + 512;
363+
if (fileOffset + fileSize <= size) {
364+
longLinkName.assign(reinterpret_cast<const char*>(data + fileOffset), fileSize);
365+
// Remove null terminator if present
366+
if (!longLinkName.empty() && longLinkName.back() == '\0') {
367+
longLinkName.pop_back();
368+
}
369+
}
370+
// Skip this entry and continue
371+
size_t totalEntrySize = 512 + ((fileSize + 511) & ~511);
372+
offset += totalEntrySize;
373+
continue;
374+
}
375+
376+
// Handle PaxHeaders (POSIX extended headers)
377+
if (typeFlag == 'x' || name.find("PaxHeaders.") == 0) {
378+
// Skip extended header entries for now
379+
// (Full implementation would parse the extended attributes)
380+
size_t totalEntrySize = 512 + ((fileSize + 511) & ~511);
381+
offset += totalEntrySize;
382+
continue;
383+
}
384+
385+
File outFile = destRoot.getChildFile(String(name));
386+
332387
if (typeFlag == '5') {
333388
outFile.createDirectory();
334-
#if !JUCE_WINDOWS
389+
#if !JUCE_WINDOWS
335390
outFile.setExecutePermission(executable);
336-
#endif
391+
#endif
337392
} else if (typeFlag == '0' || typeFlag == '\0') {
338393
outFile.getParentDirectory().createDirectory();
339394
std::ofstream out(outFile.getFullPathName().toRawUTF8(), std::ios::binary);
@@ -346,18 +401,18 @@ class ToolchainInstaller final : public Component
346401
return false;
347402
}
348403
out.close();
349-
#if !JUCE_WINDOWS
404+
#if !JUCE_WINDOWS
350405
outFile.setExecutePermission(executable);
351-
#endif
406+
#endif
352407
}
353-
408+
354409
size_t totalEntrySize = 512 + ((fileSize + 511) & ~511); // pad to next 512
355410
offset += totalEntrySize;
356411
}
357412
return true;
358413
};
359414

360-
if(!extractTar(decompressedToolchain.data(), decompressedToolchain.size(), toolchainDir)) {
415+
if(!extractTar(decompressedToolchain.data(), decompressedToolchain.size(), toolchainDir.getParentDirectory())) {
361416
failed = true;
362417
}
363418

@@ -412,7 +467,7 @@ class ToolchainInstaller final : public Component
412467
float installProgress = 0.0f;
413468

414469
bool needsUpdate = false;
415-
int statusCode;
470+
int statusCode = 0;
416471

417472
#if JUCE_WINDOWS
418473
String downloadSize = "1.2 GB";

0 commit comments

Comments
 (0)