diff --git a/bin/xbps-create/main.c b/bin/xbps-create/main.c index 8729bfde..74c4f026 100644 --- a/bin/xbps-create/main.c +++ b/bin/xbps-create/main.c @@ -40,6 +40,9 @@ #include #include "queue.h" +/* + * XXX: Add a flag to set "packaged-with" object in XBPS_PKGPROPS? + */ #define _PROGNAME "xbps-create" struct xentry { @@ -50,6 +53,7 @@ struct xentry { static TAILQ_HEAD(xentry_head, xentry) xentry_list = TAILQ_HEAD_INITIALIZER(xentry_list); +static uint64_t instsize; static prop_dictionary_t pkg_propsd, pkg_filesd; 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)ftwbuf; + /* Ignore metadata files generated by xbps-src and destdir */ if ((strcmp(fpath, ".") == 0) || (strcmp(fpath, "./props.plist") == 0) || - (strcmp(fpath, "./files.plist") == 0)) + (strcmp(fpath, "./files.plist") == 0) || + (strcmp(fpath, "./flist") == 0)) return 0; /* sanitized file path */ - filep = strchr(fpath, '/') + 1; - + filep = strchr(fpath, '.') + 1; xe = calloc(1, sizeof(*xe)); assert(xe); - xe->file = strdup(filep); + xe->file = strdup(fpath); assert(xe->file); 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) { - /* symlink */ + /* + * Symlinks. + * + * Find out target file. + */ xe->type = strdup("links"); assert(xe->type); - /* Find out target file */ memset(&buf, 0, sizeof(buf)); if (realpath(fpath, buf) == NULL) 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); assert(xe->target); } 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)) 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"); assert(xe->type); - /* calculate sha256 hash */ if ((xe->hash = xbps_file_hash(fpath)) == NULL) die("failed to process hash for %s:", fpath); + + instsize += sb->st_size; + } else if (type == FTW_D) { /* directory */ xe->type = strdup("dirs"); @@ -230,6 +241,7 @@ process_xentry(const char *key) prop_array_t a; prop_dictionary_t d; struct xentry *xe; + char *p; bool found = false; a = prop_array_create(); @@ -242,7 +254,9 @@ process_xentry(const char *key) found = true; d = prop_dictionary_create(); 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) prop_dictionary_set_cstring(d, "target", xe->target); 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_entry *entry; - char buf[BUFSIZ]; + char buf[BUFSIZ], *p; int fd; size_t len; @@ -299,8 +313,11 @@ process_entry_file(struct archive *ar, struct xentry *xe, const char *filematch) assert(entry); archive_entry_set_pathname(entry, xe->file); - if ((fd = open(xe->file, O_RDONLY)) == -1) - die("failed to add entry (open) %s to archive:", xe->file); + p = xbps_xasprintf("%s/%s", destdir, 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) 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) archive_write_data(ar, buf, len); + free(p); close(fd); archive_entry_free(entry); archive_read_free(ard); @@ -365,20 +383,24 @@ process_archive(struct archive *ar, const char *pkgver) /* Add INSTALL/REMOVE metadata scripts first */ TAILQ_FOREACH(xe, &xentry_list, entries) { - process_entry_file(ar, xe, "INSTALL"); - process_entry_file(ar, xe, "REMOVE"); + process_entry_file(ar, xe, "./INSTALL"); + 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 */ xml = prop_dictionary_externalize(pkg_propsd); assert(xml); - process_entry_memory(ar, xml, "props.plist"); + process_entry_memory(ar, xml, "./props.plist"); free(xml); /* Add files.plist metadata file */ xml = prop_dictionary_externalize(pkg_filesd); assert(xml); - process_entry_memory(ar, xml, "files.plist"); + process_entry_memory(ar, xml, "./files.plist"); free(xml); /* 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 main(int argc, char **argv) { @@ -423,9 +463,10 @@ main(int argc, char **argv) const char *conflicts, *deps, *homepage, *license, *maint; const char *provides, *pkgver, *replaces, *desc, *ldesc; const char *arch, *config_files, *mutable_files, *version; - char *pkgname, *binpkg; + char *pkgname, *binpkg, *tname, *p, cwd[PATH_MAX-1]; bool preserve = false; - int c; + int c, pkg_fd; + mode_t myumask; arch = conflicts = deps = homepage = license = maint = 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, "pkgver", pkgver); prop_dictionary_set_cstring_nocopy(pkg_propsd, "short_desc", desc); + set_build_date(); /* Optional properties */ if (homepage) @@ -544,8 +586,13 @@ main(int argc, char **argv) process_array("provides", provides); process_array("replaces", replaces); + /* save cwd */ + memset(&cwd, 0, sizeof(cwd)); + p = getcwd(cwd, sizeof(cwd)); + assert(p); + if (chdir(destdir) == -1) - die("cannot chdir() to destdir:"); + die("cannot chdir() to destdir %s:", destdir); /* * Process XBPS_PKGFILES metadata file. */ @@ -553,29 +600,56 @@ main(int argc, char **argv) assert(pkg_filesd); 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(); assert(ar); archive_write_add_filter_xz(ar); archive_write_set_format_ustar(ar); archive_write_set_options(ar, "compression-level=9"); - - binpkg = xbps_xasprintf("%s.%s.xbps", pkgver, arch); - assert(binpkg); - if (archive_write_open_filename(ar, binpkg) != 0) - die("failed to create %s:", binpkg); + if (archive_write_open_fd(ar, pkg_fd) != 0) + die("Failed to open %s fd for writing:", tname); process_archive(ar, pkgver); 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(pkgname); + close(pkg_fd); + prop_object_release(pkg_propsd); + prop_object_release(pkg_filesd); exit(EXIT_SUCCESS); }