Add "rhizome extract manifest" command

This commit is contained in:
Andrew Bettison 2012-05-02 16:03:09 +09:30
parent c9e429e36b
commit 146eb7cdfd
6 changed files with 171 additions and 6 deletions

View File

@ -1024,6 +1024,48 @@ int app_rhizome_add_file(int argc, const char *const *argv, struct command_line_
return ret;
}
int cli_manifestid(const char *arg)
{
return rhizome_str_is_manifest_id(arg);
}
int app_rhizome_extract_manifest(int argc, const char *const *argv, struct command_line_option *o)
{
const char *manifestid, *manifestpath;
cli_arg(argc, argv, o, "manifestid", &manifestid, cli_manifestid, NULL);
cli_arg(argc, argv, o, "manifestpath", &manifestpath, NULL, "");
/* Ensure the Rhizome database exists and is open */
if (create_serval_instance_dir() == -1)
return -1;
rhizome_datastore_path = serval_instancepath();
rhizome_opendb();
/* Extract the manifest from the database */
rhizome_manifest *m = NULL;
int ret = -1;
switch (rhizome_retrieve_manifest(manifestid, &m)) {
case 0:
ret = 0;
break;
case 1:
ret = 0;
if (manifestpath[0]) {
if (rhizome_manifest_finalise(m, 1) == -1)
ret = WHY("Could not overwrite manifest file.");
else if (rhizome_write_manifest_file(m, manifestpath) == -1)
ret = WHY("Could not overwrite manifest file.");
}
break;
}
if (m)
rhizome_manifest_free(m);
return ret;
}
int app_rhizome_extract_file(int argc, const char *const *argv, struct command_line_option *o)
{
return WHY("Not implemented");
}
int cli_uint(const char *arg)
{
register const char *s = arg;
@ -1328,6 +1370,10 @@ command_line_option command_line_options[]={
"Add a file to Rhizome and optionally write its manifest to the given path"},
{app_rhizome_list,{"rhizome","list","[<offset>]","[<limit>]",NULL},CLIFLAG_STANDALONE,
"List all manifests and files in Rhizome"},
{app_rhizome_extract_manifest,{"rhizome","extract","manifest","<manifestid>","<manifestpath>",NULL},CLIFLAG_STANDALONE,
"Extract a manifest from Rhizome and write it to the given path"},
{app_rhizome_extract_file,{"rhizome","extract","file","<fileid>","<filepath>",NULL},CLIFLAG_STANDALONE,
"Extract a file from Rhizome and write it to the given path"},
{app_keyring_create,{"keyring","create",NULL},0,
"Create a new keyring file."},
{app_keyring_list,{"keyring","list","[<pin,pin ...>]",NULL},CLIFLAG_STANDALONE,

View File

@ -303,7 +303,7 @@ int chartonybl(int c)
return 0;
}
int rhizome_hex_to_bytes(char *in,unsigned char *out,int hexChars)
int rhizome_hex_to_bytes(const char *in,unsigned char *out,int hexChars)
{
int i;

View File

@ -160,6 +160,8 @@ extern sqlite3 *rhizome_db;
int rhizome_opendb();
int rhizome_manifest_createid(rhizome_manifest *m);
int rhizome_strn_is_manifest_id(const char *id);
int rhizome_str_is_manifest_id(const char *id);
int rhizome_write_manifest_file(rhizome_manifest *m, const char *filename);
int rhizome_manifest_sign(rhizome_manifest *m);
int rhizome_drop_stored_file(char *id,int maximum_priority);
@ -190,7 +192,7 @@ int rhizome_add_manifest(rhizome_manifest *m_in, rhizome_manifest **m_out, const
int verifyP, int checkFileP, int signP);
int rhizome_manifest_finalise(rhizome_manifest *m,int signP);
char *rhizome_bytes_to_hex(unsigned char *in,int byteCount);
int rhizome_hex_to_bytes(char *in,unsigned char *out,int hexChars);
int rhizome_hex_to_bytes(const char *in,unsigned char *out,int hexChars);
int rhizome_store_keypair_bytes(unsigned char *p,unsigned char *s);
int rhizome_find_keypair_bytes(unsigned char *p,unsigned char *s);
rhizome_signature *rhizome_sign_hash(unsigned char *hash,unsigned char *publicKeyBytes);
@ -214,6 +216,7 @@ int rhizome_manifest_to_bar(rhizome_manifest *m,unsigned char *bar);
char nybltochar(int n);
int rhizome_queue_manifest_import(rhizome_manifest *m,struct sockaddr_in *peerip);
int rhizome_list_manifests(int limit, int offset);
int rhizome_retrieve_manifest(const char *id, rhizome_manifest **mp);
#define RHIZOME_DONTVERIFY 0
#define RHIZOME_VERIFY 1

View File

@ -20,6 +20,22 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "serval.h"
#include "rhizome.h"
#include <stdlib.h>
#include <ctype.h>
int rhizome_strn_is_manifest_id(const char *id)
{
int i;
for (i = 0; i != crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES * 2; ++i)
if (!isxdigit(id[i]))
return 0;
return 1;
}
int rhizome_str_is_manifest_id(const char *id)
{
size_t len = strlen(id);
return len == crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES * 2 && rhizome_strn_is_manifest_id(id);
}
int rhizome_manifest_createid(rhizome_manifest *m)
{

View File

@ -840,3 +840,80 @@ int rhizome_find_duplicate(const rhizome_manifest *m, rhizome_manifest **found)
sqlite3_finalize(statement);
return ret;
}
/* Retrieve a manifest from the database, given its manifest ID.
Returns 1 if manifest is found (new manifest is allocated and assigned to *m, caller is
responsible for freeing).
Returns 0 if manifest is not found (*m is unchanged).
Returns -1 on error (*m is unchanged).
*/
int rhizome_retrieve_manifest(const char *id, rhizome_manifest **mp)
{
char sqlcmd[1024];
int n = snprintf(sqlcmd, sizeof(sqlcmd), "SELECT id, manifest, version, inserttime FROM manifests WHERE id = ?");
if (n >= sizeof(sqlcmd))
return WHY("SQL command too long");
sqlite3_stmt *statement;
const char *cmdtail;
int ret = 0;
rhizome_manifest *m = NULL;
if (sqlite3_prepare_v2(rhizome_db, sqlcmd, strlen(sqlcmd) + 1, &statement, &cmdtail) != SQLITE_OK) {
sqlite3_finalize(statement);
ret = WHY(sqlite3_errmsg(rhizome_db));
} else {
sqlite3_bind_text(statement, 1, id, crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES * 2, SQLITE_STATIC);
while (sqlite3_step(statement) == SQLITE_ROW) {
if (!( sqlite3_column_count(statement) == 4
&& sqlite3_column_type(statement, 0) == SQLITE_TEXT
&& sqlite3_column_type(statement, 1) == SQLITE_BLOB
&& sqlite3_column_type(statement, 2) == SQLITE_INTEGER
&& sqlite3_column_type(statement, 3) == SQLITE_INTEGER
)) {
ret = WHY("Incorrect statement column");
break;
}
const char *manifestblob = (char *) sqlite3_column_blob(statement, 1);
size_t manifestblobsize = sqlite3_column_bytes(statement, 1); // must call after sqlite3_column_blob()
m = rhizome_read_manifest_file(manifestblob, manifestblobsize, 0);
if (m == NULL) {
ret = WHY("Invalid manifest blob from database");
} else {
rhizome_hex_to_bytes(id, m->cryptoSignPublic, crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES*2);
const char *filehashq = rhizome_manifest_get(m, "filehash", NULL, 0);
if (filehashq == NULL)
ret = WHY("Manifest is missing filehash line");
else {
memcpy(m->fileHexHash, filehashq, SHA512_DIGEST_STRING_LENGTH);
m->fileHashedP = 1;
}
long long versionq = rhizome_manifest_get_ll(m, "version");
if (versionq == -1)
ret = WHY("Manifest is missing version line");
else
m->version = versionq;
long long lengthq = rhizome_manifest_get_ll(m, "filesize");
if (lengthq == -1)
ret = WHY("Manifest is missing filesize line");
else
m->fileLength = lengthq;
cli_puts("manifestid"); cli_delim(":");
cli_puts((const char *)sqlite3_column_text(statement, 0)); cli_delim("\n");
cli_puts("version"); cli_delim(":");
cli_printf("%lld", (long long) sqlite3_column_int64(statement, 2)); cli_delim("\n");
cli_puts("inserttime"); cli_delim(":");
cli_printf("%lld", (long long) sqlite3_column_int64(statement, 3)); cli_delim("\n");
// Could write the manifest blob to the CLI output here, but that would require the output to
// support byte[] fields as well as String fields.
ret = 1;
}
break;
}
}
sqlite3_finalize(statement);
if (ret > 0)
*mp = m;
return ret;
}

View File

@ -34,15 +34,17 @@ assert_rhizome_list() {
local filename
for filename; do
local filehash='[^:]\+'
local manifestid='[^:]\+'
# If there is a manifest file that looks like it matches this payload
# file, then use its file hash to check the rhizome list output.
if [ -r "$filename.manifest" ]; then
local name=$(sed -n -e '/^name=/s///p' "$filename.manifest")
if [ "$name" == "$filename" ]; then
filehash=$(sed -n -e '/^filehash=/s///p' "$filename.manifest")
manifestid=$(sed -n -e '/^id=/s///p' "$filename.manifest")
fi
fi
assertStdoutGrep --matches=1 "^$filehash:.*:$filename\$"
assertStdoutGrep --matches=1 "^$filehash:$manifestid:.*:$filename\$"
done
}
@ -65,6 +67,14 @@ strip_signatures() {
done
}
extract_manifest_id() {
local _var="$1"
local _manifestfile="$2"
local _id=$(sed -n -e '/^id=[0-9a-fA-F]\{64\}$/s/^id=//p' "$_manifestfile")
assert --message="$_manifestfile contains valid 'id=' line" [ -n "$_id" ]
[ -n "$_var" ] && eval $_var=$_id
}
extract_manifest_version() {
local _var="$1"
local _manifestfile="$2"
@ -116,7 +126,7 @@ test_AddNonExistManifest() {
assertGrep file1.manifest '^name=file1$'
assertGrep file1.manifest '^date=[0-9]\+$'
assertGrep file1.manifest '^version=[0-9]\+$'
assertGrep file1.manifest '^id=[0-9a-fA-F]\+$'
assertGrep file1.manifest '^id=[0-9a-fA-F]\{64\}$'
assertGrep file1.manifest "^filesize=$size\$"
assertGrep file1.manifest "^first_byte=0$"
assertGrep file1.manifest "^last_byte=$size\$"
@ -136,10 +146,10 @@ test_AddManifest() {
tfw_cat --stderr
tfw_cat -v file1.manifest
local size=$(( $(cat file1 | wc -c) + 0 ))
assertGrep file1.manifest '^id=[0-9a-fA-F]\{64\}$'
assertGrep file1.manifest '^name=wah$'
assertGrep file1.manifest '^date=12345$'
assertGrep file1.manifest '^version=[0-9]\+$'
assertGrep file1.manifest '^id=[0-9a-fA-F]\+$'
assertGrep file1.manifest '^date=12345$'
assertGrep file1.manifest "^filesize=$size\$"
assertGrep file1.manifest "^first_byte=0$"
assertGrep file1.manifest "^last_byte=$size\$"
@ -161,6 +171,19 @@ test_AddThenList() {
assert_rhizome_list file1 file2
}
doc_ExtractManifest="Extract manifest after one add"
setup_ExtractManifest() {
setup_dna_rhizome
echo "A test file" >file1
executeOk $dna rhizome add file file1 file1.manifest
assert_rhizome_list file1
extract_manifest_id manifestid file1.manifest
}
test_ExtractManifest() {
executeOk $dna rhizome extract manifest $manifestid file1x.manifest
assert cmp file1.manifest file1x.manifest
}
doc_AddDuplicate="Add same manifest detects duplicate"
setup_AddDuplicate() {
setup_dna_rhizome