diff --git a/java/org/servalproject/servaldna/ServalDCommand.java b/java/org/servalproject/servaldna/ServalDCommand.java index be933ea5..977fca89 100644 --- a/java/org/servalproject/servaldna/ServalDCommand.java +++ b/java/org/servalproject/servaldna/ServalDCommand.java @@ -456,6 +456,13 @@ public class ServalDCommand return result; } + public static ManifestResult rhizomeImportZipBundle(File payloadFile) throws ServalDFailureException { + ManifestResult result = new ManifestResult(); + result.setResult(command(result, "rhizome", "import", "bundle", "--zip-comment", + payloadFile.getAbsolutePath(), payloadFile.getAbsolutePath())); + return result; + } + public static ManifestResult rhizomeExtractBundle(BundleId manifestId, File manifestFile, File payloadFile) throws ServalDFailureException{ ManifestResult result = new ManifestResult(); result.setResult(command(result, "rhizome", "extract", "bundle", @@ -465,6 +472,15 @@ public class ServalDCommand return result; } + public static ManifestResult rhizomeExportZipBundle(BundleId manifestId, File payloadFile) throws ServalDFailureException{ + ManifestResult result = new ManifestResult(); + result.setResult(command(result, "rhizome", "export", "bundle", "--zip-comment", + manifestId.toHex(), + payloadFile.getAbsolutePath(), + payloadFile.getAbsolutePath())); + return result; + } + public static ManifestResult rhizomeExportManifest(BundleId manifestId, File manifestFile) throws ServalDFailureException{ ManifestResult result = new ManifestResult(); result.setResult(command(result, "rhizome", "export", "manifest", diff --git a/rhizome.c b/rhizome.c index 908f7273..6a44e641 100644 --- a/rhizome.c +++ b/rhizome.c @@ -340,87 +340,184 @@ error: * containing the payload. The work is all done by rhizome_bundle_import() and * rhizome_store_manifest(). */ -enum rhizome_bundle_status rhizome_bundle_import_files(rhizome_manifest *m, rhizome_manifest **mout, const char *manifest_path, const char *filepath) +enum rhizome_bundle_status rhizome_bundle_import_files(rhizome_manifest *m, rhizome_manifest **mout, const char *manifest_path, const char *filepath, int zip_comment) { - DEBUGF(rhizome, "(manifest_path=%s, filepath=%s)", + DEBUGF(rhizome, "(manifest_path=%s, filepath=%s, zip_comment=%d)", manifest_path ? alloca_str_toprint(manifest_path) : "NULL", - filepath ? alloca_str_toprint(filepath) : "NULL"); + filepath ? alloca_str_toprint(filepath) : "NULL", + zip_comment); - size_t buffer_len = 0; - int ret = 0; - - // manifest has been appended to the end of the file. - if (strcmp(manifest_path, filepath)==0){ - unsigned char marker[4]; - FILE *f = fopen(filepath, "r"); - - if (f == NULL) - return WHYF_perror("Could not open manifest file %s for reading.", filepath); - if (fseek(f, -sizeof(marker), SEEK_END)) - ret=WHY_perror("Unable to seek to end of file"); - if (ret==0){ - ret = fread(marker, 1, sizeof(marker), f); - if (ret==sizeof(marker)) - ret=0; - else - ret=WHY_perror("Unable to read end of manifest marker"); - } - if (ret==0){ - if (marker[2]!=0x41 || marker[3]!=0x10) - ret=WHYF("Expected 0x4110 marker at end of file"); - } - if (ret==0){ - buffer_len = read_uint16(marker); - if (buffer_len < 1 || buffer_len > MAX_MANIFEST_BYTES) - ret=WHYF("Invalid manifest length %zu", buffer_len); - } - if (ret==0){ - if (fseek(f, -(buffer_len+sizeof(marker)), SEEK_END)) - ret=WHY_perror("Unable to seek to end of file"); - } - if (ret == 0 && fread(m->manifestdata, buffer_len, 1, f) != 1) { - if (ferror(f)) - ret = WHYF("fread(%p,%zu,1,%s) error", m->manifestdata, buffer_len, alloca_str_toprint(filepath)); - else if (feof(f)) - ret = WHYF("fread(%p,%zu,1,%s) hit end of file", m->manifestdata, buffer_len, alloca_str_toprint(filepath)); - } - fclose(f); - } else { - ssize_t size = read_whole_file(manifest_path, m->manifestdata, sizeof m->manifestdata); - if (size == -1) - ret = -1; - buffer_len = (size_t) size; + enum rhizome_bundle_status ret; + int single_file = strcmp(manifest_path, filepath)==0; + + int fd = open(manifest_path, O_RDONLY); + if (fd == -1) + return WHYF_perror("Could not open manifest file %s for reading.", filepath); + + off_t file_len = lseek(fd, 0, SEEK_END); + if (file_len==-1){ + ret=WHY_perror("Unable to determine file length"); + goto end; } - if (ret) - return ret; - m->manifest_all_bytes = buffer_len; + + uint8_t buff[MAX_MANIFEST_BYTES + 22]; + off_t read_len = sizeof buff; + + if (read_len > file_len) + read_len = file_len; + + if (lseek(fd, -read_len, SEEK_END)==-1){ + ret=WHYF_perror("lseek(%d, %d, SEEK_END) - Failed to seek to near the end of %s, len %u", fd, (int)-read_len, manifest_path, (int)file_len); + goto end; + } + + if (read(fd, buff, read_len)!=read_len){ + ret=WHYF_perror("Failed to read %u bytes of the manifest", (int)read_len); + goto end; + } + uint8_t *manifest_ptr; + + // manifest has been appended to the end of the file. + if (single_file){ + if (zip_comment){ + // scan backwards for EOCD marker 0x504b0506 + uint8_t *EOCD = &buff[read_len - 22]; + while(EOCD){ + if (EOCD[0]==0x50 && EOCD[1]==0x4b && EOCD[2]==0x05 && EOCD[3]==0x06) + break; + EOCD--; + } + + if (!EOCD){ + ret=WHY("Expected zip EOCD marker 0x504b0506 near end of file"); + goto end; + } + + m->manifest_all_bytes = EOCD[20] | (EOCD[21]<<8); + manifest_ptr = &EOCD[22]; + + }else{ + if (buff[read_len-2]!=0x41 || buff[read_len-1]!=0x10){ + ret=WHYF("Expected 0x4110 marker at end of file"); + goto end; + } + m->manifest_all_bytes = read_uint16(&buff[read_len-4]); + manifest_ptr = &buff[read_len - m->manifest_all_bytes - 4]; + } + }else{ + manifest_ptr = buff; + m->manifest_all_bytes = read_len; + } + + if (m->manifest_all_bytes < 1 || m->manifest_all_bytes > MAX_MANIFEST_BYTES){ + ret=WHYF("Invalid manifest length %zu", m->manifest_all_bytes); + goto end; + } + if (manifest_ptr < buff || manifest_ptr + m->manifest_all_bytes > buff + read_len){ + ret=WHY("Invalid manifest offset"); + goto end; + } + bcopy(manifest_ptr, m->manifestdata, m->manifest_all_bytes); + if ( rhizome_manifest_parse(m) == -1 || !rhizome_manifest_validate(m) || !rhizome_manifest_verify(m) - ) - return RHIZOME_BUNDLE_STATUS_INVALID; - enum rhizome_bundle_status status = rhizome_manifest_check_stored(m, mout); - if (status != RHIZOME_BUNDLE_STATUS_NEW) - return status; - enum rhizome_payload_status pstatus = rhizome_import_payload_from_file(m, filepath); + ){ + ret = RHIZOME_BUNDLE_STATUS_INVALID; + goto end; + } + + ret = rhizome_manifest_check_stored(m, mout); + if (ret != RHIZOME_BUNDLE_STATUS_NEW) + goto end; + + enum rhizome_payload_status pstatus = RHIZOME_PAYLOAD_STATUS_EMPTY; + if (m->filesize > 0){ + + if (single_file){ + if (lseek(fd, 0, SEEK_SET)==-1){ + ret=WHY_perror("Unable to seek to start of file"); + goto end; + } + }else{ + close(fd); + fd = open(filepath, O_RDONLY); + if (fd==-1) + return WHYF_perror("Could not open payload file %s for reading.", filepath); + } + + /* Import the file, checking the hash as we go */ + struct rhizome_write write; + bzero(&write, sizeof(write)); + + pstatus = rhizome_open_write(&write, &m->filehash, m->filesize); + if (pstatus == RHIZOME_PAYLOAD_STATUS_NEW){ + off_t read_len = m->filesize; + uint8_t payload_buffer[RHIZOME_CRYPT_PAGE_SIZE]; + if (zip_comment) + read_len -=2; + while(write.file_offset < (uint64_t)read_len){ + size_t size = sizeof payload_buffer; + if (write.file_offset + size > (uint64_t)read_len) + size = read_len - write.file_offset; + ssize_t r = read(fd, payload_buffer, size); + if (r == -1) { + ret = WHYF_perror("read(%d,%p,%zu)", fd, payload_buffer, size); + rhizome_fail_write(&write); + goto end; + } + if ((size_t) r != size) { + ret = WHYF("file truncated - read(%d,%p,%zu) returned %zu", fd, payload_buffer, size, (size_t) r); + rhizome_fail_write(&write); + goto end; + } + if (r && rhizome_write_buffer(&write, payload_buffer, (size_t) r)) { + ret = -1; + rhizome_fail_write(&write); + goto end; + } + } + + if (zip_comment){ + uint8_t comment_len[2] = {0,0}; + if (rhizome_write_buffer(&write, comment_len, sizeof comment_len)){ + ret = -1; + rhizome_fail_write(&write); + goto end; + } + } + + pstatus = rhizome_finish_write(&write); + } + + } + switch (pstatus) { case RHIZOME_PAYLOAD_STATUS_EMPTY: case RHIZOME_PAYLOAD_STATUS_STORED: case RHIZOME_PAYLOAD_STATUS_NEW: if (rhizome_store_manifest(m) == -1) - return -1; - return status; + ret = -1; + break; case RHIZOME_PAYLOAD_STATUS_TOO_BIG: case RHIZOME_PAYLOAD_STATUS_EVICTED: - return RHIZOME_BUNDLE_STATUS_NO_ROOM; + ret = RHIZOME_BUNDLE_STATUS_NO_ROOM; + break; case RHIZOME_PAYLOAD_STATUS_ERROR: case RHIZOME_PAYLOAD_STATUS_CRYPTO_FAIL: - return -1; + ret = -1; + break; case RHIZOME_PAYLOAD_STATUS_WRONG_SIZE: case RHIZOME_PAYLOAD_STATUS_WRONG_HASH: - return RHIZOME_BUNDLE_STATUS_INCONSISTENT; + ret = RHIZOME_BUNDLE_STATUS_INCONSISTENT; + break; + default: + FATALF("rhizome_import_payload_from_file() returned status = %d", pstatus); } - FATALF("rhizome_import_payload_from_file() returned status = %d", pstatus); + +end: + close(fd); + return ret; } /* Sets the bundle key "BK" field of a manifest. Returns 1 if the field was set, 0 if not. diff --git a/rhizome.h b/rhizome.h index 9f14d31b..1a108d8f 100644 --- a/rhizome.h +++ b/rhizome.h @@ -501,7 +501,7 @@ struct rhizome_bundle_result rhizome_manifest_add_file(int appending, const char *file_path, unsigned nassignments, const struct rhizome_manifest_field_assignment *assignments); -int rhizome_bundle_import_files(rhizome_manifest *m, rhizome_manifest **m_out, const char *manifest_path, const char *filepath); +int rhizome_bundle_import_files(rhizome_manifest *m, rhizome_manifest **m_out, const char *manifest_path, const char *filepath, int zip_files); int rhizome_manifest_set_name_from_path(rhizome_manifest *m, const char *filepath); struct rhizome_bundle_result rhizome_fill_manifest(rhizome_manifest *m, const char *filepath, const sid_t *authorSidp); @@ -915,7 +915,7 @@ int rhizome_write_buffer(struct rhizome_write *write_state, uint8_t *buffer, siz int rhizome_random_write(struct rhizome_write *write_state, uint64_t offset, uint8_t *buffer, size_t data_size); enum rhizome_payload_status rhizome_write_open_manifest(struct rhizome_write *write, rhizome_manifest *m); enum rhizome_payload_status rhizome_write_open_journal(struct rhizome_write *write, rhizome_manifest *m, uint64_t advance_by, uint64_t append_size); -int rhizome_write_file(struct rhizome_write *write, const char *filename); +int rhizome_write_file(struct rhizome_write *write, const char *filename, off_t offset, uint64_t length); void rhizome_fail_write(struct rhizome_write *write); enum rhizome_payload_status rhizome_finish_write(struct rhizome_write *write); enum rhizome_payload_status rhizome_finish_store(struct rhizome_write *write, rhizome_manifest *m, enum rhizome_payload_status status); diff --git a/rhizome_cli.c b/rhizome_cli.c index b68522a3..aa537602 100644 --- a/rhizome_cli.c +++ b/rhizome_cli.c @@ -17,6 +17,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include #include "cli.h" #include "conf.h" #include "keyring.h" @@ -101,9 +102,59 @@ static int app_rhizome_hash_file(const struct cli_parsed *parsed, struct cli_con return 0; } +static int append_manifest_zip_comment(const char *filepath, rhizome_manifest *m) +{ + int fd = open(filepath, O_RDWR); + if (fd==-1) + return WHYF_perror("open(%s,O_RDWR)", alloca_str_toprint(filepath)); + int ret=0; + uint8_t EOCD[22]; + + if (lseek(fd, -(sizeof EOCD), SEEK_END)==-1){ + ret = WHYF_perror("lseek(%d,%d,SEEK_END)", fd, -(sizeof EOCD)); + goto end; + } + + if (read(fd, EOCD, sizeof EOCD)==-1){ + ret = WHYF_perror("read(%d,%p,%zu)", fd, EOCD, sizeof EOCD); + goto end; + } + + if(EOCD[20] || EOCD[21]){ + ret = WHYF("Expected 0x00 0x00 at end of file, found 0x%02x 0x%02x", EOCD[20], EOCD[21]); + goto end; + } + + if(EOCD[0]!=0x50 || EOCD[1]!=0x4b || EOCD[2]!=0x05 || EOCD[3]!=0x06){ + ret = WHYF("Expected zip EOCD marker 0x504b0506 near end of file"); + goto end; + } + + if (lseek(fd, -2, SEEK_END)==-1){ + ret = WHYF_perror("lseek(%d,-2,SEEK_END)", fd); + goto end; + } + + uint8_t len[2]; + len[0]=m->manifest_all_bytes & 0xFF; + len[1]=(m->manifest_all_bytes >> 8)& 0xFF; + if (write(fd, len, sizeof len)==-1){ + ret = WHYF_perror("write(%d,%p,2)", fd, len); + goto end; + } + if (write(fd, m->manifestdata, m->manifest_all_bytes)==-1){ + ret = WHYF_perror("write(%d,%p,%d)", fd, m->manifestdata, m->manifest_all_bytes); + goto end; + } + +end: + close(fd); + return ret; +} + DEFINE_CMD(app_rhizome_add_file, 0, "Add a file to Rhizome and optionally write its manifest to the given path", - "rhizome","add","file" KEYRING_PIN_OPTIONS,"[--bundle=]","[--force-new]","","","[]","[]","..."); + "rhizome","add","file" KEYRING_PIN_OPTIONS,"[--zip-comment]","[--bundle=]","[--force-new]","","","[]","[]","..."); DEFINE_CMD(app_rhizome_add_file, 0, "Append content to a journal bundle", "rhizome", "journal", "append" KEYRING_PIN_OPTIONS, "", "", "", "[]"); @@ -121,6 +172,7 @@ static int app_rhizome_add_file(const struct cli_parsed *parsed, struct cli_cont cli_arg(parsed, "bundleid", &bundleIdHex, cli_optional_bid, ""); if (cli_arg(parsed, "bsk", &bsktext, cli_optional_bundle_secret_key, NULL) == -1) return -1; + int zip_comment = 0 == cli_arg(parsed, "--zip-comment", NULL, NULL, NULL); sid_t authorSid; if (!authorSidHex || !*authorSidHex) @@ -294,6 +346,10 @@ static int app_rhizome_add_file(const struct cli_parsed *parsed, struct cli_cont case RHIZOME_BUNDLE_STATUS_OLD: assert(mout != NULL); cli_put_manifest(context, mout); + + if (zip_comment) + append_manifest_zip_comment(filepath, mout); + if ( manifestpath && *manifestpath && rhizome_write_manifest_file(mout, manifestpath, 0) == -1 ) @@ -329,20 +385,22 @@ finish: DEFINE_CMD(app_rhizome_import_bundle, 0, "Import a payload/manifest pair into Rhizome", - "rhizome","import","bundle","",""); + "rhizome","import","bundle","[--zip-comment]","",""); static int app_rhizome_import_bundle(const struct cli_parsed *parsed, struct cli_context *context) { DEBUG_cli_parsed(verbose, parsed); const char *filepath, *manifestpath; cli_arg(parsed, "filepath", &filepath, NULL, ""); cli_arg(parsed, "manifestpath", &manifestpath, NULL, ""); + int zip_comment = 0 == cli_arg(parsed, "--zip-comment", NULL, NULL, NULL); + if (rhizome_opendb() == -1) return -1; rhizome_manifest *m = rhizome_new_manifest(); if (!m) return WHY("Out of manifests."); rhizome_manifest *m_out = NULL; - enum rhizome_bundle_status status = rhizome_bundle_import_files(m, &m_out, manifestpath, filepath); + enum rhizome_bundle_status status = rhizome_bundle_import_files(m, &m_out, manifestpath, filepath, zip_comment); switch (status) { case RHIZOME_BUNDLE_STATUS_NEW: cli_put_manifest(context, m); @@ -368,7 +426,7 @@ static int app_rhizome_import_bundle(const struct cli_parsed *parsed, struct cli DEFINE_CMD(app_rhizome_append_manifest, 0, "Append a manifest to the end of the file it belongs to.", - "rhizome", "append", "manifest", "", ""); + "rhizome", "append", "manifest", "[--zip-comment]", "", ""); static int app_rhizome_append_manifest(const struct cli_parsed *parsed, struct cli_context *UNUSED(context)) { DEBUG_cli_parsed(verbose, parsed); @@ -376,6 +434,8 @@ static int app_rhizome_append_manifest(const struct cli_parsed *parsed, struct c if ( cli_arg(parsed, "manifestpath", &manifestpath, NULL, "") == -1 || cli_arg(parsed, "filepath", &filepath, NULL, "") == -1) return -1; + int zip_comment = 0 == cli_arg(parsed, "--zip-comment", NULL, NULL, NULL); + rhizome_manifest *m = rhizome_new_manifest(); if (!m) return WHY("Out of manifests."); @@ -384,8 +444,12 @@ static int app_rhizome_append_manifest(const struct cli_parsed *parsed, struct c && rhizome_manifest_validate(m) && rhizome_manifest_verify(m) ) { - if (rhizome_write_manifest_file(m, filepath, 1) != -1) - ret = 0; + if (zip_comment){ + append_manifest_zip_comment(filepath, m); + }else{ + if (rhizome_write_manifest_file(m, filepath, 1) != -1) + ret = 0; + } } rhizome_manifest_free(m); return ret; @@ -488,7 +552,7 @@ static int app_rhizome_clean(const struct cli_parsed *parsed, struct cli_context DEFINE_CMD(app_rhizome_extract, 0, "Export a manifest and payload file to the given paths, without decrypting.", "rhizome","export","bundle" KEYRING_PIN_OPTIONS, - "","[]","[]"); + "[--zip-comment]","","[]","[]"); DEFINE_CMD(app_rhizome_extract, 0, "Export a manifest from Rhizome and write it to the given path", "rhizome","export","manifest" KEYRING_PIN_OPTIONS, @@ -512,7 +576,8 @@ static int app_rhizome_extract(const struct cli_parsed *parsed, struct cli_conte return -1; int extract = strcasecmp(parsed->args[1], "extract")==0; - + int zip_comment = 0 == cli_arg(parsed, "--zip-comment", NULL, NULL, NULL); + /* Ensure the Rhizome database exists and is open */ if (create_serval_instance_dir() == -1) return -1; @@ -577,13 +642,18 @@ static int app_rhizome_extract(const struct cli_parsed *parsed, struct cli_conte } } + if (ret==0 && zip_comment && pstatus == RHIZOME_PAYLOAD_STATUS_STORED){ + if (append_manifest_zip_comment(filepath, m) == -1) + ret = -1; + } + if (ret==0 && manifestpath && *manifestpath){ if (strcmp(manifestpath, "-") == 0) { // always extract a manifest to stdout, even if writing the file itself failed. cli_field_name(context, "manifest", ":"); cli_write(context, m->manifestdata, m->manifest_all_bytes); cli_delim(context, "\n"); - } else { + } else if (!zip_comment) { int append = (strcmp(manifestpath, filepath)==0)?1:0; // don't write out the manifest if we were asked to append it and writing the file failed. if (!append || (pstatus == RHIZOME_PAYLOAD_STATUS_EMPTY || pstatus == RHIZOME_PAYLOAD_STATUS_STORED)) { diff --git a/rhizome_direct_http.c b/rhizome_direct_http.c index 08dcaaee..d1105cd2 100644 --- a/rhizome_direct_http.c +++ b/rhizome_direct_http.c @@ -127,7 +127,7 @@ static int rhizome_direct_import_end(struct http_request *hr) return 0; } struct rhizome_bundle_result result = INVALID_RHIZOME_BUNDLE_RESULT; - result.status = rhizome_bundle_import_files(m, NULL, manifest_path, payload_path); + result.status = rhizome_bundle_import_files(m, NULL, manifest_path, payload_path, 0); rhizome_manifest_free(m); rhizome_direct_clear_temporary_files(r); http_request_rhizome_bundle_status_response(r, result, NULL); diff --git a/rhizome_store.c b/rhizome_store.c index 8458f11d..ff31141b 100644 --- a/rhizome_store.c +++ b/rhizome_store.c @@ -609,23 +609,29 @@ int rhizome_write_buffer(struct rhizome_write *write_state, uint8_t *buffer, siz /* If file_length is known, then expects file to be at least file_length in size, ignoring anything * longer than that. Returns 0 if successful, -1 if error (logged). */ -int rhizome_write_file(struct rhizome_write *write, const char *filename) +int rhizome_write_file(struct rhizome_write *write, const char *filename, off_t offset, uint64_t length) { int fd = open(filename, O_RDONLY); if (fd == -1) return WHYF_perror("open(%s,O_RDONLY)", alloca_str_toprint(filename)); unsigned char buffer[RHIZOME_CRYPT_PAGE_SIZE]; int ret=0; - while (write->file_length == RHIZOME_SIZE_UNSET || write->file_offset < write->file_length) { + if (offset){ + if (lseek(fd, offset, SEEK_SET)==-1) + return WHYF_perror("lseek(%d,%zu,SEEK_SET)", fd, (unsigned long long)offset); + } + if (length == RHIZOME_SIZE_UNSET || length > write->file_length) + length = write->file_length; + while (length == RHIZOME_SIZE_UNSET || write->file_offset < length) { size_t size = sizeof buffer; - if (write->file_length != RHIZOME_SIZE_UNSET && write->file_offset + size > write->file_length) - size = write->file_length - write->file_offset; + if (length != RHIZOME_SIZE_UNSET && write->file_offset + size > length) + size = length - write->file_offset; ssize_t r = read(fd, buffer, size); if (r == -1) { ret = WHYF_perror("read(%d,%p,%zu)", fd, buffer, size); break; } - if (write->file_length != RHIZOME_SIZE_UNSET && (size_t) r != size) { + if (length != RHIZOME_SIZE_UNSET && (size_t) r != size) { ret = WHYF("file truncated - read(%d,%p,%zu) returned %zu", fd, buffer, size, (size_t) r); break; } @@ -847,7 +853,7 @@ enum rhizome_payload_status rhizome_import_payload_from_file(rhizome_manifest *m return status; // file payload is not in the store yet - if (rhizome_write_file(&write, filepath)){ + if (rhizome_write_file(&write, filepath, 0, RHIZOME_SIZE_UNSET)){ rhizome_fail_write(&write); return RHIZOME_PAYLOAD_STATUS_ERROR; } @@ -971,7 +977,7 @@ enum rhizome_payload_status rhizome_store_payload_file(rhizome_manifest *m, cons } if (!status_ok) FATALF("rhizome_write_open_manifest() returned status = %d", status); - if (rhizome_write_file(&write, filepath) == -1) + if (rhizome_write_file(&write, filepath, 0, RHIZOME_SIZE_UNSET) == -1) status = RHIZOME_PAYLOAD_STATUS_ERROR; else status = rhizome_finish_write(&write); @@ -1382,7 +1388,7 @@ static int write_file(struct rhizome_read *read, const char *filepath){ while((ret=rhizome_read(read, buffer, sizeof(buffer)))>0){ if (fd!=-1){ if (write(fd,buffer,ret)!=ret) { - ret = WHY("Failed to write data to file"); + ret = WHY_perror("Failed to write data to file"); break; } } @@ -1677,7 +1683,7 @@ enum rhizome_payload_status rhizome_append_journal_file(rhizome_manifest *m, uin enum rhizome_payload_status status = rhizome_write_open_journal(&write, m, advance_by, stat.st_size); if (status != RHIZOME_PAYLOAD_STATUS_NEW) return status; - if (stat.st_size != 0 && rhizome_write_file(&write, filename) == -1) + if (stat.st_size != 0 && rhizome_write_file(&write, filename, 0, RHIZOME_SIZE_UNSET) == -1) status = RHIZOME_PAYLOAD_STATUS_ERROR; else status = rhizome_finish_write(&write); diff --git a/tests/rhizomeops b/tests/rhizomeops index 6f071ddd..e89e9f2b 100755 --- a/tests/rhizomeops +++ b/tests/rhizomeops @@ -1431,6 +1431,34 @@ test_ImportCombinedBundle() { assert diff fileA fileAx } +doc_ImportCombinedZipBundle="Create and import combined zip bundle" +setup_ImportCombinedZipBundle() { + # A "combined bundle" is a single file consisting of a payload with its + # manifest appended to the end. + setup_servald + setup_rhizome + echo "Hello from A" >fileA + zip fileA.zip fileA +} +test_ImportCombinedZipBundle() { + # Create the combined bundle + executeOk_servald rhizome add file --zip-comment $SIDA fileA.zip fileA.manifest + extract_manifest_id manifestid fileA.manifest + extract_manifest_filehash filehash fileA.manifest + extract_manifest_filesize filesize fileA.manifest + # Import the combined bundle + set_instance +B + executeOk_servald rhizome import bundle --zip-comment fileA.zip fileA.zip + assertStdoutGrep --matches=1 "^service:file$" + assertStdoutGrep --matches=1 "^manifestid:$manifestid\$" + assertStdoutGrep --matches=1 "^filehash:$filehash\$" + assertStdoutGrep --matches=1 "^filesize:$filesize\$" + executeOk_servald rhizome list + assert_rhizome_list --fromhere=0 fileA.zip + executeOk_servald rhizome export bundle --zip-comment $manifestid fileAx.zip fileAx.zip + assert diff fileA.zip fileAx.zip +} + doc_ImportJournal="Import a journal bundle" setup_ImportJournal() { B_IDENTITY_COUNT=1