Tar Archive I/O

TarReader reads entries incrementally from a std::istream, suitable for both blocking file I/O and non-blocking event-loop use. TarWriter writes entries synchronously to a std::ostream. TarEntry holds the metadata and content of a single archive entry.

Archive Entry

A TarEntry holds the metadata and provides access to the content of one entry in a tar archive. Instances are produced by TarReader::advance() and remain valid until the next advance() call.

Use type() to distinguish files, directories, symbolic links, and hard links. Use path() for the archive path, mtime() for the modification time, and permissions() for the POSIX permission bits.

File content is delivered in one or more chunks. After each advance() call, up to avail() bytes are readable at data(). Process those bytes before calling advance() again — the buffer is reused on the next call. Repeat until isEnd() returns true, which means all size() bytes have been delivered.

Reading Archives

TarReader parses a tar archive from a std::istream one entry at a time. It is designed for non-blocking use: advance() delivers only the bytes already in the stream buffer and returns nullptr when the stream is starved.

Call advance() in a loop. A non-null return value holds a TarEntry with the current entry's metadata and the first content chunk. Read TarEntry::data() for TarEntry::avail() bytes, then call advance() again to fetch the next chunk. Repeat until TarEntry::isEnd() is true, then call advance() once more to move to the next archive entry. The loop ends when isEnd() on the reader itself returns true.

Pass a non-zero importSize to advance() to read more bytes from the stream per call — this may block and is suitable for file-based use.

Pax extended headers handle long paths (> 99 characters), UTF-8 paths, and extended modification times automatically.

TarReader reader(stream);
while( ! reader.isEnd() )
{
const TarEntry* entry = reader.advance();
if( ! entry )
break; // not enough data, call advance() again when more arrives
if(entry->type() == TarEntry::File)
{
do
{
outFile.write(entry->data(), entry->avail());
if(entry->isEnd())
break;
entry = reader.advance();
}
while(entry);
}
}

Writing Archives

TarWriter writes entries sequentially into a tar archive. All operations are synchronous and write directly to the attached std::ostream.

Use addFile(), addDirectory(), addSymlink(), or addHardlink() to write complete entries in a single call. For large files, use the streaming API: beginFile() writes the header, writeFile() delivers the content in one or more chunks, and endFile() closes the entry.

Always call finish() before closing the stream to write the mandatory end-of-archive marker. Paths are interpreted as UTF-8; Pax extended headers are written automatically for long or non-ASCII paths.

std::ofstream ofs("archive.tar", std::ios::binary);
TarWriter writer(ofs);
// complete entries
writer.addDirectory(Pt::System::Path("src/"), dirPerms);
writer.addFile(Pt::System::Path("src/main.cpp"),
src.data(), src.size(), filePerms);
// streaming a large file
writer.beginFile(Pt::System::Path("data.bin"), totalSize, filePerms);
writer.writeFile(chunk1, size1);
writer.writeFile(chunk2, size2);
writer.endFile();
writer.finish();
Represents a path in the file-system.
Definition: Path.h:48