diff --git a/commandline.c b/commandline.c index 950f49bf..f67ad31b 100644 --- a/commandline.c +++ b/commandline.c @@ -1216,21 +1216,26 @@ cleanup: return status; } -int app_rhizome_extract_manifest(int argc, const char *const *argv, const struct command_line_option *o, void *context) +int app_rhizome_extract_bundle(int argc, const char *const *argv, const struct command_line_option *o, void *context) { if (config.debug.verbose) DEBUG_argv("command", argc, argv); - const char *pins, *manifestid, *manifestpath; - cli_arg(argc, argv, o, "pin,pin...", &pins, NULL, ""); - if (cli_arg(argc, argv, o, "manifestid", &manifestid, cli_manifestid, NULL) == -1 - || cli_arg(argc, argv, o, "manifestpath", &manifestpath, NULL, NULL) == -1) + const char *manifestpath, *filepath, *manifestid, *pins, *bskhex; + if (cli_arg(argc, argv, o, "manifestid", &manifestid, cli_manifestid, "") == -1 + || cli_arg(argc, argv, o, "manifestpath", &manifestpath, NULL, "") == -1 + || cli_arg(argc, argv, o, "filepath", &filepath, NULL, "") == -1 + || cli_arg(argc, argv, o, "pin,pin...", &pins, NULL, "") == -1 + || cli_arg(argc, argv, o, "bsk", &bskhex, cli_optional_bundle_key, NULL) == -1) return -1; + /* Ensure the Rhizome database exists and is open */ if (create_serval_instance_dir() == -1) return -1; - if (!(keyring = keyring_open_with_pins(pins))) - return -1; if (rhizome_opendb() == -1) return -1; + if (!(keyring = keyring_open_with_pins(pins))) + return -1; + + int ret=0; unsigned char manifest_id[RHIZOME_MANIFEST_ID_BYTES]; if (fromhexstr(manifest_id, manifestid, RHIZOME_MANIFEST_ID_BYTES) == -1) @@ -1239,18 +1244,23 @@ int app_rhizome_extract_manifest(int argc, const char *const *argv, const struct char manifestIdUpper[RHIZOME_MANIFEST_ID_STRLEN + 1]; tohex(manifestIdUpper, manifest_id, RHIZOME_MANIFEST_ID_BYTES); + // treat empty string the same as null + if (bskhex && !*bskhex) + bskhex=NULL; + + rhizome_bk_t bsk; + if (bskhex && fromhexstr(bsk.binary, bskhex, RHIZOME_BUNDLE_KEY_BYTES) == -1) + return WHYF("invalid bsk: \"%s\"", bskhex); + rhizome_manifest *m = rhizome_new_manifest(); - if (m == NULL) + if (m==NULL) return WHY("Out of manifests"); - int ret = rhizome_retrieve_manifest(manifestIdUpper, m); + ret = rhizome_retrieve_manifest(manifestIdUpper, m); + if (ret==0){ - if (m->errors){ - // fail if the manifest is invalid? - } - + // ignore errors rhizome_extract_privatekey(m, NULL); - const char *blob_service = rhizome_manifest_get(m, "service", NULL, 0); cli_puts("service"); cli_delim(":"); cli_puts(blob_service); cli_delim("\n"); @@ -1265,13 +1275,23 @@ int app_rhizome_extract_manifest(int argc, const char *const *argv, const struct if (m->fileLength != 0) { cli_puts("filehash"); cli_delim(":"); cli_puts(m->fileHexHash); cli_delim("\n"); } - - if (manifestpath && strcmp(manifestpath, "-") == 0) { + } + + int retfile=0; + + if (ret==0 && m->fileLength != 0 && filepath && *filepath){ + // TODO, this may cause us to search for an author a second time if the above call to rhizome_extract_privatekey failed + retfile = rhizome_extract_file(m, filepath, bskhex?&bsk:NULL); + } + + if (ret==0 && manifestpath && *manifestpath){ + if (strcmp(manifestpath, "-") == 0) { + // always extract a manifest to stdout, even if writing the file itself failed. cli_puts("manifest"); cli_delim(":"); cli_write(m->manifestdata, m->manifest_all_bytes); cli_delim("\n"); - } else if (manifestpath) { + } else { /* If the manifest has been read in from database, the blob is there, and we can lie and say we are finalised and just want to write it out. TODO: really should have a dirty/clean flag, so that write @@ -1279,85 +1299,45 @@ int app_rhizome_extract_manifest(int argc, const char *const *argv, const struct m->finalised=1; if (rhizome_write_manifest_file(m, manifestpath) == -1) ret = -1; + } } } - rhizome_manifest_free(m); + if (retfile) + ret=retfile; + + if (m) + rhizome_manifest_free(m); + return ret; } -int app_rhizome_extract_file(int argc, const char *const *argv, const struct command_line_option *o, void *context) +int app_rhizome_dump_file(int argc, const char *const *argv, const struct command_line_option *o, void *context) { if (config.debug.verbose) DEBUG_argv("command", argc, argv); - const char *fileid, *filepath, *manifestid, *pins, *bskhex; - if (cli_arg(argc, argv, o, "manifestid", &manifestid, cli_manifestid, NULL) == -1 - || cli_arg(argc, argv, o, "filepath", &filepath, NULL, "") == -1 - || cli_arg(argc, argv, o, "fileid", &fileid, cli_fileid, NULL) == -1 - || cli_arg(argc, argv, o, "pin,pin...", &pins, NULL, "") == -1 - || cli_arg(argc, argv, o, "bsk", &bskhex, cli_optional_bundle_key, NULL) == -1) + const char *fileid, *filepath; + if (cli_arg(argc, argv, o, "filepath", &filepath, NULL, "") == -1 + || cli_arg(argc, argv, o, "fileid", &fileid, cli_fileid, NULL) == -1) return -1; - /* Ensure the Rhizome database exists and is open */ if (create_serval_instance_dir() == -1) return -1; if (rhizome_opendb() == -1) return -1; - int ret=0; + if (!rhizome_exists(fileid)) + return 1; - if (manifestid){ - if (!(keyring = keyring_open_with_pins(pins))) - return -1; - - unsigned char manifest_id[RHIZOME_MANIFEST_ID_BYTES]; - if (fromhexstr(manifest_id, manifestid, RHIZOME_MANIFEST_ID_BYTES) == -1) - return WHY("Invalid manifest ID"); - - char manifestIdUpper[RHIZOME_MANIFEST_ID_STRLEN + 1]; - tohex(manifestIdUpper, manifest_id, RHIZOME_MANIFEST_ID_BYTES); - - // treat empty string the same as null - if (bskhex && !*bskhex) - bskhex=NULL; - - rhizome_bk_t bsk; - if (bskhex && fromhexstr(bsk.binary, bskhex, RHIZOME_BUNDLE_KEY_BYTES) == -1) - return WHYF("invalid bsk: \"%s\"", bskhex); - - rhizome_manifest *m = rhizome_new_manifest(); - if (m==NULL) - return WHY("Out of manifests"); - - ret = rhizome_retrieve_manifest(manifestIdUpper, m); - if (ret==0){ - ret = rhizome_extract_file(m, filepath, bskhex?&bsk:NULL); - } - - if (ret==0){ - cli_puts("filehash"); cli_delim(":"); - cli_puts(m->fileHexHash); cli_delim("\n"); - cli_puts("filesize"); cli_delim(":"); - cli_printf("%lld", m->fileLength); cli_delim("\n"); - } - - if (m) - rhizome_manifest_free(m); - - }else if(fileid){ - if (!rhizome_exists(fileid)) - return 1; - int64_t length; - ret = rhizome_dump_file(fileid, filepath, &length); - - if (ret==0){ - cli_puts("filehash"); cli_delim(":"); - cli_puts(fileid); cli_delim("\n"); - cli_puts("filesize"); cli_delim(":"); - cli_printf("%lld", length); cli_delim("\n"); - } - } + int64_t length; + if (rhizome_dump_file(fileid, filepath, &length)) + return -1; - return ret; + cli_puts("filehash"); cli_delim(":"); + cli_puts(fileid); cli_delim("\n"); + cli_puts("filesize"); cli_delim(":"); + cli_printf("%lld", length); cli_delim("\n"); + + return 0; } int app_rhizome_list(int argc, const char *const *argv, const struct command_line_option *o, void *context) @@ -1992,11 +1972,16 @@ struct command_line_option command_line_options[]={ "Import a payload/manifest pair into Rhizome"}, {app_rhizome_list,{"rhizome","list","","[]","[]","[]","[]","[]",NULL},CLIFLAG_STANDALONE, "List all manifests and files in Rhizome"}, - {app_rhizome_extract_manifest,{"rhizome","extract","manifest","","[]","[]",NULL},CLIFLAG_STANDALONE, - "Extract a manifest from Rhizome and write it to the given path"}, - {app_rhizome_extract_file,{"rhizome","extract","file","","[]","[]","[]",NULL},CLIFLAG_STANDALONE, - "Extract a file from Rhizome and write it to the given path"}, - {app_rhizome_extract_file,{"rhizome","dump","file","","[]",NULL},CLIFLAG_STANDALONE, + {app_rhizome_extract_bundle,{"rhizome","extract","bundle", + "","[]","[]","[]","[]",NULL},CLIFLAG_STANDALONE, + "Extract a manifest and decrypted file to the given paths."}, + {app_rhizome_extract_bundle,{"rhizome","extract","manifest", + "","[]","[]",NULL},CLIFLAG_STANDALONE, + "Extract a manifest from Rhizome and write it to the given path"}, + {app_rhizome_extract_bundle,{"rhizome","extract","file", + "","[]","[]","[]",NULL},CLIFLAG_STANDALONE, + "Extract a file from Rhizome and write it to the given path"}, + {app_rhizome_dump_file,{"rhizome","dump","file","","[]",NULL},CLIFLAG_STANDALONE, "Extract a file from Rhizome and write it to the given path without attempting decryption"}, {app_rhizome_direct_sync,{"rhizome","direct","sync","[peer url]",NULL}, CLIFLAG_STANDALONE, diff --git a/tests/rhizomeops b/tests/rhizomeops index 5d6519aa..652e6e1c 100755 --- a/tests/rhizomeops +++ b/tests/rhizomeops @@ -193,6 +193,7 @@ setup_ExtractManifestAfterAdd() { } test_ExtractManifestAfterAdd() { executeOk_servald rhizome extract manifest $manifestid file1x.manifest + tfw_cat --stdout --stderr assertStdoutLineCount '==' 8 local size=$(( $(cat file1 | wc -c) + 0 )) assertStdoutGrep --matches=1 "^service:file$" @@ -203,7 +204,39 @@ test_ExtractManifestAfterAdd() { assertStdoutGrep --matches=1 "^filesize:$size\$" assertStdoutGrep --matches=1 "^\.author:$SIDB1\$" assertStdoutGrep --matches=1 "^\.readonly:0\$" - assert cmp file1.manifest file1x.manifest + assert [ -e file1x.manifest ] + assert diff file1.manifest file1x.manifest +} + +doc_ExtractManifestFileAfterAdd="Extract manifest and file after one add" +setup_ExtractManifestFileAfterAdd() { + setup_servald + setup_rhizome + echo "A test file" >file1 + executeOk_servald rhizome add file $SIDB1 '' file1 file1.manifest + executeOk_servald rhizome list '' + assert_rhizome_list --fromhere=1 --author=$SIDB1 file1 + extract_manifest_id manifestid file1.manifest + extract_manifest_version version file1.manifest + extract_manifest_filehash filehash file1.manifest +} +test_ExtractManifestFileAfterAdd() { + executeOk_servald rhizome extract bundle $manifestid file1x.manifest file1x + tfw_cat --stdout --stderr + assertStdoutLineCount '==' 8 + local size=$(( $(cat file1 | wc -c) + 0 )) + assertStdoutGrep --matches=1 "^service:file$" + assertStdoutGrep --matches=1 "^manifestid:$manifestid\$" + assertStdoutGrep --matches=1 "^version:$version\$" + assertStdoutGrep --matches=1 "^inserttime:$rexp_date\$" + assertStdoutGrep --matches=1 "^filehash:$filehash\$" + assertStdoutGrep --matches=1 "^filesize:$size\$" + assertStdoutGrep --matches=1 "^\.author:$SIDB1\$" + assertStdoutGrep --matches=1 "^\.readonly:0\$" + assert [ -e file1x.manifest ] + assert diff file1.manifest file1x.manifest + assert [ -e file1x ] + assert diff file1 file1x } doc_ExtractManifestToStdout="Extract manifest to output field" @@ -234,7 +267,7 @@ test_ExtractManifestToStdout() { cat file1.manifest >file1n.manifest echo >>file1n.manifest tfw_cat file1n.manifest file1x.manifest - assert cmp file1n.manifest file1x.manifest + assert diff file1n.manifest file1x.manifest } doc_ExtractManifestAfterAddNoAuthor="Extract manifest after one add with no author" @@ -251,7 +284,7 @@ setup_ExtractManifestAfterAddNoAuthor() { } test_ExtractManifestAfterAddNoAuthor() { executeOk_servald rhizome extract manifest $manifestid file1x.manifest - assert cmp file1.manifest file1x.manifest + assert diff file1.manifest file1x.manifest assertStdoutLineCount '==' 7 local size=$(( $(cat file1 | wc -c) + 0 )) assertStdoutGrep --matches=1 "^service:file$" @@ -301,17 +334,24 @@ setup_ExtractFileAfterAdd() { tfw_cat --stderr executeOk_servald rhizome list '' assert_rhizome_list --fromhere=1 --author=$SIDB1 file1 - extract_manifest_id BID file1.manifest + extract_manifest_id manifestid file1.manifest + extract_manifest_version version file1.manifest extract_manifest_filehash filehash file1.manifest } test_ExtractFileAfterAdd() { - executeOk_servald rhizome extract file $BID file1x + executeOk_servald rhizome extract file $manifestid file1x tfw_cat --stderr - assert cmp file1 file1x + assert diff file1 file1x local size=$(( $(cat file1 | wc -c) + 0 )) - assertStdoutLineCount '==' 2 - assertStdoutGrep --matches=1 "^filehash:$filehash$" - assertStdoutGrep --matches=1 "^filesize:$size$" + assertStdoutLineCount '==' 8 + assertStdoutGrep --matches=1 "^service:file$" + assertStdoutGrep --matches=1 "^manifestid:$manifestid\$" + assertStdoutGrep --matches=1 "^version:$version\$" + assertStdoutGrep --matches=1 "^inserttime:$rexp_date\$" + assertStdoutGrep --matches=1 "^filehash:$filehash\$" + assertStdoutGrep --matches=1 "^filesize:$size\$" + assertStdoutGrep --matches=1 "^\.author:$SIDB1\$" + assertStdoutGrep --matches=1 "^\.readonly:0\$" } doc_ExtractFileMissing="Extract non-existent file" @@ -412,7 +452,7 @@ test_AddMismatched() { cp file1.manifest file1_2.manifest execute $servald rhizome add file $SIDB1 '' file1_2 file1_2.manifest assertExitStatus '!=' 0 - assert cmp file1.manifest file1_2.manifest + assert diff file1.manifest file1_2.manifest # And rhizome store should be unchanged. executeOk_servald rhizome list '' assert_rhizome_list --fromhere=1 --author=$SIDB1 file1 file2