From b9f1e054731d3dab452cc87c628928033713ee2b Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 22 Sep 2017 08:41:46 -0600 Subject: [PATCH] Add support for creating packages with a small hash in the filename This is work is to support making mirroring packages easier and avoiding the bug where we atomically switch a new package set in while someone is downloading from the set. --- libpkg/pkg.h.in | 2 +- libpkg/pkg_create.c | 28 ++++++++++++++++++++-- libpkg/private/pkg.h | 1 + src/create.c | 52 ++++++++++++++++++++++------------------ tests/frontend/create.sh | 14 +++++++++++ 5 files changed, 71 insertions(+), 26 deletions(-) diff --git a/libpkg/pkg.h.in b/libpkg/pkg.h.in index a0a9c7bdaa..10fc84752b 100644 --- a/libpkg/pkg.h.in +++ b/libpkg/pkg.h.in @@ -1141,7 +1141,7 @@ int pkg_create_from_manifest(const char *, pkg_formats, const char *, /** * Create package from stage install with a metadata directory */ -int pkg_create_staged(const char *, pkg_formats, const char *, const char *, char *); +int pkg_create_staged(const char *, pkg_formats, const char *, const char *, char *, bool); int pkg_load_metadata(struct pkg *, const char *, const char *, const char *, const char *, bool); /** diff --git a/libpkg/pkg_create.c b/libpkg/pkg_create.c index 671eb4e445..6c8b82e967 100644 --- a/libpkg/pkg_create.c +++ b/libpkg/pkg_create.c @@ -394,8 +394,10 @@ pkg_load_metadata(struct pkg *pkg, const char *mfile, const char *md_dir, int pkg_create_staged(const char *outdir, pkg_formats format, const char *rootdir, - const char *md_dir, char *plist) + const char *md_dir, char *plist, bool hash) { + char hash_dest[MAXPATHLEN]; + char filename[MAXPATHLEN]; struct pkg *pkg = NULL; struct pkg_file *file = NULL; struct pkg_dir *dir = NULL; @@ -430,8 +432,30 @@ pkg_create_staged(const char *outdir, pkg_formats format, const char *rootdir, } cleanup: - free(pkg); packing_finish(pkg_archive); + if (hash && ret == EPKG_OK) { + /* Find the hash and rename the file and create a symlink */ + pkg_snprintf(filename, sizeof(filename), "%n-%v.%S", + pkg, pkg, packing_format_to_string(format)); + pkg->sum = pkg_checksum_file(filename, + PKG_HASH_TYPE_SHA256_HEX); + pkg_snprintf(hash_dest, sizeof(hash_dest), "%n-%v-%z.%S", + pkg, pkg, pkg, packing_format_to_string(format)); + + pkg_debug(1, "Rename the pkg file from: %s to: %s", + filename, hash_dest); + + if (rename(filename, hash_dest) == -1) { + pkg_emit_errno("rename", hash_dest); + unlink(hash_dest); + return (EPKG_FATAL); + } + if (symlink(hash_dest, filename) == -1) { + pkg_emit_errno("symlink", hash_dest); + return (EPKG_FATAL); + } + } + free(pkg); return (ret); } diff --git a/libpkg/private/pkg.h b/libpkg/private/pkg.h index 1fba71130d..63bc298c6f 100644 --- a/libpkg/private/pkg.h +++ b/libpkg/private/pkg.h @@ -694,6 +694,7 @@ int packing_append_buffer(struct packing *pack, const char *buffer, const char *path, int size); int packing_append_tree(struct packing *pack, const char *treepath, const char *newroot); +void packing_get_filename(struct packing *pack, const char *filename); void packing_finish(struct packing *pack); pkg_formats packing_format_from_string(const char *str); const char* packing_format_to_string(pkg_formats format); diff --git a/src/create.c b/src/create.c index be76973a91..f379508e18 100644 --- a/src/create.c +++ b/src/create.c @@ -62,13 +62,13 @@ struct pkg_entry *pkg_head = NULL; void usage_create(void) { - fprintf(stderr, "Usage: pkg create [-Onqv] [-f format] [-o outdir] " + fprintf(stderr, "Usage: pkg create [-Ohnqv] [-f format] [-o outdir] " "[-p plist] [-r rootdir] -m metadatadir\n"); - fprintf(stderr, "Usage: pkg create [-Onqv] [-f format] [-o outdir] " + fprintf(stderr, "Usage: pkg create [-Ohnqv] [-f format] [-o outdir] " "[-r rootdir] -M manifest\n"); - fprintf(stderr, " pkg create [-Ognqvx] [-f format] [-o outdir] " + fprintf(stderr, " pkg create [-Ohgnqvx] [-f format] [-o outdir] " "[-r rootdir] pkg-name ...\n"); - fprintf(stderr, " pkg create [-Onqv] [-f format] [-o outdir] " + fprintf(stderr, " pkg create [-Ohnqv] [-f format] [-o outdir] " "[-r rootdir] -a\n\n"); fprintf(stderr, "For more information see 'pkg help create'.\n"); } @@ -179,14 +179,15 @@ pkg_create_matches(int argc, char **argv, match_t match, pkg_formats fmt, /* * options: - * -x: regex - * -g: globbing - * -r: rootdir for the package - * -m: path to dir where to find the metadata - * -q: quiet mode * -M: manifest file * -f : format could be txz, tgz, tbz or tar + * -g: globbing + * -h: pkg name with hash and symlink + * -m: path to dir where to find the metadata * -o: output directory where to create packages by default ./ is used + * -q: quiet mode + * -r: rootdir for the package + * -x: regex */ int @@ -202,6 +203,7 @@ exec_create(int argc, char **argv) pkg_formats fmt; int ch; bool overwrite = true; + bool hash = false; /* POLA: pkg create is quiet by default, unless @@ -212,39 +214,34 @@ exec_create(int argc, char **argv) struct option longopts[] = { { "all", no_argument, NULL, 'a' }, + { "format", required_argument, NULL, 'f' }, { "glob", no_argument, NULL, 'g' }, + { "hash", no_argument, NULL, 'h' }, { "regex", no_argument, NULL, 'x' }, - { "format", required_argument, NULL, 'f' }, { "root-dir", required_argument, NULL, 'r' }, { "metadata", required_argument, NULL, 'm' }, { "manifest", required_argument, NULL, 'M' }, - { "out-dir", required_argument, NULL, 'o' }, { "no-clobber", no_argument, NULL, 'n' }, + { "out-dir", required_argument, NULL, 'o' }, { "plist", required_argument, NULL, 'p' }, { "quiet", no_argument, NULL, 'q' }, { "verbose", no_argument, NULL, 'v' }, { NULL, 0, NULL, 0 }, }; - while ((ch = getopt_long(argc, argv, "+agxf:r:m:M:o:np:qv", longopts, NULL)) != -1) { + while ((ch = getopt_long(argc, argv, "+aghxf:r:m:M:o:np:qv", longopts, NULL)) != -1) { switch (ch) { case 'a': match = MATCH_ALL; break; - case 'g': - match = MATCH_GLOB; - break; - case 'x': - match = MATCH_REGEX; - break; case 'f': format = optarg; break; - case 'o': - outdir = optarg; + case 'g': + match = MATCH_GLOB; break; - case 'r': - rootdir = optarg; + case 'h': + hash = true; break; case 'm': metadatadir = optarg; @@ -255,15 +252,24 @@ exec_create(int argc, char **argv) case 'n': overwrite = false; break; + case 'o': + outdir = optarg; + break; case 'p': plist = optarg; break; case 'q': quiet = true; break; + case 'r': + rootdir = optarg; + break; case 'v': quiet = false; break; + case 'x': + match = MATCH_REGEX; + break; default: usage_create(); return (EX_USAGE); @@ -312,7 +318,7 @@ exec_create(int argc, char **argv) overwrite) == EPKG_OK ? EX_OK : EX_SOFTWARE); } else if (metadatadir != NULL) { return (pkg_create_staged(outdir, fmt, rootdir, metadatadir, - plist) == EPKG_OK ? EX_OK : EX_SOFTWARE); + plist, hash) == EPKG_OK ? EX_OK : EX_SOFTWARE); } else { /* (manifest != NULL) */ return (pkg_create_from_manifest(outdir, fmt, rootdir, manifest, plist) == EPKG_OK ? EX_OK : EX_SOFTWARE); diff --git a/tests/frontend/create.sh b/tests/frontend/create.sh index 4925bb52fc..2aad4fe3d4 100755 --- a/tests/frontend/create.sh +++ b/tests/frontend/create.sh @@ -15,6 +15,7 @@ tests_init \ create_from_plist_with_keyword_arguments \ create_from_manifest_and_plist \ create_from_plist_pkg_descr \ + create_from_plist_hash \ create_from_plist_with_keyword_and_message genmanifest() { @@ -391,6 +392,19 @@ message upgrade } +create_from_plist_hash_body() { + touch file1 + genmanifest + genplist "file1" + + atf_check \ + -o empty \ + -e empty \ + -s exit:0 \ + pkg create -h -o ${TMPDIR} -m . -p test.plist -r . + +} + create_from_plist_with_keyword_and_message_body() { genmanifest genplist "@showmsg plop"