]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Copy ae digests to mtree_entry
authorNicholas Vinson <nvinson234@gmail.com>
Sun, 13 Apr 2025 11:33:43 +0000 (07:33 -0400)
committerNicholas Vinson <nvinson234@gmail.com>
Sat, 17 May 2025 15:33:15 +0000 (11:33 -0400)
    Copy ae digests to mtree_entry. This simplifies porting non-archive
    formats to archive formats while preserving supported message
    digests specifically in cases where recomputing digests is not
    viable.

Signed-off-by: Nicholas Vinson <nvinson234@gmail.com>
Makefile.am
libarchive/archive_entry.c
libarchive/archive_entry_private.h
libarchive/archive_write_set_format_mtree.c
libarchive/test/CMakeLists.txt
libarchive/test/test_write_format_mtree_preset_digests.c [new file with mode: 0644]

index 4e17ab2e280b130df58db6f660965d9190ec178c..74cb6e14b6092e58bba75b2bfffd2817761c71ef 100644 (file)
@@ -633,6 +633,7 @@ libarchive_test_SOURCES= \
        libarchive/test/test_write_format_mtree_classic_indent.c\
        libarchive/test/test_write_format_mtree_fflags.c \
        libarchive/test/test_write_format_mtree_no_separator.c \
+       libarchive/test/test_write_format_mtree_preset_digests.c \
        libarchive/test/test_write_format_mtree_quoted_filename.c\
        libarchive/test/test_write_format_pax.c \
        libarchive/test/test_write_format_raw.c \
index c727b9cd85f34d0bacd7ef3079660521e0225465..7e7d518704713c91bfaea17edbe297e57439906a 100644 (file)
@@ -1607,21 +1607,27 @@ archive_entry_set_digest(struct archive_entry *entry, int type,
        switch (type) {
        case ARCHIVE_ENTRY_DIGEST_MD5:
                copy_digest(entry, md5, digest);
+               entry->mset_digest.md5 = 1;
                break;
        case ARCHIVE_ENTRY_DIGEST_RMD160:
                copy_digest(entry, rmd160, digest);
+               entry->mset_digest.rmd160 = 1;
                break;
        case ARCHIVE_ENTRY_DIGEST_SHA1:
                copy_digest(entry, sha1, digest);
+               entry->mset_digest.sha1 = 1;
                break;
        case ARCHIVE_ENTRY_DIGEST_SHA256:
                copy_digest(entry, sha256, digest);
+               entry->mset_digest.sha256 = 1;
                break;
        case ARCHIVE_ENTRY_DIGEST_SHA384:
                copy_digest(entry, sha384, digest);
+               entry->mset_digest.sha384 = 1;
                break;
        case ARCHIVE_ENTRY_DIGEST_SHA512:
                copy_digest(entry, sha512, digest);
+               entry->mset_digest.sha512 = 1;
                break;
        default:
                return ARCHIVE_WARN;
index 0eba648d27f38af848aafff97cf1f0dcc4ea7939..2af7b2b8c9de9166aef222819f1d1409ea49f515 100644 (file)
@@ -48,6 +48,15 @@ struct ae_sparse {
        int64_t  length;
 };
 
+struct ae_mset_digest {
+       char md5;
+       char rmd160;
+       char sha1;
+       char sha256;
+       char sha384;
+       char sha512;
+};
+
 struct ae_digest {
        unsigned char md5[16];
        unsigned char rmd160[20];
@@ -174,6 +183,7 @@ struct archive_entry {
        size_t mac_metadata_size;
 
        /* Digest support. */
+       struct ae_mset_digest mset_digest;
        struct ae_digest digest;
 
        /* ACL support. */
index 14d68516fba68b47c37cd03839dea4e3a476c1da..b2767bfec020bd0400c2469ffcef9ee86190be84 100644 (file)
@@ -82,6 +82,7 @@ struct dir_info {
 struct reg_info {
        int compute_sum;
        uint32_t crc;
+       struct ae_mset_digest mset_digest;
        struct ae_digest digest;
 };
 
@@ -862,6 +863,40 @@ mtree_entry_free(struct mtree_entry *me)
        free(me);
 }
 
+static void
+mtree_copy_ae_digests(struct reg_info *reg, struct archive_entry *entry, int compute_sum)
+{
+       reg->compute_sum = compute_sum;
+       if ((reg->compute_sum & F_MD5) && entry->mset_digest.md5) {
+               memcpy(&reg->digest.md5, entry->digest.md5, sizeof(reg->digest.md5));
+                reg->mset_digest.md5 = entry->mset_digest.md5;
+       }
+       if (reg->compute_sum & F_RMD160 && entry->mset_digest.rmd160) {
+               memcpy(&reg->digest.rmd160, entry->digest.rmd160,
+                       sizeof(reg->digest.rmd160));
+                reg->mset_digest.rmd160 = entry->mset_digest.rmd160;
+       }
+       if (reg->compute_sum & F_SHA1 && entry->mset_digest.sha1) {
+               memcpy(&reg->digest.sha1, entry->digest.sha1, sizeof(reg->digest.sha1));
+                reg->mset_digest.sha1 = entry->mset_digest.sha1;
+       }
+       if (reg->compute_sum & F_SHA256 && entry->mset_digest.sha256) {
+               memcpy(&reg->digest.sha256, entry->digest.sha256,
+                       sizeof(reg->digest.sha256));
+                reg->mset_digest.sha256 = entry->mset_digest.sha256;
+       }
+       if (reg->compute_sum & F_SHA384 && entry->mset_digest.sha384) {
+               memcpy(&reg->digest.sha384, entry->digest.sha384,
+                       sizeof(reg->digest.sha384));
+                reg->mset_digest.sha384 = entry->mset_digest.sha384;
+       }
+       if (reg->compute_sum & F_SHA512 && entry->mset_digest.sha512) {
+               memcpy(&reg->digest.sha512, entry->digest.sha512,
+                       sizeof(reg->digest.sha512));
+                reg->mset_digest.sha512 = entry->mset_digest.sha512;
+       }
+}
+
 static int
 archive_write_mtree_header(struct archive_write *a,
     struct archive_entry *entry)
@@ -896,8 +931,12 @@ archive_write_mtree_header(struct archive_write *a,
        /* If the current file is a regular file, we have to
         * compute the sum of its content.
         * Initialize a bunch of checksum context. */
-       if (mtree_entry->reg_info)
+       if (mtree_entry->reg_info) {
                sum_init(mtree);
+               /* honor archive_entry_set_digest() calls. These values will be
+                * overwritten if archive_write_mtree_data() is called */
+               mtree_copy_ae_digests(mtree_entry->reg_info, entry, mtree->compute_sum);
+       }
 
        return (r2);
 }
@@ -1516,28 +1555,40 @@ sum_update(struct mtree_writer *mtree, const void *buff, size_t n)
                mtree->crc_len += n;
        }
 #ifdef ARCHIVE_HAS_MD5
-       if (mtree->compute_sum & F_MD5)
+       if (mtree->compute_sum & F_MD5) {
                archive_md5_update(&mtree->md5ctx, buff, n);
+               mtree->mtree_entry->reg_info->mset_digest.md5 = 0;
+       }
 #endif
 #ifdef ARCHIVE_HAS_RMD160
-       if (mtree->compute_sum & F_RMD160)
+       if (mtree->compute_sum & F_RMD160) {
                archive_rmd160_update(&mtree->rmd160ctx, buff, n);
+               mtree->mtree_entry->reg_info->mset_digest.rmd160 = 0;
+       }
 #endif
 #ifdef ARCHIVE_HAS_SHA1
-       if (mtree->compute_sum & F_SHA1)
+       if (mtree->compute_sum & F_SHA1) {
                archive_sha1_update(&mtree->sha1ctx, buff, n);
+               mtree->mtree_entry->reg_info->mset_digest.sha1 = 0;
+       }
 #endif
 #ifdef ARCHIVE_HAS_SHA256
-       if (mtree->compute_sum & F_SHA256)
+       if (mtree->compute_sum & F_SHA256) {
                archive_sha256_update(&mtree->sha256ctx, buff, n);
+               mtree->mtree_entry->reg_info->mset_digest.sha256 = 0;
+       }
 #endif
 #ifdef ARCHIVE_HAS_SHA384
-       if (mtree->compute_sum & F_SHA384)
+       if (mtree->compute_sum & F_SHA384) {
                archive_sha384_update(&mtree->sha384ctx, buff, n);
+               mtree->mtree_entry->reg_info->mset_digest.sha384 = 0;
+       }
 #endif
 #ifdef ARCHIVE_HAS_SHA512
-       if (mtree->compute_sum & F_SHA512)
+       if (mtree->compute_sum & F_SHA512) {
                archive_sha512_update(&mtree->sha512ctx, buff, n);
+               mtree->mtree_entry->reg_info->mset_digest.sha512 = 0;
+       }
 #endif
 }
 
@@ -1553,27 +1604,27 @@ sum_final(struct mtree_writer *mtree, struct reg_info *reg)
                reg->crc = ~mtree->crc;
        }
 #ifdef ARCHIVE_HAS_MD5
-       if (mtree->compute_sum & F_MD5)
+       if (mtree->compute_sum & F_MD5 && !reg->mset_digest.md5)
                archive_md5_final(&mtree->md5ctx, reg->digest.md5);
 #endif
 #ifdef ARCHIVE_HAS_RMD160
-       if (mtree->compute_sum & F_RMD160)
+       if (mtree->compute_sum & F_RMD160 && !reg->mset_digest.rmd160)
                archive_rmd160_final(&mtree->rmd160ctx, reg->digest.rmd160);
 #endif
 #ifdef ARCHIVE_HAS_SHA1
-       if (mtree->compute_sum & F_SHA1)
+       if (mtree->compute_sum & F_SHA1 && !reg->mset_digest.sha1)
                archive_sha1_final(&mtree->sha1ctx, reg->digest.sha1);
 #endif
 #ifdef ARCHIVE_HAS_SHA256
-       if (mtree->compute_sum & F_SHA256)
+       if (mtree->compute_sum & F_SHA256 && !reg->mset_digest.sha256)
                archive_sha256_final(&mtree->sha256ctx, reg->digest.sha256);
 #endif
 #ifdef ARCHIVE_HAS_SHA384
-       if (mtree->compute_sum & F_SHA384)
+       if (mtree->compute_sum & F_SHA384 && !reg->mset_digest.sha384)
                archive_sha384_final(&mtree->sha384ctx, reg->digest.sha384);
 #endif
 #ifdef ARCHIVE_HAS_SHA512
-       if (mtree->compute_sum & F_SHA512)
+       if (mtree->compute_sum & F_SHA512 && !reg->mset_digest.sha512)
                archive_sha512_final(&mtree->sha512ctx, reg->digest.sha512);
 #endif
        /* Save what types of sum are computed. */
index 4217e43623ed271072bbbc6bee0b209986b2b9a2..ffdb5b4ef7c52a5b65f3d67e129941870e65c0b7 100644 (file)
@@ -276,6 +276,7 @@ IF(ENABLE_TEST)
     test_write_format_mtree_classic_indent.c
     test_write_format_mtree_fflags.c
     test_write_format_mtree_no_separator.c
+    test_write_format_mtree_preset_digests.c
     test_write_format_mtree_quoted_filename.c
     test_write_format_pax.c
     test_write_format_raw.c
diff --git a/libarchive/test/test_write_format_mtree_preset_digests.c b/libarchive/test/test_write_format_mtree_preset_digests.c
new file mode 100644 (file)
index 0000000..cdf789b
--- /dev/null
@@ -0,0 +1,2107 @@
+/*-
+ * Copyright (c) 2025 Nicholas Vinson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer
+ *    in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "test.h"
+
+#define __LIBARCHIVE_BUILD 1
+#include "archive_digest_private.h"
+
+struct expected_digests {
+       unsigned char md5[16];
+       unsigned char rmd160[20];
+       unsigned char sha1[20];
+       unsigned char sha256[32];
+       unsigned char sha384[48];
+       unsigned char sha512[64];
+};
+
+archive_md5_ctx expectedMd5Ctx;
+archive_rmd160_ctx expectedRmd160Ctx;
+archive_sha1_ctx expectedSha1Ctx;
+archive_sha256_ctx expectedSha256Ctx;
+archive_sha384_ctx expectedSha384Ctx;
+archive_sha512_ctx expectedSha512Ctx;
+
+DEFINE_TEST(test_write_format_mtree_digests_no_digests_set_no_data)
+{
+       char buff[4096] = {0};
+       size_t used = 0;
+       struct archive *a;
+       struct archive_entry *entry;
+       struct expected_digests ed;
+
+#ifdef ARCHIVE_HAS_MD5
+       assertEqualInt(ARCHIVE_OK, archive_md5_init(&expectedMd5Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_md5_update(&expectedMd5Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_md5_final(&expectedMd5Ctx, ed.md5));
+#endif
+
+#ifdef ARCHIVE_HAS_RMD160
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_init(&expectedRmd160Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_update(&expectedRmd160Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_final(&expectedRmd160Ctx, ed.rmd160));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA1
+       assertEqualInt(ARCHIVE_OK, archive_sha1_init(&expectedSha1Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha1_update(&expectedSha1Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha1_final(&expectedSha1Ctx, ed.sha1));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA256
+       assertEqualInt(ARCHIVE_OK, archive_sha256_init(&expectedSha256Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha256_update(&expectedSha256Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha256_final(&expectedSha256Ctx, ed.sha256));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA384
+       assertEqualInt(ARCHIVE_OK, archive_sha384_init(&expectedSha384Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha384_update(&expectedSha384Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha384_final(&expectedSha384Ctx, ed.sha384));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA512
+       assertEqualInt(ARCHIVE_OK, archive_sha512_init(&expectedSha512Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha512_update(&expectedSha512Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha512_final(&expectedSha512Ctx, ed.sha512));
+#endif
+
+       assert((a = archive_write_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_mtree(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_set_options(a, "all"));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, sizeof(buff) - 1, &used));
+       assert((entry = archive_entry_new()) != NULL);
+       archive_entry_set_pathname(entry, "test.data");
+       archive_entry_set_filetype(entry, AE_IFREG);
+       archive_entry_set_size(entry, 4);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, entry));
+       archive_entry_free(entry);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_free(a));
+
+       assert((a = archive_read_new()) != NULL);
+       assert((entry = archive_entry_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_open_memory(a, buff, used));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &entry));
+
+#ifdef ARCHIVE_HAS_MD5
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_MD5), ed.md5, sizeof(ed.md5)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_RMD160
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_RMD160), ed.rmd160, sizeof(ed.rmd160)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA1
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA1), ed.sha1, sizeof(ed.sha1)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA256
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA256), ed.sha256, sizeof(ed.sha256)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA384
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA384), ed.sha384, sizeof(ed.sha384)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA512
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA512), ed.sha512, sizeof(ed.sha512)) == 0);
+#endif
+       archive_entry_free(entry);
+}
+
+DEFINE_TEST(test_write_format_mtree_digests_no_digests_set_empty_data)
+{
+       char buff[4096] = {0};
+       size_t used = 0;
+       struct archive *a;
+       struct archive_entry *entry;
+       struct expected_digests ed;
+
+#ifdef ARCHIVE_HAS_MD5
+       assertEqualInt(ARCHIVE_OK, archive_md5_init(&expectedMd5Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_md5_update(&expectedMd5Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_md5_final(&expectedMd5Ctx, ed.md5));
+#endif
+
+#ifdef ARCHIVE_HAS_RMD160
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_init(&expectedRmd160Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_update(&expectedRmd160Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_final(&expectedRmd160Ctx, ed.rmd160));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA1
+       assertEqualInt(ARCHIVE_OK, archive_sha1_init(&expectedSha1Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha1_update(&expectedSha1Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha1_final(&expectedSha1Ctx, ed.sha1));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA256
+       assertEqualInt(ARCHIVE_OK, archive_sha256_init(&expectedSha256Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha256_update(&expectedSha256Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha256_final(&expectedSha256Ctx, ed.sha256));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA384
+       assertEqualInt(ARCHIVE_OK, archive_sha384_init(&expectedSha384Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha384_update(&expectedSha384Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha384_final(&expectedSha384Ctx, ed.sha384));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA512
+       assertEqualInt(ARCHIVE_OK, archive_sha512_init(&expectedSha512Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha512_update(&expectedSha512Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha512_final(&expectedSha512Ctx, ed.sha512));
+#endif
+
+       assert((a = archive_write_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_mtree(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_set_options(a, "all"));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, sizeof(buff) - 1, &used));
+       assert((entry = archive_entry_new()) != NULL);
+       archive_entry_set_pathname(entry, "test.data");
+       archive_entry_set_filetype(entry, AE_IFREG);
+       archive_entry_set_size(entry, 4);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, entry));
+       archive_write_data(a, "", 0);
+       archive_entry_free(entry);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_free(a));
+
+       assert((a = archive_read_new()) != NULL);
+       assert((entry = archive_entry_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_open_memory(a, buff, used));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &entry));
+
+#ifdef ARCHIVE_HAS_MD5
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_MD5), ed.md5, sizeof(ed.md5)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_RMD160
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_RMD160), ed.rmd160, sizeof(ed.rmd160)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA1
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA1), ed.sha1, sizeof(ed.sha1)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA256
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA256), ed.sha256, sizeof(ed.sha256)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA384
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA384), ed.sha384, sizeof(ed.sha384)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA512
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA512), ed.sha512, sizeof(ed.sha512)) == 0);
+#endif
+       archive_entry_free(entry);
+}
+
+DEFINE_TEST(test_write_format_mtree_digests_no_digests_set_non_empty_data)
+{
+       char buff[4096] = {0};
+       size_t used = 0;
+       struct archive *a;
+       struct archive_entry *entry;
+       struct expected_digests ed;
+       char *data = "abcd";
+
+#ifdef ARCHIVE_HAS_MD5
+       assertEqualInt(ARCHIVE_OK, archive_md5_init(&expectedMd5Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_md5_update(&expectedMd5Ctx, data, 4));
+       assertEqualInt(ARCHIVE_OK, archive_md5_final(&expectedMd5Ctx, ed.md5));
+#endif
+
+#ifdef ARCHIVE_HAS_RMD160
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_init(&expectedRmd160Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_update(&expectedRmd160Ctx, data, 4));
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_final(&expectedRmd160Ctx, ed.rmd160));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA1
+       assertEqualInt(ARCHIVE_OK, archive_sha1_init(&expectedSha1Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha1_update(&expectedSha1Ctx, data, 4));
+       assertEqualInt(ARCHIVE_OK, archive_sha1_final(&expectedSha1Ctx, ed.sha1));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA256
+       assertEqualInt(ARCHIVE_OK, archive_sha256_init(&expectedSha256Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha256_update(&expectedSha256Ctx, data, 4));
+       assertEqualInt(ARCHIVE_OK, archive_sha256_final(&expectedSha256Ctx, ed.sha256));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA384
+       assertEqualInt(ARCHIVE_OK, archive_sha384_init(&expectedSha384Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha384_update(&expectedSha384Ctx, data, 4));
+       assertEqualInt(ARCHIVE_OK, archive_sha384_final(&expectedSha384Ctx, ed.sha384));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA512
+       assertEqualInt(ARCHIVE_OK, archive_sha512_init(&expectedSha512Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha512_update(&expectedSha512Ctx, data, 4));
+       assertEqualInt(ARCHIVE_OK, archive_sha512_final(&expectedSha512Ctx, ed.sha512));
+#endif
+
+       assert((a = archive_write_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_mtree(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_set_options(a, "all"));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, sizeof(buff) - 1, &used));
+       assert((entry = archive_entry_new()) != NULL);
+       archive_entry_set_pathname(entry, "test.data");
+       archive_entry_set_filetype(entry, AE_IFREG);
+       archive_entry_set_size(entry, 4);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, entry));
+       archive_write_data(a, data, 4);
+       archive_entry_free(entry);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_free(a));
+
+       assert((a = archive_read_new()) != NULL);
+       assert((entry = archive_entry_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_open_memory(a, buff, used));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &entry));
+
+#ifdef ARCHIVE_HAS_MD5
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_MD5), ed.md5, sizeof(ed.md5)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_RMD160
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_RMD160), ed.rmd160, sizeof(ed.rmd160)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA1
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA1), ed.sha1, sizeof(ed.sha1)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA256
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA256), ed.sha256, sizeof(ed.sha256)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA384
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA384), ed.sha384, sizeof(ed.sha384)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA512
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA512), ed.sha512, sizeof(ed.sha512)) == 0);
+#endif
+       archive_entry_free(entry);
+}
+
+DEFINE_TEST(test_write_format_mtree_digests_md5_digest_set_no_data)
+{
+#ifdef ARCHIVE_HAS_MD5
+       char buff[4096] = {0};
+       size_t used = 0;
+       struct archive *a;
+       struct archive_entry *entry;
+       struct expected_digests ed;
+
+       memcpy(ed.md5, (unsigned char[]) {
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+       }, sizeof(ed.md5));
+
+#ifdef ARCHIVE_HAS_RMD160
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_init(&expectedRmd160Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_update(&expectedRmd160Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_final(&expectedRmd160Ctx, ed.rmd160));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA1
+       assertEqualInt(ARCHIVE_OK, archive_sha1_init(&expectedSha1Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha1_update(&expectedSha1Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha1_final(&expectedSha1Ctx, ed.sha1));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA256
+       assertEqualInt(ARCHIVE_OK, archive_sha256_init(&expectedSha256Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha256_update(&expectedSha256Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha256_final(&expectedSha256Ctx, ed.sha256));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA384
+       assertEqualInt(ARCHIVE_OK, archive_sha384_init(&expectedSha384Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha384_update(&expectedSha384Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha384_final(&expectedSha384Ctx, ed.sha384));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA512
+       assertEqualInt(ARCHIVE_OK, archive_sha512_init(&expectedSha512Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha512_update(&expectedSha512Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha512_final(&expectedSha512Ctx, ed.sha512));
+#endif
+
+       assert((a = archive_write_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_mtree(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_set_options(a, "all"));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, sizeof(buff) - 1, &used));
+       assert((entry = archive_entry_new()) != NULL);
+       archive_entry_set_pathname(entry, "test.data");
+       archive_entry_set_filetype(entry, AE_IFREG);
+       archive_entry_set_size(entry, 4);
+       archive_entry_set_digest(entry, ARCHIVE_ENTRY_DIGEST_MD5, ed.md5);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, entry));
+       archive_entry_free(entry);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_free(a));
+
+       assert((a = archive_read_new()) != NULL);
+       assert((entry = archive_entry_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_open_memory(a, buff, used));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &entry));
+
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_MD5), ed.md5, sizeof(ed.md5)) == 0);
+
+#ifdef ARCHIVE_HAS_RMD160
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_RMD160), ed.rmd160, sizeof(ed.rmd160)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA1
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA1), ed.sha1, sizeof(ed.sha1)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA256
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA256), ed.sha256, sizeof(ed.sha256)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA384
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA384), ed.sha384, sizeof(ed.sha384)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA512
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA512), ed.sha512, sizeof(ed.sha512)) == 0);
+#endif
+       archive_entry_free(entry);
+#else
+       skipping("This platform does not support MD5");
+       return;
+#endif
+}
+
+DEFINE_TEST(test_write_format_mtree_digests_md5_digest_set_empty_data)
+{
+#ifdef ARCHIVE_HAS_MD5
+       char buff[4096] = {0};
+       size_t used = 0;
+       struct archive *a;
+       struct archive_entry *entry;
+       struct expected_digests ed;
+
+       memcpy(ed.md5, (unsigned char[]) {
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+       }, sizeof(ed.md5));
+
+#ifdef ARCHIVE_HAS_RMD160
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_init(&expectedRmd160Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_update(&expectedRmd160Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_final(&expectedRmd160Ctx, ed.rmd160));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA1
+       assertEqualInt(ARCHIVE_OK, archive_sha1_init(&expectedSha1Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha1_update(&expectedSha1Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha1_final(&expectedSha1Ctx, ed.sha1));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA256
+       assertEqualInt(ARCHIVE_OK, archive_sha256_init(&expectedSha256Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha256_update(&expectedSha256Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha256_final(&expectedSha256Ctx, ed.sha256));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA384
+       assertEqualInt(ARCHIVE_OK, archive_sha384_init(&expectedSha384Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha384_update(&expectedSha384Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha384_final(&expectedSha384Ctx, ed.sha384));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA512
+       assertEqualInt(ARCHIVE_OK, archive_sha512_init(&expectedSha512Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha512_update(&expectedSha512Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha512_final(&expectedSha512Ctx, ed.sha512));
+#endif
+
+       assert((a = archive_write_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_mtree(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_set_options(a, "all"));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, sizeof(buff) - 1, &used));
+       assert((entry = archive_entry_new()) != NULL);
+       archive_entry_set_pathname(entry, "test.data");
+       archive_entry_set_filetype(entry, AE_IFREG);
+       archive_entry_set_size(entry, 4);
+       archive_entry_set_digest(entry, ARCHIVE_ENTRY_DIGEST_MD5, ed.md5);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, entry));
+       archive_write_data(a, "", 0);
+       archive_entry_free(entry);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_free(a));
+
+       assert((a = archive_read_new()) != NULL);
+       assert((entry = archive_entry_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_open_memory(a, buff, used));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &entry));
+
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_MD5), ed.md5, sizeof(ed.md5)) != 0);
+
+       assertEqualInt(ARCHIVE_OK, archive_md5_init(&expectedMd5Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_md5_update(&expectedMd5Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_md5_final(&expectedMd5Ctx, ed.md5));
+
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_MD5), ed.md5, sizeof(ed.md5)) == 0);
+
+#ifdef ARCHIVE_HAS_RMD160
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_RMD160), ed.rmd160, sizeof(ed.rmd160)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA1
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA1), ed.sha1, sizeof(ed.sha1)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA256
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA256), ed.sha256, sizeof(ed.sha256)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA384
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA384), ed.sha384, sizeof(ed.sha384)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA512
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA512), ed.sha512, sizeof(ed.sha512)) == 0);
+#endif
+       archive_entry_free(entry);
+#else
+       skipping("This platform does not support MD5");
+       return;
+#endif
+}
+
+DEFINE_TEST(test_write_format_mtree_digests_md5_digest_set_non_empty_data)
+{
+#ifdef ARCHIVE_HAS_MD5
+       char buff[4096] = {0};
+       size_t used = 0;
+       struct archive *a;
+       struct archive_entry *entry;
+       struct expected_digests ed;
+
+       memcpy(ed.md5, (unsigned char[]) {
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+       }, sizeof(ed.md5));
+
+#ifdef ARCHIVE_HAS_RMD160
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_init(&expectedRmd160Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_update(&expectedRmd160Ctx, "abcd", 4));
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_final(&expectedRmd160Ctx, ed.rmd160));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA1
+       assertEqualInt(ARCHIVE_OK, archive_sha1_init(&expectedSha1Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha1_update(&expectedSha1Ctx, "abcd", 4));
+       assertEqualInt(ARCHIVE_OK, archive_sha1_final(&expectedSha1Ctx, ed.sha1));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA256
+       assertEqualInt(ARCHIVE_OK, archive_sha256_init(&expectedSha256Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha256_update(&expectedSha256Ctx, "abcd", 4));
+       assertEqualInt(ARCHIVE_OK, archive_sha256_final(&expectedSha256Ctx, ed.sha256));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA384
+       assertEqualInt(ARCHIVE_OK, archive_sha384_init(&expectedSha384Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha384_update(&expectedSha384Ctx, "abcd", 4));
+       assertEqualInt(ARCHIVE_OK, archive_sha384_final(&expectedSha384Ctx, ed.sha384));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA512
+       assertEqualInt(ARCHIVE_OK, archive_sha512_init(&expectedSha512Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha512_update(&expectedSha512Ctx, "abcd", 4));
+       assertEqualInt(ARCHIVE_OK, archive_sha512_final(&expectedSha512Ctx, ed.sha512));
+#endif
+
+       assert((a = archive_write_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_mtree(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_set_options(a, "all"));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, sizeof(buff) - 1, &used));
+       assert((entry = archive_entry_new()) != NULL);
+       archive_entry_set_pathname(entry, "test.data");
+       archive_entry_set_filetype(entry, AE_IFREG);
+       archive_entry_set_size(entry, 4);
+       archive_entry_set_digest(entry, ARCHIVE_ENTRY_DIGEST_MD5, ed.md5);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, entry));
+       archive_write_data(a, "abcd", 4);
+       archive_entry_free(entry);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_free(a));
+
+       assert((a = archive_read_new()) != NULL);
+       assert((entry = archive_entry_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_open_memory(a, buff, used));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &entry));
+
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_MD5), ed.md5, sizeof(ed.md5)) != 0);
+
+       assertEqualInt(ARCHIVE_OK, archive_md5_init(&expectedMd5Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_md5_update(&expectedMd5Ctx, "abcd", 4));
+       assertEqualInt(ARCHIVE_OK, archive_md5_final(&expectedMd5Ctx, ed.md5));
+
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_MD5), ed.md5, sizeof(ed.md5)) == 0);
+
+#ifdef ARCHIVE_HAS_RMD160
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_RMD160), ed.rmd160, sizeof(ed.rmd160)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA1
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA1), ed.sha1, sizeof(ed.sha1)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA256
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA256), ed.sha256, sizeof(ed.sha256)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA384
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA384), ed.sha384, sizeof(ed.sha384)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA512
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA512), ed.sha512, sizeof(ed.sha512)) == 0);
+#endif
+       archive_entry_free(entry);
+#else
+       skipping("This platform does not support MD5");
+       return;
+#endif
+}
+
+DEFINE_TEST(test_write_format_mtree_digests_rmd160_digest_set_no_data)
+{
+#ifdef ARCHIVE_HAS_RMD160
+       char buff[4096] = {0};
+       size_t used = 0;
+       struct archive *a;
+       struct archive_entry *entry;
+       struct expected_digests ed;
+
+#ifdef ARCHIVE_HAS_MD5
+       assertEqualInt(ARCHIVE_OK, archive_md5_init(&expectedMd5Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_md5_update(&expectedMd5Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_md5_final(&expectedMd5Ctx, ed.md5));
+#endif
+
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_init(&expectedRmd160Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_update(&expectedRmd160Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_final(&expectedRmd160Ctx, ed.rmd160));
+
+#ifdef ARCHIVE_HAS_SHA1
+       assertEqualInt(ARCHIVE_OK, archive_sha1_init(&expectedSha1Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha1_update(&expectedSha1Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha1_final(&expectedSha1Ctx, ed.sha1));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA256
+       assertEqualInt(ARCHIVE_OK, archive_sha256_init(&expectedSha256Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha256_update(&expectedSha256Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha256_final(&expectedSha256Ctx, ed.sha256));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA384
+       assertEqualInt(ARCHIVE_OK, archive_sha384_init(&expectedSha384Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha384_update(&expectedSha384Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha384_final(&expectedSha384Ctx, ed.sha384));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA512
+       assertEqualInt(ARCHIVE_OK, archive_sha512_init(&expectedSha512Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha512_update(&expectedSha512Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha512_final(&expectedSha512Ctx, ed.sha512));
+#endif
+
+       assert((a = archive_write_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_mtree(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_set_options(a, "all"));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, sizeof(buff) - 1, &used));
+       assert((entry = archive_entry_new()) != NULL);
+       archive_entry_set_pathname(entry, "test.data");
+       archive_entry_set_filetype(entry, AE_IFREG);
+       archive_entry_set_size(entry, 4);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, entry));
+       archive_entry_free(entry);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_free(a));
+
+       assert((a = archive_read_new()) != NULL);
+       assert((entry = archive_entry_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_open_memory(a, buff, used));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &entry));
+
+#ifdef ARCHIVE_HAS_MD5
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_MD5), ed.md5, sizeof(ed.md5)) == 0);
+#endif
+
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_RMD160), ed.rmd160, sizeof(ed.rmd160)) == 0);
+
+#ifdef ARCHIVE_HAS_SHA1
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA1), ed.sha1, sizeof(ed.sha1)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA256
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA256), ed.sha256, sizeof(ed.sha256)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA384
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA384), ed.sha384, sizeof(ed.sha384)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA512
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA512), ed.sha512, sizeof(ed.sha512)) == 0);
+#endif
+       archive_entry_free(entry);
+#else
+       skipping("This platform does not support RMD160");
+       return;
+#endif
+}
+
+DEFINE_TEST(test_write_format_mtree_digests_rmd160_digest_set_empty_data)
+{
+#ifdef ARCHIVE_HAS_RMD160
+       char buff[4096] = {0};
+       size_t used = 0;
+       struct archive *a;
+       struct archive_entry *entry;
+       struct expected_digests ed;
+
+       memcpy(ed.rmd160, (unsigned char[]) {
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed
+       }, sizeof(ed.rmd160));
+
+#ifdef ARCHIVE_HAS_MD5
+       assertEqualInt(ARCHIVE_OK, archive_md5_init(&expectedMd5Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_md5_update(&expectedMd5Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_md5_final(&expectedMd5Ctx, ed.md5));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA1
+       assertEqualInt(ARCHIVE_OK, archive_sha1_init(&expectedSha1Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha1_update(&expectedSha1Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha1_final(&expectedSha1Ctx, ed.sha1));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA256
+       assertEqualInt(ARCHIVE_OK, archive_sha256_init(&expectedSha256Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha256_update(&expectedSha256Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha256_final(&expectedSha256Ctx, ed.sha256));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA384
+       assertEqualInt(ARCHIVE_OK, archive_sha384_init(&expectedSha384Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha384_update(&expectedSha384Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha384_final(&expectedSha384Ctx, ed.sha384));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA512
+       assertEqualInt(ARCHIVE_OK, archive_sha512_init(&expectedSha512Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha512_update(&expectedSha512Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha512_final(&expectedSha512Ctx, ed.sha512));
+#endif
+
+       assert((a = archive_write_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_mtree(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_set_options(a, "all"));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, sizeof(buff) - 1, &used));
+       assert((entry = archive_entry_new()) != NULL);
+       archive_entry_set_pathname(entry, "test.data");
+       archive_entry_set_filetype(entry, AE_IFREG);
+       archive_entry_set_size(entry, 4);
+       archive_entry_set_digest(entry, ARCHIVE_ENTRY_DIGEST_RMD160, ed.rmd160);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, entry));
+       archive_write_data(a, "", 0);
+       archive_entry_free(entry);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_free(a));
+
+       assert((a = archive_read_new()) != NULL);
+       assert((entry = archive_entry_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_open_memory(a, buff, used));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &entry));
+
+#ifdef ARCHIVE_HAS_MD5
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_MD5), ed.md5, sizeof(ed.md5)) == 0);
+#endif
+
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_RMD160), ed.rmd160, sizeof(ed.rmd160)) != 0);
+
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_init(&expectedRmd160Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_update(&expectedRmd160Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_final(&expectedRmd160Ctx, ed.rmd160));
+
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_RMD160), ed.rmd160, sizeof(ed.rmd160)) == 0);
+
+#ifdef ARCHIVE_HAS_SHA1
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA1), ed.sha1, sizeof(ed.sha1)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA256
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA256), ed.sha256, sizeof(ed.sha256)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA384
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA384), ed.sha384, sizeof(ed.sha384)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA512
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA512), ed.sha512, sizeof(ed.sha512)) == 0);
+#endif
+       archive_entry_free(entry);
+#else
+       skipping("This platform does not support RMD160");
+       return;
+#endif
+}
+
+DEFINE_TEST(test_write_format_mtree_digests_rmd160_digest_set_non_empty_data)
+{
+#ifdef ARCHIVE_HAS_RMD160
+       char buff[4096] = {0};
+       size_t used = 0;
+       struct archive *a;
+       struct archive_entry *entry;
+       struct expected_digests ed;
+
+       memcpy(ed.rmd160, (unsigned char[]) {
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed
+       }, sizeof(ed.rmd160));
+
+#ifdef ARCHIVE_HAS_MD5
+       assertEqualInt(ARCHIVE_OK, archive_md5_init(&expectedMd5Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_md5_update(&expectedMd5Ctx, "abcd", 4));
+       assertEqualInt(ARCHIVE_OK, archive_md5_final(&expectedMd5Ctx, ed.md5));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA1
+       assertEqualInt(ARCHIVE_OK, archive_sha1_init(&expectedSha1Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha1_update(&expectedSha1Ctx, "abcd", 4));
+       assertEqualInt(ARCHIVE_OK, archive_sha1_final(&expectedSha1Ctx, ed.sha1));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA256
+       assertEqualInt(ARCHIVE_OK, archive_sha256_init(&expectedSha256Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha256_update(&expectedSha256Ctx, "abcd", 4));
+       assertEqualInt(ARCHIVE_OK, archive_sha256_final(&expectedSha256Ctx, ed.sha256));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA384
+       assertEqualInt(ARCHIVE_OK, archive_sha384_init(&expectedSha384Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha384_update(&expectedSha384Ctx, "abcd", 4));
+       assertEqualInt(ARCHIVE_OK, archive_sha384_final(&expectedSha384Ctx, ed.sha384));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA512
+       assertEqualInt(ARCHIVE_OK, archive_sha512_init(&expectedSha512Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha512_update(&expectedSha512Ctx, "abcd", 4));
+       assertEqualInt(ARCHIVE_OK, archive_sha512_final(&expectedSha512Ctx, ed.sha512));
+#endif
+
+       assert((a = archive_write_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_mtree(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_set_options(a, "all"));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, sizeof(buff) - 1, &used));
+       assert((entry = archive_entry_new()) != NULL);
+       archive_entry_set_pathname(entry, "test.data");
+       archive_entry_set_filetype(entry, AE_IFREG);
+       archive_entry_set_size(entry, 4);
+       archive_entry_set_digest(entry, ARCHIVE_ENTRY_DIGEST_RMD160, ed.rmd160);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, entry));
+       archive_write_data(a, "abcd", 4);
+       archive_entry_free(entry);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_free(a));
+
+       assert((a = archive_read_new()) != NULL);
+       assert((entry = archive_entry_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_open_memory(a, buff, used));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &entry));
+
+#ifdef ARCHIVE_HAS_MD5
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_MD5), ed.md5, sizeof(ed.md5)) == 0);
+#endif
+
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_RMD160), ed.rmd160, sizeof(ed.rmd160)) != 0);
+
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_init(&expectedRmd160Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_update(&expectedRmd160Ctx, "abcd", 4));
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_final(&expectedRmd160Ctx, ed.rmd160));
+
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_RMD160), ed.rmd160, sizeof(ed.rmd160)) == 0);
+
+#ifdef ARCHIVE_HAS_SHA1
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA1), ed.sha1, sizeof(ed.sha1)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA256
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA256), ed.sha256, sizeof(ed.sha256)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA384
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA384), ed.sha384, sizeof(ed.sha384)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA512
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA512), ed.sha512, sizeof(ed.sha512)) == 0);
+#endif
+       archive_entry_free(entry);
+#else
+       skipping("This platform does not support RMD160");
+       return;
+#endif
+}
+
+DEFINE_TEST(test_write_format_mtree_digests_sha1_digest_set_no_data)
+{
+#ifdef ARCHIVE_HAS_SHA1
+       char buff[4096] = {0};
+       size_t used = 0;
+       struct archive *a;
+       struct archive_entry *entry;
+       struct expected_digests ed;
+
+       memcpy(ed.sha1, (unsigned char[]) {
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed
+       }, sizeof(ed.sha1));
+
+#ifdef ARCHIVE_HAS_MD5
+       assertEqualInt(ARCHIVE_OK, archive_md5_init(&expectedMd5Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_md5_update(&expectedMd5Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_md5_final(&expectedMd5Ctx, ed.md5));
+#endif
+
+#ifdef ARCHIVE_HAS_RMD160
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_init(&expectedRmd160Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_update(&expectedRmd160Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_final(&expectedRmd160Ctx, ed.rmd160));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA256
+       assertEqualInt(ARCHIVE_OK, archive_sha256_init(&expectedSha256Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha256_update(&expectedSha256Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha256_final(&expectedSha256Ctx, ed.sha256));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA384
+       assertEqualInt(ARCHIVE_OK, archive_sha384_init(&expectedSha384Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha384_update(&expectedSha384Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha384_final(&expectedSha384Ctx, ed.sha384));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA512
+       assertEqualInt(ARCHIVE_OK, archive_sha512_init(&expectedSha512Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha512_update(&expectedSha512Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha512_final(&expectedSha512Ctx, ed.sha512));
+#endif
+
+       assert((a = archive_write_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_mtree(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_set_options(a, "all"));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, sizeof(buff) - 1, &used));
+       assert((entry = archive_entry_new()) != NULL);
+       archive_entry_set_pathname(entry, "test.data");
+       archive_entry_set_filetype(entry, AE_IFREG);
+       archive_entry_set_size(entry, 4);
+       archive_entry_set_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA1, ed.sha1);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, entry));
+       archive_entry_free(entry);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_free(a));
+
+       assert((a = archive_read_new()) != NULL);
+       assert((entry = archive_entry_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_open_memory(a, buff, used));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &entry));
+
+#ifdef ARCHIVE_HAS_MD5
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_MD5), ed.md5, sizeof(ed.md5)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_RMD160
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_RMD160), ed.rmd160, sizeof(ed.rmd160)) == 0);
+#endif
+
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA1), ed.sha1, sizeof(ed.sha1)) == 0);
+
+#ifdef ARCHIVE_HAS_SHA256
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA256), ed.sha256, sizeof(ed.sha256)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA384
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA384), ed.sha384, sizeof(ed.sha384)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA512
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA512), ed.sha512, sizeof(ed.sha512)) == 0);
+#endif
+       archive_entry_free(entry);
+#else
+       skipping("This platform does not support SHA1");
+       return;
+#endif
+}
+
+DEFINE_TEST(test_write_format_mtree_digests_sha1_digest_set_empty_data)
+{
+#ifdef ARCHIVE_HAS_SHA1
+       char buff[4096] = {0};
+       size_t used = 0;
+       struct archive *a;
+       struct archive_entry *entry;
+       struct expected_digests ed;
+
+       memcpy(ed.sha1, (unsigned char[]) {
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed
+       }, sizeof(ed.sha1));
+
+#ifdef ARCHIVE_HAS_MD5
+       assertEqualInt(ARCHIVE_OK, archive_md5_init(&expectedMd5Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_md5_update(&expectedMd5Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_md5_final(&expectedMd5Ctx, ed.md5));
+#endif
+
+#ifdef ARCHIVE_HAS_RMD160
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_init(&expectedRmd160Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_update(&expectedRmd160Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_final(&expectedRmd160Ctx, ed.rmd160));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA256
+       assertEqualInt(ARCHIVE_OK, archive_sha256_init(&expectedSha256Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha256_update(&expectedSha256Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha256_final(&expectedSha256Ctx, ed.sha256));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA384
+       assertEqualInt(ARCHIVE_OK, archive_sha384_init(&expectedSha384Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha384_update(&expectedSha384Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha384_final(&expectedSha384Ctx, ed.sha384));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA512
+       assertEqualInt(ARCHIVE_OK, archive_sha512_init(&expectedSha512Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha512_update(&expectedSha512Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha512_final(&expectedSha512Ctx, ed.sha512));
+#endif
+
+       assert((a = archive_write_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_mtree(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_set_options(a, "all"));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, sizeof(buff) - 1, &used));
+       assert((entry = archive_entry_new()) != NULL);
+       archive_entry_set_pathname(entry, "test.data");
+       archive_entry_set_filetype(entry, AE_IFREG);
+       archive_entry_set_size(entry, 4);
+       archive_entry_set_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA1, ed.sha1);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, entry));
+       archive_write_data(a, "", 0);
+       archive_entry_free(entry);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_free(a));
+
+       assert((a = archive_read_new()) != NULL);
+       assert((entry = archive_entry_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_open_memory(a, buff, used));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &entry));
+
+#ifdef ARCHIVE_HAS_MD5
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_MD5), ed.md5, sizeof(ed.md5)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_RMD160
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_RMD160), ed.rmd160, sizeof(ed.rmd160)) == 0);
+#endif
+
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA1), ed.sha1, sizeof(ed.sha1)) != 0);
+
+       assertEqualInt(ARCHIVE_OK, archive_sha1_init(&expectedSha1Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha1_update(&expectedSha1Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha1_final(&expectedSha1Ctx, ed.sha1));
+
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA1), ed.sha1, sizeof(ed.sha1)) == 0);
+
+#ifdef ARCHIVE_HAS_SHA256
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA256), ed.sha256, sizeof(ed.sha256)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA384
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA384), ed.sha384, sizeof(ed.sha384)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA512
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA512), ed.sha512, sizeof(ed.sha512)) == 0);
+#endif
+       archive_entry_free(entry);
+#else
+       skipping("This platform does not support SHA1");
+       return;
+#endif
+}
+
+DEFINE_TEST(test_write_format_mtree_digests_sha1_digest_set_non_empty_data)
+{
+#ifdef ARCHIVE_HAS_SHA1
+       char buff[4096] = {0};
+       size_t used = 0;
+       struct archive *a;
+       struct archive_entry *entry;
+       struct expected_digests ed;
+
+       memcpy(ed.sha1, (unsigned char[]) {
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed
+       }, sizeof(ed.sha1));
+
+#ifdef ARCHIVE_HAS_MD5
+       assertEqualInt(ARCHIVE_OK, archive_md5_init(&expectedMd5Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_md5_update(&expectedMd5Ctx, "abcd", 4));
+       assertEqualInt(ARCHIVE_OK, archive_md5_final(&expectedMd5Ctx, ed.md5));
+#endif
+
+#ifdef ARCHIVE_HAS_RMD160
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_init(&expectedRmd160Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_update(&expectedRmd160Ctx, "abcd", 4));
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_final(&expectedRmd160Ctx, ed.rmd160));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA256
+       assertEqualInt(ARCHIVE_OK, archive_sha256_init(&expectedSha256Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha256_update(&expectedSha256Ctx, "abcd", 4));
+       assertEqualInt(ARCHIVE_OK, archive_sha256_final(&expectedSha256Ctx, ed.sha256));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA384
+       assertEqualInt(ARCHIVE_OK, archive_sha384_init(&expectedSha384Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha384_update(&expectedSha384Ctx, "abcd", 4));
+       assertEqualInt(ARCHIVE_OK, archive_sha384_final(&expectedSha384Ctx, ed.sha384));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA512
+       assertEqualInt(ARCHIVE_OK, archive_sha512_init(&expectedSha512Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha512_update(&expectedSha512Ctx, "abcd", 4));
+       assertEqualInt(ARCHIVE_OK, archive_sha512_final(&expectedSha512Ctx, ed.sha512));
+#endif
+
+       assert((a = archive_write_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_mtree(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_set_options(a, "all"));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, sizeof(buff) - 1, &used));
+       assert((entry = archive_entry_new()) != NULL);
+       archive_entry_set_pathname(entry, "test.data");
+       archive_entry_set_filetype(entry, AE_IFREG);
+       archive_entry_set_size(entry, 4);
+       archive_entry_set_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA1, ed.sha1);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, entry));
+       archive_write_data(a, "abcd", 4);
+       archive_entry_free(entry);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_free(a));
+
+       assert((a = archive_read_new()) != NULL);
+       assert((entry = archive_entry_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_open_memory(a, buff, used));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &entry));
+
+#ifdef ARCHIVE_HAS_MD5
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_MD5), ed.md5, sizeof(ed.md5)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_RMD160
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_RMD160), ed.rmd160, sizeof(ed.rmd160)) == 0);
+#endif
+
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA1), ed.sha1, sizeof(ed.sha1)) != 0);
+
+       assertEqualInt(ARCHIVE_OK, archive_sha1_init(&expectedSha1Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha1_update(&expectedSha1Ctx, "abcd", 4));
+       assertEqualInt(ARCHIVE_OK, archive_sha1_final(&expectedSha1Ctx, ed.sha1));
+
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA1), ed.sha1, sizeof(ed.sha1)) == 0);
+
+#ifdef ARCHIVE_HAS_SHA256
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA256), ed.sha256, sizeof(ed.sha256)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA384
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA384), ed.sha384, sizeof(ed.sha384)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA512
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA512), ed.sha512, sizeof(ed.sha512)) == 0);
+#endif
+       archive_entry_free(entry);
+#else
+       skipping("This platform does not support SHA1");
+       return;
+#endif
+}
+
+DEFINE_TEST(test_write_format_mtree_digests_sha256_digest_set_no_data)
+{
+#ifdef ARCHIVE_HAS_SHA256
+       char buff[4096] = {0};
+       size_t used = 0;
+       struct archive *a;
+       struct archive_entry *entry;
+       struct expected_digests ed;
+
+       memcpy(ed.sha256, (unsigned char[]) {
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+               0xfe, 0xed
+       }, sizeof(ed.sha256));
+
+#ifdef ARCHIVE_HAS_MD5
+       assertEqualInt(ARCHIVE_OK, archive_md5_init(&expectedMd5Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_md5_update(&expectedMd5Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_md5_final(&expectedMd5Ctx, ed.md5));
+#endif
+
+#ifdef ARCHIVE_HAS_RMD160
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_init(&expectedRmd160Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_update(&expectedRmd160Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_final(&expectedRmd160Ctx, ed.rmd160));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA1
+       assertEqualInt(ARCHIVE_OK, archive_sha1_init(&expectedSha1Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha1_update(&expectedSha1Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha1_final(&expectedSha1Ctx, ed.sha1));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA384
+       assertEqualInt(ARCHIVE_OK, archive_sha384_init(&expectedSha384Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha384_update(&expectedSha384Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha384_final(&expectedSha384Ctx, ed.sha384));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA512
+       assertEqualInt(ARCHIVE_OK, archive_sha512_init(&expectedSha512Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha512_update(&expectedSha512Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha512_final(&expectedSha512Ctx, ed.sha512));
+#endif
+
+       assert((a = archive_write_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_mtree(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_set_options(a, "all"));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, sizeof(buff) - 1, &used));
+       assert((entry = archive_entry_new()) != NULL);
+       archive_entry_set_pathname(entry, "test.data");
+       archive_entry_set_filetype(entry, AE_IFREG);
+       archive_entry_set_size(entry, 4);
+       archive_entry_set_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA256, ed.sha256);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, entry));
+       archive_entry_free(entry);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_free(a));
+
+       assert((a = archive_read_new()) != NULL);
+       assert((entry = archive_entry_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_open_memory(a, buff, used));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &entry));
+
+#ifdef ARCHIVE_HAS_MD5
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_MD5), ed.md5, sizeof(ed.md5)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_RMD160
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_RMD160), ed.rmd160, sizeof(ed.rmd160)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA1
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA1), ed.sha1, sizeof(ed.sha1)) == 0);
+#endif
+
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA256), ed.sha256, sizeof(ed.sha256)) == 0);
+
+#ifdef ARCHIVE_HAS_SHA384
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA384), ed.sha384, sizeof(ed.sha384)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA512
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA512), ed.sha512, sizeof(ed.sha512)) == 0);
+#endif
+       archive_entry_free(entry);
+#else
+       skipping("This platform does not support SHA256");
+       return;
+#endif
+}
+
+DEFINE_TEST(test_write_format_mtree_digests_sha256_digest_set_empty_data)
+{
+#ifdef ARCHIVE_HAS_SHA256
+       char buff[4096] = {0};
+       size_t used = 0;
+       struct archive *a;
+       struct archive_entry *entry;
+       struct expected_digests ed;
+
+       memcpy(ed.sha256, (unsigned char[]) {
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+               0xfe, 0xed
+       }, sizeof(ed.sha256));
+
+#ifdef ARCHIVE_HAS_MD5
+       assertEqualInt(ARCHIVE_OK, archive_md5_init(&expectedMd5Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_md5_update(&expectedMd5Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_md5_final(&expectedMd5Ctx, ed.md5));
+#endif
+
+#ifdef ARCHIVE_HAS_RMD160
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_init(&expectedRmd160Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_update(&expectedRmd160Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_final(&expectedRmd160Ctx, ed.rmd160));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA1
+       assertEqualInt(ARCHIVE_OK, archive_sha1_init(&expectedSha1Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha1_update(&expectedSha1Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha1_final(&expectedSha1Ctx, ed.sha1));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA384
+       assertEqualInt(ARCHIVE_OK, archive_sha384_init(&expectedSha384Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha384_update(&expectedSha384Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha384_final(&expectedSha384Ctx, ed.sha384));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA512
+       assertEqualInt(ARCHIVE_OK, archive_sha512_init(&expectedSha512Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha512_update(&expectedSha512Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha512_final(&expectedSha512Ctx, ed.sha512));
+#endif
+
+       assert((a = archive_write_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_mtree(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_set_options(a, "all"));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, sizeof(buff) - 1, &used));
+       assert((entry = archive_entry_new()) != NULL);
+       archive_entry_set_pathname(entry, "test.data");
+       archive_entry_set_filetype(entry, AE_IFREG);
+       archive_entry_set_size(entry, 4);
+       archive_entry_set_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA256, ed.sha256);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, entry));
+       archive_write_data(a, "", 0);
+       archive_entry_free(entry);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_free(a));
+
+       assert((a = archive_read_new()) != NULL);
+       assert((entry = archive_entry_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_open_memory(a, buff, used));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &entry));
+
+#ifdef ARCHIVE_HAS_MD5
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_MD5), ed.md5, sizeof(ed.md5)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_RMD160
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_RMD160), ed.rmd160, sizeof(ed.rmd160)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA1
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA1), ed.sha1, sizeof(ed.sha1)) == 0);
+#endif
+
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA256), ed.sha256, sizeof(ed.sha256)) != 0);
+
+       assertEqualInt(ARCHIVE_OK, archive_sha256_init(&expectedSha256Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha256_update(&expectedSha256Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha256_final(&expectedSha256Ctx, ed.sha256));
+
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA256), ed.sha256, sizeof(ed.sha256)) == 0);
+
+#ifdef ARCHIVE_HAS_SHA384
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA384), ed.sha384, sizeof(ed.sha384)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA512
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA512), ed.sha512, sizeof(ed.sha512)) == 0);
+#endif
+       archive_entry_free(entry);
+#else
+       skipping("This platform does not support SHA256");
+       return;
+#endif
+}
+
+DEFINE_TEST(test_write_format_mtree_digests_sha256_digest_set_non_empty_data)
+{
+#ifdef ARCHIVE_HAS_SHA256
+       char buff[4096] = {0};
+       size_t used = 0;
+       struct archive *a;
+       struct archive_entry *entry;
+       struct expected_digests ed;
+
+       memcpy(ed.sha256, (unsigned char[]) {
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+               0xfe, 0xed
+       }, sizeof(ed.sha256));
+
+#ifdef ARCHIVE_HAS_MD5
+       assertEqualInt(ARCHIVE_OK, archive_md5_init(&expectedMd5Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_md5_update(&expectedMd5Ctx, "abcd", 4));
+       assertEqualInt(ARCHIVE_OK, archive_md5_final(&expectedMd5Ctx, ed.md5));
+#endif
+
+#ifdef ARCHIVE_HAS_RMD160
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_init(&expectedRmd160Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_update(&expectedRmd160Ctx, "abcd", 4));
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_final(&expectedRmd160Ctx, ed.rmd160));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA1
+       assertEqualInt(ARCHIVE_OK, archive_sha1_init(&expectedSha1Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha1_update(&expectedSha1Ctx, "abcd", 4));
+       assertEqualInt(ARCHIVE_OK, archive_sha1_final(&expectedSha1Ctx, ed.sha1));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA384
+       assertEqualInt(ARCHIVE_OK, archive_sha384_init(&expectedSha384Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha384_update(&expectedSha384Ctx, "abcd", 4));
+       assertEqualInt(ARCHIVE_OK, archive_sha384_final(&expectedSha384Ctx, ed.sha384));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA512
+       assertEqualInt(ARCHIVE_OK, archive_sha512_init(&expectedSha512Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha512_update(&expectedSha512Ctx, "abcd", 4));
+       assertEqualInt(ARCHIVE_OK, archive_sha512_final(&expectedSha512Ctx, ed.sha512));
+#endif
+
+       assert((a = archive_write_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_mtree(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_set_options(a, "all"));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, sizeof(buff) - 1, &used));
+       assert((entry = archive_entry_new()) != NULL);
+       archive_entry_set_pathname(entry, "test.data");
+       archive_entry_set_filetype(entry, AE_IFREG);
+       archive_entry_set_size(entry, 4);
+       archive_entry_set_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA256, ed.sha256);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, entry));
+       archive_write_data(a, "abcd", 4);
+       archive_entry_free(entry);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_free(a));
+
+       assert((a = archive_read_new()) != NULL);
+       assert((entry = archive_entry_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_open_memory(a, buff, used));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &entry));
+
+#ifdef ARCHIVE_HAS_MD5
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_MD5), ed.md5, sizeof(ed.md5)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_RMD160
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_RMD160), ed.rmd160, sizeof(ed.rmd160)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA1
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA1), ed.sha1, sizeof(ed.sha1)) == 0);
+#endif
+
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA256), ed.sha256, sizeof(ed.sha256)) != 0);
+
+       assertEqualInt(ARCHIVE_OK, archive_sha256_init(&expectedSha256Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha256_update(&expectedSha256Ctx, "abcd", 4));
+       assertEqualInt(ARCHIVE_OK, archive_sha256_final(&expectedSha256Ctx, ed.sha256));
+
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA256), ed.sha256, sizeof(ed.sha256)) == 0);
+
+#ifdef ARCHIVE_HAS_SHA384
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA384), ed.sha384, sizeof(ed.sha384)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA512
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA512), ed.sha512, sizeof(ed.sha512)) == 0);
+#endif
+       archive_entry_free(entry);
+#else
+       skipping("This platform does not support SHA256");
+       return;
+#endif
+}
+
+DEFINE_TEST(test_write_format_mtree_digests_sha384_digest_set_no_data)
+{
+#ifdef ARCHIVE_HAS_SHA384
+       char buff[4096] = {0};
+       size_t used = 0;
+       struct archive *a;
+       struct archive_entry *entry;
+       struct expected_digests ed;
+
+       memcpy(ed.sha384, (unsigned char[]) {
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed
+       }, sizeof(ed.sha384));
+
+#ifdef ARCHIVE_HAS_MD5
+       assertEqualInt(ARCHIVE_OK, archive_md5_init(&expectedMd5Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_md5_update(&expectedMd5Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_md5_final(&expectedMd5Ctx, ed.md5));
+#endif
+
+#ifdef ARCHIVE_HAS_RMD160
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_init(&expectedRmd160Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_update(&expectedRmd160Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_final(&expectedRmd160Ctx, ed.rmd160));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA1
+       assertEqualInt(ARCHIVE_OK, archive_sha1_init(&expectedSha1Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha1_update(&expectedSha1Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha1_final(&expectedSha1Ctx, ed.sha1));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA256
+       assertEqualInt(ARCHIVE_OK, archive_sha256_init(&expectedSha256Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha256_update(&expectedSha256Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha256_final(&expectedSha256Ctx, ed.sha256));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA512
+       assertEqualInt(ARCHIVE_OK, archive_sha512_init(&expectedSha512Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha512_update(&expectedSha512Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha512_final(&expectedSha512Ctx, ed.sha512));
+#endif
+
+       assert((a = archive_write_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_mtree(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_set_options(a, "all"));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, sizeof(buff) - 1, &used));
+       assert((entry = archive_entry_new()) != NULL);
+       archive_entry_set_pathname(entry, "test.data");
+       archive_entry_set_filetype(entry, AE_IFREG);
+       archive_entry_set_size(entry, 4);
+       archive_entry_set_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA384, ed.sha384);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, entry));
+       archive_entry_free(entry);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_free(a));
+
+       assert((a = archive_read_new()) != NULL);
+       assert((entry = archive_entry_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_open_memory(a, buff, used));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &entry));
+
+#ifdef ARCHIVE_HAS_MD5
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_MD5), ed.md5, sizeof(ed.md5)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_RMD160
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_RMD160), ed.rmd160, sizeof(ed.rmd160)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA1
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA1), ed.sha1, sizeof(ed.sha1)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA256
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA256), ed.sha256, sizeof(ed.sha256)) == 0);
+#endif
+
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA384), ed.sha384, sizeof(ed.sha384)) == 0);
+
+#ifdef ARCHIVE_HAS_SHA512
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA512), ed.sha512, sizeof(ed.sha512)) == 0);
+#endif
+       archive_entry_free(entry);
+#else
+       skipping("This platform does not support SHA384");
+       return;
+#endif
+}
+
+DEFINE_TEST(test_write_format_mtree_digests_sha384_digest_set_empty_data)
+{
+#ifdef ARCHIVE_HAS_SHA384
+       char buff[4096] = {0};
+       size_t used = 0;
+       struct archive *a;
+       struct archive_entry *entry;
+       struct expected_digests ed;
+
+       memcpy(ed.sha384, (unsigned char[]) {
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed
+       }, sizeof(ed.sha384));
+
+#ifdef ARCHIVE_HAS_MD5
+       assertEqualInt(ARCHIVE_OK, archive_md5_init(&expectedMd5Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_md5_update(&expectedMd5Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_md5_final(&expectedMd5Ctx, ed.md5));
+#endif
+
+#ifdef ARCHIVE_HAS_RMD160
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_init(&expectedRmd160Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_update(&expectedRmd160Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_final(&expectedRmd160Ctx, ed.rmd160));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA1
+       assertEqualInt(ARCHIVE_OK, archive_sha1_init(&expectedSha1Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha1_update(&expectedSha1Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha1_final(&expectedSha1Ctx, ed.sha1));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA256
+       assertEqualInt(ARCHIVE_OK, archive_sha256_init(&expectedSha256Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha256_update(&expectedSha256Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha256_final(&expectedSha256Ctx, ed.sha256));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA512
+       assertEqualInt(ARCHIVE_OK, archive_sha512_init(&expectedSha512Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha512_update(&expectedSha512Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha512_final(&expectedSha512Ctx, ed.sha512));
+#endif
+
+       assert((a = archive_write_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_mtree(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_set_options(a, "all"));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, sizeof(buff) - 1, &used));
+       assert((entry = archive_entry_new()) != NULL);
+       archive_entry_set_pathname(entry, "test.data");
+       archive_entry_set_filetype(entry, AE_IFREG);
+       archive_entry_set_size(entry, 4);
+       archive_entry_set_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA384, ed.sha384);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, entry));
+       archive_write_data(a, "", 0);
+       archive_entry_free(entry);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_free(a));
+
+       assert((a = archive_read_new()) != NULL);
+       assert((entry = archive_entry_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_open_memory(a, buff, used));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &entry));
+
+#ifdef ARCHIVE_HAS_MD5
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_MD5), ed.md5, sizeof(ed.md5)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_RMD160
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_RMD160), ed.rmd160, sizeof(ed.rmd160)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA1
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA1), ed.sha1, sizeof(ed.sha1)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA256
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA256), ed.sha256, sizeof(ed.sha256)) == 0);
+#endif
+
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA384), ed.sha384, sizeof(ed.sha384)) != 0);
+
+       assertEqualInt(ARCHIVE_OK, archive_sha384_init(&expectedSha384Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha384_update(&expectedSha384Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha384_final(&expectedSha384Ctx, ed.sha384));
+
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA384), ed.sha384, sizeof(ed.sha384)) == 0);
+
+#ifdef ARCHIVE_HAS_SHA512
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA512), ed.sha512, sizeof(ed.sha512)) == 0);
+#endif
+       archive_entry_free(entry);
+#else
+       skipping("This platform does not support SHA384");
+       return;
+#endif
+}
+
+DEFINE_TEST(test_write_format_mtree_digests_sha384_digest_set_non_empty_data)
+{
+#ifdef ARCHIVE_HAS_SHA384
+       char buff[4096] = {0};
+       size_t used = 0;
+       struct archive *a;
+       struct archive_entry *entry;
+       struct expected_digests ed;
+
+       memcpy(ed.sha384, (unsigned char[]) {
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed
+       }, sizeof(ed.sha384));
+
+#ifdef ARCHIVE_HAS_MD5
+       assertEqualInt(ARCHIVE_OK, archive_md5_init(&expectedMd5Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_md5_update(&expectedMd5Ctx, "abcd", 4));
+       assertEqualInt(ARCHIVE_OK, archive_md5_final(&expectedMd5Ctx, ed.md5));
+#endif
+
+#ifdef ARCHIVE_HAS_RMD160
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_init(&expectedRmd160Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_update(&expectedRmd160Ctx, "abcd", 4));
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_final(&expectedRmd160Ctx, ed.rmd160));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA1
+       assertEqualInt(ARCHIVE_OK, archive_sha1_init(&expectedSha1Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha1_update(&expectedSha1Ctx, "abcd", 4));
+       assertEqualInt(ARCHIVE_OK, archive_sha1_final(&expectedSha1Ctx, ed.sha1));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA256
+       assertEqualInt(ARCHIVE_OK, archive_sha256_init(&expectedSha256Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha256_update(&expectedSha256Ctx, "abcd", 4));
+       assertEqualInt(ARCHIVE_OK, archive_sha256_final(&expectedSha256Ctx, ed.sha256));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA512
+       assertEqualInt(ARCHIVE_OK, archive_sha512_init(&expectedSha512Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha512_update(&expectedSha512Ctx, "abcd", 4));
+       assertEqualInt(ARCHIVE_OK, archive_sha512_final(&expectedSha512Ctx, ed.sha512));
+#endif
+
+       assert((a = archive_write_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_mtree(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_set_options(a, "all"));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, sizeof(buff) - 1, &used));
+       assert((entry = archive_entry_new()) != NULL);
+       archive_entry_set_pathname(entry, "test.data");
+       archive_entry_set_filetype(entry, AE_IFREG);
+       archive_entry_set_size(entry, 4);
+       archive_entry_set_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA384, ed.sha384);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, entry));
+       archive_write_data(a, "abcd", 4);
+       archive_entry_free(entry);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_free(a));
+
+       assert((a = archive_read_new()) != NULL);
+       assert((entry = archive_entry_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_open_memory(a, buff, used));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &entry));
+
+#ifdef ARCHIVE_HAS_MD5
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_MD5), ed.md5, sizeof(ed.md5)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_RMD160
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_RMD160), ed.rmd160, sizeof(ed.rmd160)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA1
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA1), ed.sha1, sizeof(ed.sha1)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA256
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA256), ed.sha256, sizeof(ed.sha256)) == 0);
+#endif
+
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA384), ed.sha384, sizeof(ed.sha384)) != 0);
+
+       assertEqualInt(ARCHIVE_OK, archive_sha384_init(&expectedSha384Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha384_update(&expectedSha384Ctx, "abcd", 4));
+       assertEqualInt(ARCHIVE_OK, archive_sha384_final(&expectedSha384Ctx, ed.sha384));
+
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA384), ed.sha384, sizeof(ed.sha384)) == 0);
+
+#ifdef ARCHIVE_HAS_SHA512
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA512), ed.sha512, sizeof(ed.sha512)) == 0);
+#endif
+       archive_entry_free(entry);
+#else
+       skipping("This platform does not support SHA384");
+       return;
+#endif
+}
+
+DEFINE_TEST(test_write_format_mtree_digests_sha512_digest_set_no_data)
+{
+#ifdef ARCHIVE_HAS_SHA512
+       char buff[4096] = {0};
+       size_t used = 0;
+       struct archive *a;
+       struct archive_entry *entry;
+       struct expected_digests ed;
+
+       memcpy(ed.sha512, (unsigned char[]) {
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+               0xfe, 0xed, 0xfe, 0xed
+       }, sizeof(ed.sha512));
+
+#ifdef ARCHIVE_HAS_MD5
+       assertEqualInt(ARCHIVE_OK, archive_md5_init(&expectedMd5Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_md5_update(&expectedMd5Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_md5_final(&expectedMd5Ctx, ed.md5));
+#endif
+
+#ifdef ARCHIVE_HAS_RMD160
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_init(&expectedRmd160Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_update(&expectedRmd160Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_final(&expectedRmd160Ctx, ed.rmd160));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA1
+       assertEqualInt(ARCHIVE_OK, archive_sha1_init(&expectedSha1Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha1_update(&expectedSha1Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha1_final(&expectedSha1Ctx, ed.sha1));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA256
+       assertEqualInt(ARCHIVE_OK, archive_sha256_init(&expectedSha256Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha256_update(&expectedSha256Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha256_final(&expectedSha256Ctx, ed.sha256));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA384
+       assertEqualInt(ARCHIVE_OK, archive_sha384_init(&expectedSha384Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha384_update(&expectedSha384Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha384_final(&expectedSha384Ctx, ed.sha384));
+#endif
+
+       assert((a = archive_write_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_mtree(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_set_options(a, "all"));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, sizeof(buff) - 1, &used));
+       assert((entry = archive_entry_new()) != NULL);
+       archive_entry_set_pathname(entry, "test.data");
+       archive_entry_set_filetype(entry, AE_IFREG);
+       archive_entry_set_size(entry, 4);
+       archive_entry_set_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA512, ed.sha512);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, entry));
+       archive_entry_free(entry);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_free(a));
+
+       assert((a = archive_read_new()) != NULL);
+       assert((entry = archive_entry_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_open_memory(a, buff, used));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &entry));
+
+#ifdef ARCHIVE_HAS_MD5
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_MD5), ed.md5, sizeof(ed.md5)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_RMD160
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_RMD160), ed.rmd160, sizeof(ed.rmd160)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA1
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA1), ed.sha1, sizeof(ed.sha1)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA256
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA256), ed.sha256, sizeof(ed.sha256)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA384
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA384), ed.sha384, sizeof(ed.sha384)) == 0);
+#endif
+
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA512), ed.sha512, sizeof(ed.sha512)) == 0);
+
+       archive_entry_free(entry);
+#else
+       skipping("This platform does not support SHA512");
+       return;
+#endif
+}
+
+DEFINE_TEST(test_write_format_mtree_digests_sha512_digest_set_empty_data)
+{
+#ifdef ARCHIVE_HAS_SHA512
+       char buff[4096] = {0};
+       size_t used = 0;
+       struct archive *a;
+       struct archive_entry *entry;
+       struct expected_digests ed;
+
+       memcpy(ed.sha512, (unsigned char[]) {
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+               0xfe, 0xed, 0xfe, 0xed
+       }, sizeof(ed.sha512));
+
+#ifdef ARCHIVE_HAS_MD5
+       assertEqualInt(ARCHIVE_OK, archive_md5_init(&expectedMd5Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_md5_update(&expectedMd5Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_md5_final(&expectedMd5Ctx, ed.md5));
+#endif
+
+#ifdef ARCHIVE_HAS_RMD160
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_init(&expectedRmd160Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_update(&expectedRmd160Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_final(&expectedRmd160Ctx, ed.rmd160));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA1
+       assertEqualInt(ARCHIVE_OK, archive_sha1_init(&expectedSha1Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha1_update(&expectedSha1Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha1_final(&expectedSha1Ctx, ed.sha1));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA256
+       assertEqualInt(ARCHIVE_OK, archive_sha256_init(&expectedSha256Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha256_update(&expectedSha256Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha256_final(&expectedSha256Ctx, ed.sha256));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA384
+       assertEqualInt(ARCHIVE_OK, archive_sha384_init(&expectedSha384Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha384_update(&expectedSha384Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha384_final(&expectedSha384Ctx, ed.sha384));
+#endif
+
+       assert((a = archive_write_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_mtree(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_set_options(a, "all"));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, sizeof(buff) - 1, &used));
+       assert((entry = archive_entry_new()) != NULL);
+       archive_entry_set_pathname(entry, "test.data");
+       archive_entry_set_filetype(entry, AE_IFREG);
+       archive_entry_set_size(entry, 4);
+       archive_entry_set_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA512, ed.sha512);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, entry));
+       archive_write_data(a, "", 0);
+       archive_entry_free(entry);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_free(a));
+
+       assert((a = archive_read_new()) != NULL);
+       assert((entry = archive_entry_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_open_memory(a, buff, used));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &entry));
+
+#ifdef ARCHIVE_HAS_MD5
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_MD5), ed.md5, sizeof(ed.md5)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_RMD160
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_RMD160), ed.rmd160, sizeof(ed.rmd160)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA1
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA1), ed.sha1, sizeof(ed.sha1)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA256
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA256), ed.sha256, sizeof(ed.sha256)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA384
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA384), ed.sha384, sizeof(ed.sha384)) == 0);
+#endif
+
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA512), ed.sha512, sizeof(ed.sha512)) != 0);
+
+       assertEqualInt(ARCHIVE_OK, archive_sha512_init(&expectedSha512Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha512_update(&expectedSha512Ctx, "", 0));
+       assertEqualInt(ARCHIVE_OK, archive_sha512_final(&expectedSha512Ctx, ed.sha512));
+
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA512), ed.sha512, sizeof(ed.sha512)) == 0);
+
+       archive_entry_free(entry);
+#else
+       skipping("This platform does not support SHA512");
+       return;
+#endif
+}
+
+DEFINE_TEST(test_write_format_mtree_digests_sha512_digest_set_non_empty_data)
+{
+#ifdef ARCHIVE_HAS_SHA512
+       char buff[4096] = {0};
+       size_t used = 0;
+       struct archive *a;
+       struct archive_entry *entry;
+       struct expected_digests ed;
+
+       memcpy(ed.sha512, (unsigned char[]) {
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+               0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed,
+               0xfe, 0xed, 0xfe, 0xed
+       }, sizeof(ed.sha512));
+
+#ifdef ARCHIVE_HAS_MD5
+       assertEqualInt(ARCHIVE_OK, archive_md5_init(&expectedMd5Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_md5_update(&expectedMd5Ctx, "abcd", 4));
+       assertEqualInt(ARCHIVE_OK, archive_md5_final(&expectedMd5Ctx, ed.md5));
+#endif
+
+#ifdef ARCHIVE_HAS_RMD160
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_init(&expectedRmd160Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_update(&expectedRmd160Ctx, "abcd", 4));
+       assertEqualInt(ARCHIVE_OK, archive_rmd160_final(&expectedRmd160Ctx, ed.rmd160));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA1
+       assertEqualInt(ARCHIVE_OK, archive_sha1_init(&expectedSha1Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha1_update(&expectedSha1Ctx, "abcd", 4));
+       assertEqualInt(ARCHIVE_OK, archive_sha1_final(&expectedSha1Ctx, ed.sha1));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA256
+       assertEqualInt(ARCHIVE_OK, archive_sha256_init(&expectedSha256Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha256_update(&expectedSha256Ctx, "abcd", 4));
+       assertEqualInt(ARCHIVE_OK, archive_sha256_final(&expectedSha256Ctx, ed.sha256));
+#endif
+
+#ifdef ARCHIVE_HAS_SHA384
+       assertEqualInt(ARCHIVE_OK, archive_sha384_init(&expectedSha384Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha384_update(&expectedSha384Ctx, "abcd", 4));
+       assertEqualInt(ARCHIVE_OK, archive_sha384_final(&expectedSha384Ctx, ed.sha384));
+#endif
+
+       assert((a = archive_write_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_mtree(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_set_options(a, "all"));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, sizeof(buff) - 1, &used));
+       assert((entry = archive_entry_new()) != NULL);
+       archive_entry_set_pathname(entry, "test.data");
+       archive_entry_set_filetype(entry, AE_IFREG);
+       archive_entry_set_size(entry, 4);
+       archive_entry_set_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA512, ed.sha512);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, entry));
+       archive_write_data(a, "abcd", 4);
+       archive_entry_free(entry);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_free(a));
+
+       assert((a = archive_read_new()) != NULL);
+       assert((entry = archive_entry_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_open_memory(a, buff, used));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &entry));
+
+#ifdef ARCHIVE_HAS_MD5
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_MD5), ed.md5, sizeof(ed.md5)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_RMD160
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_RMD160), ed.rmd160, sizeof(ed.rmd160)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA1
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA1), ed.sha1, sizeof(ed.sha1)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA256
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA256), ed.sha256, sizeof(ed.sha256)) == 0);
+#endif
+
+#ifdef ARCHIVE_HAS_SHA384
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA384), ed.sha384, sizeof(ed.sha384)) == 0);
+#endif
+
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA512), ed.sha512, sizeof(ed.sha512)) != 0);
+
+       assertEqualInt(ARCHIVE_OK, archive_sha512_init(&expectedSha512Ctx));
+       assertEqualInt(ARCHIVE_OK, archive_sha512_update(&expectedSha512Ctx, "abcd", 4));
+       assertEqualInt(ARCHIVE_OK, archive_sha512_final(&expectedSha512Ctx, ed.sha512));
+
+       assert(memcmp(archive_entry_digest(entry, ARCHIVE_ENTRY_DIGEST_SHA512), ed.sha512, sizeof(ed.sha512)) == 0);
+
+       archive_entry_free(entry);
+#else
+       skipping("This platform does not support SHA512");
+       return;
+#endif
+}