diff options
author | 2012-02-26 16:47:27 +0900 | |
---|---|---|
committer | 2012-02-26 12:32:29 +0000 | |
commit | 173137d89a835556f625750375bc2ceba97d1dd3 (patch) | |
tree | fab7e8e9ff4be7bed42cf2264c6a40f29526ed68 | |
parent | 8f4f01deaf9fad78ec0a6c9cd5928855109a054c (diff) | |
download | paludis-173137d89a835556f625750375bc2ceba97d1dd3.tar.gz paludis-173137d89a835556f625750375bc2ceba97d1dd3.tar.xz |
Support hardlinks in pbins
Luckily libarchive has had hardlink support for a while, and it will
always do the right thing.
This implementation does not take into account the libarchive behaviour
when writing new cpio archives, but it should work just fine with pax
and gnutar.
For more details:
man 3 archive_entry_linkify
Fixes: ticket:1225
-rw-r--r-- | paludis/tar_extras.cc | 37 |
1 files changed, 27 insertions, 10 deletions
diff --git a/paludis/tar_extras.cc b/paludis/tar_extras.cc index 00f860334..da883241d 100644 --- a/paludis/tar_extras.cc +++ b/paludis/tar_extras.cc @@ -32,6 +32,7 @@ using namespace paludis; struct PaludisTarExtras { struct archive * archive; + struct archive_entry_linkresolver * linkresolver; }; extern "C" @@ -57,6 +58,14 @@ paludis_tar_extras_init(const std::string & f, const std::string & compress) if (ARCHIVE_OK != archive_write_open_filename(extras->archive, f.c_str())) throw MergerError("archive_write_open_filename failed"); + + extras->linkresolver = archive_entry_linkresolver_new(); + + if (extras->linkresolver == NULL) + throw MergerError("archive_entry_linkresolver_new failed"); + + archive_entry_linkresolver_set_strategy(extras->linkresolver, archive_format(extras->archive)); + return extras; } @@ -71,28 +80,35 @@ paludis_tar_extras_add_file(PaludisTarExtras * const extras, const std::string & archive_read_disk_set_standard_lookup(disk_archive); struct archive_entry * entry(archive_entry_new()); + struct archive_entry * sparse(archive_entry_new()); int fd(open(from.c_str(), O_RDONLY)); archive_entry_copy_pathname(entry, path.c_str()); if (ARCHIVE_OK != archive_read_disk_entry_from_file(disk_archive, entry, fd, 0)) throw MergerError("archive_read_disk_entry_from_file failed"); + + archive_entry_linkify(extras->linkresolver, &entry, &sparse); + if (ARCHIVE_OK != archive_write_header(extras->archive, entry)) throw MergerError("archive_write_header failed"); - int bytes_read; - char buf[4096]; - while ((bytes_read = read(fd, buf, sizeof(buf))) > 0) - if (bytes_read != archive_write_data(extras->archive, buf, bytes_read)) - throw MergerError("archive_write_data failed"); + if (archive_entry_size(entry) > 0) + { + int bytes_read; + char buf[4096]; + while ((bytes_read = read(fd, buf, sizeof(buf))) > 0) + if (bytes_read != archive_write_data(extras->archive, buf, bytes_read)) + throw MergerError("archive_write_data failed"); - close(fd); + close(fd); - if (ARCHIVE_OK != archive_write_finish_entry(extras->archive)) - throw MergerError("archive_write_finish_entry failed"); + if (ARCHIVE_OK != archive_write_finish_entry(extras->archive)) + throw MergerError("archive_write_finish_entry failed"); - if (ARCHIVE_OK != archive_read_finish(disk_archive)) - throw MergerError("archive_read_finish failed"); + if (ARCHIVE_OK != archive_read_finish(disk_archive)) + throw MergerError("archive_read_finish failed"); + } archive_entry_free(entry); } @@ -130,6 +146,7 @@ paludis_tar_extras_cleanup(PaludisTarExtras * const extras) throw MergerError("archive_write_close failed"); if (ARCHIVE_OK != archive_write_finish(extras->archive)) throw MergerError("archive_write_finish failed"); + archive_entry_linkresolver_free(extras->linkresolver); delete extras; } |