vfs: GNU long file name support for tar

This commit is contained in:
Sebastian Sumpf 2017-09-11 18:01:11 +02:00 committed by Christian Helmuth
parent 67869a697b
commit 89a9e88a7e

View File

@ -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;