xbps-create: added support to add hardlinks.

This commit is contained in:
Juan RP 2012-12-12 03:48:27 +01:00
parent f2d2b2fde9
commit db5da575a4
2 changed files with 101 additions and 53 deletions

2
NEWS
View File

@ -1,5 +1,7 @@
xbps-0.19 (???): xbps-0.19 (???):
* xbps-create(8): hardlinks can be added and archived correctly.
* xbps-rindex(8): in clean mode (-c), entries with unmatched hashes * xbps-rindex(8): in clean mode (-c), entries with unmatched hashes
are now removed from index. are now removed from index.

View File

@ -255,9 +255,10 @@ ftw_cb(const char *fpath, const struct stat *sb, int type, struct FTW *ftwbuf)
if ((xe->hash = xbps_file_hash(fpath)) == NULL) if ((xe->hash = xbps_file_hash(fpath)) == NULL)
die("failed to process hash for %s:", fpath); die("failed to process hash for %s:", fpath);
instsize += sb->st_size; if (sb->st_nlink <= 1)
instsize += sb->st_size;
} else if (type == FTW_D) { } else if (type == FTW_D || type == FTW_DP) {
/* directory */ /* directory */
xe->type = strdup("dirs"); xe->type = strdup("dirs");
assert(xe->type); assert(xe->type);
@ -348,16 +349,62 @@ process_destdir(const char *mutable_files)
} }
static void static void
process_entry_file(struct archive *ar, struct xentry *xe, const char *filematch) write_entry(struct archive *ar, struct archive_entry *entry)
{ {
struct archive *ard; char buf[16384];
struct archive_entry *entry; const char *name;
struct stat st;
void *map = NULL;
char *buf, *p;
int fd = -1; int fd = -1;
ssize_t r; off_t len;
size_t len; ssize_t buf_len;
if (archive_entry_pathname(entry) == NULL)
return;
if (archive_write_header(ar, entry)) {
die("cannot write %s to archive: %s",
archive_entry_pathname(entry),
archive_error_string(ar));
}
/* Only regular files can have data. */
if (archive_entry_filetype(entry) != AE_IFREG ||
archive_entry_size(entry) == 0) {
archive_entry_free(entry);
return;
}
name = archive_entry_sourcepath(entry);
fd = open(name, O_RDONLY);
assert(fd != -1);
len = archive_entry_size(entry);
while (len > 0) {
buf_len = (len > (off_t)sizeof(buf)) ?
(ssize_t)sizeof(buf) : (ssize_t)len;
if ((buf_len = read(fd, buf, buf_len)) == 0)
break;
else if (buf_len < 0)
die("cannot read from %s", name);
archive_write_data(ar, buf, (size_t)buf_len);
len -= buf_len;
}
close(fd);
archive_entry_free(entry);
}
static void
process_entry_file(struct archive *ar,
struct archive_entry_linkresolver *resolver,
struct xentry *xe, const char *filematch)
{
struct archive_entry *entry, *sparse_entry;
struct stat st;
char buf[16384], *p;
ssize_t len;
assert(ar); assert(ar);
assert(xe); assert(xe);
@ -365,53 +412,32 @@ process_entry_file(struct archive *ar, struct xentry *xe, const char *filematch)
if (filematch && strcmp(xe->file, filematch)) if (filematch && strcmp(xe->file, filematch))
return; return;
ard = archive_read_disk_new();
assert(ard);
archive_read_disk_set_standard_lookup(ard);
archive_read_disk_set_symlink_physical(ard);
entry = archive_entry_new();
assert(entry);
p = xbps_xasprintf("%s/%s", destdir, xe->file); p = xbps_xasprintf("%s/%s", destdir, xe->file);
archive_entry_set_pathname(entry, xe->file);
archive_entry_copy_sourcepath(entry, p);
if (lstat(p, &st) == -1) if (lstat(p, &st) == -1)
die("failed to add entry (fstat) %s to archive:", xe->file); die("failed to add entry (fstat) %s to archive:", xe->file);
if (st.st_size > SSIZE_MAX - 1) entry = archive_entry_new();
die("failed to add entry (SSIZE_MAX) %s to archive:", xe->file); assert(entry);
archive_entry_set_pathname(entry, xe->file);
archive_entry_copy_stat(entry, &st);
archive_entry_copy_sourcepath(entry, p);
if ((archive_read_disk_entry_from_file(ard, entry, -1, &st)) != 0)
die("failed to add entry %s to archive:", xe->file);
archive_write_header(ar, entry);
len = st.st_size + 1;
buf = malloc(len);
assert(buf);
if (S_ISLNK(st.st_mode)) { if (S_ISLNK(st.st_mode)) {
r = readlink(p, buf, len); len = readlink(p, buf, sizeof(buf));
if (r < 0 || r > st.st_size) if (len < 0 || len > st.st_size)
die("failed to add entry %s (readlink) to archive:", die("failed to add entry %s (readlink) to archive:",
xe->file); xe->file);
buf[len-1] = '\0'; buf[len] = '\0';
archive_write_data(ar, buf, len); archive_entry_set_symlink(entry, buf);
} else {
fd = open(p, O_RDONLY);
assert(fd != -1);
map = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
if (map == MAP_FAILED)
die("failed to add entry %s (mmap) to archive:",
xe->file);
close(fd);
archive_write_data(ar, map, len);
munmap(map, len);
} }
archive_entry_free(entry);
archive_read_close(ard);
archive_read_free(ard);
free(buf);
free(p); free(p);
archive_entry_linkify(resolver, &entry, &sparse_entry);
if (entry != NULL)
write_entry(ar, entry);
if (sparse_entry != NULL)
write_entry(ar, sparse_entry);
} }
static void static void
@ -457,15 +483,17 @@ destroy_xentry(struct xentry *xe)
} }
static void static void
process_archive(struct archive *ar, const char *pkgver, bool quiet) process_archive(struct archive *ar,
struct archive_entry_linkresolver *resolver,
const char *pkgver, bool quiet)
{ {
struct xentry *xe; struct xentry *xe;
char *xml; char *xml;
/* Add INSTALL/REMOVE metadata scripts first */ /* Add INSTALL/REMOVE metadata scripts first */
TAILQ_FOREACH(xe, &xentry_list, entries) { TAILQ_FOREACH(xe, &xentry_list, entries) {
process_entry_file(ar, xe, "./INSTALL"); process_entry_file(ar, resolver, xe, "./INSTALL");
process_entry_file(ar, xe, "./REMOVE"); process_entry_file(ar, resolver, xe, "./REMOVE");
} }
/* /*
* Add the installed-size object. * Add the installed-size object.
@ -496,7 +524,7 @@ process_archive(struct archive *ar, const char *pkgver, bool quiet)
printf("%s: adding `%s' ...\n", pkgver, xe->file); printf("%s: adding `%s' ...\n", pkgver, xe->file);
fflush(stdout); fflush(stdout);
} }
process_entry_file(ar, xe, NULL); process_entry_file(ar, resolver, xe, NULL);
destroy_xentry(xe); destroy_xentry(xe);
} }
} }
@ -546,6 +574,8 @@ main(int argc, char **argv)
{ NULL, 0, NULL, 0 } { NULL, 0, NULL, 0 }
}; };
struct archive *ar; struct archive *ar;
struct archive_entry *entry, *sparse_entry;
struct archive_entry_linkresolver *resolver;
struct stat st; struct stat st;
const char *conflicts, *deps, *homepage, *license, *maint, *bwith; const char *conflicts, *deps, *homepage, *license, *maint, *bwith;
const char *provides, *pkgver, *replaces, *desc, *ldesc; const char *provides, *pkgver, *replaces, *desc, *ldesc;
@ -725,13 +755,29 @@ main(int argc, char **argv)
ar = archive_write_new(); ar = archive_write_new();
assert(ar); assert(ar);
archive_write_add_filter_xz(ar); archive_write_add_filter_xz(ar);
archive_write_set_format_ustar(ar); archive_write_set_format_pax_restricted(ar);
if ((resolver = archive_entry_linkresolver_new()) == NULL)
die("cannot create link resolver");
archive_entry_linkresolver_set_strategy(resolver,
archive_format(ar));
archive_write_set_options(ar, "compression-level=9"); archive_write_set_options(ar, "compression-level=9");
if (archive_write_open_fd(ar, pkg_fd) != 0) if (archive_write_open_fd(ar, pkg_fd) != 0)
die("Failed to open %s fd for writing:", tname); die("Failed to open %s fd for writing:", tname);
process_archive(ar, pkgver, quiet); process_archive(ar, resolver, pkgver, quiet);
/* Process hardlinks */
entry = NULL;
archive_entry_linkify(resolver, &entry, &sparse_entry);
while (entry != NULL) {
write_entry(ar, entry);
entry = NULL;
archive_entry_linkify(resolver, &entry, &sparse_entry);
}
archive_entry_linkresolver_free(resolver);
/* close and free archive */
archive_write_free(ar); archive_write_free(ar);
prop_object_release(pkg_propsd); prop_object_release(pkg_propsd);
prop_object_release(pkg_filesd); prop_object_release(pkg_filesd);
/* /*