Importing the same bundle twice returns duplicate flag

This commit is contained in:
Jeremy Lakeman 2013-01-15 10:32:48 +10:30
parent 2d66a150b8
commit b25ff45438
7 changed files with 113 additions and 101 deletions

View File

@ -1098,21 +1098,29 @@ int app_rhizome_add_file(int argc, const char *const *argv, const struct command
if (config.debug.rhizome) DEBUGF("manifest file %s does not exist -- creating new manifest", manifestpath);
}
if (rhizome_stat_file(m, filepath))
if (rhizome_stat_file(m, filepath)){
rhizome_manifest_free(m);
return -1;
}
if (rhizome_fill_manifest(m, filepath, *authorSidHex?&authorSid:NULL, bskhex?&bsk:NULL))
if (rhizome_fill_manifest(m, filepath, *authorSidHex?&authorSid:NULL, bskhex?&bsk:NULL)){
rhizome_manifest_free(m);
return -1;
}
if (m->fileLength){
if (rhizome_add_file(m, filepath))
if (rhizome_add_file(m, filepath)){
rhizome_manifest_free(m);
return -1;
}
}
rhizome_manifest *mout = NULL;
int ret=rhizome_manifest_finalise(m,&mout);
if (ret<0)
if (ret<0){
rhizome_manifest_free(m);
return -1;
}
if (manifestpath[0]
&& rhizome_write_manifest_file(mout, manifestpath, 0) == -1)

View File

@ -141,18 +141,11 @@ int rhizome_bundle_import_files(rhizome_manifest *m, const char *manifest_path,
if (status<0)
return status;
status = rhizome_manifest_check_duplicate(m, NULL);
if (status<0)
status = rhizome_manifest_check_duplicate(m, NULL, 0);
if (status)
return status;
if (status==0){
if (rhizome_add_manifest(m, 1) == -1) { // ttl = 1
return WHY("rhizome_add_manifest() failed");
}
}else
INFO("Duplicate found in store");
return status;
return rhizome_add_manifest(m, 1);
}
/* Import a bundle from a finalised manifest struct. The dataFileName element must give the path
@ -165,7 +158,7 @@ int rhizome_bundle_import(rhizome_manifest *m, int ttl)
{
if (config.debug.rhizome)
DEBUGF("(m=%p, ttl=%d)", m, ttl);
int ret = rhizome_manifest_check_duplicate(m, NULL);
int ret = rhizome_manifest_check_duplicate(m, NULL, 0);
if (ret == 0) {
ret = rhizome_add_manifest(m, ttl);
if (ret == -1)
@ -185,6 +178,12 @@ int rhizome_manifest_check_sanity(rhizome_manifest *m_in)
return WHY("Manifest missing 'service' field");
if (rhizome_manifest_get_ll(m_in, "date") == -1)
return WHY("Manifest missing 'date' field");
/* Get manifest version number. */
m_in->version = rhizome_manifest_get_ll(m_in, "version");
if (m_in->version==-1)
return WHY("Manifest must have a version number");
if (strcasecmp(service, RHIZOME_SERVICE_FILE) == 0) {
const char *name = rhizome_manifest_get(m_in, "name", NULL, 0);
if (name == NULL)
@ -259,17 +258,12 @@ int rhizome_manifest_bind_id(rhizome_manifest *m_in)
/* Check if a manifest is already stored for the same payload with the same details.
This catches the case of "rhizome add file <filename>" on the same file more than once.
(Debounce!) */
int rhizome_manifest_check_duplicate(rhizome_manifest *m_in, rhizome_manifest **m_out)
int rhizome_manifest_check_duplicate(rhizome_manifest *m_in, rhizome_manifest **m_out, int check_author)
{
// if a manifest was supplied with an ID, don't bother to check for a duplicate.
// we only want to filter out added files with no existing manifest.
if (m_in->haveSecret!=NEW_BUNDLE_ID)
return 0;
if (config.debug.rhizome) DEBUG("Checking for duplicate");
if (m_out) *m_out = NULL;
rhizome_manifest *dupm = NULL;
if (rhizome_find_duplicate(m_in, &dupm) == -1)
if (rhizome_find_duplicate(m_in, &dupm, check_author) == -1)
return WHY("Errors encountered searching for duplicate manifest");
if (dupm) {
/* If the caller wants the duplicate manifest, it must be finalised, otherwise discarded. */
@ -297,21 +291,19 @@ int rhizome_add_manifest(rhizome_manifest *m_in,int ttl)
m_in->ttl = ttl < 0 ? 0 : ttl > 254 ? 254 : ttl;
if (rhizome_manifest_check_sanity(m_in))
return WHY("Sanity checks on manifest failed");
return -1;
if (m_in->fileLength){
if (!rhizome_exists(m_in->fileHexHash))
return WHY("File has not been imported");
}
/* Get manifest version number. */
m_in->version = rhizome_manifest_get_ll(m_in, "version");
if (m_in->version==-1)
return WHY("Manifest must have a version number");
/* If the manifest already has an ID */
char id[SID_STRLEN + 1];
if (rhizome_manifest_get(m_in, "id", id, SID_STRLEN + 1)) {
if (!rhizome_manifest_get(m_in, "id", id, SID_STRLEN + 1))
/* no manifest ID */
return WHY("Manifest does not have an ID");
str_toupper_inplace(id);
/* Discard the new manifest unless it is newer than the most recent known version with the same ID */
long long storedversion = -1;
@ -331,24 +323,9 @@ int rhizome_add_manifest(rhizome_manifest *m_in,int ttl)
default:
return WHY("Select found too many rows!");
}
} else {
/* no manifest ID */
return WHY("Manifest does not have an ID");
}
/* Okay, it is written, and can be put directly into the rhizome database now */
if (rhizome_store_bundle(m_in) == -1)
return WHY("rhizome_store_bundle() failed.");
// This message used in tests; do not modify or remove.
const char *service = rhizome_manifest_get(m_in, "service", NULL, 0);
INFOF("RHIZOME ADD MANIFEST service=%s bid=%s version=%lld",
service ? service : "NULL",
alloca_tohex_sid(m_in->cryptoSignPublic),
m_in->version
);
monitor_announce_bundle(m_in);
return 0;
return rhizome_store_bundle(m_in);
}
/* Update an existing Rhizome bundle */

View File

@ -252,7 +252,7 @@ int rhizome_fill_manifest(rhizome_manifest *m, const char *filepath, const sid_t
int rhizome_manifest_verify(rhizome_manifest *m);
int rhizome_manifest_check_sanity(rhizome_manifest *m_in);
int rhizome_manifest_check_duplicate(rhizome_manifest *m_in,rhizome_manifest **m_out);
int rhizome_manifest_check_duplicate(rhizome_manifest *m_in,rhizome_manifest **m_out, int check_author);
int rhizome_manifest_bind_id(rhizome_manifest *m_in);
int rhizome_manifest_finalise(rhizome_manifest *m, rhizome_manifest **mout);
@ -304,7 +304,7 @@ int _sqlite_exec_strbuf(struct __sourceloc, strbuf sb, const char *sqlformat,...
double rhizome_manifest_get_double(rhizome_manifest *m,char *var,double default_value);
int rhizome_manifest_extract_signature(rhizome_manifest *m,int *ofs);
int rhizome_update_file_priority(const char *fileid);
int rhizome_find_duplicate(const rhizome_manifest *m, rhizome_manifest **found);
int rhizome_find_duplicate(const rhizome_manifest *m, rhizome_manifest **found, int check_author);
int rhizome_manifest_to_bar(rhizome_manifest *m,unsigned char *bar);
long long rhizome_bar_version(unsigned char *bar);
unsigned long long rhizome_bar_bidprefix_ll(unsigned char *bar);

View File

@ -638,11 +638,16 @@ int rhizome_manifest_finalise(rhizome_manifest *m, rhizome_manifest **mout)
IN();
int ret=0;
if (rhizome_manifest_check_duplicate(m, mout) == 2) {
// if a manifest was supplied with an ID, don't bother to check for a duplicate.
// we only want to filter out added files with no existing manifest.
if (m->haveSecret==NEW_BUNDLE_ID){
if (rhizome_manifest_check_duplicate(m, mout, 1) == 2) {
/* duplicate found -- verify it so that we can write it out later */
rhizome_manifest_verify(*mout);
ret=2;
} else {
RETURN(2);
}
}
*mout=m;
/* Convert to final form for signing and writing to disk */
@ -655,11 +660,7 @@ int rhizome_manifest_finalise(rhizome_manifest *m, rhizome_manifest **mout)
/* mark manifest as finalised */
m->finalised=1;
if (rhizome_add_manifest(m, 255 /* TTL */)) {
rhizome_manifest_free(m);
RETURN(WHY("Manifest not added to Rhizome database"));
}
}
ret=rhizome_add_manifest(m, 255 /* TTL */);
RETURN(ret);
}

View File

@ -855,8 +855,17 @@ int rhizome_store_bundle(rhizome_manifest *m)
sqlite3_finalize(stmt);
stmt = NULL;
}
if (sqlite_exec_void_retry(&retry, "COMMIT;") == SQLITE_OK)
if (sqlite_exec_void_retry(&retry, "COMMIT;") == SQLITE_OK){
// This message used in tests; do not modify or remove.
const char *service = rhizome_manifest_get(m, "service", NULL, 0);
INFOF("RHIZOME ADD MANIFEST service=%s bid=%s version=%lld",
service ? service : "NULL",
alloca_tohex_sid(m->cryptoSignPublic),
m->version
);
monitor_announce_bundle(m);
return 0;
}
rollback:
if (stmt)
sqlite3_finalize(stmt);
@ -1066,7 +1075,7 @@ int rhizome_update_file_priority(const char *fileid)
@author Andrew Bettison <andrew@servalproject.com>
*/
int rhizome_find_duplicate(const rhizome_manifest *m, rhizome_manifest **found)
int rhizome_find_duplicate(const rhizome_manifest *m, rhizome_manifest **found, int check_author)
{
// TODO, add service, name, sender & recipient to manifests table so we can simply query them.
@ -1202,29 +1211,34 @@ int rhizome_find_duplicate(const rhizome_manifest *m, rhizome_manifest **found)
if (blob_name && !strcmp(blob_name, name)) {
if (config.debug.rhizome)
strbuf_sprintf(b, " name=\"%s\"", blob_name);
ret = 1;
}
}else
++inconsistent;
} else if (strcasecmp(service, RHIZOME_SERVICE_MESHMS) == 0) {
const char *blob_sender = rhizome_manifest_get(blob_m, "sender", NULL, 0);
const char *blob_recipient = rhizome_manifest_get(blob_m, "recipient", NULL, 0);
if (blob_sender && !strcasecmp(blob_sender, sender) && blob_recipient && !strcasecmp(blob_recipient, recipient)) {
if (config.debug.rhizome)
strbuf_sprintf(b, " sender=%s recipient=%s", blob_sender, blob_recipient);
ret = 1;
}else
++inconsistent;
}
}
if (ret == 1) {
if ((!inconsistent) && check_author) {
// check that we can re-author this manifest
if (rhizome_extract_privatekey(blob_m, NULL)==0){
if (rhizome_extract_privatekey(blob_m, NULL))
++inconsistent;
}
if (!inconsistent) {
*found = blob_m;
DEBUGF("Found duplicate payload: service=%s%s version=%llu hexhash=%s",
blob_service, strbuf_str(b), blob_m->version, blob_m->fileHexHash, q_author ? q_author : ""
);
ret = 1;
break;
}
}
}
}
if (blob_m)
rhizome_manifest_free(blob_m);
}

View File

@ -309,6 +309,8 @@ int rhizome_import_file(rhizome_manifest *m, const char *filepath)
int rhizome_stat_file(rhizome_manifest *m, const char *filepath)
{
long long existing = rhizome_manifest_get_ll(m, "filesize");
m->fileLength = 0;
if (filepath[0]) {
struct stat stat;
@ -317,6 +319,14 @@ int rhizome_stat_file(rhizome_manifest *m, const char *filepath)
m->fileLength = stat.st_size;
}
// fail if the file is shorter than specified by the manifest
if (existing > m->fileLength)
return WHY("Manifest length is longer than the file");
// if the file is longer than specified by the manifest, ignore the end.
if (existing!=-1 && existing < m->fileLength)
m->fileLength = existing;
rhizome_manifest_set_ll(m, "filesize", m->fileLength);
if (m->fileLength == 0){

View File

@ -762,6 +762,8 @@ setup_ImportForeignBundle() {
test_ImportForeignBundle() {
executeOk_servald rhizome import bundle fileA fileA.manifest
assert_stdout_import_bundle fileA
execute --exit-status=2 --stdout --stderr $servald rhizome import bundle fileA fileA.manifest
assert_stdout_import_bundle fileA
executeOk_servald rhizome list ''
assert_rhizome_list --fromhere=0 fileA
}