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-03-01 15:35:05 Functions: 10 10 100.0 %

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

Generated by: LCOV version 1.0