diff --git a/repos/os/src/lib/vfs/tar_file_system.h b/repos/os/src/lib/vfs/tar_file_system.h index c0a529f311..c3deff89f1 100644 --- a/repos/os/src/lib/vfs/tar_file_system.h +++ b/repos/os/src/lib/vfs/tar_file_system.h @@ -72,24 +72,63 @@ class Vfs::Tar_file_system : public File_system return value; } + char const *_data_begin() const { return (char const *)this + BLOCK_LEN; } + + /* + * GNU extension for long path names, which support unlimited sizes using + * separate records + */ + bool _long_name() const + { + return _type[0] == TYPE_LONG_LINK || _type[0] == TYPE_LONG_NAME; + } + + /* + * Round up up next block + */ + file_size _block_align(file_size size) const { + return Genode::align_addr(size, BLOCK_SHIFT); } + + /* + * Next record header + */ + Record *_next() const { + return (Record *)(_data_begin() + _block_align(_read(_size))); } + public: - /* length of on data block in tar */ - enum { BLOCK_LEN = 512 }; + /* length of one data block in tar */ + enum { + BLOCK_SHIFT = 9, /* 512 bytes */ + BLOCK_LEN = 1ul << BLOCK_SHIFT, + }; /* record type values */ - enum { TYPE_FILE = 0, TYPE_HARDLINK = 1, - TYPE_SYMLINK = 2, TYPE_DIR = 5 }; + enum { + TYPE_FILE = 0, TYPE_HARDLINK = 1, TYPE_SYMLINK = 2, TYPE_DIR = 5, + /* GNU extensions */ + TYPE_LONG_LINK = 75, TYPE_LONG_NAME = 76 + }; - file_size size() const { return _read(_size); } - unsigned uid() const { return _read(_uid); } - unsigned gid() const { return _read(_gid); } - unsigned mode() const { return _read(_mode); } - unsigned type() const { return _read(_type); } - char const *name() const { return _name; } - char const *linked_name() const { return _linked_name; } + file_size size() const { return _long_name() ? _next()->size() : _read(_size); } + unsigned uid() const { return _long_name() ? _next()->uid() : _read(_uid); } + unsigned gid() const { return _long_name() ? _next()->gid() : _read(_gid); } + unsigned mode() const { return _long_name() ? _next()->mode() : _read(_mode); } + unsigned type() const { return _long_name() ? _next()->type() : _read(_type); } + void *data() const { return _long_name() ? _next()->data() : (void *)_data_begin(); } - void *data() const { return (char *)this + BLOCK_LEN; } + char const *name() const { return _long_name() ? _data_begin() : _name; } + char const *linked_name() const { return _long_name() ? _data_begin() : _linked_name; } + + file_size storage_size() + { + if (_long_name()) { + /* this size + next header + next size */ + return _block_align(_read(_size)) + BLOCK_LEN + _block_align(_next()->size()); + } + + return _read(_size); + } }; class Node; @@ -392,7 +431,7 @@ class Vfs::Tar_file_system : public File_system tar_record_action(record); - file_size size = record->size(); + file_size size = record->storage_size(); /* some datablocks */ /* one metablock */ block_id = block_id + (size / Record::BLOCK_LEN) + 1;