LCOV - code coverage report
Current view: top level - cmdline - check.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 766 862 88.9 %
Date: 2026-04-29 15:04:44 Functions: 10 10 100.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-3.0-or-later
       2             : // Copyright (C) 2011 Andrea Mazzoleni
       3             : 
       4             : #include "portable.h"
       5             : 
       6             : #include "support.h"
       7             : #include "util.h"
       8             : #include "elem.h"
       9             : #include "import.h"
      10             : #include "search.h"
      11             : #include "state.h"
      12             : #include "parity.h"
      13             : #include "handle.h"
      14             : #include "raid/raid.h"
      15             : #include "raid/combo.h"
      16             : 
      17             : /****************************************************************************/
      18             : /* check */
      19             : 
      20      779458 : static const char* es(int err)
      21             : {
      22      779458 :         if (is_hw(err))
      23           0 :                 return "error_io";
      24             :         else
      25      779458 :                 return "error";
      26             : }
      27             : 
      28             : /**
      29             :  * A block that failed the hash check, or that was deleted.
      30             :  */
      31             : struct failed_struct {
      32             :         /**
      33             :          * If we know for sure that the block is garbage or missing
      34             :          * and it needs to be recovered and rewritten to the disk.
      35             :          */
      36             :         int is_bad;
      37             : 
      38             :         /**
      39             :          * If what we have recovered may be not updated data,
      40             :          * an old version, or just garbage.
      41             :          *
      42             :          * Essentially, it means that we are not sure what we have recovered
      43             :          * is really correct. It's just our best guess.
      44             :          *
      45             :          * These "recovered" blocks are also written to the disk if the block is marked as ::is_bad.
      46             :          * But these files are marked also as FILE_IS_DAMAGED, and then renamed to .unrecoverable.
      47             :          *
      48             :          * Note that this could happen only for CHG blocks.
      49             :          */
      50             :         int is_outofdate;
      51             : 
      52             :         unsigned index; /**< Index of the failed block. */
      53             :         struct snapraid_block* block; /**< The failed block */
      54             :         struct snapraid_disk* disk; /**< The failed disk. */
      55             :         struct snapraid_file* file; /**< The failed file. 0 for DELETED block. */
      56             :         block_off_t file_pos; /**< Offset inside the file */
      57             :         struct snapraid_handle* handle; /**< The handle containing the failed block, or 0 for a DELETED block */
      58             : };
      59             : 
      60             : /**
      61             :  * Check if a block hash matches the specified buffer.
      62             :  * Return ==0 if equal
      63             :  */
      64      511889 : static int blockcmp(struct snapraid_state* state, int rehash, struct snapraid_block* block, unsigned pos_size, unsigned char* buffer, unsigned char* buffer_zero)
      65             : {
      66             :         unsigned char hash[HASH_MAX];
      67             : 
      68             :         /* now compute the hash of the valid part */
      69      511889 :         if (rehash) {
      70           0 :                 memhash(state->prevhash, state->prevhashseed, hash, buffer, pos_size);
      71             :         } else {
      72      511889 :                 memhash(state->hash, state->hashseed, hash, buffer, pos_size);
      73             :         }
      74             : 
      75             :         /* compare the hash */
      76      511889 :         if (memcmp(hash, block->hash, BLOCK_HASH_SIZE) != 0) {
      77       15681 :                 return -1;
      78             :         }
      79             : 
      80             :         /* compare to the end of the block */
      81      496208 :         if (pos_size < state->block_size) {
      82      206294 :                 if (memcmp(buffer + pos_size, buffer_zero + pos_size, state->block_size - pos_size) != 0) {
      83          54 :                         return -1;
      84             :                 }
      85             :         }
      86             : 
      87      496154 :         return 0;
      88             : }
      89             : 
      90             : /**
      91             :  * Check if the hash of all the failed blocks we are expecting to recover are now matching.
      92             :  */
      93      227459 : static int is_hash_matching(struct snapraid_state* state, int rehash, unsigned diskmax, struct failed_struct* failed, unsigned* failed_map, unsigned failed_count, void** buffer, void* buffer_zero)
      94             : {
      95             :         unsigned j;
      96             :         int hash_checked;
      97             : 
      98      227459 :         hash_checked = 0; /* keep track if we check at least one block */
      99             : 
     100             :         /* check if the recovered blocks are OK */
     101      728176 :         for (j = 0; j < failed_count; ++j) {
     102             :                 /* if we are expected to recover this block */
     103      516452 :                 if (!failed[failed_map[j]].is_outofdate
     104             :                         /* if the block has a hash to check */
     105      511889 :                         && block_has_updated_hash(failed[failed_map[j]].block)
     106             :                 ) {
     107             :                         /* if a hash doesn't match, fail the check */
     108      511889 :                         unsigned pos_size = file_block_size(failed[failed_map[j]].file, failed[failed_map[j]].file_pos, state->block_size);
     109      511889 :                         if (blockcmp(state, rehash, failed[failed_map[j]].block, pos_size, buffer[failed[failed_map[j]].index], buffer_zero) != 0) {
     110       15735 :                                 log_tag("repair_hash_error:%u: Hash mismatch\n", failed_map[j]);
     111       15735 :                                 return 0;
     112             :                         }
     113             : 
     114      496154 :                         hash_checked = 1;
     115             :                 }
     116             :         }
     117             : 
     118             :         /*
     119             :          * If nothing checked, we reject it
     120             :          * note that we are excluding this case at upper level
     121             :          * but checking again doesn't hurt
     122             :          */
     123      211724 :         if (!hash_checked) {
     124             :                 /* LCOV_EXCL_START */
     125             :                 return 0;
     126             :                 /* LCOV_EXCL_STOP */
     127             :         }
     128             : 
     129             :         /*
     130             :          * If we checked something, and no block failed the check
     131             :          * recompute all the redundancy information
     132             :          */
     133      211724 :         raid_gen(diskmax, state->level, state->block_size, buffer);
     134      211724 :         return 1;
     135             : }
     136             : 
     137             : /**
     138             :  * Check if specified parity is now matching with a recomputed one.
     139             :  */
     140           8 : static int is_parity_matching(struct snapraid_state* state, unsigned diskmax, unsigned i, void** buffer, void** buffer_recov)
     141             : {
     142             :         /* recompute parity, note that we don't need parity over i */
     143           8 :         raid_gen(diskmax, i + 1, state->block_size, buffer);
     144             : 
     145             :         /* if the recovered parity block matches */
     146           8 :         if (memcmp(buffer[diskmax + i], buffer_recov[i], state->block_size) == 0) {
     147             :                 /* recompute all the redundancy information */
     148           8 :                 raid_gen(diskmax, state->level, state->block_size, buffer);
     149           8 :                 return 1;
     150             :         }
     151             : 
     152           0 :         return 0;
     153             : }
     154             : 
     155             : /**
     156             :  * Repair errors.
     157             :  * Return <0 if failure for missing strategy, >0 if data is wrong and we cannot rebuild correctly, 0 on success.
     158             :  * If success, the parity is computed in the buffer variable.
     159             :  */
     160      269628 : static int repair_step(struct snapraid_state* state, int rehash, unsigned pos, unsigned diskmax, struct failed_struct* failed, unsigned* failed_map, unsigned failed_count, void** buffer, void** buffer_recov, void* buffer_zero)
     161             : {
     162             :         unsigned i, n;
     163             :         int error;
     164             :         int has_hash;
     165             :         int id[LEV_MAX];
     166             :         int ip[LEV_MAX];
     167             : 
     168             :         /* no fix required, already checked at higher level, but just to be sure */
     169      269628 :         if (failed_count == 0) {
     170             :                 /* LCOV_EXCL_START */
     171             :                 /* recompute only the parity */
     172             :                 raid_gen(diskmax, state->level, state->block_size, buffer);
     173             :                 return 0;
     174             :                 /* LCOV_EXCL_STOP */
     175             :         }
     176             : 
     177      269628 :         n = state->level;
     178      269628 :         error = 0;
     179             : 
     180             :         /* setup vector of failed disk indexes */
     181      950945 :         for (i = 0; i < failed_count; ++i)
     182      681317 :                 id[i] = failed[failed_map[i]].index;
     183             : 
     184             :         /*
     185             :          * Check if there is at least a failed block that can be checked for correctness using the hash
     186             :          * if there isn't, we have to sacrifice a parity block to check that the result is correct
     187             :          */
     188      269628 :         has_hash = 0;
     189      950945 :         for (i = 0; i < failed_count; ++i) {
     190             :                 /* if we are expected to recover this block */
     191      681317 :                 if (!failed[failed_map[i]].is_outofdate
     192             :                         /* if the block has a hash to check */
     193      672191 :                         && block_has_updated_hash(failed[failed_map[i]].block)
     194             :                 )
     195      672183 :                         has_hash = 1;
     196             :         }
     197             : 
     198             :         /*
     199             :          * If we don't have a hash, but we have an extra parity
     200             :          * (strictly-less failures than number of parities)
     201             :          */
     202      269628 :         if (!has_hash && failed_count < n) {
     203             :                 /* number of parity to use, one more to check the recovering */
     204           8 :                 unsigned r = failed_count + 1;
     205             : 
     206             :                 /* all combinations (r of n) parities */
     207           8 :                 combination_first(r, n, ip);
     208             :                 do {
     209             :                         /* if a parity is missing, do nothing */
     210          24 :                         for (i = 0; i < r; ++i) {
     211          16 :                                 if (buffer_recov[ip[i]] == 0)
     212           0 :                                         break;
     213             :                         }
     214           8 :                         if (i != r)
     215           0 :                                 continue;
     216             : 
     217             :                         /* copy the parities to use, one less because the last is used for checking */
     218          16 :                         for (i = 0; i < r - 1; ++i)
     219           8 :                                 memcpy(buffer[diskmax + ip[i]], buffer_recov[ip[i]], state->block_size);
     220             : 
     221             :                         /* recover using one less parity, the ip[r-1] one */
     222           8 :                         raid_data(r - 1, id, ip, diskmax, state->block_size, buffer);
     223             : 
     224             :                         /* use the remaining ip[r-1] parity to check the result */
     225           8 :                         if (is_parity_matching(state, diskmax, ip[r - 1], buffer, buffer_recov))
     226           8 :                                 return 0;
     227             : 
     228             :                         /* log */
     229           0 :                         log_tag("recover_parity_error:%u:", pos);
     230           0 :                         for (i = 0; i < r; ++i) {
     231           0 :                                 if (i != 0)
     232           0 :                                         log_tag(",");
     233           0 :                                 log_tag("%s", lev_config_name(ip[i]));
     234             :                         }
     235           0 :                         log_tag(": Parity mismatch\n");
     236           0 :                         ++error;
     237           0 :                 } while (combination_next(r, n, ip));
     238             :         }
     239             : 
     240             :         /*
     241             :          * If we have a hash, and enough parities
     242             :          * (less-or-equal failures than number of parities)
     243             :          */
     244      269620 :         if (has_hash && failed_count <= n) {
     245             :                 /* number of parities to use equal to the number of failures */
     246      222150 :                 unsigned r = failed_count;
     247             : 
     248             :                 /* all combinations (r of n) parities */
     249      222150 :                 combination_first(r, n, ip);
     250             :                 do {
     251             :                         /* if a parity is missing, do nothing */
     252      748664 :                         for (i = 0; i < r; ++i) {
     253      521205 :                                 if (buffer_recov[ip[i]] == 0)
     254        4753 :                                         break;
     255             :                         }
     256      232212 :                         if (i != r)
     257        4753 :                                 continue;
     258             : 
     259             :                         /* copy the parities to use */
     260      743911 :                         for (i = 0; i < r; ++i)
     261      516452 :                                 memcpy(buffer[diskmax + ip[i]], buffer_recov[ip[i]], state->block_size);
     262             : 
     263             :                         /* recover */
     264      227459 :                         raid_data(r, id, ip, diskmax, state->block_size, buffer);
     265             : 
     266             :                         /* use the hash to check the result */
     267      227459 :                         if (is_hash_matching(state, rehash, diskmax, failed, failed_map, failed_count, buffer, buffer_zero))
     268      211724 :                                 return 0;
     269             : 
     270             :                         /* log */
     271       15735 :                         log_tag("recover_hash_error:%u:", pos);
     272       31470 :                         for (i = 0; i < r; ++i) {
     273       15735 :                                 if (i != 0)
     274           0 :                                         log_tag("/");
     275       15735 :                                 log_tag("%s", lev_config_name(ip[i]));
     276             :                         }
     277       15735 :                         log_tag(": Hash mismatch\n");
     278       15735 :                         ++error;
     279       40976 :                 } while (combination_next(r, n, ip));
     280             :         }
     281             : 
     282             :         /* return the number of failed attempts, or -1 if no strategy */
     283       57896 :         if (error)
     284       10426 :                 return error;
     285             : 
     286       47470 :         log_tag("recover_strategy_error:%u: No strategy to recover from %u failures with %u parity %s hash\n",
     287             :                 pos, failed_count, n, has_hash ? "with" : "without");
     288       47470 :         return -1;
     289             : }
     290             : 
     291      913667 : static int repair(struct snapraid_state* state, int rehash, unsigned pos, unsigned diskmax, struct failed_struct* failed, unsigned* failed_map, unsigned failed_count, void** buffer, void** buffer_recov, void* buffer_zero)
     292             : {
     293             :         int ret;
     294             :         int error;
     295             :         unsigned j;
     296             :         int n;
     297             :         int something_to_recover;
     298             :         int something_unsynced;
     299             :         char esc_buffer[ESC_MAX];
     300             : 
     301      913667 :         error = 0;
     302             : 
     303             :         /* if nothing failed, just recompute the parity */
     304      913667 :         if (failed_count == 0) {
     305      608377 :                 raid_gen(diskmax, state->level, state->block_size, buffer);
     306      608377 :                 return 0;
     307             :         }
     308             : 
     309             :         /* logs the status */
     310     1077440 :         for (j = 0; j < failed_count; ++j) {
     311             :                 const char* desc;
     312             :                 const char* hash;
     313             :                 const char* data;
     314      772150 :                 struct snapraid_block* block = failed[j].block;
     315      772150 :                 unsigned block_state = block_state_get(block);
     316             : 
     317      772150 :                 switch (block_state) {
     318       19434 :                 case BLOCK_STATE_DELETED : desc = "delete"; break;
     319       16227 :                 case BLOCK_STATE_CHG : desc = "change"; break;
     320       60632 :                 case BLOCK_STATE_REP : desc = "replace"; break;
     321      675857 :                 case BLOCK_STATE_BLK : desc = "block"; break;
     322             :                 /* LCOV_EXCL_START */
     323             :                 default : desc = "unknown"; break;
     324             :                         /* LCOV_EXCL_STOP */
     325             :                 }
     326             : 
     327      772150 :                 if (hash_is_invalid(block->hash)) {
     328           0 :                         hash = "lost";
     329      772150 :                 } else if (hash_is_zero(block->hash)) {
     330       13175 :                         hash = "zero";
     331             :                 } else {
     332      758975 :                         hash = "known";
     333             :                 }
     334             : 
     335      772150 :                 if (failed[j].is_bad)
     336      684349 :                         data = "bad";
     337             :                 else
     338       87801 :                         data = "good";
     339             : 
     340      772150 :                 if (failed[j].file) {
     341      752716 :                         struct snapraid_disk* disk = failed[j].disk;
     342      752716 :                         struct snapraid_file* file = failed[j].file;
     343      752716 :                         block_off_t file_pos = failed[j].file_pos;
     344             : 
     345      752716 :                         log_tag("repair_entry:%u:%s:%s:%s:%s:%s:%u:\n", j, desc, hash, data, disk->name, esc_tag(file->sub, esc_buffer), file_pos);
     346             :                 } else {
     347       19434 :                         log_tag("repair_entry:%u:%s:%s:%s:\n", j, desc, hash, data);
     348             :                 }
     349             :         }
     350             : 
     351             :         /*
     352             :          * Here we have to try two different strategies to recover, because in case the 'sync'
     353             :          * process is aborted, we don't know if the parity data is really updated just like after 'sync',
     354             :          * or if it still represents the state before the 'sync'.
     355             :          */
     356             : 
     357             :         /*
     358             :          * Note that if the 'sync' ends normally, we don't have any DELETED, REP and CHG blocks
     359             :          * and the two strategies are identical
     360             :          */
     361             : 
     362             :         /*
     363             :          * As first, we assume that the parity IS updated for the current state
     364             :          * and that we are going to recover the state after the last 'sync'.
     365             :          * In this case, parity contains info from BLK, REP and CHG blocks,
     366             :          * but not for DELETED.
     367             :          * We need to put in the recovering process only the bad blocks, because all the
     368             :          * others already contains the correct data read from disk, and the parity is correctly computed for them.
     369             :          * We are interested to recover BLK, REP and CHG blocks if they are marked as bad,
     370             :          * but we are not interested in DELETED ones.
     371             :          */
     372             : 
     373      305290 :         n = 0;
     374      305290 :         something_to_recover = 0; /* keep track if there is at least one block to fix */
     375     1077440 :         for (j = 0; j < failed_count; ++j) {
     376      772150 :                 if (failed[j].is_bad) {
     377      684349 :                         unsigned block_state = block_state_get(failed[j].block);
     378             : 
     379      684349 :                         assert(block_state != BLOCK_STATE_DELETED); /* we cannot have bad DELETED blocks */
     380             : 
     381             :                         /* if we have the hash for it */
     382      684349 :                         if ((block_state == BLOCK_STATE_BLK || block_state == BLOCK_STATE_REP)
     383             :                                 /* try to fetch the block using the known hash */
     384      684341 :                                 && (state_import_fetch(state, rehash, failed[j].block, buffer[failed[j].index]) == 0
     385      679808 :                                 || state_search_fetch(state, rehash, failed[j].file, failed[j].file_pos, failed[j].block, buffer[failed[j].index]) == 0)
     386             :                         ) {
     387             :                                 /* we already have corrected it! */
     388       22211 :                                 log_tag("repair_hash_import:%u: Fixed by import\n", j);
     389             :                         } else {
     390             :                                 /* otherwise try to recover it */
     391      662138 :                                 failed_map[n] = j;
     392      662138 :                                 ++n;
     393             : 
     394             :                                 /* we have something to try to recover */
     395      662138 :                                 something_to_recover = 1;
     396             :                         }
     397             :                 }
     398             :         }
     399             : 
     400             :         /* if nothing to fix */
     401      305290 :         if (!something_to_recover) {
     402       45715 :                 log_tag("recover_sync:%u:%u: Skipped for already recovered\n", pos, n);
     403             : 
     404             :                 /* recompute only the parity */
     405       45715 :                 raid_gen(diskmax, state->level, state->block_size, buffer);
     406       45715 :                 return 0;
     407             :         }
     408             : 
     409      259575 :         ret = repair_step(state, rehash, pos, diskmax, failed, failed_map, n, buffer, buffer_recov, buffer_zero);
     410      259575 :         if (ret == 0) {
     411             :                 /*
     412             :                  * Reprocess the CHG blocks, for which we don't have a hash to check
     413             :                  * if they were BAD we have to use some heuristics to ensure that we have recovered
     414             :                  * the state after the sync. If unsure, we assume the worst case
     415             :                  */
     416             : 
     417      723740 :                 for (j = 0; j < failed_count; ++j) {
     418             :                         /* we take care only of BAD blocks we have to write back */
     419      517498 :                         if (failed[j].is_bad) {
     420      503594 :                                 unsigned block_state = block_state_get(failed[j].block);
     421             : 
     422             :                                 /*
     423             :                                  * BLK and REP blocks are always OK, because at this point
     424             :                                  * we have already checked their hash
     425             :                                  */
     426      503594 :                                 if (block_state != BLOCK_STATE_CHG) {
     427      503586 :                                         assert(block_state == BLOCK_STATE_BLK || block_state == BLOCK_STATE_REP);
     428      503586 :                                         continue;
     429             :                                 }
     430             : 
     431             :                                 /* for CHG blocks we have to 'guess' if they are correct or not */
     432             : 
     433             :                                 /*
     434             :                                  * If the hash is invalid we cannot check the result
     435             :                                  * this could happen if we have lost this information
     436             :                                  * after an aborted sync
     437             :                                  */
     438           8 :                                 if (hash_is_invalid(failed[j].block->hash)) {
     439             :                                         /* it may contain garbage */
     440           0 :                                         failed[j].is_outofdate = 1;
     441             : 
     442           0 :                                         log_tag("repair:hash_unknown:%u: Unknown hash\n", j);
     443           8 :                                 } else if (hash_is_zero(failed[j].block->hash)) {
     444             :                                         /*
     445             :                                          * If the block is not filled with 0, we are sure to have
     446             :                                          * restored it to the state after the 'sync'
     447             :                                          * instead, if the block is filled with 0, it could be either that the
     448             :                                          * block after the sync is really filled by 0, or that
     449             :                                          * we restored the block before the 'sync'.
     450             :                                          */
     451           8 :                                         if (memcmp(buffer[failed[j].index], buffer_zero, state->block_size) == 0) {
     452             :                                                 /* it may contain garbage */
     453           8 :                                                 failed[j].is_outofdate = 1;
     454             : 
     455           8 :                                                 log_tag("repair_hash_unknown:%u: Maybe old zero\n", j);
     456             :                                         }
     457             :                                 } else {
     458             :                                         /*
     459             :                                          * If the hash is different than the previous one, we are sure to have
     460             :                                          * restored it to the state after the 'sync'
     461             :                                          * instead, if the hash matches, it could be either that the
     462             :                                          * block after the sync has this hash, or that
     463             :                                          * we restored the block before the 'sync'.
     464             :                                          */
     465           0 :                                         unsigned pos_size = file_block_size(failed[j].file, failed[j].file_pos, state->block_size);
     466           0 :                                         if (blockcmp(state, rehash, failed[j].block, pos_size, buffer[failed[j].index], buffer_zero) == 0) {
     467             :                                                 /* it may contain garbage */
     468           0 :                                                 failed[j].is_outofdate = 1;
     469             : 
     470           0 :                                                 log_tag("repair_hash_unknown:%u: Maybe old data\n", j);
     471             :                                         }
     472             :                                 }
     473             :                         }
     474             :                 }
     475             : 
     476      206242 :                 return 0;
     477             :         }
     478       53333 :         if (ret > 0)
     479       10426 :                 error += ret;
     480             : 
     481       53333 :         if (ret < 0)
     482       42907 :                 log_tag("recover_sync:%u:%u: Failed with no attempts\n", pos, n);
     483             :         else
     484       10426 :                 log_tag("recover_sync:%u:%u: Failed with %d attempts\n", pos, n, ret);
     485             : 
     486             :         /*
     487             :          * Now assume that the parity IS NOT updated at the current state,
     488             :          * but still represent the state before the last 'sync' process.
     489             :          * In this case, parity contains info from BLK, REP (old version), CHG (old version) and DELETED blocks,
     490             :          * but not for REP (new version) and CHG (new version).
     491             :          * We are interested to recover BLK ones marked as bad,
     492             :          * but we are not interested to recover CHG (new version) and REP (new version) blocks,
     493             :          * even if marked as bad, because we don't have parity for them and it's just impossible,
     494             :          * and we are not interested to recover DELETED ones.
     495             :          */
     496       53333 :         n = 0;
     497       53333 :         something_to_recover = 0; /* keep track if there is at least one block to fix */
     498       53333 :         something_unsynced = 0; /* keep track if we have some unsynced info to process */
     499      234852 :         for (j = 0; j < failed_count; ++j) {
     500      181519 :                 unsigned block_state = block_state_get(failed[j].block);
     501             : 
     502      181519 :                 if (block_state == BLOCK_STATE_DELETED
     503      172169 :                         || block_state == BLOCK_STATE_CHG
     504      171466 :                         || block_state == BLOCK_STATE_REP
     505             :                 ) {
     506             :                         /*
     507             :                          * If the block is CHG, REP or DELETED, we don't have the original content of block,
     508             :                          * and we must try to recover it.
     509             :                          * This applies to CHG and REP blocks even if they are not marked bad,
     510             :                          * because the parity is computed with old content, and not with the new one.
     511             :                          * Note that this recovering is done just to make it possible to recover any other BLK one,
     512             :                          * we are not really interested in DELETED, CHG (old version) and REP (old version).
     513             :                          */
     514       10053 :                         something_unsynced = 1;
     515             : 
     516       10053 :                         if (block_state == BLOCK_STATE_CHG
     517         703 :                                 && hash_is_zero(failed[j].block->hash)
     518             :                         ) {
     519             :                                 /*
     520             :                                  * If the block was a ZERO block, restore it to the original 0 as before the 'sync'
     521             :                                  * We do this to just allow recovering of other BLK ones
     522             :                                  */
     523             : 
     524           0 :                                 memset(buffer[failed[j].index], 0, state->block_size);
     525             :                                 /*
     526             :                                  * Note that from now the buffer is definitely lost
     527             :                                  * we can do this only because it's the last retry of recovering
     528             :                                  */
     529             : 
     530             :                                 /* try to fetch the old block using the old hash for CHG and DELETED blocks */
     531       10053 :                         } else if ((block_state == BLOCK_STATE_CHG || block_state == BLOCK_STATE_DELETED)
     532       10053 :                                 && hash_is_unique(failed[j].block->hash)
     533       10053 :                                 && state_import_fetch(state, rehash, failed[j].block, buffer[failed[j].index]) == 0) {
     534             : 
     535             :                                 /*
     536             :                                  * Note that from now the buffer is definitely lost
     537             :                                  * we can do this only because it's the last retry of recovering
     538             :                                  */
     539             :                         } else {
     540             :                                 /* otherwise try to recover it */
     541        9126 :                                 failed_map[n] = j;
     542        9126 :                                 ++n;
     543             : 
     544             :                                 /*
     545             :                                  * Note that we don't set something_to_recover, because we are
     546             :                                  * not really interested to recover *only* old blocks.
     547             :                                  */
     548             :                         }
     549             : 
     550             :                         /*
     551             :                          * Avoid using the hash of this block to verify the recovering
     552             :                          * this applies to REP blocks because we are going to recover the old state
     553             :                          * and the REP hash represents the new one
     554             :                          * it also applies to CHG and DELETE blocks because we want to have
     555             :                          * a successful recovering only if a BLK one is matching
     556             :                          */
     557       10053 :                         failed[j].is_outofdate = 1;
     558      171466 :                 } else if (failed[j].is_bad) {
     559             :                         /*
     560             :                          * If the block is bad we don't know its content, and we try to recover it
     561             :                          * At this point, we can have only BLK ones
     562             :                          */
     563             : 
     564      171466 :                         assert(block_state == BLOCK_STATE_BLK);
     565             : 
     566             :                         /* we have something we are interested to recover */
     567      171466 :                         something_to_recover = 1;
     568             : 
     569             :                         /* we try to recover it */
     570      171466 :                         failed_map[n] = j;
     571      171466 :                         ++n;
     572             :                 }
     573             :         }
     574             : 
     575             :         /*
     576             :          * If nothing to fix, we just don't try
     577             :          * if nothing unsynced we also don't retry, because it's the same try as before
     578             :          */
     579       53333 :         if (something_to_recover && something_unsynced) {
     580       10053 :                 ret = repair_step(state, rehash, pos, diskmax, failed, failed_map, n, buffer, buffer_recov, buffer_zero);
     581       10053 :                 if (ret == 0) {
     582             :                         /*
     583             :                          * Reprocess the REP and CHG blocks, for which we have recovered an old state
     584             :                          * that we don't want to save into disk
     585             :                          * we have already marked them, but we redo it for logging
     586             :                          */
     587             : 
     588       16470 :                         for (j = 0; j < failed_count; ++j) {
     589             :                                 /* we take care only of BAD blocks we have to write back */
     590       10980 :                                 if (failed[j].is_bad) {
     591        5490 :                                         unsigned block_state = block_state_get(failed[j].block);
     592             : 
     593        5490 :                                         if (block_state == BLOCK_STATE_CHG
     594        5490 :                                                 || block_state == BLOCK_STATE_REP
     595             :                                         ) {
     596             :                                                 /*
     597             :                                                  * Mark that we have restored an old state
     598             :                                                  * and we don't want to write it to the disk
     599             :                                                  */
     600           0 :                                                 failed[j].is_outofdate = 1;
     601             : 
     602           0 :                                                 log_tag("repair_hash_unknown:%u: Surely old data\n", j);
     603             :                                         }
     604             :                                 }
     605             :                         }
     606             : 
     607        5490 :                         return 0;
     608             :                 }
     609        4563 :                 if (ret > 0)
     610           0 :                         error += ret;
     611             : 
     612        4563 :                 if (ret < 0)
     613        4563 :                         log_tag("recover_unsync:%u:%u: Failed with no attempts\n", pos, n);
     614             :                 else
     615           0 :                         log_tag("recover_unsync:%u:%u: Failed with %d attempts\n", pos, n, ret);
     616             :         } else {
     617       43280 :                 log_tag("recover_unsync:%u:%u: Skipped for%s%s\n", pos, n,
     618             :                         !something_to_recover ? " nothing to recover" : "",
     619             :                         !something_unsynced ? " nothing unsynced" : ""
     620             :                 );
     621             :         }
     622             : 
     623             :         /* return the number of failed attempts, or -1 if no strategy */
     624       47843 :         if (error)
     625        4936 :                 return error;
     626             :         else
     627       42907 :                 return -1;
     628             : }
     629             : 
     630             : /**
     631             :  * Post process all the files at the specified block index ::i.
     632             :  * For each file, if we are at the last block, close it,
     633             :  * adjust the timestamp, and print the result.
     634             :  *
     635             :  * This works only if the whole file is processed, including its last block.
     636             :  * This doesn't always happen, like with an explicit end block.
     637             :  *
     638             :  * In such case, the check/fix command won't report any information of the
     639             :  * files partially checked.
     640             :  */
     641      953182 : static int file_post(struct snapraid_state* state, int fix, unsigned i, struct snapraid_handle* handle, unsigned diskmax)
     642             : {
     643             :         unsigned j;
     644             :         int ret;
     645             :         char esc_buffer[ESC_MAX];
     646             :         char esc_buffer_alt[ESC_MAX];
     647             : 
     648             :         /*
     649             :          * For all the files print the final status, and do the final time fix
     650             :          * we also ensure to close files after processing the last block
     651             :          */
     652     6643786 :         for (j = 0; j < diskmax; ++j) {
     653             :                 struct snapraid_block* block;
     654             :                 struct snapraid_disk* disk;
     655             :                 struct snapraid_file* collide_file;
     656             :                 struct snapraid_file* file;
     657             :                 block_off_t file_pos;
     658             :                 uint64_t inode;
     659             : 
     660     5690604 :                 disk = handle[j].disk;
     661     5690604 :                 if (!disk) {
     662             :                         /* if no disk, nothing to do */
     663     3471117 :                         continue;
     664             :                 }
     665             : 
     666     5676543 :                 block = fs_par2block_find(disk, i);
     667     5676543 :                 if (!block_has_file(block)) {
     668             :                         /* if no file, nothing to do */
     669      241947 :                         continue;
     670             :                 }
     671             : 
     672     5434596 :                 file = fs_par2file_get(disk, i, &file_pos);
     673             : 
     674             :                 /* if it isn't the last block in the file */
     675     5434596 :                 if (!file_block_is_last(file, file_pos)) {
     676             :                         /* nothing to do */
     677     3215109 :                         continue;
     678             :                 }
     679             : 
     680             :                 /* if the file is excluded, we have nothing to adjust as the file is never written */
     681     2219487 :                 if (file_flag_has(file, FILE_IS_EXCLUDED)
     682     2136675 :                         || (state->opt.syncedonly && file_flag_has(file, FILE_IS_UNSYNCED))) {
     683             :                         /* nothing to do, but close the file */
     684       82812 :                         goto close_and_continue;
     685             :                 }
     686             : 
     687             :                 /* finish the fix process if it's the last block of the files */
     688     2136675 :                 if (fix) {
     689             :                         /*
     690             :                          * Mark that we finished with this file
     691             :                          * to identify later any NOT finished ones
     692             :                          */
     693      784484 :                         file_flag_set(file, FILE_IS_FINISHED);
     694             : 
     695             :                         /* if the file is damaged, meaning that a fix failed */
     696      784484 :                         if (file_flag_has(file, FILE_IS_DAMAGED)) {
     697             :                                 /* rename it to .unrecoverable */
     698             :                                 char path[PATH_MAX];
     699             :                                 char path_to[PATH_MAX];
     700             : 
     701       62987 :                                 pathprint(path, sizeof(path), "%s%s", disk->dir, file->sub);
     702       62987 :                                 pathprint(path_to, sizeof(path_to), "%s%s.unrecoverable", disk->dir, file->sub);
     703             : 
     704             :                                 /* ensure to close the file before renaming */
     705       62987 :                                 if (handle[j].file == file) {
     706       62987 :                                         ret = handle_close(&handle[j]);
     707       62987 :                                         if (ret != 0) {
     708             :                                                 /* LCOV_EXCL_START */
     709             :                                                 log_tag("%s:%u:%s:%s: Close error. %s.\n", es(errno), i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno));
     710             :                                                 log_fatal_errno(errno, disk->name);
     711             :                                                 return -1;
     712             :                                                 /* LCOV_EXCL_STOP */
     713             :                                         }
     714             :                                 }
     715             : 
     716       62987 :                                 ret = rename(path, path_to);
     717       62987 :                                 if (ret != 0) {
     718             :                                         /* LCOV_EXCL_START */
     719             :                                         log_fatal(errno, "Error renaming '%s%s'. %s.\n", disk->dir, file->sub, strerror(errno));
     720             :                                         log_tag("%s:%u:%s:%s: Rename error. %s.\n", es(errno), i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno));
     721             :                                         log_fatal_errno(errno, disk->name);
     722             :                                         return -1;
     723             :                                         /* LCOV_EXCL_STOP */
     724             :                                 }
     725             : 
     726       62987 :                                 log_tag("status:unrecoverable:%s:%s\n", disk->name, esc_tag(file->sub, esc_buffer));
     727       62987 :                                 msg_info("unrecoverable %s\n", fmt_term(disk, file->sub, esc_buffer));
     728             : 
     729             :                                 /* and do not set the time if damaged */
     730       62987 :                                 goto close_and_continue;
     731             :                         }
     732             : 
     733             :                         /* if the file is not fixed, meaning that it is untouched */
     734      721497 :                         if (!file_flag_has(file, FILE_IS_FIXED)) {
     735             :                                 /* nothing to do, but close the file */
     736      589540 :                                 goto close_and_continue;
     737             :                         }
     738             : 
     739             :                         /*
     740             :                          * If the file is closed or different than the one expected, reopen it
     741             :                          * a different open file could happen when filtering for bad blocks
     742             :                          */
     743      131957 :                         if (handle[j].file != file) {
     744             :                                 /* keep a pointer at the file we are going to close for error reporting */
     745           0 :                                 struct snapraid_file* report = handle[j].file;
     746           0 :                                 ret = handle_close(&handle[j]);
     747           0 :                                 if (ret != 0) {
     748             :                                         /* LCOV_EXCL_START */
     749             :                                         log_tag("%s:%u:%s:%s: Close error. %s.\n", es(errno), i, disk->name, esc_tag(report->sub, esc_buffer), strerror(errno));
     750             :                                         log_fatal_errno(errno, disk->name);
     751             :                                         return -1;
     752             :                                         /* LCOV_EXCL_STOP */
     753             :                                 }
     754             : 
     755             :                                 /*
     756             :                                  * Reopen it as readonly, as to set the mtime readonly access it's enough
     757             :                                  * we know that the file exists because it has the FILE_IS_FIXED tag
     758             :                                  */
     759           0 :                                 ret = handle_open(&handle[j], file, state->file_mode, log_error, log_error); /* output a message for missing files */
     760           0 :                                 if (ret != 0) {
     761             :                                         /* LCOV_EXCL_START */
     762             :                                         log_tag("%s:%u:%s:%s: Open error. %s.\n", es(errno), i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno));
     763             :                                         log_fatal_errno(errno, disk->name);
     764             :                                         return -1;
     765             :                                         /* LCOV_EXCL_STOP */
     766             :                                 }
     767             :                         }
     768             : 
     769      131957 :                         log_tag("status:recovered:%s:%s\n", disk->name, esc_tag(file->sub, esc_buffer));
     770      131957 :                         msg_info("recovered %s\n", fmt_term(disk, file->sub, esc_buffer));
     771             : 
     772      131957 :                         inode = handle[j].st.st_ino;
     773             : 
     774             :                         /* search for the corresponding inode */
     775      131957 :                         collide_file = tommy_hashdyn_search(&disk->inodeset, file_inode_compare_to_arg, &inode, file_inode_hash(inode));
     776             : 
     777             :                         /*
     778             :                          * If the inode is already in the database and it refers to a different file name,
     779             :                          * we can fix the file time ONLY if the time and size allow to differentiate
     780             :                          * between the two files
     781             :                          *
     782             :                          * For example, suppose we delete a bunch of files with all the same size and time,
     783             :                          * when recreating them the inodes may be reused in a different order,
     784             :                          * and at the next sync some files may have matching inode/size/time even if different name
     785             :                          * not allowing sync to detect that the file is changed and not renamed
     786             :                          */
     787      131957 :                         if (!collide_file /* if not in the database, there is no collision */
     788       37370 :                                 || strcmp(collide_file->sub, file->sub) == 0 /* if the name is the same, it's the right collision */
     789       27768 :                                 || collide_file->size != file->size /* if the size is different, the collision is identified */
     790          14 :                                 || collide_file->mtime_sec != file->mtime_sec /* if the mtime is different, the collision is identified */
     791           9 :                                 || collide_file->mtime_nsec != file->mtime_nsec /* same for mtime_nsec */
     792             :                         ) {
     793             :                                 /* set the original modification time */
     794      131956 :                                 ret = handle_utime(&handle[j]);
     795      131956 :                                 if (ret == -1) {
     796             :                                         /* LCOV_EXCL_START */
     797             :                                         log_tag("%s:%u:%s:%s: Time error. %s.\n", es(errno), i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno));
     798             :                                         log_fatal_errno(errno, disk->name);
     799             : 
     800             :                                         /* mark the file as damaged */
     801             :                                         file_flag_set(file, FILE_IS_DAMAGED);
     802             :                                         return -1;
     803             :                                         /* LCOV_EXCL_STOP */
     804             :                                 }
     805             :                         } else {
     806           1 :                                 log_tag("collision:%s:%s:%s: Not setting modification time to avoid inode collision\n", disk->name, esc_tag(file->sub, esc_buffer), esc_tag(collide_file->sub, esc_buffer_alt));
     807             :                         }
     808             :                 } else {
     809             :                         /*
     810             :                          * We are not fixing, but only checking
     811             :                          * print just the final status
     812             :                          */
     813     1352191 :                         if (file_flag_has(file, FILE_IS_DAMAGED)) {
     814        9595 :                                 log_tag("status:unrecoverable:%s:%s\n", disk->name, esc_tag(file->sub, esc_buffer));
     815        9595 :                                 msg_info("unrecoverable %s\n", fmt_term(disk, file->sub, esc_buffer));
     816     1342596 :                         } else if (file_flag_has(file, FILE_IS_FIXED)) {
     817       84208 :                                 log_tag("status:recoverable:%s:%s\n", disk->name, esc_tag(file->sub, esc_buffer));
     818       84208 :                                 msg_info("recoverable %s\n", fmt_term(disk, file->sub, esc_buffer));
     819             :                         } else {
     820             :                                 /* we don't use msg_verbose() because it also goes into the log */
     821     1258388 :                                 if (msg_level >= MSG_VERBOSE) {
     822       23147 :                                         log_tag("status:correct:%s:%s\n", disk->name, esc_tag(file->sub, esc_buffer));
     823       23147 :                                         msg_info("correct %s\n", fmt_term(disk, file->sub, esc_buffer));
     824             :                                 }
     825             :                         }
     826             :                 }
     827             : 
     828     1235241 : close_and_continue:
     829             :                 /*
     830             :                  * If the opened file is the correct one, close it
     831             :                  * in case of excluded and fragmented files it's possible
     832             :                  * that the opened file is not the current one
     833             :                  */
     834     2219487 :                 if (handle[j].file == file) {
     835             :                         /*
     836             :                          * Ensure to close the file just after finishing with it
     837             :                          * to avoid keeping it open without any possible use
     838             :                          */
     839     2069882 :                         ret = handle_close(&handle[j]);
     840     2069882 :                         if (ret != 0) {
     841             :                                 /* LCOV_EXCL_START */
     842             :                                 log_tag("%s:%u:%s:%s: Close error. %s.\n", es(errno), i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno));
     843             :                                 log_fatal_errno(errno, disk->name);
     844             :                                 return -1;
     845             :                                 /* LCOV_EXCL_STOP */
     846             :                         }
     847             :                 }
     848             :         }
     849             : 
     850      953182 :         return 0;
     851             : }
     852             : 
     853             : /**
     854             :  * Check if we have to process the specified block index ::i.
     855             :  */
     856      975899 : static int block_is_enabled(struct snapraid_state* state, block_off_t i, struct snapraid_handle* handle, unsigned diskmax)
     857             : {
     858             :         unsigned j;
     859             :         unsigned l;
     860             : 
     861             :         /* filter for bad blocks */
     862      975899 :         if (state->opt.badblockonly) {
     863             :                 snapraid_info info;
     864             : 
     865             :                 /* get block specific info */
     866           0 :                 info = info_get(&state->infoarr, i);
     867             : 
     868             :                 /*
     869             :                  * Filter specifically only for bad blocks
     870             :                  */
     871           0 :                 return info_get_bad(info);
     872             :         }
     873             : 
     874             :         /* filter for the parity */
     875      975899 :         if (state->opt.badfileonly) {
     876             :                 snapraid_info info;
     877             : 
     878             :                 /* get block specific info */
     879        9374 :                 info = info_get(&state->infoarr, i);
     880             : 
     881             :                 /*
     882             :                  * If the block is bad, it has to be processed
     883             :                  *
     884             :                  * This is not necessary in normal cases because if a block is bad,
     885             :                  * it necessary needs to have a file related to it, and files with
     886             :                  * bad blocks are fully included.
     887             :                  *
     888             :                  * But some files may be excluded by additional filter options,
     889             :                  * so it's not always true, and this ensures to always check all
     890             :                  * the bad blocks.
     891             :                  */
     892        9374 :                 if (info_get_bad(info))
     893        1772 :                         return 1;
     894             :         } else {
     895             :                 /* if a parity is not excluded, include all blocks, even unused ones */
     896     1120961 :                 for (l = 0; l < state->level; ++l) {
     897     1074281 :                         if (!state->parity[l].is_excluded_by_filter) {
     898      919845 :                                 return 1;
     899             :                         }
     900             :                 }
     901             :         }
     902             : 
     903             :         /* filter for the files */
     904      240006 :         for (j = 0; j < diskmax; ++j) {
     905             :                 struct snapraid_block* block;
     906             : 
     907             :                 /* if no disk, nothing to check */
     908      217289 :                 if (!handle[j].disk)
     909           0 :                         continue;
     910             : 
     911      217289 :                 block = fs_par2block_find(handle[j].disk, i);
     912             : 
     913             :                 /*
     914             :                  * Try to recover all files, even the ones without hash
     915             :                  * because in some cases we can recover also them
     916             :                  */
     917      217289 :                 if (block_has_file(block)) {
     918      210825 :                         struct snapraid_file* file = fs_par2file_get(handle[j].disk, i, 0);
     919      210825 :                         if (!file_flag_has(file, FILE_IS_EXCLUDED)) { /* only if the file is not filtered out */
     920       31565 :                                 return 1;
     921             :                         }
     922             :                 }
     923             :         }
     924             : 
     925       22717 :         return 0;
     926             : }
     927             : 
     928         132 : static int state_check_process(struct snapraid_state* state, int fix, struct snapraid_parity_handle** parity, block_off_t blockstart, block_off_t blockmax)
     929             : {
     930             :         struct snapraid_handle* handle;
     931             :         unsigned diskmax;
     932             :         block_off_t i;
     933             :         unsigned j;
     934             :         void* buffer_alloc;
     935             :         void** buffer;
     936             :         unsigned buffermax;
     937             :         int ret;
     938             :         data_off_t countsize;
     939             :         block_off_t countpos;
     940             :         block_off_t countmax;
     941             :         unsigned soft_error;
     942             :         unsigned io_error;
     943             :         unsigned silent_error;
     944             :         unsigned unrecoverable_error;
     945             :         unsigned recovered_error;
     946             :         struct failed_struct* failed;
     947             :         unsigned* failed_map;
     948             :         unsigned l;
     949             :         char esc_buffer[ESC_MAX];
     950             :         char esc_buffer_alt[ESC_MAX];
     951             :         bit_vect_t* block_enabled;
     952             :         struct snapraid_bw bw;
     953             : 
     954         132 :         handle = handle_mapping(state, &diskmax);
     955             : 
     956             :         /* initialize the bandwidth context */
     957         132 :         bw_init(&bw, state->opt.bwlimit);
     958             : 
     959             :         /* share the bandwidth context with all handles */
     960         894 :         for (j = 0; j < diskmax; ++j)
     961         762 :                 handle[j].bw = &bw;
     962         626 :         for (j = 0; j < state->level; ++j)
     963         494 :                 if (parity[j])
     964         476 :                         parity[j]->bw = &bw;
     965             : 
     966             :         /* we need 1 * data + 2 * parity + 1 * zero */
     967         132 :         buffermax = diskmax + 2 * state->level + 1;
     968             : 
     969         132 :         buffer = malloc_nofail_vector_align(diskmax, buffermax, state->block_size, &buffer_alloc);
     970         132 :         if (!state->opt.skip_self)
     971           0 :                 mtest_vector(buffermax, state->block_size, buffer);
     972             : 
     973             :         /* fill up the zero buffer */
     974         132 :         memset(buffer[buffermax - 1], 0, state->block_size);
     975         132 :         raid_zero(buffer[buffermax - 1]);
     976             : 
     977         132 :         failed = malloc_nofail(diskmax * sizeof(struct failed_struct));
     978         132 :         failed_map = malloc_nofail(diskmax * sizeof(unsigned));
     979             : 
     980         132 :         soft_error = 0;
     981         132 :         io_error = 0;
     982         132 :         silent_error = 0;
     983         132 :         unrecoverable_error = 0;
     984         132 :         recovered_error = 0;
     985             : 
     986         132 :         msg_progress("Selecting...\n");
     987             : 
     988             :         /* first count the number of blocks to process */
     989         132 :         countmax = 0;
     990         132 :         block_enabled = calloc_nofail(1, bit_vect_size(blockmax)); /* preinitialize to 0 */
     991      976031 :         for (i = blockstart; i < blockmax; ++i) {
     992      975899 :                 if (!block_is_enabled(state, i, handle, diskmax))
     993       22717 :                         continue;
     994      953182 :                 bit_vect_set(block_enabled, i);
     995      953182 :                 ++countmax;
     996             :         }
     997             : 
     998         132 :         if (fix)
     999          51 :                 msg_progress("Fixing...\n");
    1000          81 :         else if (!state->opt.auditonly)
    1001          76 :                 msg_progress("Checking...\n");
    1002             :         else
    1003           5 :                 msg_progress("Hashing...\n");
    1004             : 
    1005             :         /* check all the blocks in files */
    1006         132 :         countsize = 0;
    1007         132 :         countpos = 0;
    1008             : 
    1009         132 :         int alert = state_progress_begin(state, blockstart, blockmax, countmax);
    1010         132 :         if (alert > 0)
    1011           0 :                 goto end;
    1012         132 :         if (alert < 0)
    1013           0 :                 goto bail;
    1014             : 
    1015      976031 :         for (i = blockstart; i < blockmax; ++i) {
    1016             :                 unsigned failed_count;
    1017             :                 int valid_parity;
    1018             :                 int used_parity;
    1019             :                 snapraid_info info;
    1020             :                 int rehash;
    1021             : 
    1022      975899 :                 if (!bit_vect_test(block_enabled, i)) {
    1023             :                         /* continue with the next block */
    1024       22717 :                         continue;
    1025             :                 }
    1026             : 
    1027             :                 /*
    1028             :                  * If we have valid parity, and it makes sense to check its content.
    1029             :                  * If we already know that the parity is invalid, we just read the file
    1030             :                  * but we don't report parity errors
    1031             :                  * Note that with auditonly, we anyway skip the full parity check,
    1032             :                  * because we also don't read it at all
    1033             :                  */
    1034      953182 :                 valid_parity = 1;
    1035             : 
    1036             :                 /* If the parity is used by at least one file */
    1037      953182 :                 used_parity = 0;
    1038             : 
    1039             :                 /* keep track of the number of failed blocks */
    1040      953182 :                 failed_count = 0;
    1041             : 
    1042             :                 /* get block specific info */
    1043      953182 :                 info = info_get(&state->infoarr, i);
    1044             : 
    1045             :                 /* if we have to use the old hash */
    1046      953182 :                 rehash = info_get_rehash(info);
    1047             : 
    1048             :                 /* for each disk, process the block */
    1049     6643786 :                 for (j = 0; j < diskmax; ++j) {
    1050             :                         int read_size;
    1051             :                         unsigned char hash[HASH_MAX];
    1052             :                         struct snapraid_disk* disk;
    1053             :                         struct snapraid_block* block;
    1054             :                         struct snapraid_file* file;
    1055             :                         block_off_t file_pos;
    1056             :                         unsigned block_state;
    1057             : 
    1058             :                         /* if the disk position is not used */
    1059     5690604 :                         disk = handle[j].disk;
    1060     5690604 :                         if (!disk) {
    1061             :                                 /* use an empty block */
    1062       14061 :                                 memset(buffer[j], 0, state->block_size);
    1063     1014777 :                                 continue;
    1064             :                         }
    1065             : 
    1066             :                         /* if the disk block is not used */
    1067     5676543 :                         block = fs_par2block_find(disk, i);
    1068     5676543 :                         if (block == BLOCK_NULL) {
    1069             :                                 /* use an empty block */
    1070      222513 :                                 memset(buffer[j], 0, state->block_size);
    1071      222513 :                                 continue;
    1072             :                         }
    1073             : 
    1074             :                         /* get the state of the block */
    1075     5454030 :                         block_state = block_state_get(block);
    1076             : 
    1077             :                         /* if the parity is not valid */
    1078     5454030 :                         if (block_has_invalid_parity(block)) {
    1079             :                                 /*
    1080             :                                  * Mark the parity as invalid, and don't try to check/fix it
    1081             :                                  * because it will be recomputed at the next sync
    1082             :                                  */
    1083       96293 :                                 valid_parity = 0;
    1084             :                                 /* follow */
    1085             :                         }
    1086             : 
    1087             :                         /* if the block is DELETED */
    1088     5454030 :                         if (block_state == BLOCK_STATE_DELETED) {
    1089             :                                 /* use an empty block */
    1090       19434 :                                 memset(buffer[j], 0, state->block_size);
    1091             : 
    1092             :                                 /*
    1093             :                                  * Store it in the failed set, because potentially
    1094             :                                  * the parity may be still computed with the previous content
    1095             :                                  */
    1096       19434 :                                 failed[failed_count].is_bad = 0; /* note that is_bad==0 <=> file==0 */
    1097       19434 :                                 failed[failed_count].is_outofdate = 0;
    1098       19434 :                                 failed[failed_count].index = j;
    1099       19434 :                                 failed[failed_count].block = block;
    1100       19434 :                                 failed[failed_count].disk = disk;
    1101       19434 :                                 failed[failed_count].file = 0;
    1102       19434 :                                 failed[failed_count].file_pos = 0;
    1103       19434 :                                 failed[failed_count].handle = 0;
    1104       19434 :                                 ++failed_count;
    1105       19434 :                                 continue;
    1106             :                         }
    1107             : 
    1108             :                         /* here we are sure that the parity is used by a file */
    1109     5434596 :                         used_parity = 1;
    1110             : 
    1111             :                         /* get the file of this block */
    1112     5434596 :                         file = fs_par2file_get(disk, i, &file_pos);
    1113             : 
    1114             :                         /* if we are only hashing, we can skip excluded files and don't even read them */
    1115     5434596 :                         if (state->opt.auditonly && file_flag_has(file, FILE_IS_EXCLUDED)) {
    1116             :                                 /*
    1117             :                                  * Use an empty block
    1118             :                                  * in true, this is unnecessary, because we are not checking any parity
    1119             :                                  * but we keep it for completeness
    1120             :                                  */
    1121           0 :                                 memset(buffer[j], 0, state->block_size);
    1122           0 :                                 continue;
    1123             :                         }
    1124             : 
    1125             :                         /* if the file is closed or different than the current one */
    1126     5434596 :                         if (handle[j].file == 0 || handle[j].file != file) {
    1127             :                                 /* keep a pointer at the file we are going to close for error reporting */
    1128     2363483 :                                 struct snapraid_file* report = handle[j].file;
    1129     2363483 :                                 ret = handle_close(&handle[j]);
    1130     2363483 :                                 if (ret == -1) {
    1131             :                                         /* LCOV_EXCL_START */
    1132             :                                         log_tag("%s:%u:%s:%s: Close error. %s.\n", es(errno), i, disk->name, esc_tag(report->sub, esc_buffer), strerror(errno));
    1133             :                                         log_fatal_errno(errno, disk->name);
    1134             :                                         log_fatal(errno, "Stopping at block %u\n", i);
    1135             : 
    1136             :                                         ++unrecoverable_error;
    1137             :                                         goto bail;
    1138             :                                         /* LCOV_EXCL_STOP */
    1139             :                                 }
    1140             : 
    1141             :                                 /* if fixing, and the file is not excluded, we must open for writing */
    1142     2363483 :                                 if (fix && !file_flag_has(file, FILE_IS_EXCLUDED)) {
    1143             :                                         /* if fixing, create the file, open for writing and resize if required */
    1144      790591 :                                         ret = handle_create(&handle[j], file, state->file_mode);
    1145      790591 :                                         if (ret == -1) {
    1146             :                                                 /* LCOV_EXCL_START */
    1147             :                                                 log_tag("%s:%u:%s:%s: Create error. %s.\n", es(errno), i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno));
    1148             :                                                 log_fatal_errno(errno, disk->name);
    1149             :                                                 log_fatal(errno, "Stopping at block %u\n", i);
    1150             : 
    1151             :                                                 ++unrecoverable_error;
    1152             :                                                 goto bail;
    1153             :                                                 /* LCOV_EXCL_STOP */
    1154             :                                         }
    1155             : 
    1156             :                                         /* check if the file was just created */
    1157      790591 :                                         if (handle[j].created != 0) {
    1158             :                                                 /*
    1159             :                                                  * If fragmented, it may be reopened, so remember that the file
    1160             :                                                  * was originally missing
    1161             :                                                  */
    1162      123783 :                                                 file_flag_set(file, FILE_IS_CREATED);
    1163             :                                         }
    1164             :                                 } else {
    1165             :                                         /* open the file only for reading */
    1166     1572892 :                                         if (!file_flag_has(file, FILE_IS_MISSING)) {
    1167     1445287 :                                                 ret = handle_open(&handle[j], file, state->file_mode, log_error, state->opt.expected_missing ? log_expected : 0);
    1168             :                                         } else {
    1169      127605 :                                                 errno = ENOENT;
    1170      127605 :                                                 ret = -1; /* if the file is missing, we cannot open it */
    1171             :                                         }
    1172     1572892 :                                         if (ret == -1) {
    1173             :                                                 /* save the failed block for the check/fix */
    1174      214224 :                                                 failed[failed_count].is_bad = 1;
    1175      214224 :                                                 failed[failed_count].is_outofdate = 0;
    1176      214224 :                                                 failed[failed_count].index = j;
    1177      214224 :                                                 failed[failed_count].block = block;
    1178      214224 :                                                 failed[failed_count].disk = disk;
    1179      214224 :                                                 failed[failed_count].file = file;
    1180      214224 :                                                 failed[failed_count].file_pos = file_pos;
    1181      214224 :                                                 failed[failed_count].handle = &handle[j];
    1182      214224 :                                                 ++failed_count;
    1183             : 
    1184      214224 :                                                 log_tag("%s:%u:%s:%s: Open error at position %u. %s.\n", es(errno), i, disk->name, esc_tag(file->sub, esc_buffer), file_pos, strerror(errno));
    1185             : 
    1186      214224 :                                                 if (is_hw(errno)) {
    1187           0 :                                                         ++io_error;
    1188             :                                                 } else {
    1189      214224 :                                                         ++soft_error;
    1190             :                                                 }
    1191             : 
    1192             :                                                 /*
    1193             :                                                  * Mark the file as missing, to avoid to retry to open it again
    1194             :                                                  * note that this can be done only if we are not fixing it
    1195             :                                                  * otherwise, it could be recreated
    1196             :                                                  */
    1197      214224 :                                                 file_flag_set(file, FILE_IS_MISSING);
    1198      214224 :                                                 continue;
    1199             :                                         }
    1200             :                                 }
    1201             : 
    1202             :                                 /* if it's the first open, and not excluded */
    1203     2149259 :                                 if (!file_flag_has(file, FILE_IS_OPENED)
    1204     2132967 :                                         && !file_flag_has(file, FILE_IS_EXCLUDED)) {
    1205             : 
    1206             :                                         /* check if the file is changed */
    1207     2053770 :                                         if (handle[j].st.st_size != file->size
    1208     1850913 :                                                 || handle[j].st.st_mtime != file->mtime_sec
    1209     1828045 :                                                 || STAT_NSEC(&handle[j].st) != file->mtime_nsec
    1210             :                                                 /* don't check the inode to support file-system without persistent inodes */
    1211             :                                         ) {
    1212             :                                                 /* report that the file is not synced */
    1213      225725 :                                                 file_flag_set(file, FILE_IS_UNSYNCED);
    1214             :                                         }
    1215             :                                 }
    1216             : 
    1217             :                                 /* if it's the first open, and not excluded and larger */
    1218     2149259 :                                 if (!file_flag_has(file, FILE_IS_OPENED)
    1219     2132967 :                                         && !file_flag_has(file, FILE_IS_EXCLUDED)
    1220     2053770 :                                         && !(state->opt.syncedonly && file_flag_has(file, FILE_IS_UNSYNCED))
    1221     2053770 :                                         && handle[j].st.st_size > file->size
    1222             :                                 ) {
    1223        8473 :                                         log_error(ESOFT, "File '%s' is larger than expected.\n", handle[j].path);
    1224        8473 :                                         log_tag("error:%u:%s:%s: Size error\n", i, disk->name, esc_tag(file->sub, esc_buffer));
    1225        8473 :                                         ++soft_error;
    1226             : 
    1227        8473 :                                         if (fix) {
    1228        3131 :                                                 ret = handle_truncate(&handle[j], file);
    1229        3131 :                                                 if (ret == -1) {
    1230             :                                                         /* LCOV_EXCL_START */
    1231             :                                                         log_tag("%s:%u:%s:%s: Truncate error. %s.\n", es(errno), i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno));
    1232             :                                                         log_fatal_errno(errno, disk->name);
    1233             :                                                         log_fatal(errno, "Stopping at block %u\n", i);
    1234             : 
    1235             :                                                         ++unrecoverable_error;
    1236             :                                                         goto bail;
    1237             :                                                         /* LCOV_EXCL_STOP */
    1238             :                                                 }
    1239             : 
    1240        3131 :                                                 log_tag("fixed:%u:%s:%s: Fixed size\n", i, disk->name, esc_tag(file->sub, esc_buffer));
    1241        3131 :                                                 ++recovered_error;
    1242             :                                         }
    1243             :                                 }
    1244             : 
    1245             :                                 /*
    1246             :                                  * Mark the file as opened at least one time
    1247             :                                  * this is used to avoid to check the unsynced and size
    1248             :                                  * more than one time, in case the file is reopened later
    1249             :                                  */
    1250     2149259 :                                 file_flag_set(file, FILE_IS_OPENED);
    1251             :                         }
    1252             : 
    1253             :                         /* read from the file */
    1254     5220372 :                         if (file_flag_has(file, FILE_IS_MISSING)) {
    1255             :                                 /* if the file is reported missing, don't even try to read it */
    1256      267179 :                                 errno = ENOENT;
    1257      267179 :                                 read_size = -1;
    1258             :                         } else {
    1259     4953193 :                                 read_size = handle_read(&handle[j], file_pos, buffer[j], state->block_size, log_error, state->opt.expected_missing ? log_expected : 0);
    1260             :                         }
    1261     5220372 :                         if (read_size == -1) {
    1262             :                                 /* save the failed block for the check/fix */
    1263      463107 :                                 failed[failed_count].is_bad = 1; /* it's bad because we cannot read it */
    1264      463107 :                                 failed[failed_count].is_outofdate = 0;
    1265      463107 :                                 failed[failed_count].index = j;
    1266      463107 :                                 failed[failed_count].block = block;
    1267      463107 :                                 failed[failed_count].disk = disk;
    1268      463107 :                                 failed[failed_count].file = file;
    1269      463107 :                                 failed[failed_count].file_pos = file_pos;
    1270      463107 :                                 failed[failed_count].handle = &handle[j];
    1271      463107 :                                 ++failed_count;
    1272             : 
    1273      463107 :                                 log_tag("%s:%u:%s:%s: Read error at position %u. %s.\n", es(errno), i, disk->name, esc_tag(file->sub, esc_buffer), file_pos, strerror(errno));
    1274             : 
    1275      463107 :                                 if (is_hw(errno)) {
    1276           0 :                                         ++io_error;
    1277             :                                 } else {
    1278      463107 :                                         ++soft_error;
    1279             :                                 }
    1280             : 
    1281             :                                 /* if we are reading at the end, mark the file as missing to avoid to try to read it again at the next block */
    1282      463107 :                                 if (errno == ENOENT) {
    1283      453263 :                                         file_flag_set(file, FILE_IS_MISSING);
    1284             :                                 }
    1285      463107 :                                 continue;
    1286             :                         }
    1287             : 
    1288     4757265 :                         countsize += read_size;
    1289             : 
    1290             :                         /*
    1291             :                          * Always insert CHG blocks, the repair functions needs all of them
    1292             :                          * because the parity may be still referring at the old state
    1293             :                          * and the repair must be aware of it
    1294             :                          */
    1295     4757265 :                         if (block_state == BLOCK_STATE_CHG) {
    1296             :                                 /*
    1297             :                                  * We DO NOT mark them as bad to avoid to overwrite them with wrong data.
    1298             :                                  * if we don't have a hash, we always assume the first read of the block correct.
    1299             :                                  */
    1300       16219 :                                 failed[failed_count].is_bad = 0; /* we assume the CHG block correct */
    1301       16219 :                                 failed[failed_count].is_outofdate = 0;
    1302       16219 :                                 failed[failed_count].index = j;
    1303       16219 :                                 failed[failed_count].block = block;
    1304       16219 :                                 failed[failed_count].disk = disk;
    1305       16219 :                                 failed[failed_count].file = file;
    1306       16219 :                                 failed[failed_count].file_pos = file_pos;
    1307       16219 :                                 failed[failed_count].handle = &handle[j];
    1308       16219 :                                 ++failed_count;
    1309       16219 :                                 continue;
    1310             :                         }
    1311             : 
    1312     4741046 :                         assert(block_state == BLOCK_STATE_BLK || block_state == BLOCK_STATE_REP);
    1313             : 
    1314             :                         /* compute the hash of the block just read */
    1315     4741046 :                         if (rehash) {
    1316       27200 :                                 memhash(state->prevhash, state->prevhashseed, hash, buffer[j], read_size);
    1317             :                         } else {
    1318     4713846 :                                 memhash(state->hash, state->hashseed, hash, buffer[j], read_size);
    1319             :                         }
    1320             : 
    1321             :                         /* compare the hash */
    1322     4741046 :                         if (memcmp(hash, block->hash, BLOCK_HASH_SIZE) != 0) {
    1323       13071 :                                 unsigned diff = memdiff(hash, block->hash, BLOCK_HASH_SIZE);
    1324             : 
    1325             :                                 /* save the failed block for the check/fix */
    1326       13071 :                                 failed[failed_count].is_bad = 1; /* it's bad because the hash doesn't match */
    1327       13071 :                                 failed[failed_count].is_outofdate = 0;
    1328       13071 :                                 failed[failed_count].index = j;
    1329       13071 :                                 failed[failed_count].block = block;
    1330       13071 :                                 failed[failed_count].disk = disk;
    1331       13071 :                                 failed[failed_count].file = file;
    1332       13071 :                                 failed[failed_count].file_pos = file_pos;
    1333       13071 :                                 failed[failed_count].handle = &handle[j];
    1334       13071 :                                 ++failed_count;
    1335             : 
    1336       13071 :                                 log_tag("error:%u:%s:%s: Data error at position %u, diff hash bits %u/%u\n", i, disk->name, esc_tag(file->sub, esc_buffer), file_pos, diff, BLOCK_HASH_SIZE * 8);
    1337       13071 :                                 ++silent_error;
    1338       13071 :                                 continue;
    1339             :                         }
    1340             : 
    1341             :                         /*
    1342             :                          * Always insert REP blocks, the repair functions needs all of them
    1343             :                          * because the parity may be still referring at the old state
    1344             :                          * and the repair must be aware of it
    1345             :                          */
    1346     4727975 :                         if (block_state == BLOCK_STATE_REP) {
    1347       52148 :                                 failed[failed_count].is_bad = 0; /* it's not bad */
    1348       52148 :                                 failed[failed_count].is_outofdate = 0;
    1349       52148 :                                 failed[failed_count].index = j;
    1350       52148 :                                 failed[failed_count].block = block;
    1351       52148 :                                 failed[failed_count].disk = disk;
    1352       52148 :                                 failed[failed_count].file = file;
    1353       52148 :                                 failed[failed_count].file_pos = file_pos;
    1354       52148 :                                 failed[failed_count].handle = &handle[j];
    1355       52148 :                                 ++failed_count;
    1356       52148 :                                 continue;
    1357             :                         }
    1358             :                 }
    1359             : 
    1360             :                 /* now read and check the parity if requested */
    1361      953182 :                 if (!state->opt.auditonly) {
    1362             :                         void* buffer_recov[LEV_MAX];
    1363             :                         void* buffer_zero;
    1364             : 
    1365             :                         /* buffers for parity read and not computed */
    1366     4353661 :                         for (l = 0; l < state->level; ++l)
    1367     3439994 :                                 buffer_recov[l] = buffer[diskmax + state->level + l];
    1368     2955675 :                         for (; l < LEV_MAX; ++l)
    1369     2042008 :                                 buffer_recov[l] = 0;
    1370             : 
    1371             :                         /* the zero buffer is the last one */
    1372      913667 :                         buffer_zero = buffer[buffermax - 1];
    1373             : 
    1374             :                         /* read the parity */
    1375     4353661 :                         for (l = 0; l < state->level; ++l) {
    1376     3439994 :                                 if (parity[l]) {
    1377     3426032 :                                         ret = parity_read(parity[l], i, buffer_recov[l], state->block_size, log_error);
    1378     3426032 :                                         if (ret == -1) {
    1379       96822 :                                                 log_tag("parity_%s:%u:%s: Read error. %s.\n", es(errno), i, lev_config_name(l), strerror(errno));
    1380             : 
    1381       96822 :                                                 buffer_recov[l] = 0; /* no parity to use */
    1382             : 
    1383       96822 :                                                 if (is_hw(errno)) {
    1384           0 :                                                         ++io_error;
    1385             :                                                 } else {
    1386       96822 :                                                         ++soft_error;
    1387             :                                                 }
    1388             :                                         }
    1389             :                                 } else {
    1390       13962 :                                         buffer_recov[l] = 0;
    1391             :                                 }
    1392             :                         }
    1393             : 
    1394             :                         /* try all the recovering strategies */
    1395      913667 :                         ret = repair(state, rehash, i, diskmax, failed, failed_map, failed_count, buffer, buffer_recov, buffer_zero);
    1396      913667 :                         if (ret != 0) {
    1397             :                                 /* increment the number of errors */
    1398       47843 :                                 if (ret > 0)
    1399        4936 :                                         silent_error += ret;
    1400       47843 :                                 ++unrecoverable_error;
    1401             : 
    1402             :                                 /* print a list of all the errors in files */
    1403      218382 :                                 for (j = 0; j < failed_count; ++j) {
    1404      170539 :                                         if (failed[j].is_bad)
    1405      165976 :                                                 log_tag("unrecoverable:%u:%s:%s: Unrecoverable error at position %u\n", i, failed[j].disk->name, esc_tag(failed[j].file->sub, esc_buffer), failed[j].file_pos);
    1406             :                                 }
    1407             : 
    1408             :                                 /* keep track of damaged files */
    1409      218382 :                                 for (j = 0; j < failed_count; ++j) {
    1410      170539 :                                         if (failed[j].is_bad)
    1411      165976 :                                                 file_flag_set(failed[j].file, FILE_IS_DAMAGED);
    1412             :                                 }
    1413             :                         } else {
    1414             :                                 /*
    1415             :                                  * Now counts partial recovers
    1416             :                                  * note that this could happen only when we have an incomplete 'sync'
    1417             :                                  * and that we have recovered is the state before the 'sync'
    1418             :                                  */
    1419      865824 :                                 int partial_recover_error = 0;
    1420             : 
    1421             :                                 /* print a list of all the errors in files */
    1422     1467435 :                                 for (j = 0; j < failed_count; ++j) {
    1423      601611 :                                         if (failed[j].is_bad && failed[j].is_outofdate) {
    1424           8 :                                                 ++partial_recover_error;
    1425           8 :                                                 log_tag("unrecoverable:%u:%s:%s: Unrecoverable unsynced error at position %u\n", i, failed[j].disk->name, esc_tag(failed[j].file->sub, esc_buffer), failed[j].file_pos);
    1426             :                                         }
    1427             :                                 }
    1428      865824 :                                 if (partial_recover_error != 0) {
    1429           8 :                                         silent_error += partial_recover_error;
    1430           8 :                                         ++unrecoverable_error;
    1431             :                                 }
    1432             : 
    1433             :                                 /*
    1434             :                                  * Check parities, but only if all the blocks have it computed and it's used.
    1435             :                                  *
    1436             :                                  * If you check/fix after a partial sync, it's OK to have parity errors
    1437             :                                  * on the blocks with invalid parity and doesn't make sense to try to fix it.
    1438             :                                  *
    1439             :                                  * It's also OK to have data errors on unused parity, because sync doesn't
    1440             :                                  * update it.
    1441             :                                  */
    1442      865824 :                                 if (used_parity && valid_parity) {
    1443             :                                         /* check the parity */
    1444     3906083 :                                         for (l = 0; l < state->level; ++l) {
    1445     3104571 :                                                 if (buffer_recov[l] != 0 && memcmp(buffer_recov[l], buffer[diskmax + l], state->block_size) != 0) {
    1446       21631 :                                                         unsigned diff = memdiff(buffer_recov[l], buffer[diskmax + l], state->block_size);
    1447             : 
    1448             :                                                         /* mark that the read parity is wrong, setting ptr to 0 */
    1449       21631 :                                                         buffer_recov[l] = 0;
    1450             : 
    1451       21631 :                                                         log_tag("parity_error:%u:%s: Data error, diff parity bits %u/%u\n", i, lev_config_name(l), diff, state->block_size * 8);
    1452       21631 :                                                         ++silent_error;
    1453             :                                                 }
    1454             :                                         }
    1455             :                                 }
    1456             : 
    1457             :                                 /* now write recovered files */
    1458      865824 :                                 if (fix) {
    1459             :                                         /* update the fixed files */
    1460      696842 :                                         for (j = 0; j < failed_count; ++j) {
    1461             :                                                 /* nothing to do if it doesn't need recovering */
    1462      361058 :                                                 if (!failed[j].is_bad)
    1463       41411 :                                                         continue;
    1464             : 
    1465             :                                                 /* do not fix if the file is excluded */
    1466      319647 :                                                 if (file_flag_has(failed[j].file, FILE_IS_EXCLUDED)
    1467      310483 :                                                         || (state->opt.syncedonly && file_flag_has(failed[j].file, FILE_IS_UNSYNCED)))
    1468        9164 :                                                         continue;
    1469             : 
    1470      310483 :                                                 ret = handle_write(failed[j].handle, failed[j].file_pos, buffer[failed[j].index], state->block_size);
    1471      310483 :                                                 if (ret == -1) {
    1472             :                                                         /* LCOV_EXCL_START */
    1473             :                                                         log_tag("%s:%u:%s:%s: Write error. %s.\n", es(errno), i, failed[j].disk->name, esc_tag(failed[j].file->sub, esc_buffer), strerror(errno));
    1474             :                                                         log_fatal_errno(errno, failed[j].disk->name);
    1475             :                                                         log_fatal(errno, "Stopping at block %u\n", i);
    1476             : 
    1477             :                                                         /* mark the file as damaged */
    1478             :                                                         file_flag_set(failed[j].file, FILE_IS_DAMAGED);
    1479             : 
    1480             :                                                         ++unrecoverable_error;
    1481             :                                                         goto bail;
    1482             :                                                         /* LCOV_EXCL_STOP */
    1483             :                                                 }
    1484             : 
    1485             :                                                 /* if we are not sure that the recovered content is uptodate */
    1486      310483 :                                                 if (failed[j].is_outofdate) {
    1487             :                                                         /* mark the file as damaged */
    1488           8 :                                                         file_flag_set(failed[j].file, FILE_IS_DAMAGED);
    1489           8 :                                                         continue;
    1490             :                                                 }
    1491             : 
    1492             :                                                 /*
    1493             :                                                  * Mark the file as containing some fixes
    1494             :                                                  * note that it could be also marked as damaged in other iterations
    1495             :                                                  */
    1496      310475 :                                                 file_flag_set(failed[j].file, FILE_IS_FIXED);
    1497             : 
    1498      310475 :                                                 log_tag("fixed:%u:%s:%s: Fixed data error at position %u\n", i, failed[j].disk->name, esc_tag(failed[j].file->sub, esc_buffer), failed[j].file_pos);
    1499      310475 :                                                 ++recovered_error;
    1500             :                                         }
    1501             : 
    1502             :                                         /*
    1503             :                                          * Update parity only if all the blocks have it computed and it's used.
    1504             :                                          *
    1505             :                                          * If you check/fix after a partial sync, you do not want to fix parity
    1506             :                                          * for blocks that are going to have it computed in the sync completion.
    1507             :                                          *
    1508             :                                          * For unused parity there is no need to write it, because when fixing
    1509             :                                          * we already have allocated space for it on parity file creation,
    1510             :                                          * and its content doesn't matter.
    1511             :                                          */
    1512      335784 :                                         if (used_parity && valid_parity) {
    1513             :                                                 /* update the parity */
    1514     1048077 :                                                 for (l = 0; l < state->level; ++l) {
    1515             :                                                         /* if the parity on disk is wrong */
    1516      762196 :                                                         if (buffer_recov[l] == 0
    1517             :                                                                 /* and we have access at the parity */
    1518       79589 :                                                                 && parity[l] != 0
    1519             :                                                                 /* and the parity is not excluded */
    1520       74902 :                                                                 && !state->parity[l].is_excluded_by_filter
    1521             :                                                         ) {
    1522       74902 :                                                                 ret = parity_write(parity[l], i, buffer[diskmax + l], state->block_size);
    1523       74902 :                                                                 if (ret == -1) {
    1524             :                                                                         /* LCOV_EXCL_START */
    1525             :                                                                         log_tag("%s:%u:%s: Write error. %s.\n", es(errno), i, lev_config_name(l), strerror(errno));
    1526             :                                                                         log_fatal_errno(errno, lev_config_name(l));
    1527             :                                                                         log_fatal(errno, "Stopping at block %u\n", i);
    1528             : 
    1529             :                                                                         ++unrecoverable_error;
    1530             :                                                                         goto bail;
    1531             :                                                                         /* LCOV_EXCL_STOP */
    1532             :                                                                 }
    1533             : 
    1534       74902 :                                                                 log_tag("parity_fixed:%u:%s: Fixed data error\n", i, lev_config_name(l));
    1535       74902 :                                                                 ++recovered_error;
    1536             :                                                         }
    1537             :                                                 }
    1538             :                                         }
    1539             :                                 } else {
    1540             :                                         /*
    1541             :                                          * If we are not fixing, we just set the FIXED flag
    1542             :                                          * meaning that we could fix this file if we try
    1543             :                                          */
    1544      770593 :                                         for (j = 0; j < failed_count; ++j) {
    1545      240553 :                                                 if (failed[j].is_bad) {
    1546      198726 :                                                         file_flag_set(failed[j].file, FILE_IS_FIXED);
    1547             :                                                 }
    1548             :                                         }
    1549             :                                 }
    1550             :                         }
    1551             :                 } else {
    1552             :                         /*
    1553             :                          * If we are not checking, we just set the DAMAGED flag
    1554             :                          * to report that the file is damaged, and we don't know if we can fix it
    1555             :                          */
    1556       45568 :                         for (j = 0; j < failed_count; ++j) {
    1557        6053 :                                 if (failed[j].is_bad) {
    1558        6053 :                                         file_flag_set(failed[j].file, FILE_IS_DAMAGED);
    1559             :                                 }
    1560             :                         }
    1561             :                 }
    1562             : 
    1563             :                 /* post process the files */
    1564      953182 :                 ret = file_post(state, fix, i, handle, diskmax);
    1565      953182 :                 if (ret == -1) {
    1566             :                         /* LCOV_EXCL_START */
    1567             :                         log_fatal(errno, "Stopping at block %u\n", i);
    1568             : 
    1569             :                         ++unrecoverable_error;
    1570             :                         goto bail;
    1571             :                         /* LCOV_EXCL_STOP */
    1572             :                 }
    1573             : 
    1574             :                 /* count the number of processed block */
    1575      953182 :                 ++countpos;
    1576             : 
    1577             :                 /* progress */
    1578      953182 :                 if (state_progress(state, 0, i, countpos, countmax, countsize)) {
    1579             :                         /* LCOV_EXCL_START */
    1580             :                         break;
    1581             :                         /* LCOV_EXCL_STOP */
    1582             :                 }
    1583             : 
    1584             :                 /* thermal control */
    1585      953182 :                 if (state_thermal_alarm(state)) {
    1586             :                         /* until now is misc */
    1587           0 :                         state_usage_misc(state);
    1588             : 
    1589           0 :                         state_progress_stop(state);
    1590             : 
    1591           0 :                         state_thermal_cooldown(state);
    1592             : 
    1593           0 :                         state_progress_restart(state);
    1594             : 
    1595             :                         /* drop until now */
    1596           0 :                         state_usage_waste(state);
    1597             :                 }
    1598             :         }
    1599             : 
    1600             :         /* for each disk, recover empty files, symlinks and empty dirs */
    1601         894 :         for (i = 0; i < diskmax; ++i) {
    1602             :                 tommy_node* node;
    1603             :                 struct snapraid_disk* disk;
    1604             : 
    1605         762 :                 if (!handle[i].disk)
    1606           3 :                         continue;
    1607             : 
    1608             :                 /* for each empty file in the disk */
    1609         759 :                 disk = handle[i].disk;
    1610         759 :                 node = disk->filelist;
    1611     2276845 :                 while (node) {
    1612             :                         char path[PATH_MAX];
    1613             :                         struct stat st;
    1614             :                         struct snapraid_file* file;
    1615     2276086 :                         int unsuccessful = 0;
    1616             : 
    1617     2276086 :                         file = node->data;
    1618     2276086 :                         node = node->next; /* next node */
    1619             : 
    1620             :                         /* if not empty, it's already checked and continue to the next one */
    1621     2276086 :                         if (file->size != 0) {
    1622     2273217 :                                 continue;
    1623             :                         }
    1624             : 
    1625             :                         /* if excluded continue to the next one */
    1626        3071 :                         if (file_flag_has(file, FILE_IS_EXCLUDED)) {
    1627         202 :                                 continue;
    1628             :                         }
    1629             : 
    1630             :                         /* stat the file */
    1631        2869 :                         pathprint(path, sizeof(path), "%s%s", disk->dir, file->sub);
    1632        2869 :                         ret = stat(path, &st);
    1633        2869 :                         if (ret == -1) {
    1634         197 :                                 unsuccessful = 1;
    1635             : 
    1636         197 :                                 log_error(errno, "Error stating empty file '%s'. %s.\n", path, strerror(errno));
    1637         197 :                                 log_tag("empty_%s:%s:%s: Empty file stat error\n", es(errno), disk->name, esc_tag(file->sub, esc_buffer));
    1638             : 
    1639         197 :                                 if (is_hw(errno)) {
    1640           0 :                                         ++io_error;
    1641             :                                 } else {
    1642         197 :                                         ++soft_error;
    1643             :                                 }
    1644        2672 :                         } else if (!S_ISREG(st.st_mode)) {
    1645           0 :                                 unsuccessful = 1;
    1646             : 
    1647           0 :                                 log_error(ESOFT, "Error stating empty file '%s' for not regular file.\n", path);
    1648           0 :                                 log_tag("empty_error:%s:%s: Empty file error for not regular file\n", disk->name, esc_tag(file->sub, esc_buffer));
    1649           0 :                                 ++soft_error;
    1650        2672 :                         } else if (st.st_size != 0) {
    1651          20 :                                 unsuccessful = 1;
    1652             : 
    1653          20 :                                 log_error(ESOFT, "Error stating empty file '%s' for not empty file.\n", path);
    1654          20 :                                 log_tag("empty_error:%s:%s: Empty file error for size '%" PRIu64 "'\n", disk->name, esc_tag(file->sub, esc_buffer), (uint64_t)st.st_size);
    1655          20 :                                 ++soft_error;
    1656             :                         }
    1657             : 
    1658        2869 :                         if (fix && unsuccessful) {
    1659             :                                 int f;
    1660             : 
    1661             :                                 /* create the ancestor directories */
    1662         174 :                                 ret = mkancestor(path);
    1663         174 :                                 if (ret != 0) {
    1664             :                                         /* LCOV_EXCL_START */
    1665             :                                         log_fatal(errno, "Error creating ancestor '%s%s'. %s.\n", disk->dir, file->sub, strerror(errno));
    1666             :                                         log_tag("empty_%s:%u:%s:%s: Create ancestor error. %s.\n", es(errno), i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno));
    1667             :                                         log_fatal_errno(errno, disk->name);
    1668             :                                         log_fatal(errno, "Stopping\n");
    1669             : 
    1670             :                                         ++unrecoverable_error;
    1671             :                                         goto bail;
    1672             :                                         /* LCOV_EXCL_STOP */
    1673             :                                 }
    1674             : 
    1675             :                                 /*
    1676             :                                  * Create it
    1677             :                                  * O_NOFOLLOW: do not follow links to ensure to open the real file
    1678             :                                  */
    1679         174 :                                 f = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_NOFOLLOW, 0600);
    1680         174 :                                 if (f == -1) {
    1681             :                                         /* LCOV_EXCL_START */
    1682             :                                         log_fatal(errno, "Error creating '%s%s'. %s.\n", disk->dir, file->sub, strerror(errno));
    1683             :                                         log_tag("empty_%s:%u:%s:%s: Create error. %s.\n", es(errno), i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno));
    1684             :                                         log_fatal_errno(errno, disk->name);
    1685             :                                         log_fatal(errno, "Stopping\n");
    1686             : 
    1687             :                                         ++unrecoverable_error;
    1688             :                                         goto bail;
    1689             :                                         /* LCOV_EXCL_STOP */
    1690             :                                 }
    1691             : 
    1692             :                                 /* set the original modification time */
    1693         174 :                                 ret = fmtime(f, file->mtime_sec, file->mtime_nsec);
    1694         174 :                                 if (ret != 0) {
    1695             :                                         /* LCOV_EXCL_START */
    1696             :                                         log_fatal(errno, "Error timing '%s%s'. %s.\n", disk->dir, file->sub, strerror(errno));
    1697             :                                         log_tag("empty_%s:%u:%s:%s: Time error. %s.\n", es(errno), i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno));
    1698             :                                         log_fatal_errno(errno, disk->name);
    1699             :                                         log_fatal(errno, "Stopping\n");
    1700             : 
    1701             :                                         close(f);
    1702             : 
    1703             :                                         ++unrecoverable_error;
    1704             :                                         goto bail;
    1705             :                                         /* LCOV_EXCL_STOP */
    1706             :                                 }
    1707             : 
    1708             :                                 /* close it */
    1709         174 :                                 ret = close(f);
    1710         174 :                                 if (ret != 0) {
    1711             :                                         /* LCOV_EXCL_START */
    1712             :                                         log_fatal(errno, "Error closing '%s%s'. %s.\n", disk->dir, file->sub, strerror(errno));
    1713             :                                         log_tag("empty_%s:%u:%s:%s: Close error. %s.\n", es(errno), i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno));
    1714             :                                         log_fatal_errno(errno, disk->name);
    1715             :                                         log_fatal(errno, "Stopping\n");
    1716             : 
    1717             :                                         ++unrecoverable_error;
    1718             :                                         goto bail;
    1719             :                                         /* LCOV_EXCL_STOP */
    1720             :                                 }
    1721             : 
    1722         174 :                                 log_tag("empty_fixed:%s:%s: Fixed empty file\n", disk->name, esc_tag(file->sub, esc_buffer));
    1723         174 :                                 ++recovered_error;
    1724             : 
    1725         174 :                                 log_tag("status:recovered:%s:%s\n", disk->name, esc_tag(file->sub, esc_buffer));
    1726         174 :                                 msg_info("recovered %s\n", fmt_term(disk, file->sub, esc_buffer));
    1727             :                         }
    1728             :                 }
    1729             : 
    1730             :                 /* for each link in the disk */
    1731         759 :                 disk = handle[i].disk;
    1732         759 :                 node = disk->linklist;
    1733       73578 :                 while (node) {
    1734             :                         char path[PATH_MAX];
    1735             :                         char pathto[PATH_MAX];
    1736             :                         char linkto[PATH_MAX];
    1737             :                         struct stat st;
    1738             :                         struct stat stto;
    1739             :                         struct snapraid_link* slink;
    1740       72819 :                         int unsuccessful = 0;
    1741       72819 :                         int unrecoverable = 0;
    1742             : 
    1743       72819 :                         slink = node->data;
    1744       72819 :                         node = node->next; /* next node */
    1745             : 
    1746             :                         /* if excluded continue to the next one */
    1747       72819 :                         if (link_flag_has(slink, FILE_IS_EXCLUDED)) {
    1748        4169 :                                 continue;
    1749             :                         }
    1750             : 
    1751       68650 :                         if (link_flag_has(slink, FILE_IS_HARDLINK)) {
    1752             :                                 /* stat the link */
    1753         327 :                                 pathprint(path, sizeof(path), "%s%s", disk->dir, slink->sub);
    1754         327 :                                 ret = stat(path, &st);
    1755         327 :                                 if (ret == -1) {
    1756          36 :                                         unsuccessful = 1;
    1757             : 
    1758          36 :                                         log_error(errno, "Error stating hardlink '%s'. %s.\n", path, strerror(errno));
    1759          36 :                                         log_tag("hardlink_%s:%s:%s:%s: Hardlink stat error. %s.\n", es(errno), disk->name, esc_tag(slink->sub, esc_buffer), esc_tag(slink->linkto, esc_buffer_alt), strerror(errno));
    1760             : 
    1761          36 :                                         if (is_hw(errno)) {
    1762           0 :                                                 ++io_error;
    1763             :                                         } else {
    1764          36 :                                                 ++soft_error;
    1765             :                                         }
    1766         291 :                                 } else if (!S_ISREG(st.st_mode)) {
    1767           0 :                                         unsuccessful = 1;
    1768             : 
    1769           0 :                                         log_error(ESOFT, "Error stating hardlink '%s' for not regular file.\n", path);
    1770           0 :                                         log_tag("hardlink_error:%s:%s:%s: Hardlink error for not regular file\n", disk->name, esc_tag(slink->sub, esc_buffer), esc_tag(slink->linkto, esc_buffer_alt));
    1771           0 :                                         ++soft_error;
    1772             :                                 }
    1773             : 
    1774             :                                 /* stat the "to" file */
    1775         327 :                                 pathprint(pathto, sizeof(pathto), "%s%s", disk->dir, slink->linkto);
    1776         327 :                                 ret = stat(pathto, &stto);
    1777         327 :                                 if (ret == -1) {
    1778          24 :                                         unsuccessful = 1;
    1779             : 
    1780          24 :                                         if (errno == ENOENT) {
    1781          24 :                                                 unrecoverable = 1;
    1782          24 :                                                 if (fix) {
    1783             :                                                         /*
    1784             :                                                          * If the target doesn't exist, it's unrecoverable
    1785             :                                                          * because we cannot create an hardlink of a file that
    1786             :                                                          * doesn't exists
    1787             :                                                          * but in check, we can assume that fixing will recover
    1788             :                                                          * such missing file, so we assume a less drastic error
    1789             :                                                          */
    1790          12 :                                                         ++unrecoverable_error;
    1791             :                                                 }
    1792             :                                         }
    1793             : 
    1794          24 :                                         log_error(errno, "Error stating hardlink-to '%s'. %s.\n", pathto, strerror(errno));
    1795          24 :                                         log_tag("hardlink_%s:%s:%s:%s: Hardlink to stat error. %s.\n", es(errno), disk->name, esc_tag(slink->sub, esc_buffer), esc_tag(slink->linkto, esc_buffer_alt), strerror(errno));
    1796             : 
    1797          24 :                                         if (is_hw(errno)) {
    1798           0 :                                                 ++io_error;
    1799             :                                         } else {
    1800          24 :                                                 ++soft_error;
    1801             :                                         }
    1802         303 :                                 } else if (!S_ISREG(stto.st_mode)) {
    1803           0 :                                         unsuccessful = 1;
    1804             : 
    1805           0 :                                         log_error(ESOFT, "Error stating hardlink-to '%s' for not regular file.\n", path);
    1806           0 :                                         log_tag("hardlink_error:%s:%s:%s: Hardlink-to error for not regular file\n", disk->name, esc_tag(slink->sub, esc_buffer), esc_tag(slink->linkto, esc_buffer_alt));
    1807           0 :                                         ++soft_error;
    1808         303 :                                 } else if (!unsuccessful && st.st_ino != stto.st_ino) {
    1809           0 :                                         unsuccessful = 1;
    1810             : 
    1811           0 :                                         log_error(ESOFT, "Mismatch hardlink '%s' and '%s'. Different inode.\n", path, pathto);
    1812           0 :                                         log_tag("hardlink_error:%s:%s:%s: Hardlink mismatch for different inode\n", disk->name, esc_tag(slink->sub, esc_buffer), esc_tag(slink->linkto, esc_buffer_alt));
    1813           0 :                                         ++soft_error;
    1814             :                                 }
    1815             :                         } else {
    1816             :                                 /* read the symlink */
    1817       68323 :                                 pathprint(path, sizeof(path), "%s%s", disk->dir, slink->sub);
    1818       68323 :                                 ret = readlink(path, linkto, sizeof(linkto));
    1819       68323 :                                 if (ret < 0) {
    1820        5020 :                                         unsuccessful = 1;
    1821             : 
    1822        5020 :                                         log_error(errno, "Error reading symlink '%s'. %s.\n", path, strerror(errno));
    1823        5020 :                                         log_tag("symlink_%s:%s:%s: Symlink read error. %s.\n", es(errno), disk->name, esc_tag(slink->sub, esc_buffer), strerror(errno));
    1824             : 
    1825        5020 :                                         if (is_hw(errno)) {
    1826           0 :                                                 ++io_error;
    1827             :                                         } else {
    1828        5020 :                                                 ++soft_error;
    1829             :                                         }
    1830       63303 :                                 } else if (ret >= PATH_MAX) {
    1831           0 :                                         unsuccessful = 1;
    1832             : 
    1833           0 :                                         log_error(ESOFT, "Error reading symlink '%s'. Symlink too long.\n", path);
    1834           0 :                                         log_tag("symlink_error:%s:%s: Symlink too long\n", disk->name, esc_tag(slink->sub, esc_buffer));
    1835           0 :                                         ++soft_error;
    1836             :                                 } else {
    1837       63303 :                                         linkto[ret] = 0;
    1838             : 
    1839       63303 :                                         if (strcmp(linkto, slink->linkto) != 0) {
    1840         499 :                                                 unsuccessful = 1;
    1841             : 
    1842         499 :                                                 log_tag("symlink_error:%s:%s: Symlink data error '%s' instead of '%s'\n", disk->name, esc_tag(slink->sub, esc_buffer), linkto, slink->linkto);
    1843         499 :                                                 ++soft_error;
    1844             :                                         }
    1845             :                                 }
    1846             :                         }
    1847             : 
    1848       68650 :                         if (fix && unsuccessful && !unrecoverable) {
    1849        4340 :                                 const char* link = link_flag_has(slink, FILE_IS_HARDLINK) ? "hard" : "sym";
    1850             : 
    1851             :                                 /* create the ancestor directories */
    1852        4340 :                                 ret = mkancestor(path);
    1853        4340 :                                 if (ret != 0) {
    1854             :                                         /* LCOV_EXCL_START */
    1855             :                                         log_fatal(errno, "Error creating ancestor '%s%s'. %s.\n", disk->dir, slink->sub, strerror(errno));
    1856             :                                         log_tag("%slink_%s:%u:%s:%s: Create ancestor error. %s.\n", link, es(errno), i, disk->name, esc_tag(slink->sub, esc_buffer), strerror(errno));
    1857             :                                         log_fatal_errno(errno, disk->name);
    1858             :                                         log_fatal(errno, "Stopping\n");
    1859             : 
    1860             :                                         ++unrecoverable_error;
    1861             :                                         goto bail;
    1862             :                                         /* LCOV_EXCL_STOP */
    1863             :                                 }
    1864             : 
    1865             :                                 /* if it exists, it must be deleted before recreating */
    1866        4340 :                                 ret = remove(path);
    1867        4340 :                                 if (ret != 0 && errno != ENOENT) {
    1868             :                                         /* LCOV_EXCL_START */
    1869             :                                         log_fatal(errno, "Error removing '%s%s'. %s.\n", disk->dir, slink->sub, strerror(errno));
    1870             :                                         log_tag("%slink_%s:%u:%s:%s: Remove error. %s.\n", link, es(errno), i, disk->name, esc_tag(slink->sub, esc_buffer), strerror(errno));
    1871             :                                         log_fatal_errno(errno, disk->name);
    1872             :                                         log_fatal(errno, "Stopping\n");
    1873             : 
    1874             :                                         ++unrecoverable_error;
    1875             :                                         goto bail;
    1876             :                                         /* LCOV_EXCL_STOP */
    1877             :                                 }
    1878             : 
    1879             :                                 /* create it */
    1880        4340 :                                 if (link_flag_has(slink, FILE_IS_HARDLINK)) {
    1881          12 :                                         ret = hardlink(pathto, path);
    1882          12 :                                         if (ret != 0) {
    1883             :                                                 /* LCOV_EXCL_START */
    1884             :                                                 log_fatal(errno, "Error writing hardlink '%s' to '%s'. %s.\n", path, pathto, strerror(errno));
    1885             :                                                 log_tag("hardlink_%s:%u:%s:%s: Hardlink error. %s.\n", es(errno), i, disk->name, esc_tag(slink->sub, esc_buffer), strerror(errno));
    1886             :                                                 log_fatal_errno(errno, disk->name);
    1887             :                                                 log_fatal(errno, "Stopping\n");
    1888             : 
    1889             :                                                 ++unrecoverable_error;
    1890             :                                                 goto bail;
    1891             :                                                 /* LCOV_EXCL_STOP */
    1892             :                                         }
    1893             : 
    1894          12 :                                         log_tag("hardlink_fixed:%s:%s: Fixed hardlink error\n", disk->name, esc_tag(slink->sub, esc_buffer));
    1895          12 :                                         ++recovered_error;
    1896             :                                 } else {
    1897        4328 :                                         ret = symlink(slink->linkto, path);
    1898        4328 :                                         if (ret != 0) {
    1899             :                                                 /* LCOV_EXCL_START */
    1900             :                                                 log_fatal(errno, "Error writing symlink '%s' to '%s'. %s.\n", path, slink->linkto, strerror(errno));
    1901             :                                                 log_tag("symlink_%s:%u:%s:%s: Hardlink error. %s.\n", es(errno), i, disk->name, esc_tag(slink->sub, esc_buffer), strerror(errno));
    1902             :                                                 log_fatal_errno(errno, disk->name);
    1903             :                                                 log_fatal(errno, "Stopping\n");
    1904             : 
    1905             :                                                 ++unrecoverable_error;
    1906             :                                                 goto bail;
    1907             :                                                 /* LCOV_EXCL_STOP */
    1908             :                                         }
    1909             : 
    1910        4328 :                                         log_tag("symlink_fixed:%s:%s: Fixed symlink error\n", disk->name, esc_tag(slink->sub, esc_buffer));
    1911        4328 :                                         ++recovered_error;
    1912             :                                 }
    1913             : 
    1914        4340 :                                 log_tag("status:recovered:%s:%s\n", disk->name, esc_tag(slink->sub, esc_buffer));
    1915        4340 :                                 msg_info("recovered %s\n", fmt_term(disk, slink->sub, esc_buffer));
    1916             :                         }
    1917             :                 }
    1918             : 
    1919             :                 /* for each dir in the disk */
    1920         759 :                 disk = handle[i].disk;
    1921         759 :                 node = disk->dirlist;
    1922        1215 :                 while (node) {
    1923             :                         char path[PATH_MAX];
    1924             :                         struct stat st;
    1925             :                         struct snapraid_dir* dir;
    1926         456 :                         int unsuccessful = 0;
    1927             : 
    1928         456 :                         dir = node->data;
    1929         456 :                         node = node->next; /* next node */
    1930             : 
    1931             :                         /* if excluded continue to the next one */
    1932         456 :                         if (dir_flag_has(dir, FILE_IS_EXCLUDED)) {
    1933          23 :                                 continue;
    1934             :                         }
    1935             : 
    1936             :                         /* stat the dir */
    1937         433 :                         pathprint(path, sizeof(path), "%s%s", disk->dir, dir->sub);
    1938         433 :                         ret = stat(path, &st);
    1939         433 :                         if (ret == -1) {
    1940          27 :                                 unsuccessful = 1;
    1941             : 
    1942          27 :                                 log_error(errno, "Error stating dir '%s'. %s.\n", path, strerror(errno));
    1943          27 :                                 log_tag("dir_%s:%s:%s: Dir stat error. %s.\n", es(errno), disk->name, esc_tag(dir->sub, esc_buffer), strerror(errno));
    1944             : 
    1945          27 :                                 if (is_hw(errno)) {
    1946           0 :                                         ++io_error;
    1947             :                                 } else {
    1948          27 :                                         ++soft_error;
    1949             :                                 }
    1950         406 :                         } else if (!S_ISDIR(st.st_mode)) {
    1951           0 :                                 unsuccessful = 1;
    1952             : 
    1953           0 :                                 log_tag("dir_error:%s:%s: Dir error for not directory\n", disk->name, esc_tag(dir->sub, esc_buffer));
    1954           0 :                                 ++soft_error;
    1955             :                         }
    1956             : 
    1957         433 :                         if (fix && unsuccessful) {
    1958             :                                 /* create the ancestor directories */
    1959          23 :                                 ret = mkancestor(path);
    1960          23 :                                 if (ret != 0) {
    1961             :                                         /* LCOV_EXCL_START */
    1962             :                                         log_fatal(errno, "Error creating ancestor '%s%s'. %s.\n", disk->dir, dir->sub, strerror(errno));
    1963             :                                         log_tag("dir_%s:%u:%s:%s: Create ancestor error. %s.\n", es(errno), i, disk->name, esc_tag(dir->sub, esc_buffer), strerror(errno));
    1964             :                                         log_fatal_errno(errno, disk->name);
    1965             :                                         log_fatal(errno, "Stopping\n");
    1966             : 
    1967             :                                         ++unrecoverable_error;
    1968             :                                         goto bail;
    1969             :                                         /* LCOV_EXCL_STOP */
    1970             :                                 }
    1971             : 
    1972             :                                 /* create it */
    1973          23 :                                 ret = mkdir(path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
    1974          23 :                                 if (ret != 0) {
    1975             :                                         /* LCOV_EXCL_START */
    1976             :                                         log_fatal(errno, "Error creating directory '%s%s'. %s.\n", disk->dir, dir->sub, strerror(errno));
    1977             :                                         log_tag("dir_%s:%u:%s:%s: Create directory error. %s.\n", es(errno), i, disk->name, esc_tag(dir->sub, esc_buffer), strerror(errno));
    1978             :                                         log_fatal_errno(errno, disk->name);
    1979             :                                         log_fatal(errno, "Stopping\n");
    1980             : 
    1981             :                                         ++unrecoverable_error;
    1982             :                                         goto bail;
    1983             :                                         /* LCOV_EXCL_STOP */
    1984             :                                 }
    1985             : 
    1986          23 :                                 log_tag("dir_fixed:%s:%s: Fixed dir error\n", disk->name, esc_tag(dir->sub, esc_buffer));
    1987          23 :                                 ++recovered_error;
    1988             : 
    1989          23 :                                 log_tag("status:recovered:%s:%s\n", disk->name, esc_tag(dir->sub, esc_buffer));
    1990          23 :                                 msg_info("recovered %s\n", fmt_term(disk, dir->sub, esc_buffer));
    1991             :                         }
    1992             :                 }
    1993             :         }
    1994             : 
    1995         132 : end:
    1996         132 :         state_progress_end(state, countpos, countmax, countsize, "Nothing to check.\n");
    1997             : 
    1998         132 : bail:
    1999             :         /* close all the files left open */
    2000         894 :         for (j = 0; j < diskmax; ++j) {
    2001         762 :                 struct snapraid_file* file = handle[j].file;
    2002         762 :                 struct snapraid_disk* disk = handle[j].disk;
    2003         762 :                 ret = handle_close(&handle[j]);
    2004         762 :                 if (ret == -1) {
    2005             :                         /* LCOV_EXCL_START */
    2006             :                         log_tag("%s:%u:%s:%s: Close error. %s.\n", es(errno), blockmax, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno));
    2007             :                         log_fatal_errno(errno, disk->name);
    2008             : 
    2009             :                         ++unrecoverable_error;
    2010             :                         /* continue, as we are already exiting */
    2011             :                         /* LCOV_EXCL_STOP */
    2012             :                 }
    2013             :         }
    2014             : 
    2015             :         /*
    2016             :          * Remove all the files created from scratch that have not finished the processing
    2017             :          * it happens only when aborting pressing Ctrl+C or other reason.
    2018             :          */
    2019         132 :         if (fix) {
    2020             :                 /* for each disk */
    2021         345 :                 for (i = 0; i < diskmax; ++i) {
    2022             :                         tommy_node* node;
    2023             :                         struct snapraid_disk* disk;
    2024             : 
    2025         294 :                         if (!handle[i].disk)
    2026           1 :                                 continue;
    2027             : 
    2028             :                         /* for each file in the disk */
    2029         293 :                         disk = handle[i].disk;
    2030         293 :                         node = disk->filelist;
    2031      912853 :                         while (node) {
    2032             :                                 char path[PATH_MAX];
    2033             :                                 struct snapraid_file* file;
    2034             : 
    2035      912560 :                                 file = node->data;
    2036      912560 :                                 node = node->next; /* next node */
    2037             : 
    2038             :                                 /* if the file was not created, meaning that it was already existing */
    2039      912560 :                                 if (!file_flag_has(file, FILE_IS_CREATED)) {
    2040             :                                         /* nothing to do */
    2041      912560 :                                         continue;
    2042             :                                 }
    2043             : 
    2044             :                                 /* if processing was finished */
    2045      123783 :                                 if (file_flag_has(file, FILE_IS_FINISHED)) {
    2046             :                                         /* nothing to do */
    2047      123783 :                                         continue;
    2048             :                                 }
    2049             : 
    2050             :                                 /*
    2051             :                                  * If the file was originally missing, and processing not yet finished
    2052             :                                  * we have to throw it away  to ensure that at the next run we will retry
    2053             :                                  * to fix it, in case we select to undelete missing files
    2054             :                                  */
    2055           0 :                                 pathprint(path, sizeof(path), "%s%s", disk->dir, file->sub);
    2056             : 
    2057           0 :                                 ret = remove(path);
    2058           0 :                                 if (ret != 0) {
    2059             :                                         /* LCOV_EXCL_START */
    2060             :                                         log_fatal(errno, "Error removing '%s'. %s.\n", path, strerror(errno));
    2061             :                                         log_tag("%s:%u:%s:%s: Close error. %s.\n", es(errno), blockmax, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno));
    2062             :                                         log_fatal_errno(errno, disk->name);
    2063             : 
    2064             :                                         ++unrecoverable_error;
    2065             :                                         /* continue, as we are already exiting */
    2066             :                                         /* LCOV_EXCL_STOP */
    2067             :                                 }
    2068             :                         }
    2069             :                 }
    2070             :         }
    2071             : 
    2072         132 :         if (soft_error || io_error || silent_error || recovered_error || unrecoverable_error) {
    2073          75 :                 msg_status("\n");
    2074          75 :                 msg_status("%8u soft errors\n", soft_error);
    2075          75 :                 msg_status("%8u io errors\n", io_error);
    2076          75 :                 msg_status("%8u data errors\n", silent_error);
    2077          75 :                 if (fix) {
    2078          50 :                         msg_status("%8u recovered errors\n", recovered_error);
    2079             :                 }
    2080          75 :                 if (unrecoverable_error) {
    2081          13 :                         msg_status("%8u UNRECOVERABLE errors\n", unrecoverable_error);
    2082             :                 } else {
    2083             :                         /* without checking, we don't know if they are really recoverable or not */
    2084          62 :                         if (!state->opt.auditonly)
    2085          60 :                                 msg_status("%8u unrecoverable errors\n", unrecoverable_error);
    2086          62 :                         if (fix)
    2087          41 :                                 msg_status("Everything OK\n");
    2088             :                 }
    2089             :         } else {
    2090          57 :                 msg_status("Everything OK\n");
    2091             :         }
    2092             : 
    2093         132 :         if ((soft_error || io_error || silent_error) && !fix) {
    2094          25 :                 if (soft_error)
    2095          22 :                         log_fatal(ESOFT, "WARNING! There are soft errors!\n");
    2096          25 :                 if (io_error)
    2097           0 :                         log_fatal(EIO, "DANGER! Unexpected input/output errors!\n");
    2098          25 :                 if (silent_error)
    2099          13 :                         log_fatal(EDATA, "DANGER! Unexpected silent data errors!\n");
    2100             :         }
    2101         132 :         if (unrecoverable_error)
    2102          13 :                 log_fatal(ESOFT, "DANGER! Unrecoverable errors detected!\n");
    2103             : 
    2104         132 :         log_tag("summary:error_soft:%u\n", soft_error);
    2105         132 :         log_tag("summary:error_io:%u\n", io_error);
    2106         132 :         log_tag("summary:error_data:%u\n", silent_error);
    2107         132 :         if (fix)
    2108          51 :                 log_tag("summary:error_recovered:%u\n", recovered_error);
    2109         132 :         if (!state->opt.auditonly)
    2110         127 :                 log_tag("summary:error_unrecoverable:%u\n", unrecoverable_error);
    2111         132 :         if (fix) {
    2112          51 :                 if (soft_error + io_error + silent_error + recovered_error + unrecoverable_error == 0)
    2113           1 :                         log_tag("summary:exit:ok\n");
    2114          50 :                 else if (unrecoverable_error == 0)
    2115          41 :                         log_tag("summary:exit:recovered\n");
    2116             :                 else
    2117           9 :                         log_tag("summary:exit:unrecoverable\n");
    2118          81 :         } else if (!state->opt.auditonly) {
    2119          76 :                 if (soft_error + io_error + silent_error + unrecoverable_error == 0)
    2120          53 :                         log_tag("summary:exit:ok\n");
    2121          23 :                 else if (unrecoverable_error == 0)
    2122          19 :                         log_tag("summary:exit:recoverable\n");
    2123             :                 else
    2124           4 :                         log_tag("summary:exit:unrecoverable\n");
    2125             :         } else { /* audit only */
    2126           5 :                 if (soft_error + silent_error + io_error == 0)
    2127           3 :                         log_tag("summary:exit:ok\n");
    2128           2 :                 else if (silent_error + io_error == 0)
    2129           1 :                         log_tag("summary:exit:warning\n");
    2130             :                 else
    2131           1 :                         log_tag("summary:exit:error\n");
    2132             :         }
    2133         132 :         log_flush();
    2134             : 
    2135         132 :         free(failed);
    2136         132 :         free(failed_map);
    2137         132 :         free(block_enabled);
    2138         132 :         free(handle);
    2139         132 :         free(buffer_alloc);
    2140         132 :         free(buffer);
    2141             : 
    2142             :         /* fail if some error are present after the run */
    2143         132 :         if (fix) {
    2144          51 :                 if (state->opt.expect_unrecoverable) {
    2145           9 :                         if (unrecoverable_error == 0)
    2146           0 :                                 return -1;
    2147             :                 } else {
    2148          42 :                         if (unrecoverable_error != 0)
    2149           0 :                                 return -1;
    2150             :                 }
    2151             :         } else {
    2152          81 :                 if (state->opt.expect_unrecoverable) {
    2153           4 :                         if (unrecoverable_error == 0)
    2154           0 :                                 return -1;
    2155          77 :                 } else if (state->opt.expect_recoverable) {
    2156          21 :                         if (unrecoverable_error != 0)
    2157           0 :                                 return -1;
    2158          21 :                         if (soft_error + silent_error + io_error == 0)
    2159           0 :                                 return -1;
    2160             :                 } else {
    2161          56 :                         if (unrecoverable_error != 0)
    2162           0 :                                 return -1;
    2163          56 :                         if (soft_error + silent_error + io_error != 0)
    2164           0 :                                 return -1;
    2165             :                 }
    2166             :         }
    2167             : 
    2168         132 :         if (alert < 0)
    2169           0 :                 return -1;
    2170             : 
    2171         132 :         return 0;
    2172             : }
    2173             : 
    2174         134 : int state_check(struct snapraid_state* state, int fix, block_off_t blockstart, block_off_t blockcount)
    2175             : {
    2176             :         block_off_t blockmax;
    2177             :         data_off_t size;
    2178             :         int ret;
    2179             :         struct snapraid_parity_handle parity[LEV_MAX];
    2180             :         struct snapraid_parity_handle* parity_ptr[LEV_MAX];
    2181             :         unsigned process_error;
    2182             :         unsigned l;
    2183             : 
    2184         134 :         msg_progress("Initializing...\n");
    2185             : 
    2186         134 :         blockmax = parity_allocated_size(state);
    2187         134 :         size = blockmax * (data_off_t)state->block_size;
    2188             : 
    2189         134 :         if (blockstart > blockmax) {
    2190             :                 /* LCOV_EXCL_START */
    2191             :                 log_fatal(EUSER, "Error in the specified starting block %u. It's larger than the parity size %u.\n", blockstart, blockmax);
    2192             :                 exit(EXIT_FAILURE);
    2193             :                 /* LCOV_EXCL_STOP */
    2194             :         }
    2195             : 
    2196             :         /* adjust the number of block to process */
    2197         134 :         if (blockcount != 0 && blockstart + blockcount < blockmax) {
    2198           0 :                 blockmax = blockstart + blockcount;
    2199             :         }
    2200             : 
    2201         134 :         if (fix) {
    2202             :                 /*
    2203             :                  * If fixing, create the file and open for writing
    2204             :                  * if it fails, we cannot continue
    2205             :                  */
    2206         196 :                 for (l = 0; l < state->level; ++l) {
    2207             :                         /* skip parity disks that are not accessible */
    2208         145 :                         if (state->parity[l].skip_access) {
    2209           1 :                                 parity_ptr[l] = 0;
    2210           1 :                                 continue;
    2211             :                         }
    2212             : 
    2213         144 :                         parity_ptr[l] = &parity[l];
    2214             : 
    2215             :                         /* if the parity is excluded */
    2216         144 :                         if (state->parity[l].is_excluded_by_filter) {
    2217             :                                 /* open for reading, and ignore error */
    2218          18 :                                 ret = parity_open(parity_ptr[l], &state->parity[l], l, state->file_mode, state->block_size, state->opt.parity_limit_size);
    2219          18 :                                 if (ret == -1) {
    2220           0 :                                         log_tag("parity_%s:%u:%s: Open error. %s.\n", es(errno), blockmax, lev_config_name(l), strerror(errno));
    2221           0 :                                         if (is_hw(errno)) {
    2222           0 :                                                 log_fatal_errno(errno, lev_config_name(l));
    2223           0 :                                                 exit(EXIT_FAILURE);
    2224             :                                         }
    2225             : 
    2226             :                                         /* continue anyway */
    2227           0 :                                         parity_ptr[l] = 0;
    2228             :                                 }
    2229             :                         } else {
    2230             :                                 /* open for writing */
    2231         126 :                                 ret = parity_create(parity_ptr[l], &state->parity[l], l, state->file_mode, state->block_size, state->opt.parity_limit_size);
    2232         126 :                                 if (ret == -1) {
    2233             :                                         /* LCOV_EXCL_START */
    2234             :                                         log_tag("parity_%s:%u:%s: Create error. %s.\n", es(errno), 0, lev_config_name(l), strerror(errno));
    2235             :                                         log_fatal_errno(errno, lev_config_name(l));
    2236             :                                         exit(EXIT_FAILURE);
    2237             :                                         /* LCOV_EXCL_STOP */
    2238             :                                 }
    2239             : 
    2240         126 :                                 ret = parity_chsize(parity_ptr[l], &state->parity[l], 0, size, state->block_size, state->opt.skip_fallocate, state->opt.skip_space_holder);
    2241         126 :                                 if (ret == -1) {
    2242             :                                         /* LCOV_EXCL_START */
    2243             :                                         log_tag("parity_%s:%u:%s: Create error. %s.\n", es(errno), 0, lev_config_name(l), strerror(errno));
    2244             :                                         log_fatal_errno(errno, lev_config_name(l));
    2245             :                                         exit(EXIT_FAILURE);
    2246             :                                         /* LCOV_EXCL_STOP */
    2247             :                                 }
    2248             :                         }
    2249             :                 }
    2250          83 :         } else if (!state->opt.auditonly) {
    2251             :                 /*
    2252             :                  * If checking, open the file for reading
    2253             :                  * it may fail if the file doesn't exist, in this case we continue to check the files
    2254             :                  */
    2255         416 :                 for (l = 0; l < state->level; ++l) {
    2256         339 :                         parity_ptr[l] = &parity[l];
    2257         339 :                         ret = parity_open(parity_ptr[l], &state->parity[l], l, state->file_mode, state->block_size, state->opt.parity_limit_size);
    2258         339 :                         if (ret == -1) {
    2259           1 :                                 log_tag("parity_%s:%u:%s: Open error. %s.\n", es(errno), blockmax, lev_config_name(l), strerror(errno));
    2260           1 :                                 if (is_hw(errno)) {
    2261           0 :                                         log_fatal_errno(errno, lev_config_name(l));
    2262           0 :                                         exit(EXIT_FAILURE);
    2263             :                                 }
    2264             : 
    2265           1 :                                 msg_status("No accessible %s file, only files will be checked.\n", lev_name(l));
    2266             : 
    2267             :                                 /* continue anyway */
    2268           1 :                                 parity_ptr[l] = 0;
    2269             :                         }
    2270             :                 }
    2271             :         } else {
    2272             :                 /* otherwise don't use any parity */
    2273          28 :                 for (l = 0; l < state->level; ++l)
    2274          22 :                         parity_ptr[l] = 0;
    2275             :         }
    2276             : 
    2277         134 :         process_error = 0;
    2278             : 
    2279             :         /* skip degenerated cases of empty parity, or skipping all */
    2280         134 :         if (blockstart < blockmax) {
    2281         132 :                 ret = state_check_process(state, fix, parity_ptr, blockstart, blockmax);
    2282         132 :                 if (ret == -1) {
    2283             :                         /* LCOV_EXCL_START */
    2284             :                         ++process_error;
    2285             :                         /* continue, as we are already exiting */
    2286             :                         /* LCOV_EXCL_STOP */
    2287             :                 }
    2288             :         }
    2289             : 
    2290             :         /* try to close only if opened */
    2291         640 :         for (l = 0; l < state->level; ++l) {
    2292         506 :                 if (parity_ptr[l]) {
    2293             :                         /* if fixing and not excluded, truncate parity not valid */
    2294         482 :                         if (fix && !state->parity[l].is_excluded_by_filter) {
    2295         126 :                                 ret = parity_truncate(parity_ptr[l]);
    2296         126 :                                 if (ret == -1) {
    2297             :                                         /* LCOV_EXCL_START */
    2298             :                                         log_tag("parity_%s:%u:%s: Truncate error. %s.\n", es(errno), blockmax, lev_config_name(l), strerror(errno));
    2299             :                                         log_fatal_errno(errno, lev_config_name(l));
    2300             : 
    2301             :                                         ++process_error;
    2302             :                                         /* continue, as we are already exiting */
    2303             :                                         /* LCOV_EXCL_STOP */
    2304             :                                 }
    2305             :                         }
    2306             : 
    2307         482 :                         ret = parity_close(parity_ptr[l]);
    2308         482 :                         if (ret == -1) {
    2309             :                                 /* LCOV_EXCL_START */
    2310             :                                 log_tag("parity_%s:%u:%s: Close error. %s.\n", es(errno), blockmax, lev_config_name(l), strerror(errno));
    2311             :                                 log_fatal_errno(errno, lev_config_name(l));
    2312             : 
    2313             :                                 ++process_error;
    2314             :                                 /* continue, as we are already exiting */
    2315             :                                 /* LCOV_EXCL_STOP */
    2316             :                         }
    2317             :                 }
    2318             :         }
    2319             : 
    2320         134 :         if (process_error != 0)
    2321           0 :                 return -1;
    2322         134 :         return 0;
    2323             : }
    2324             : 

Generated by: LCOV version 1.0