-O ro: readonly files, never write anything (except to standard streams)
[tfcrypt.git] / tfcrypt.c
index 4ba1dd530cd179dd269abfa4cca8033c347f853b..e6d422dbe25277dbf231633021e4f318fac14ee4 100644 (file)
--- a/tfcrypt.c
+++ b/tfcrypt.c
@@ -2,7 +2,7 @@
  * tfcrypt -- high security Threefish encryption tool.
  *
  * tfcrypt is copyrighted:
- * Copyright (C) 2012-2018 Andrey Rys. All rights reserved.
+ * Copyright (C) 2012-2019 Andrey Rys. All rights reserved.
  *
  * tfcrypt is licensed to you under the terms of std. MIT/X11 license:
  *
 
 #include "tfcrypt.h"
 
+static tfc_byte svctr[TF_BLOCK_SIZE];
+static tfc_fsize rwd, do_read_loops, loopcnt;
+
+static void open_log(const char *logfile)
+{
+       int fd;
+       tfc_yesno ro;
+
+       if (!strcmp(logfile, "-")) return;
+
+       ro = read_only;
+       read_only = NO;
+       fd = xopen(logfile, O_WRONLY | O_CREAT | O_LARGEFILE | O_TRUNC);
+       read_only = ro;
+       xclose(2);
+       if (dup2(fd, 2) == -1) xexit(2);
+       xclose(fd);
+       do_statline_dynamic = NO;
+}
+
 static int getps_filter(struct getpasswd_state *getps, char chr, size_t pos)
 {
        if (chr == '\x03') {
@@ -114,6 +134,7 @@ int main(int argc, char **argv)
        char *s, *d, *t, *stoi;
        size_t x, n;
 
+       progpid = getpid();
        progname = basename(argv[0]);
 
        if (!isatty(2)) do_statline_dynamic = NO;
@@ -128,8 +149,14 @@ int main(int argc, char **argv)
 _baddfname:
        memset(s, 0, n);
 
+       if (!strcmp(progname, "iotool")) {
+               do_edcrypt = TFC_DO_PLAIN;
+               password = YES;
+               ctr_mode = TFC_MODE_PLAIN;
+       }
+
        opterr = 0;
-       while ((c = getopt(argc, argv, "L:s:aU:C:r:K:t:Pkzxc:l:qedn:vV:pwE:O:S:AmM:R:Z:WHD:")) != -1) {
+       while ((c = getopt(argc, argv, "L:s:aU:C:r:K:t:Pkzxc:l:qedn:vV:pwE:o:O:S:AmuM:R:Z:WHD:")) != -1) {
                switch (c) {
                        case 'L':
                                read_defaults(optarg, NO);
@@ -195,10 +222,10 @@ _baddfname:
                                ctr_mode = TFC_MODE_PLAIN;
                                break;
                        case 'e':
-                               do_edcrypt = TFC_DO_ENCRYPT;
+                               if (do_edcrypt != TFC_DO_PLAIN) do_edcrypt = TFC_DO_ENCRYPT;
                                break;
                        case 'd':
-                               do_edcrypt = TFC_DO_DECRYPT;
+                               if (do_edcrypt != TFC_DO_PLAIN) do_edcrypt = TFC_DO_DECRYPT;
                                break;
                        case 'D':
                                macbits = strtoul(optarg, &stoi, 10);
@@ -276,6 +303,9 @@ _baddfname:
                                        error_action = TFC_ERRACT_LSYNC;
                                else xerror(NO, YES, YES, "invalid error action %s specified", optarg);
                                break;
+                       case 'o':
+                               open_log(optarg);
+                               break;
                        case 'O':
                                s = d = optarg; t = NULL;
                                while ((s = strtok_r(d, ",", &t))) {
@@ -284,10 +314,16 @@ _baddfname:
                                                write_flags |= O_SYNC;
                                        else if (!strcmp(s, "trunc"))
                                                write_flags |= O_TRUNC;
+                                       else if (!strcmp(s, "append"))
+                                               write_flags |= O_APPEND;
                                        else if (!strcmp(s, "fsync"))
                                                do_fsync = YES;
                                        else if (!strcmp(s, "pad"))
                                                do_pad = YES;
+                                       else if (!strcmp(s, "ro"))
+                                               read_only = YES;
+                                       else if (!strcmp(s, "rw"))
+                                               read_only = NO;
                                        else if (!strcmp(s, "xtime"))
                                                do_preserve_time = YES;
                                        else if (!strcmp(s, "gibsize"))
@@ -308,6 +344,16 @@ _baddfname:
                                                do_full_key = YES;
                                        else if (!strcmp(s, "showsecrets"))
                                                show_secrets = YES;
+                                       else if (!strcmp(s, "finished"))
+                                               show_when_done = YES;
+                                       else if (!strcmp(s, "pid"))
+                                               show_pid = YES;
+                                       else if (!strncmp(s, "readloops", 9) && *(s+9) == '=') {
+                                               do_read_loops = tfc_humanfsize(s+10, &stoi);
+                                               if (!str_empty(stoi)) do_read_loops = NOSIZE;
+                                       }
+                                       else if (!strncmp(s, "logfile", 7) && *(s+7) == '=')
+                                               open_log(s+8);
                                        else if (!strncmp(s, "iobs", 4) && *(s+4) == '=') {
                                                s += 5;
                                                blksize = (size_t)tfc_humanfsize(s, &stoi);
@@ -425,14 +471,21 @@ _baddfname:
                                        }
                                        else if (!strncmp(s, "ftrunc", 6) && *(s+6) == '=') {
                                                s += 7;
-                                               ftrunc_dfd = tfc_humanfsize(s, &stoi);
-                                               if (!str_empty(stoi)) {
-                                                       ftrunc_dfd = tfc_fnamesize(s, YES);
-                                                       ftrunc_dfd = tfc_modifysize(ftrunc_dfd, strchr(s, ':'));
-                                                       if (ftrunc_dfd == NOFSIZE) xerror(NO, YES, YES,
-                                                       "%s: invalid ftrunc value", s);
+                                               if (!strcmp(s, "tail")) {
+                                                       do_ftrunc = TFC_FTRUNC_TAIL;
+                                                       ftrunc_dfd = NOFSIZE;
+                                               }
+                                               else {
+                                                       do_ftrunc = TFC_DO_FTRUNC;
+                                                       ftrunc_dfd = tfc_humanfsize(s, &stoi);
+                                                       if (!str_empty(stoi)) {
+                                                               ftrunc_dfd = tfc_fnamesize(s, YES);
+                                                               ftrunc_dfd = tfc_modifysize(ftrunc_dfd, strchr(s, ':'));
+                                                               if (ftrunc_dfd == NOFSIZE) xerror(NO, YES, YES,
+                                                               "%s: invalid ftrunc value", s);
+                                                       }
+                                                       else ftrunc_dfd = tfc_modifysize(ftrunc_dfd, strchr(s, ':'));
                                                }
-                                               else ftrunc_dfd = tfc_modifysize(ftrunc_dfd, strchr(s, ':'));
                                        }
                                        else if (!strncmp(s, "xkey", 4) && *(s+4) == '=') {
                                                s += 5;
@@ -488,9 +541,11 @@ _baddfname:
                                        do_mac_file = optarg;
                                break;
                        case 'm':
+                       case 'u':
                                if (do_mac != TFC_MAC_VRFY)
                                        xerror(NO, YES, YES, "signature source was not specified");
                                do_mac = TFC_MAC_JUST_VRFY;
+                               if (c == 'u') do_mac = TFC_MAC_JUST_VRFY2;
                                break;
                        case 'R':
                        case 'Z':
@@ -534,6 +589,7 @@ _baddfname:
                                break;
                        case 'q':
                                quiet = YES;
+                               xexit_no_nl = YES;
                                verbose = NO;
                                do_full_hexdump = NO;
                                status_timer = 0;
@@ -601,8 +657,7 @@ _baddfname:
                if (!strcasecmp(saltf, "disable")) goto _nosalt;
 
                if (!strcmp(saltf, "-")) saltfd = 0;
-               else saltfd = open(saltf, O_RDONLY | O_LARGEFILE);
-               if (saltfd == -1) xerror(NO, NO, YES, "%s", saltf);
+               else saltfd = xopen(saltf, O_RDONLY | O_LARGEFILE);
                lio = xread(saltfd, tfc_salt, TFC_MAX_SALT - TF_FROM_BITS(TFC_KEY_BITS));
                if (lio == NOSIZE) xerror(NO, NO, YES, "%s", saltf);
                tfc_saltsz = lio;
@@ -615,8 +670,7 @@ _nosalt:
                tfc_yesno do_stop;
 
                if (!strcmp(mackeyf, "-")) mkfd = 0;
-               else mkfd = open(mackeyf, O_RDONLY | O_LARGEFILE);
-               if (mkfd == -1) xerror(NO, NO, YES, "%s", mackeyf);
+               else mkfd = xopen(mackeyf, O_RDONLY | O_LARGEFILE);
 
                skein_init(&sk, TFC_KEY_BITS);
 
@@ -628,7 +682,7 @@ _nosalt:
                        lrem = lblock = sizeof(tmpdata);
                        if (error_action == TFC_ERRACT_SYNC) rdpos = tfc_fdgetpos(mkfd);
 _mkragain:             lio = xread(mkfd, pblk, lrem);
-                       if (lio == 0) do_stop = YES;
+                       if (lio == 0 && do_stop == NO) do_stop = YES;
                        if (lio != NOSIZE) ldone += lio;
                        else {
                                if (errno != EIO && catch_all_errors != YES)
@@ -691,8 +745,7 @@ _mkragain:          lio = xread(mkfd, pblk, lrem);
        if (argv[idx]) {
                if (password || rawkey > TFC_RAWKEY_KEYFILE) goto _nokeyfd;
                if (!strcmp(argv[idx], "-")) kfd = 0;
-               else kfd = open(argv[idx], O_RDONLY | O_LARGEFILE);
-               if (kfd == -1) xerror(NO, NO, YES, "%s", argv[idx]);
+               else kfd = xopen(argv[idx], O_RDONLY | O_LARGEFILE);
 
                lio = strnlen(argv[idx], PATH_MAX);
                memset(argv[idx], '*', lio);
@@ -720,19 +773,12 @@ _nokeyfd:
        if (argv[idx]) {
                if (!strcmp(argv[idx], "-") && kfd) sfd = 0;
                else {
-                       sfd = open(argv[idx], O_RDONLY | O_LARGEFILE);
+                       sfd = xopen(argv[idx], O_RDONLY | O_LARGEFILE);
                        if (do_preserve_time) if (fstat(sfd, &s_stat) == -1)
                                xerror(YES, NO, YES, "stat(%s)", argv[idx]);
                }
-               if (sfd == -1) xerror(NO, NO, YES, "%s", argv[idx]);
 
-               if (do_edcrypt == TFC_DO_DECRYPT && do_mac != NO && maxlen != NOFSIZE) {
-                       if (verbose) tfc_esay("%s: disabling signature verification on "
-                               "requested partial decryption.", progname);
-                       do_mac = NO;
-               }
-
-               if ((do_mac >= TFC_MAC_VRFY || do_mac == TFC_MAC_DROP) && !do_mac_file) {
+               if ((do_mac >= TFC_MAC_VRFY || do_mac <= TFC_MAC_DROP) && !do_mac_file) {
                        maxlen = tfc_fdsize(sfd);
                        if (maxlen == NOFSIZE)
                                xerror(NO, YES, YES,
@@ -755,8 +801,7 @@ _nokeyfd:
                int ctrfd;
 
                if (!strcmp(counter_file, "-")) ctrfd = 0;
-               else ctrfd = open(counter_file, O_RDONLY | O_LARGEFILE);
-               if (ctrfd == -1) xerror(NO, NO, YES, "%s", counter_file);
+               else ctrfd = xopen(counter_file, O_RDONLY | O_LARGEFILE);
                lio = xread(ctrfd, ctr, ctrsz);
                if (lio == NOSIZE) xerror(NO, NO, YES, "%s", counter_file);
                if (lio < ctrsz) xerror(NO, YES, YES, "counter file is too small (%zu)!", lio);
@@ -803,7 +848,7 @@ _ctrskip1:
 
        if (ctr_mode == TFC_MODE_PLAIN) goto _plain;
 
-       if (verbose) tfc_esay("%s: hashing password", progname);
+       if (verbose) tfc_esay("%s: hashing password", tfc_format_pid(progname));
 
        if (rawkey == TFC_RAWKEY_KEYFILE) {
                tfc_yesno xtskeyset = NO;
@@ -956,14 +1001,13 @@ _pwdagain:       memset(&getps, 0, sizeof(struct getpasswd_state));
 
                pblk = key;
                if (!strcmp(genkeyf, "-")) krfd = 1;
-               else krfd = open(genkeyf, O_WRONLY | O_CREAT | O_LARGEFILE | write_flags, 0666);
-               if (krfd == -1) xerror(NO, NO, YES, "%s", genkeyf);
+               else krfd = xopen(genkeyf, O_WRONLY | O_CREAT | O_LARGEFILE | write_flags);
 _xts2genkey:   if (xwrite(krfd, pblk, TF_FROM_BITS(TFC_KEY_BITS)) == NOSIZE) xerror(NO, NO, YES, "%s", genkeyf);
                if (do_fsync && fsync(krfd) == -1) xerror(NO, NO, YES, "%s", genkeyf);
                if (verbose && xtskeyset == NO) {
-                       tfc_esay("%s: password hashing done", progname);
-                       tfc_esay("%s: rawkey written to %s.", progname, genkeyf);
-                       tfc_esay("%s: Have a nice day!", progname);
+                       tfc_esay("%s: password hashing done", tfc_format_pid(progname));
+                       tfc_esay("%s: rawkey written to %s.", tfc_format_pid(progname), genkeyf);
+                       tfc_esay("%s: Have a nice day!", tfc_format_pid(progname));
                }
 
                if (ctr_mode == TFC_MODE_XTS) {
@@ -979,17 +1023,11 @@ _xts2genkey:     if (xwrite(krfd, pblk, TF_FROM_BITS(TFC_KEY_BITS)) == NOSIZE) xerro
                xexit(0);
        }
 
-       if (iseek_blocks && (do_edcrypt == TFC_DO_DECRYPT && do_mac != NO)) {
-               if (verbose) tfc_esay("%s: disabling signature verification on "
-                       "requested partial decryption.", progname);
-               do_mac = NO;
-       }
-
        if (do_mac != NO) {
                if (mackey_opt == TFC_MACKEY_RAWKEY) skein(mackey, TF_MAX_BITS, key, key, TF_FROM_BITS(TFC_KEY_BITS));
                if (ctr_mode < TFC_MODE_OCB) {
                        if (verbose) tfc_esay("%s: doing MAC calculation, processing speed "
-                               "will be slower.", progname);
+                               "will be slower.", tfc_format_pid(progname));
                        if (mackey_opt) skein_init_key(&sk, mackey, macbits);
                        else skein_init(&sk, macbits);
                }
@@ -1011,6 +1049,7 @@ _xts2genkey:      if (xwrite(krfd, pblk, TF_FROM_BITS(TFC_KEY_BITS)) == NOSIZE) xerro
 
        tfc_data_to_words64(&iseek_blocks, sizeof(iseek_blocks));
        tf_ctr_set(ctr, &iseek_blocks, sizeof(iseek_blocks));
+       if (do_mac == TFC_MAC_JUST_VRFY2) memcpy(svctr, ctr, TF_BLOCK_SIZE);
 
        if (counter_opt == TFC_CTR_SHOW) {
                switch (do_outfmt) {
@@ -1026,18 +1065,15 @@ _ctrskip2:
                xclose(kfd);
                kfd = -1;
        }
-       if (verbose) tfc_esay("%s: password hashing done", progname);
+       if (verbose) tfc_esay("%s: password hashing done", tfc_format_pid(progname));
 
        if (overwrite_source && srcfname) argv[idx] = srcfname;
 
 _plain:
        if (argv[idx]) {
                if (!strcmp(argv[idx], "-")) dfd = 1;
-               else dfd = open(argv[idx], O_RDWR | O_LARGEFILE | write_flags, 0666);
-               if (dfd == -1) {
-                       dfd = open(argv[idx], O_WRONLY | O_CREAT | O_LARGEFILE | write_flags, 0666);
-                       if (dfd == -1) xerror(NO, NO, YES, "%s", argv[idx]);
-               }
+               else dfd = xxopen(YES, argv[idx], O_RDWR | O_LARGEFILE | write_flags);
+               if (dfd == -1) dfd = xopen(argv[idx], O_WRONLY | O_CREAT | O_LARGEFILE | write_flags);
                dstfname = argv[idx];
                idx++;
        }
@@ -1052,9 +1088,8 @@ _plain:
        sigact.sa_flags = SA_RESTART;
        sigact.sa_handler = print_crypt_status;
        sigaction(SIGUSR1, &sigact, NULL);
-       sigaction(SIGTSTP, &sigact, NULL);
        sigaction(SIGALRM, &sigact, NULL);
-       if (status_timer) setup_next_alarm(status_timer);
+       if (status_timer) setup_next_alarm(status_timer > 1000000 ? 1000000 : status_timer);
        sigact.sa_handler = change_status_width;
        sigaction(SIGQUIT, &sigact, NULL);
        sigact.sa_handler = change_status_timer;
@@ -1063,11 +1098,14 @@ _plain:
                sigact.sa_handler = print_crypt_status;
                sigaction(SIGINT, &sigact, NULL);
                sigaction(SIGTERM, &sigact, NULL);
+               sigaction(SIGTSTP, &sigact, NULL);
        }
        else {
                sigact.sa_handler = exit_sigterm;
                sigaction(SIGINT, &sigact, NULL);
                sigaction(SIGTERM, &sigact, NULL);
+               sigact.sa_handler = handle_sigtstp;
+               sigaction(SIGTSTP, &sigact, NULL);
        }
        memset(&sigact, 0, sizeof(struct sigaction));
 
@@ -1087,12 +1125,32 @@ _ctrwagain:     lio = xwrite(dfd, pblk, lrem);
                        lrem -= lio;
                        goto _ctrwagain;
                }
+               total_written_dst += ldone;
                total_processed_dst += ldone;
                delta_processed += ldone;
        }
 
        if (ctr_mode == TFC_MODE_STREAM) tfe_init_iv(&tfe, key, ctr);
 
+       if (do_mac == TFC_MAC_JUST_VRFY2) {
+               rwd = tfc_fdgetpos(sfd);
+               if (rwd == NOFSIZE) {
+                       tfc_esay("%s: WARNING: input is not seekable, disabling MAC testing mode", tfc_format_pid(progname));
+                       do_mac = TFC_MAC_VRFY;
+               }
+               goto _nodecrypt_again_vrfy2;
+
+_decrypt_again_vrfy2:
+               if (lseek(sfd, (off_t)rwd, SEEK_SET) == ((off_t)-1)) {
+                       xerror(ignore_seek_errors, NO, YES, "MAC testing seek failed");
+               }
+               total_processed_src = rwd;
+               memcpy(ctr, svctr, TF_BLOCK_SIZE);
+               memset(svctr, 0, TF_BLOCK_SIZE);
+       }
+
+_nodecrypt_again_vrfy2:
+       loopcnt = 1;
        errno = 0;
        do_stop = NO;
        while (1) {
@@ -1102,7 +1160,15 @@ _ctrwagain:      lio = xwrite(dfd, pblk, lrem);
                lrem = lblock = blk_len_adj(maxlen, total_processed_src, blksize);
                if (error_action == TFC_ERRACT_SYNC) rdpos = tfc_fdgetpos(sfd);
 _ragain:       lio = xread(sfd, pblk, lrem);
-               if (lio == 0) do_stop = TFC_STOP_BEGAN;
+               if (lio == 0) {
+                       if ((do_read_loops != 0 && sfd != 0) && (loopcnt < do_read_loops)) {
+                               lseek(sfd, 0L, SEEK_SET);
+                               loopcnt++;
+                               goto _ragain;
+                       }
+
+                       do_stop = YES;
+               }
                if (lio != NOSIZE) ldone += lio;
                else {
                        if (errno != EIO && catch_all_errors != YES)
@@ -1162,7 +1228,7 @@ _ragain:  lio = xread(sfd, pblk, lrem);
 
                if (do_mac >= TFC_MAC_VRFY && ctr_mode < TFC_MODE_OCB)
                        skein_update(&sk, dstblk, ldone);
-               if (do_mac == TFC_MAC_JUST_VRFY) goto _nowrite;
+               if (do_mac >= TFC_MAC_JUST_VRFY) goto _nowrite;
 
                pblk = dstblk;
                lrem = ldone;
@@ -1176,13 +1242,17 @@ _wagain:        lio = xwrite(dfd, pblk, lrem);
                        lrem -= lio;
                        goto _wagain;
                }
+               total_written_dst += ldone;
 _nowrite:      total_processed_dst += ldone;
                delta_processed += ldone;
 
-               if (maxlen != NOFSIZE && total_processed_src >= maxlen) break;
+               if (maxlen != NOFSIZE && total_processed_src >= maxlen) {
+                       do_stop = YES;
+                       break;
+               }
        }
 
-       if (do_stop == TFC_STOP_FULL) goto _nomac;
+       if (verbose && status_timer && do_statline_dynamic == YES && statline_was_shown == YES) tfc_esay("\n");
 
        errno = 0;
        if (do_mac >= TFC_MAC_VRFY) {
@@ -1220,8 +1290,7 @@ _macragain:               lio = xread(sfd, pblk, lrem);
                        int mfd;
 
                        if (!strcmp(do_mac_file, "-")) mfd = 0;
-                       else mfd = open(do_mac_file, O_RDONLY | O_LARGEFILE);
-                       if (mfd == -1) xerror(YES, NO, NO, "%s", do_mac_file);
+                       else mfd = xopen(do_mac_file, O_RDONLY | O_LARGEFILE);
                        lio = ldone = xread(mfd, tmpdata, sizeof(tmpdata));
                        if (lio == NOSIZE) xerror(NO, NO, YES, "%s", do_mac_file);
                        if (!memcmp(tmpdata, TFC_ASCII_TFC_MAC_FOURCC, TFC_ASCII_TFC_MAC_FOURCC_LEN)) {
@@ -1236,7 +1305,7 @@ _macragain:               lio = xread(sfd, pblk, lrem);
 
                if (ldone < TF_FROM_BITS(macbits)) {
                        if (quiet == NO) tfc_esay("%s: short signature (%zu), "
-                               "not verifying", progname, ldone);
+                               "not verifying", tfc_format_pid(progname), ldone);
                        exitcode = 1;
                        goto _shortmac;
                }
@@ -1253,16 +1322,25 @@ _macragain:             lio = xread(sfd, pblk, lrem);
 
                if (!memcmp(tmpdata, macresult, TF_FROM_BITS(macbits))) {
                        if (quiet == NO) {
-                               tfc_esay("%s: signature is good", progname);
+                               tfc_esay("%s: signature is good", tfc_format_pid(progname));
                                if (verbose) {
                                        if (do_outfmt == TFC_OUTFMT_B64) tfc_printbase64(stderr, macresult, TF_FROM_BITS(macbits), YES);
                                        else mehexdump(macresult, TF_FROM_BITS(macbits), TF_FROM_BITS(macbits), YES);
                                }
                        }
+                       if (do_mac == TFC_MAC_JUST_VRFY2) {
+                               if (verbose) tfc_esay("%s: -u: MAC signature is valid, proceeding with decrypting it again", tfc_format_pid(progname));
+                               maxlen = total_processed_src - SKEIN_DIGEST_SIZE;
+                               do_mac = TFC_MAC_DROP2;
+                               goto _decrypt_again_vrfy2;
+                       }
                }
                else {
-                       if (quiet == NO) tfc_esay("%s: signature is BAD: "
-                               "wrong password, key, mode, or file is not signed", progname);
+                       if (quiet == NO) {
+                               tfc_esay("%s: signature is BAD: "
+                               "wrong password, key, mode, or file is not signed", tfc_format_pid(progname));
+                               if (do_mac == TFC_MAC_JUST_VRFY2) tfc_esay("%s: -u: MAC signature is invalid, not decrypting it again", tfc_format_pid(progname));
+                       }
                        exitcode = 1;
                }
 
@@ -1270,7 +1348,6 @@ _shortmac:        memset(macvrfy, 0, sizeof(macvrfy));
                memset(macresult, 0, sizeof(macresult));
                memset(tmpdata, 0, sizeof(tmpdata));
        }
-
        else if (do_mac == TFC_MAC_SIGN) {
                if (ctr_mode < TFC_MODE_OCB) skein_final(macresult, &sk);
                else skein(macresult, macbits, mackey, macresult, TF_FROM_BITS(macbits));
@@ -1296,6 +1373,7 @@ _macwagain:               lio = xwrite(dfd, pblk, lrem);
                                lrem -= lio;
                                goto _macwagain;
                        }
+                       total_written_dst += ldone;
                        total_processed_dst += ldone;
                        delta_processed += ldone;
                }
@@ -1303,8 +1381,7 @@ _macwagain:               lio = xwrite(dfd, pblk, lrem);
                        int mfd;
 
                        if (!strcmp(do_mac_file, "-")) mfd = 1;
-                       else mfd = open(do_mac_file, O_WRONLY | O_CREAT | O_LARGEFILE | write_flags, 0666);
-                       if (mfd == -1) xerror(YES, NO, NO, "%s", do_mac_file);
+                       else mfd = xopen(do_mac_file, O_WRONLY | O_CREAT | O_LARGEFILE | write_flags);
                        if (do_outfmt == TFC_OUTFMT_B64) {
                                memcpy(macvrfy, tmpdata, TF_FROM_BITS(macbits));
                                memset(tmpdata, 0, TFC_TMPSIZE);
@@ -1327,14 +1404,9 @@ _macwagain:              lio = xwrite(dfd, pblk, lrem);
                memset(macresult, 0, sizeof(macresult));
                memset(tmpdata, 0, sizeof(tmpdata));
        }
+       else if (do_mac == TFC_MAC_DROP2) total_processed_src += SKEIN_DIGEST_SIZE;
 
-_nomac:
-       if (verbose || status_timer || do_stop == TFC_STOP_FULL) print_crypt_status(0);
-
-       if (do_preserve_time) fcopy_matime(dfd, &s_stat);
-       xclose(sfd);
-       if (ftrunc_dfd != NOFSIZE) if (ftruncate(dfd, (off_t)ftrunc_dfd) == -1) xerror(YES, NO, YES, "ftruncate(%d)", dfd);
-       xclose(dfd);
+       if (verbose || status_timer || (do_stop == YES && quiet == NO)) print_crypt_status(0);
 
        xexit(exitcode);
        return -1;