xbps-create: multiple fixes and new additions, 1 item left to finish.

- Added "build-date" object to XBPS_PKGPROPS.
- Added "installed_size" object to XBPS_PKGPROPS.
- Add entries to archive with "./" as prefix to match xbps-src.
- Create binpkg atomically (from caller's perspective) in cwd.
(cherry picked from commit efeae7c346e914bca045ffe44627c18321e45be9)
This commit is contained in:
Juan RP 2012-09-05 09:00:09 +02:00
parent 6d6d31ccc0
commit 215f6d6f31

View File

@ -40,6 +40,9 @@
#include <xbps_api.h> #include <xbps_api.h>
#include "queue.h" #include "queue.h"
/*
* XXX: Add a flag to set "packaged-with" object in XBPS_PKGPROPS?
*/
#define _PROGNAME "xbps-create" #define _PROGNAME "xbps-create"
struct xentry { struct xentry {
@ -50,6 +53,7 @@ struct xentry {
static TAILQ_HEAD(xentry_head, xentry) xentry_list = static TAILQ_HEAD(xentry_head, xentry) xentry_list =
TAILQ_HEAD_INITIALIZER(xentry_list); TAILQ_HEAD_INITIALIZER(xentry_list);
static uint64_t instsize;
static prop_dictionary_t pkg_propsd, pkg_filesd; static prop_dictionary_t pkg_propsd, pkg_filesd;
static const char *destdir; static const char *destdir;
@ -166,17 +170,18 @@ ftw_cb(const char *fpath, const struct stat *sb, int type, struct FTW *ftwbuf)
(void)sb; (void)sb;
(void)ftwbuf; (void)ftwbuf;
/* Ignore metadata files generated by xbps-src and destdir */
if ((strcmp(fpath, ".") == 0) || if ((strcmp(fpath, ".") == 0) ||
(strcmp(fpath, "./props.plist") == 0) || (strcmp(fpath, "./props.plist") == 0) ||
(strcmp(fpath, "./files.plist") == 0)) (strcmp(fpath, "./files.plist") == 0) ||
(strcmp(fpath, "./flist") == 0))
return 0; return 0;
/* sanitized file path */ /* sanitized file path */
filep = strchr(fpath, '/') + 1; filep = strchr(fpath, '.') + 1;
xe = calloc(1, sizeof(*xe)); xe = calloc(1, sizeof(*xe));
assert(xe); assert(xe);
xe->file = strdup(filep); xe->file = strdup(fpath);
assert(xe->file); assert(xe->file);
if ((strcmp(fpath, "./INSTALL") == 0) || if ((strcmp(fpath, "./INSTALL") == 0) ||
@ -188,10 +193,13 @@ ftw_cb(const char *fpath, const struct stat *sb, int type, struct FTW *ftwbuf)
} }
if (type == FTW_SL) { if (type == FTW_SL) {
/* symlink */ /*
* Symlinks.
*
* Find out target file.
*/
xe->type = strdup("links"); xe->type = strdup("links");
assert(xe->type); assert(xe->type);
/* Find out target file */
memset(&buf, 0, sizeof(buf)); memset(&buf, 0, sizeof(buf));
if (realpath(fpath, buf) == NULL) if (realpath(fpath, buf) == NULL)
die("failed to process symlink `%s':", filep); die("failed to process symlink `%s':", filep);
@ -200,9 +208,10 @@ ftw_cb(const char *fpath, const struct stat *sb, int type, struct FTW *ftwbuf)
xe->target = strdup(filep); xe->target = strdup(filep);
assert(xe->target); assert(xe->target);
} else if (type == FTW_F) { } else if (type == FTW_F) {
/* file */
/* /*
* Find out if it's a configuration file or not. * Regular files.
* Find out if it's a configuration file or not
* and calculate sha256 hash.
*/ */
if (entry_is_conf_file(filep)) if (entry_is_conf_file(filep))
xe->type = strdup("conf_files"); xe->type = strdup("conf_files");
@ -210,9 +219,11 @@ ftw_cb(const char *fpath, const struct stat *sb, int type, struct FTW *ftwbuf)
xe->type = strdup("files"); xe->type = strdup("files");
assert(xe->type); assert(xe->type);
/* calculate sha256 hash */
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;
} else if (type == FTW_D) { } else if (type == FTW_D) {
/* directory */ /* directory */
xe->type = strdup("dirs"); xe->type = strdup("dirs");
@ -230,6 +241,7 @@ process_xentry(const char *key)
prop_array_t a; prop_array_t a;
prop_dictionary_t d; prop_dictionary_t d;
struct xentry *xe; struct xentry *xe;
char *p;
bool found = false; bool found = false;
a = prop_array_create(); a = prop_array_create();
@ -242,7 +254,9 @@ process_xentry(const char *key)
found = true; found = true;
d = prop_dictionary_create(); d = prop_dictionary_create();
assert(d); assert(d);
prop_dictionary_set_cstring(d, "file", xe->file); /* sanitize file path */
p = strchr(xe->file, '.') + 1;
prop_dictionary_set_cstring(d, "file", p);
if (xe->target) if (xe->target)
prop_dictionary_set_cstring(d, "target", xe->target); prop_dictionary_set_cstring(d, "target", xe->target);
else if (xe->hash) else if (xe->hash)
@ -280,7 +294,7 @@ process_entry_file(struct archive *ar, struct xentry *xe, const char *filematch)
{ {
struct archive *ard; struct archive *ard;
struct archive_entry *entry; struct archive_entry *entry;
char buf[BUFSIZ]; char buf[BUFSIZ], *p;
int fd; int fd;
size_t len; size_t len;
@ -299,8 +313,11 @@ process_entry_file(struct archive *ar, struct xentry *xe, const char *filematch)
assert(entry); assert(entry);
archive_entry_set_pathname(entry, xe->file); archive_entry_set_pathname(entry, xe->file);
if ((fd = open(xe->file, O_RDONLY)) == -1) p = xbps_xasprintf("%s/%s", destdir, xe->file);
die("failed to add entry (open) %s to archive:", xe->file); assert(p);
if ((fd = open(p, O_RDONLY)) == -1)
die("failed to add entry (open) %s %s to archive:", xe->file);
if ((archive_read_disk_entry_from_file(ard, entry, fd, NULL)) != 0) if ((archive_read_disk_entry_from_file(ard, entry, fd, NULL)) != 0)
die("failed to add entry %s to archive:", xe->file); die("failed to add entry %s to archive:", xe->file);
@ -310,6 +327,7 @@ process_entry_file(struct archive *ar, struct xentry *xe, const char *filematch)
while ((len = read(fd, buf, sizeof(buf))) > 0) while ((len = read(fd, buf, sizeof(buf))) > 0)
archive_write_data(ar, buf, len); archive_write_data(ar, buf, len);
free(p);
close(fd); close(fd);
archive_entry_free(entry); archive_entry_free(entry);
archive_read_free(ard); archive_read_free(ard);
@ -365,20 +383,24 @@ process_archive(struct archive *ar, const char *pkgver)
/* 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, xe, "./INSTALL");
process_entry_file(ar, xe, "REMOVE"); process_entry_file(ar, xe, "./REMOVE");
} }
/*
* Add the installed-size object.
*/
prop_dictionary_set_uint64(pkg_propsd, "installed_size", instsize);
/* Add props.plist metadata file */ /* Add props.plist metadata file */
xml = prop_dictionary_externalize(pkg_propsd); xml = prop_dictionary_externalize(pkg_propsd);
assert(xml); assert(xml);
process_entry_memory(ar, xml, "props.plist"); process_entry_memory(ar, xml, "./props.plist");
free(xml); free(xml);
/* Add files.plist metadata file */ /* Add files.plist metadata file */
xml = prop_dictionary_externalize(pkg_filesd); xml = prop_dictionary_externalize(pkg_filesd);
assert(xml); assert(xml);
process_entry_memory(ar, xml, "files.plist"); process_entry_memory(ar, xml, "./files.plist");
free(xml); free(xml);
/* Add all package data files and release resources */ /* Add all package data files and release resources */
@ -396,6 +418,24 @@ process_archive(struct archive *ar, const char *pkgver)
} }
} }
static void
set_build_date(void)
{
char outstr[64];
time_t t;
struct tm *tmp;
t = time(NULL);
tmp = localtime(&t);
assert(tmp);
if (strftime(outstr, sizeof(outstr)-1, "%F %R %Z", tmp) == 0)
die("failed to set build-date object (strftime):");
if (!prop_dictionary_set_cstring(pkg_propsd, "build-date", outstr))
die("failed to add build-date object:");
}
int int
main(int argc, char **argv) main(int argc, char **argv)
{ {
@ -423,9 +463,10 @@ main(int argc, char **argv)
const char *conflicts, *deps, *homepage, *license, *maint; const char *conflicts, *deps, *homepage, *license, *maint;
const char *provides, *pkgver, *replaces, *desc, *ldesc; const char *provides, *pkgver, *replaces, *desc, *ldesc;
const char *arch, *config_files, *mutable_files, *version; const char *arch, *config_files, *mutable_files, *version;
char *pkgname, *binpkg; char *pkgname, *binpkg, *tname, *p, cwd[PATH_MAX-1];
bool preserve = false; bool preserve = false;
int c; int c, pkg_fd;
mode_t myumask;
arch = conflicts = deps = homepage = license = maint = NULL; arch = conflicts = deps = homepage = license = maint = NULL;
provides = pkgver = replaces = desc = ldesc = NULL; provides = pkgver = replaces = desc = ldesc = NULL;
@ -524,6 +565,7 @@ main(int argc, char **argv)
prop_dictionary_set_cstring_nocopy(pkg_propsd, "version", version); prop_dictionary_set_cstring_nocopy(pkg_propsd, "version", version);
prop_dictionary_set_cstring_nocopy(pkg_propsd, "pkgver", pkgver); prop_dictionary_set_cstring_nocopy(pkg_propsd, "pkgver", pkgver);
prop_dictionary_set_cstring_nocopy(pkg_propsd, "short_desc", desc); prop_dictionary_set_cstring_nocopy(pkg_propsd, "short_desc", desc);
set_build_date();
/* Optional properties */ /* Optional properties */
if (homepage) if (homepage)
@ -544,8 +586,13 @@ main(int argc, char **argv)
process_array("provides", provides); process_array("provides", provides);
process_array("replaces", replaces); process_array("replaces", replaces);
/* save cwd */
memset(&cwd, 0, sizeof(cwd));
p = getcwd(cwd, sizeof(cwd));
assert(p);
if (chdir(destdir) == -1) if (chdir(destdir) == -1)
die("cannot chdir() to destdir:"); die("cannot chdir() to destdir %s:", destdir);
/* /*
* Process XBPS_PKGFILES metadata file. * Process XBPS_PKGFILES metadata file.
*/ */
@ -553,29 +600,56 @@ main(int argc, char **argv)
assert(pkg_filesd); assert(pkg_filesd);
process_destdir(); process_destdir();
/* Back to original cwd after file tree walk processing */
if (chdir(cwd) == -1)
die("cannot chdir() to cwd %s:", cwd);
/* /*
* Create the real XBPS binary package (ustar compressed with xz). * Create a temp file to store archive data.
*/
tname = xbps_xasprintf(".xbps-pkg-XXXXXX");
assert(tname);
pkg_fd = mkstemp(tname);
assert(pkg_fd != -1);
/*
* Process the binary package's archive (ustar compressed with xz).
*/ */
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_ustar(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)
binpkg = xbps_xasprintf("%s.%s.xbps", pkgver, arch); die("Failed to open %s fd for writing:", tname);
assert(binpkg);
if (archive_write_open_filename(ar, binpkg) != 0)
die("failed to create %s:", binpkg);
process_archive(ar, pkgver); process_archive(ar, pkgver);
archive_write_free(ar); archive_write_free(ar);
/*
* Archive was created successfully; flush data to storage,
* set permissions and rename to dest file; from the caller's
* perspective it's atomic.
*/
binpkg = xbps_xasprintf("%s.%s.xbps", pkgver, arch);
assert(binpkg);
printf("%s: binary package created successfully: %s.\n", pkgver, binpkg); (void)fsync(pkg_fd);
myumask = umask(0);
(void)umask(myumask);
if (fchmod(pkg_fd, 0666 & ~myumask) == -1)
die("cannot fchmod() %s:", tname);
if (rename(tname, binpkg) == -1)
die("cannot rename %s to %s:", tname, binpkg);
/* Success, release resources */
printf("%s: binary package created successfully (%s)\n", pkgver, binpkg);
prop_object_release(pkg_propsd);
prop_object_release(pkg_filesd);
free(binpkg); free(binpkg);
free(pkgname); free(pkgname);
close(pkg_fd);
prop_object_release(pkg_propsd);
prop_object_release(pkg_filesd);
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }