aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Georgi Georgiev <chutz@gg3.net> 2012-02-26 16:47:27 +0900
committerAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2012-02-26 12:32:29 +0000
commit173137d89a835556f625750375bc2ceba97d1dd3 (patch)
treefab7e8e9ff4be7bed42cf2264c6a40f29526ed68
parent8f4f01deaf9fad78ec0a6c9cd5928855109a054c (diff)
downloadpaludis-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.cc37
1 files changed, 27 insertions, 10 deletions
diff --git a/paludis/tar_extras.cc b/paludis/tar_extras.cc
index 00f8603..da88324 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;
}