Merge pull request #159 from Gottox/reproducible-create
Reproducible create
This commit is contained in:
commit
13395d8a50
@ -42,7 +42,6 @@
|
||||
#include <locale.h>
|
||||
|
||||
#include <xbps.h>
|
||||
#include "queue.h"
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic ignored "-Wformat-nonliteral"
|
||||
@ -55,18 +54,8 @@
|
||||
# define archive_write_finish(x) archive_write_free(x)
|
||||
#endif
|
||||
|
||||
struct xentry {
|
||||
TAILQ_ENTRY(xentry) entries;
|
||||
uint64_t mtime;
|
||||
char *file, *type, *target, *hash;
|
||||
ino_t inode;
|
||||
};
|
||||
|
||||
static TAILQ_HEAD(xentry_head, xentry) xentry_list =
|
||||
TAILQ_HEAD_INITIALIZER(xentry_list);
|
||||
|
||||
static uint64_t instsize;
|
||||
static xbps_dictionary_t pkg_propsd, pkg_filesd;
|
||||
static xbps_dictionary_t pkg_propsd, pkg_filesd, all_filesd;
|
||||
static const char *destdir;
|
||||
|
||||
static void __attribute__((noreturn))
|
||||
@ -302,7 +291,7 @@ entry_is_conf_file(const char *file)
|
||||
static int
|
||||
ftw_cb(const char *fpath, const struct stat *sb, int type, struct FTW *ftwbuf _unused)
|
||||
{
|
||||
struct xentry *xe = NULL;
|
||||
xbps_dictionary_t fileinfo = NULL;
|
||||
const char *filep = NULL;
|
||||
char *buf, *p, *p2, *dname;
|
||||
ssize_t r;
|
||||
@ -321,16 +310,20 @@ ftw_cb(const char *fpath, const struct stat *sb, int type, struct FTW *ftwbuf _u
|
||||
|
||||
/* sanitized file path */
|
||||
filep = strchr(fpath, '.') + 1;
|
||||
xe = calloc(1, sizeof(*xe));
|
||||
assert(xe);
|
||||
xe->file = strdup(fpath);
|
||||
assert(xe->file);
|
||||
fileinfo = xbps_dictionary_create();
|
||||
/* XXX: fileinfo contains the sanatized path, whereas xe contains the
|
||||
* unsanatized path!
|
||||
*
|
||||
* when handing the files over, do not use the dictionary directly. Instead
|
||||
* use the keysym, as this value has the unsanatized path.
|
||||
*/
|
||||
xbps_dictionary_set_cstring(fileinfo, "file", filep);
|
||||
xbps_dictionary_set(all_filesd, fpath, fileinfo);
|
||||
|
||||
if ((strcmp(fpath, "./INSTALL") == 0) ||
|
||||
(strcmp(fpath, "./REMOVE") == 0)) {
|
||||
/* metadata file */
|
||||
xe->type = strdup("metadata");
|
||||
assert(xe->type);
|
||||
xbps_dictionary_set_cstring_nocopy(fileinfo, "type", "metadata");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -340,10 +333,10 @@ ftw_cb(const char *fpath, const struct stat *sb, int type, struct FTW *ftwbuf _u
|
||||
*
|
||||
* Find out target file.
|
||||
*/
|
||||
xe->type = strdup("links");
|
||||
assert(xe->type);
|
||||
xbps_dictionary_set_cstring_nocopy(fileinfo, "type", "links");
|
||||
/* store modification time for regular files and links */
|
||||
xe->mtime = (uint64_t)sb->st_mtime;
|
||||
xbps_dictionary_set_cstring_nocopy(fileinfo, "type", "links");
|
||||
xbps_dictionary_set_uint64(fileinfo, "mtime", (uint64_t)sb->st_mtime);
|
||||
buf = malloc(sb->st_size+1);
|
||||
assert(buf);
|
||||
r = readlink(fpath, buf, sb->st_size+1);
|
||||
@ -363,7 +356,7 @@ ftw_cb(const char *fpath, const struct stat *sb, int type, struct FTW *ftwbuf _u
|
||||
* which might be provided in another package.
|
||||
* So let's use the same target.
|
||||
*/
|
||||
xe->target = strdup(buf);
|
||||
xbps_dictionary_set_cstring(fileinfo, "target", buf);
|
||||
} else {
|
||||
/*
|
||||
* Sanitize destdir just in case.
|
||||
@ -371,7 +364,7 @@ ftw_cb(const char *fpath, const struct stat *sb, int type, struct FTW *ftwbuf _u
|
||||
if ((p2 = realpath(destdir, NULL)) == NULL)
|
||||
die("failed to sanitize destdir %s: %s", destdir, strerror(errno));
|
||||
|
||||
xe->target = strdup(p+strlen(p2));
|
||||
xbps_dictionary_set_cstring(fileinfo, "target", p+strlen(p2));
|
||||
free(p2);
|
||||
free(p);
|
||||
}
|
||||
@ -381,87 +374,101 @@ ftw_cb(const char *fpath, const struct stat *sb, int type, struct FTW *ftwbuf _u
|
||||
assert(p);
|
||||
dname = dirname(p);
|
||||
assert(dname);
|
||||
xe->target = xbps_xasprintf("%s/%s", dname, buf);
|
||||
p2 = xbps_xasprintf("%s/%s", dname, buf);
|
||||
xbps_dictionary_set_cstring(fileinfo, "target", p2);
|
||||
free(p2);
|
||||
free(p);
|
||||
} else {
|
||||
xe->target = strdup(buf);
|
||||
xbps_dictionary_set_cstring(fileinfo, "target", buf);
|
||||
}
|
||||
assert(xe->target);
|
||||
assert(xbps_dictionary_get(fileinfo, "target"));
|
||||
free(buf);
|
||||
} else if (type == FTW_F) {
|
||||
struct xentry *xep;
|
||||
bool hlink = false;
|
||||
xbps_object_iterator_t iter;
|
||||
xbps_object_t obj;
|
||||
xbps_dictionary_t linkinfo;
|
||||
uint64_t inode = 0;
|
||||
/*
|
||||
* Regular files. First find out if it's a hardlink:
|
||||
* - st_nlink > 1
|
||||
* and then search for a stored file matching its inode.
|
||||
*/
|
||||
TAILQ_FOREACH(xep, &xentry_list, entries) {
|
||||
if (sb->st_nlink > 1 && xep->inode == sb->st_ino) {
|
||||
iter = xbps_dictionary_iterator(all_filesd);
|
||||
assert(iter);
|
||||
while ((obj = xbps_object_iterator_next(iter))) {
|
||||
if (sb->st_nlink <= 1)
|
||||
continue;
|
||||
linkinfo = xbps_dictionary_get_keysym(all_filesd, obj);
|
||||
xbps_dictionary_get_uint64(linkinfo, "inode", &inode);
|
||||
if (inode == sb->st_ino) {
|
||||
/* matched */
|
||||
hlink = true;
|
||||
printf("%lu %lu\n", inode, sb->st_ino);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hlink)
|
||||
if (inode != sb->st_ino)
|
||||
instsize += sb->st_size;
|
||||
xbps_object_iterator_release(iter);
|
||||
|
||||
/*
|
||||
* Find out if it's a configuration file or not
|
||||
* and calculate sha256 hash.
|
||||
*/
|
||||
if (entry_is_conf_file(filep))
|
||||
xe->type = strdup("conf_files");
|
||||
else
|
||||
xe->type = strdup("files");
|
||||
if (entry_is_conf_file(filep)) {
|
||||
xbps_dictionary_set_cstring_nocopy(fileinfo, "type", "conf_files");
|
||||
} else {
|
||||
xbps_dictionary_set_cstring_nocopy(fileinfo, "type", "files");
|
||||
}
|
||||
|
||||
assert(xe->type);
|
||||
if ((xe->hash = xbps_file_hash(fpath)) == NULL)
|
||||
if ((p = xbps_file_hash(fpath)) == NULL)
|
||||
die("failed to process hash for %s:", fpath);
|
||||
xbps_dictionary_set_cstring(fileinfo, "sha256", p);
|
||||
free(p);
|
||||
|
||||
xe->inode = sb->st_ino;
|
||||
xbps_dictionary_set_uint64(fileinfo, "inode", sb->st_ino);
|
||||
/* store modification time for regular files and links */
|
||||
xe->mtime = (uint64_t)sb->st_mtime;
|
||||
|
||||
xbps_dictionary_set_uint64(fileinfo, "mtime", sb->st_mtime);
|
||||
} else if (type == FTW_D || type == FTW_DP) {
|
||||
/* directory */
|
||||
xe->type = strdup("dirs");
|
||||
assert(xe->type);
|
||||
xbps_dictionary_set_cstring_nocopy(fileinfo, "type", "dirs");
|
||||
}
|
||||
|
||||
out:
|
||||
TAILQ_INSERT_TAIL(&xentry_list, xe, entries);
|
||||
xbps_object_release(fileinfo);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
process_xentry(const char *key, const char *mutable_files)
|
||||
{
|
||||
xbps_object_iterator_t iter;
|
||||
xbps_object_t filepathk;
|
||||
xbps_array_t a;
|
||||
xbps_dictionary_t d;
|
||||
struct xentry *xe;
|
||||
char *p, *saveptr, *args, *tok;
|
||||
xbps_dictionary_t fileinfo;
|
||||
char *saveptr, *args, *tok;
|
||||
const char *p;
|
||||
bool found = false, mutable_found = false;
|
||||
|
||||
a = xbps_array_create();
|
||||
assert(a);
|
||||
|
||||
TAILQ_FOREACH_REVERSE(xe, &xentry_list, xentry_head, entries) {
|
||||
if (strcmp(xe->type, key))
|
||||
iter = xbps_dictionary_iterator(all_filesd);
|
||||
assert(iter);
|
||||
while ((filepathk = xbps_object_iterator_next(iter))) {
|
||||
fileinfo = xbps_dictionary_get_keysym(all_filesd, filepathk);
|
||||
|
||||
if (!xbps_string_equals_cstring(xbps_dictionary_get(fileinfo, "type"), key))
|
||||
continue;
|
||||
|
||||
found = true;
|
||||
d = xbps_dictionary_create();
|
||||
assert(d);
|
||||
/* sanitize file path */
|
||||
p = strchr(xe->file, '.') + 1;
|
||||
xbps_dictionary_get_cstring_nocopy(fileinfo, "file", &p);
|
||||
/*
|
||||
* Find out if this file is mutable.
|
||||
*/
|
||||
if (mutable_files) {
|
||||
if ((strchr(mutable_files, ' ') == NULL) &&
|
||||
(strcmp(mutable_files, p) == 0))
|
||||
xbps_dictionary_set_bool(d, "mutable", true);
|
||||
xbps_dictionary_set_bool(fileinfo, "mutable", true);
|
||||
else {
|
||||
args = strdup(mutable_files);
|
||||
assert(args);
|
||||
@ -474,23 +481,21 @@ process_xentry(const char *key, const char *mutable_files)
|
||||
}
|
||||
free(args);
|
||||
if (mutable_found) {
|
||||
xbps_dictionary_set_bool(d, "mutable",
|
||||
xbps_dictionary_set_bool(fileinfo, "mutable",
|
||||
true);
|
||||
mutable_found = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
xbps_dictionary_set_cstring(d, "file", p);
|
||||
if (xe->target)
|
||||
xbps_dictionary_set_cstring(d, "target", xe->target);
|
||||
if (xe->hash)
|
||||
xbps_dictionary_set_cstring(d, "sha256", xe->hash);
|
||||
if (xe->mtime)
|
||||
xbps_dictionary_set_uint64(d, "mtime", xe->mtime);
|
||||
/*
|
||||
* Clean up dictionary
|
||||
*/
|
||||
xbps_dictionary_remove(fileinfo, "inode");
|
||||
|
||||
xbps_array_add(a, d);
|
||||
xbps_object_release(d);
|
||||
xbps_array_add(a, fileinfo);
|
||||
xbps_object_release(fileinfo);
|
||||
}
|
||||
xbps_object_iterator_release(iter);
|
||||
if (found)
|
||||
xbps_dictionary_set(pkg_filesd, key, a);
|
||||
|
||||
@ -552,7 +557,7 @@ write_entry(struct archive *ar, struct archive_entry *entry)
|
||||
static void
|
||||
process_entry_file(struct archive *ar,
|
||||
struct archive_entry_linkresolver *resolver,
|
||||
struct xentry *xe, const char *filematch)
|
||||
const char *filename)
|
||||
{
|
||||
struct archive_entry *entry, *sparse_entry;
|
||||
struct stat st;
|
||||
@ -560,18 +565,14 @@ process_entry_file(struct archive *ar,
|
||||
ssize_t len;
|
||||
|
||||
assert(ar);
|
||||
assert(xe);
|
||||
|
||||
if (filematch && strcmp(xe->file, filematch))
|
||||
return;
|
||||
|
||||
p = xbps_xasprintf("%s/%s", destdir, xe->file);
|
||||
p = xbps_xasprintf("%s/%s", destdir, filename);
|
||||
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:", filename);
|
||||
|
||||
entry = archive_entry_new();
|
||||
assert(entry);
|
||||
archive_entry_set_pathname(entry, xe->file);
|
||||
archive_entry_set_pathname(entry, filename);
|
||||
if (st.st_uid == geteuid())
|
||||
st.st_uid = 0;
|
||||
if (st.st_gid == getegid())
|
||||
@ -590,7 +591,7 @@ process_entry_file(struct archive *ar,
|
||||
len = readlink(p, buf, st.st_size+1);
|
||||
if (len < 0 || len > st.st_size)
|
||||
die("failed to add entry %s (readlink) to archive:",
|
||||
xe->file);
|
||||
filename);
|
||||
buf[len] = '\0';
|
||||
archive_entry_set_symlink(entry, buf);
|
||||
}
|
||||
@ -611,14 +612,17 @@ process_archive(struct archive *ar,
|
||||
struct archive_entry_linkresolver *resolver,
|
||||
const char *pkgver, bool quiet)
|
||||
{
|
||||
struct xentry *xe;
|
||||
char *xml;
|
||||
const char *filepath, *p;
|
||||
xbps_object_iterator_t iter;
|
||||
xbps_object_t filepathk;
|
||||
xbps_dictionary_t fileinfo;
|
||||
|
||||
/* Add INSTALL/REMOVE metadata scripts first */
|
||||
TAILQ_FOREACH(xe, &xentry_list, entries) {
|
||||
process_entry_file(ar, resolver, xe, "./INSTALL");
|
||||
process_entry_file(ar, resolver, xe, "./REMOVE");
|
||||
}
|
||||
if (xbps_dictionary_get(all_filesd, "./INSTALL"))
|
||||
process_entry_file(ar, resolver, "./INSTALL");
|
||||
if (xbps_dictionary_get(all_filesd, "./REMOVE"))
|
||||
process_entry_file(ar, resolver, "./REMOVE");
|
||||
/*
|
||||
* Add the installed-size object.
|
||||
*/
|
||||
@ -640,18 +644,23 @@ process_archive(struct archive *ar,
|
||||
free(xml);
|
||||
|
||||
/* Add all package data files and release resources */
|
||||
while ((xe = TAILQ_FIRST(&xentry_list)) != NULL) {
|
||||
TAILQ_REMOVE(&xentry_list, xe, entries);
|
||||
if ((strcmp(xe->type, "metadata") == 0) ||
|
||||
(strcmp(xe->type, "dirs") == 0))
|
||||
iter = xbps_dictionary_iterator(all_filesd);
|
||||
assert(iter);
|
||||
while ((filepathk = xbps_object_iterator_next(iter))) {
|
||||
filepath = xbps_dictionary_keysym_cstring_nocopy(filepathk);
|
||||
fileinfo = xbps_dictionary_get_keysym(all_filesd, filepathk);
|
||||
if (xbps_string_equals_cstring(xbps_dictionary_get(fileinfo, "type"), "metadata") ||
|
||||
xbps_string_equals_cstring(xbps_dictionary_get(fileinfo, "type"), "dirs"))
|
||||
continue;
|
||||
|
||||
if (!quiet) {
|
||||
printf("%s: adding `%s' ...\n", pkgver, xe->file);
|
||||
xbps_dictionary_get_cstring_nocopy(fileinfo, "file", &p);
|
||||
printf("%s: adding `%s' ...\n", pkgver, p);
|
||||
fflush(stdout);
|
||||
}
|
||||
process_entry_file(ar, resolver, xe, NULL);
|
||||
process_entry_file(ar, resolver, filepath);
|
||||
}
|
||||
xbps_object_iterator_release(iter);
|
||||
}
|
||||
|
||||
int
|
||||
@ -889,6 +898,8 @@ main(int argc, char **argv)
|
||||
*/
|
||||
pkg_filesd = xbps_dictionary_create();
|
||||
assert(pkg_filesd);
|
||||
all_filesd = xbps_dictionary_create();
|
||||
assert(all_filesd);
|
||||
process_destdir(mutable_files);
|
||||
|
||||
/* Back to original cwd after file tree walk processing */
|
||||
|
Loading…
Reference in New Issue
Block a user