1.0.34
This commit is contained in:
56 files changed
+9101
-117
No files matched your search
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* Single-file tar extraction for raw downloads (#1180).
|
||||
*
|
||||
* Docker's /archive endpoint always wraps file contents in a USTAR tar.
|
||||
* When the user picks the "no archive" download format and the path is a
|
||||
* regular file, we strip the wrapper and emit the bytes verbatim.
|
||||
*
|
||||
* Only handles the first regular-file entry — the caller has already
|
||||
* guaranteed (via stat) that the requested path is a single file, so the
|
||||
* tar contains exactly one entry.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Extract the bytes of the first regular file entry in a USTAR tar.
|
||||
* Returns the file content as a Uint8Array.
|
||||
*
|
||||
* Throws when no regular file entry is found (e.g. the tar contained only
|
||||
* a directory header) — that's an unexpected state, since the caller is
|
||||
* supposed to have already verified the path points to a file.
|
||||
*/
|
||||
export function extractFirstFileFromTar(tarData: Uint8Array): Uint8Array {
|
||||
let offset = 0;
|
||||
while (offset + 512 <= tarData.length) {
|
||||
const header = tarData.subarray(offset, offset + 512);
|
||||
|
||||
// Two consecutive zero blocks mark end-of-archive.
|
||||
if (isZeroBlock(header)) break;
|
||||
|
||||
const name = readString(header, 0, 100);
|
||||
const sizeOctal = readString(header, 124, 12).trim();
|
||||
const size = sizeOctal ? parseInt(sizeOctal, 8) : 0;
|
||||
const typeFlag = header[156];
|
||||
|
||||
// Regular file: typeflag '0' (0x30) or NUL (0x00, legacy)
|
||||
const isRegularFile = typeFlag === 0x30 || typeFlag === 0x00;
|
||||
|
||||
if (isRegularFile && name && size >= 0) {
|
||||
const start = offset + 512;
|
||||
const end = start + size;
|
||||
if (end > tarData.length) {
|
||||
throw new Error('Truncated tar archive');
|
||||
}
|
||||
return tarData.subarray(start, end);
|
||||
}
|
||||
|
||||
// Skip header + content (padded to 512-byte boundary)
|
||||
offset += 512 + Math.ceil(size / 512) * 512;
|
||||
}
|
||||
throw new Error('No regular file entry found in tar archive');
|
||||
}
|
||||
|
||||
function isZeroBlock(block: Uint8Array): boolean {
|
||||
for (let i = 0; i < block.length; i++) {
|
||||
if (block[i] !== 0) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function readString(buf: Uint8Array, offset: number, length: number): string {
|
||||
let end = offset;
|
||||
const limit = offset + length;
|
||||
while (end < limit && buf[end] !== 0) end++;
|
||||
return new TextDecoder('utf-8').decode(buf.subarray(offset, end));
|
||||
}
|
||||
Reference in new issue
Block a user