+
+/*
+ * Compute message digest for the file specified by ff_pkt.
+ * In case of errors we need the job control record and file name.
+ */
+int digest_file(JCR *jcr, FF_PKT *ff_pkt, DIGEST *digest)
+{
+ BFILE bfd;
+
+ Dmsg0(50, "=== digest_file\n");
+ binit(&bfd);
+
+ if (ff_pkt->statp.st_size > 0 ||
+ ff_pkt->type == FT_RAW ||
+ ff_pkt->type == FT_FIFO) {
+ int noatime = ff_pkt->flags & FO_NOATIME ? O_NOATIME : 0;
+ if ((bopen(&bfd, ff_pkt->fname, O_RDONLY | O_BINARY | noatime, 0)) < 0) {
+ ff_pkt->ff_errno = errno;
+ berrno be;
+ be.set_errno(bfd.berrno);
+ Dmsg2(100, "Cannot open %s: ERR=%s\n", ff_pkt->fname, be.bstrerror());
+ Jmsg(jcr, M_ERROR, 1, _(" Cannot open %s: ERR=%s.\n"),
+ ff_pkt->fname, be.bstrerror());
+ return 1;
+ }
+ read_digest(&bfd, digest, jcr);
+ bclose(&bfd);
+ }
+
+ if (have_darwin_os) {
+ /* Open resource fork if necessary */
+ if (ff_pkt->flags & FO_HFSPLUS && ff_pkt->hfsinfo.rsrclength > 0) {
+ if (bopen_rsrc(&bfd, ff_pkt->fname, O_RDONLY | O_BINARY, 0) < 0) {
+ ff_pkt->ff_errno = errno;
+ berrno be;
+ Jmsg(jcr, M_ERROR, -1, _(" Cannot open resource fork for %s: ERR=%s.\n"),
+ ff_pkt->fname, be.bstrerror());
+ if (is_bopen(&ff_pkt->bfd)) {
+ bclose(&ff_pkt->bfd);
+ }
+ return 1;
+ }
+ read_digest(&bfd, digest, jcr);
+ bclose(&bfd);
+ }
+
+ if (digest && ff_pkt->flags & FO_HFSPLUS) {
+ crypto_digest_update(digest, (uint8_t *)ff_pkt->hfsinfo.fndrinfo, 32);
+ }
+ }
+ return 0;
+}
+
+/*
+ * Read message digest of bfd, updating digest
+ * In case of errors we need the job control record and file name.
+ */
+static int read_digest(BFILE *bfd, DIGEST *digest, JCR *jcr)
+{
+ char buf[DEFAULT_NETWORK_BUFFER_SIZE];
+ int64_t n;
+ int64_t bufsiz = (int64_t)sizeof(buf);
+ FF_PKT *ff_pkt = (FF_PKT *)jcr->ff;
+ uint64_t fileAddr = 0; /* file address */
+
+
+ Dmsg0(50, "=== read_digest\n");
+ while ((n=bread(bfd, buf, bufsiz)) > 0) {
+ /* Check for sparse blocks */
+ if (ff_pkt->flags & FO_SPARSE) {
+ bool allZeros = false;
+ if ((n == bufsiz &&
+ fileAddr+n < (uint64_t)ff_pkt->statp.st_size) ||
+ ((ff_pkt->type == FT_RAW || ff_pkt->type == FT_FIFO) &&
+ (uint64_t)ff_pkt->statp.st_size == 0)) {
+ allZeros = is_buf_zero(buf, bufsiz);
+ }
+ fileAddr += n; /* update file address */
+ /* Skip any block of all zeros */
+ if (allZeros) {
+ continue; /* skip block of zeros */
+ }
+ }
+
+ crypto_digest_update(digest, (uint8_t *)buf, n);
+
+ /* Can be used by BaseJobs, update only for Verify jobs */
+ if (jcr->getJobLevel() != L_FULL) {
+ jcr->JobBytes += n;
+ jcr->ReadBytes += n;
+ }
+ }
+ if (n < 0) {
+ berrno be;
+ be.set_errno(bfd->berrno);
+ Dmsg2(100, "Error reading file %s: ERR=%s\n", jcr->last_fname, be.bstrerror());
+ Jmsg(jcr, M_ERROR, 1, _("Error reading file %s: ERR=%s\n"),
+ jcr->last_fname, be.bstrerror());
+ jcr->JobErrors++;
+ return -1;
+ }
+ return 0;
+}