snapraid/cov/cmdline/scan.c.gcov.html
Andrea Mazzoleni e01ca1e0fa Auto update
2016-11-21 19:48:21 +01:00

1956 lines
199 KiB
HTML

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>LCOV - lcov.info - cmdline/scan.c</title>
<link rel="stylesheet" type="text/css" href="../gcov.css">
</head>
<body>
<table width="100%" border=0 cellspacing=0 cellpadding=0>
<tr><td class="title">LCOV - code coverage report</td></tr>
<tr><td class="ruler"><img src="../glass.png" width=3 height=3 alt=""></td></tr>
<tr>
<td width="100%">
<table cellpadding=1 border=0 width="100%">
<tr>
<td width="10%" class="headerItem">Current view:</td>
<td width="35%" class="headerValue"><a href="../index.html">top level</a> - <a href="index.html">cmdline</a> - scan.c<span style="font-size: 80%;"> (source / <a href="scan.c.func.html">functions</a>)</span></td>
<td width="5%"></td>
<td width="15%"></td>
<td width="10%" class="headerCovTableHead">Hit</td>
<td width="10%" class="headerCovTableHead">Total</td>
<td width="15%" class="headerCovTableHead">Coverage</td>
</tr>
<tr>
<td class="headerItem">Test:</td>
<td class="headerValue">lcov.info</td>
<td></td>
<td class="headerItem">Lines:</td>
<td class="headerCovTableEntry">565</td>
<td class="headerCovTableEntry">631</td>
<td class="headerCovTableEntryMed">89.5 %</td>
</tr>
<tr>
<td class="headerItem">Date:</td>
<td class="headerValue">2016-11-21</td>
<td></td>
<td class="headerItem">Functions:</td>
<td class="headerCovTableEntry">23</td>
<td class="headerCovTableEntry">23</td>
<td class="headerCovTableEntryHi">100.0 %</td>
</tr>
<tr><td><img src="../glass.png" width=3 height=3 alt=""></td></tr>
</table>
</td>
</tr>
<tr><td class="ruler"><img src="../glass.png" width=3 height=3 alt=""></td></tr>
</table>
<table cellpadding=0 cellspacing=0 border=0>
<tr>
<td><br></td>
</tr>
<tr>
<td>
<pre class="sourceHeading"> Line data Source code</pre>
<pre class="source">
<a name="1"><span class="lineNum"> 1 </span> : /*</a>
<span class="lineNum"> 2 </span> : * Copyright (C) 2011 Andrea Mazzoleni
<span class="lineNum"> 3 </span> : *
<span class="lineNum"> 4 </span> : * This program is free software: you can redistribute it and/or modify
<span class="lineNum"> 5 </span> : * it under the terms of the GNU General Public License as published by
<span class="lineNum"> 6 </span> : * the Free Software Foundation, either version 3 of the License, or
<span class="lineNum"> 7 </span> : * (at your option) any later version.
<span class="lineNum"> 8 </span> : *
<span class="lineNum"> 9 </span> : * This program is distributed in the hope that it will be useful,
<span class="lineNum"> 10 </span> : * but WITHOUT ANY WARRANTY; without even the implied warranty of
<span class="lineNum"> 11 </span> : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
<span class="lineNum"> 12 </span> : * GNU General Public License for more details.
<span class="lineNum"> 13 </span> : *
<span class="lineNum"> 14 </span> : * You should have received a copy of the GNU General Public License
<span class="lineNum"> 15 </span> : * along with this program. If not, see &lt;http://www.gnu.org/licenses/&gt;.
<span class="lineNum"> 16 </span> : */
<span class="lineNum"> 17 </span> :
<span class="lineNum"> 18 </span> : #include &quot;portable.h&quot;
<span class="lineNum"> 19 </span> :
<span class="lineNum"> 20 </span> : #include &quot;support.h&quot;
<span class="lineNum"> 21 </span> : #include &quot;elem.h&quot;
<span class="lineNum"> 22 </span> : #include &quot;state.h&quot;
<span class="lineNum"> 23 </span> : #include &quot;parity.h&quot;
<span class="lineNum"> 24 </span> :
<span class="lineNum"> 25 </span> : struct snapraid_scan {
<span class="lineNum"> 26 </span> : struct snapraid_state* state; /**&lt; State used. */
<span class="lineNum"> 27 </span> : struct snapraid_disk* disk; /**&lt; Disk used. */
<span class="lineNum"> 28 </span> :
<span class="lineNum"> 29 </span> : /**
<span class="lineNum"> 30 </span> : * Counters of changes.
<span class="lineNum"> 31 </span> : */
<span class="lineNum"> 32 </span> : unsigned count_equal; /**&lt; Files equal. */
<span class="lineNum"> 33 </span> : unsigned count_move; /**&lt; Files with a different name, but equal inode, size and timestamp in the same disk. */
<span class="lineNum"> 34 </span> : unsigned count_restore; /**&lt; Files with equal name, size and timestamp, but different inode. */
<span class="lineNum"> 35 </span> : unsigned count_change; /**&lt; Files with same name, but different size and/or timestamp. */
<span class="lineNum"> 36 </span> : unsigned count_copy; /**&lt; Files new, with same name size and timestamp of a file in a different disk. */
<span class="lineNum"> 37 </span> : unsigned count_insert; /**&lt; Files new. */
<span class="lineNum"> 38 </span> : unsigned count_remove; /**&lt; Files removed. */
<span class="lineNum"> 39 </span> :
<span class="lineNum"> 40 </span> : tommy_list file_insert_list; /**&lt; Files to insert. */
<span class="lineNum"> 41 </span> : tommy_list link_insert_list; /**&lt; Links to insert. */
<span class="lineNum"> 42 </span> : tommy_list dir_insert_list; /**&lt; Dirs to insert. */
<span class="lineNum"> 43 </span> :
<span class="lineNum"> 44 </span> : /* nodes for data structures */
<span class="lineNum"> 45 </span> : tommy_node node;
<span class="lineNum"> 46 </span> : };
<span class="lineNum"> 47 </span> :
<span class="lineNum"> 48 </span> : /**
<a name="49"><span class="lineNum"> 49 </span> : * Remove the specified link from the data set.</a>
<span class="lineNum"> 50 </span> : */
<span class="lineNum"> 51 </span><span class="lineCov"> 956 : static void scan_link_remove(struct snapraid_scan* scan, struct snapraid_link* slink)</span>
<span class="lineNum"> 52 </span> : {
<span class="lineNum"> 53 </span><span class="lineCov"> 956 : struct snapraid_state* state = scan-&gt;state;</span>
<span class="lineNum"> 54 </span><span class="lineCov"> 956 : struct snapraid_disk* disk = scan-&gt;disk;</span>
<span class="lineNum"> 55 </span> :
<span class="lineNum"> 56 </span> : /* state changed */
<span class="lineNum"> 57 </span><span class="lineCov"> 956 : state-&gt;need_write = 1;</span>
<span class="lineNum"> 58 </span> :
<span class="lineNum"> 59 </span> : /* remove the file from the link containers */
<span class="lineNum"> 60 </span><span class="lineCov"> 956 : tommy_hashdyn_remove_existing(&amp;disk-&gt;linkset, &amp;slink-&gt;nodeset);</span>
<span class="lineNum"> 61 </span><span class="lineCov"> 956 : tommy_list_remove_existing(&amp;disk-&gt;linklist, &amp;slink-&gt;nodelist);</span>
<span class="lineNum"> 62 </span> :
<span class="lineNum"> 63 </span> : /* deallocate */
<span class="lineNum"> 64 </span><span class="lineCov"> 956 : link_free(slink);</span>
<span class="lineNum"> 65 </span><span class="lineCov"> 956 : }</span>
<span class="lineNum"> 66 </span> :
<span class="lineNum"> 67 </span> : /**
<a name="68"><span class="lineNum"> 68 </span> : * Insert the specified link in the data set.</a>
<span class="lineNum"> 69 </span> : */
<span class="lineNum"> 70 </span><span class="lineCov"> 2457 : static void scan_link_insert(struct snapraid_scan* scan, struct snapraid_link* slink)</span>
<span class="lineNum"> 71 </span> : {
<span class="lineNum"> 72 </span><span class="lineCov"> 2457 : struct snapraid_state* state = scan-&gt;state;</span>
<span class="lineNum"> 73 </span><span class="lineCov"> 2457 : struct snapraid_disk* disk = scan-&gt;disk;</span>
<span class="lineNum"> 74 </span> :
<span class="lineNum"> 75 </span> : /* state changed */
<span class="lineNum"> 76 </span><span class="lineCov"> 2457 : state-&gt;need_write = 1;</span>
<span class="lineNum"> 77 </span> :
<span class="lineNum"> 78 </span> : /* insert the link in the link containers */
<span class="lineNum"> 79 </span><span class="lineCov"> 2457 : tommy_hashdyn_insert(&amp;disk-&gt;linkset, &amp;slink-&gt;nodeset, slink, link_name_hash(slink-&gt;sub));</span>
<span class="lineNum"> 80 </span><span class="lineCov"> 2457 : tommy_list_insert_tail(&amp;disk-&gt;linklist, &amp;slink-&gt;nodelist, slink);</span>
<span class="lineNum"> 81 </span><span class="lineCov"> 2457 : }</span>
<span class="lineNum"> 82 </span> :
<span class="lineNum"> 83 </span> : /**
<a name="84"><span class="lineNum"> 84 </span> : * Process a symbolic link.</a>
<span class="lineNum"> 85 </span> : */
<span class="lineNum"> 86 </span><span class="lineCov"> 36184 : static void scan_link(struct snapraid_scan* scan, int is_diff, const char* sub, const char* linkto, unsigned link_flag)</span>
<span class="lineNum"> 87 </span> : {
<span class="lineNum"> 88 </span><span class="lineCov"> 36184 : struct snapraid_state* state = scan-&gt;state;</span>
<span class="lineNum"> 89 </span><span class="lineCov"> 36184 : struct snapraid_disk* disk = scan-&gt;disk;</span>
<span class="lineNum"> 90 </span> : struct snapraid_link* slink;
<span class="lineNum"> 91 </span> : char esc_buffer[ESC_MAX];
<span class="lineNum"> 92 </span> :
<span class="lineNum"> 93 </span> : /* check if the link already exists */
<span class="lineNum"> 94 </span><span class="lineCov"> 36184 : slink = tommy_hashdyn_search(&amp;disk-&gt;linkset, link_name_compare_to_arg, sub, link_name_hash(sub));</span>
<span class="lineNum"> 95 </span><span class="lineCov"> 36184 : if (slink) {</span>
<span class="lineNum"> 96 </span> : /* check if multiple files have the same name */
<span class="lineNum"> 97 </span><span class="lineCov"> 33727 : if (link_flag_has(slink, FILE_IS_PRESENT)) {</span>
<span class="lineNum"> 98 </span> : /* LCOV_EXCL_START */
<span class="lineNum"> 99 </span> : log_fatal(&quot;Internal inconsistency for link '%s%s'\n&quot;, disk-&gt;dir, sub);
<span class="lineNum"> 100 </span> : os_abort();
<span class="lineNum"> 101 </span> : /* LCOV_EXCL_STOP */
<span class="lineNum"> 102 </span> : }
<span class="lineNum"> 103 </span> :
<span class="lineNum"> 104 </span> : /* mark as present */
<span class="lineNum"> 105 </span><span class="lineCov"> 33727 : link_flag_set(slink, FILE_IS_PRESENT);</span>
<span class="lineNum"> 106 </span> :
<span class="lineNum"> 107 </span> : /* check if the link is not changed and it's of the same kind */
<span class="lineNum"> 108 </span><span class="lineCov"> 33727 : if (strcmp(slink-&gt;linkto, linkto) == 0 &amp;&amp; link_flag == link_flag_get(slink, FILE_IS_LINK_MASK)) {</span>
<span class="lineNum"> 109 </span> : /* it's equal */
<span class="lineNum"> 110 </span><span class="lineCov"> 33721 : ++scan-&gt;count_equal;</span>
<span class="lineNum"> 111 </span> :
<span class="lineNum"> 112 </span><span class="lineCov"> 67442 : if (state-&gt;opt.gui) {</span>
<span class="lineNum"> 113 </span><span class="lineCov"> 829 : log_tag(&quot;scan:equal:%s:%s\n&quot;, disk-&gt;name, esc_tag(slink-&gt;sub, esc_buffer));</span>
<span class="lineNum"> 114 </span> : }
<span class="lineNum"> 115 </span> : } else {
<span class="lineNum"> 116 </span> : /* it's an update */
<span class="lineNum"> 117 </span> :
<span class="lineNum"> 118 </span> : /* we have to save the linkto/type */
<span class="lineNum"> 119 </span><span class="lineCov"> 6 : state-&gt;need_write = 1;</span>
<span class="lineNum"> 120 </span> :
<span class="lineNum"> 121 </span><span class="lineCov"> 6 : ++scan-&gt;count_change;</span>
<span class="lineNum"> 122 </span> :
<span class="lineNum"> 123 </span><span class="lineCov"> 6 : log_tag(&quot;scan:update:%s:%s\n&quot;, disk-&gt;name, esc_tag(slink-&gt;sub, esc_buffer));</span>
<span class="lineNum"> 124 </span><span class="lineCov"> 6 : if (is_diff) {</span>
<span class="lineNum"> 125 </span><span class="lineCov"> 3 : printf(&quot;update %s\n&quot;, fmt_term(disk, slink-&gt;sub, esc_buffer));</span>
<span class="lineNum"> 126 </span> : }
<span class="lineNum"> 127 </span> :
<span class="lineNum"> 128 </span> : /* update it */
<span class="lineNum"> 129 </span><span class="lineCov"> 6 : free(slink-&gt;linkto);</span>
<span class="lineNum"> 130 </span><span class="lineCov"> 6 : slink-&gt;linkto = strdup_nofail(linkto);</span>
<span class="lineNum"> 131 </span><span class="lineCov"> 6 : link_flag_let(slink, link_flag, FILE_IS_LINK_MASK);</span>
<span class="lineNum"> 132 </span> : }
<span class="lineNum"> 133 </span> :
<span class="lineNum"> 134 </span> : /* nothing more to do */
<span class="lineNum"> 135 </span><span class="lineCov"> 69911 : return;</span>
<span class="lineNum"> 136 </span> : } else {
<span class="lineNum"> 137 </span> : /* create the new link */
<span class="lineNum"> 138 </span><span class="lineCov"> 2457 : ++scan-&gt;count_insert;</span>
<span class="lineNum"> 139 </span> :
<span class="lineNum"> 140 </span><span class="lineCov"> 2457 : log_tag(&quot;scan:add:%s:%s\n&quot;, disk-&gt;name, esc_tag(sub, esc_buffer));</span>
<span class="lineNum"> 141 </span><span class="lineCov"> 2457 : if (is_diff) {</span>
<span class="lineNum"> 142 </span><span class="lineCov"> 599 : printf(&quot;add %s\n&quot;, fmt_term(disk, sub, esc_buffer));</span>
<span class="lineNum"> 143 </span> : }
<span class="lineNum"> 144 </span> :
<span class="lineNum"> 145 </span> : /* and continue to insert it */
<span class="lineNum"> 146 </span> : }
<span class="lineNum"> 147 </span> :
<span class="lineNum"> 148 </span> : /* insert it */
<span class="lineNum"> 149 </span><span class="lineCov"> 2457 : slink = link_alloc(sub, linkto, link_flag);</span>
<span class="lineNum"> 150 </span> :
<span class="lineNum"> 151 </span> : /* mark it as present */
<span class="lineNum"> 152 </span><span class="lineCov"> 2457 : link_flag_set(slink, FILE_IS_PRESENT);</span>
<span class="lineNum"> 153 </span> :
<span class="lineNum"> 154 </span> : /* insert it in the delayed insert list */
<span class="lineNum"> 155 </span><span class="lineCov"> 2457 : tommy_list_insert_tail(&amp;scan-&gt;link_insert_list, &amp;slink-&gt;nodelist, slink);</span>
<span class="lineNum"> 156 </span> : }
<span class="lineNum"> 157 </span> :
<span class="lineNum"> 158 </span> : /**
<a name="159"><span class="lineNum"> 159 </span> : * Insert the specified file in the parity.</a>
<span class="lineNum"> 160 </span> : */
<span class="lineNum"> 161 </span><span class="lineCov"> 101881 : static void scan_file_allocate(struct snapraid_scan* scan, struct snapraid_file* file)</span>
<span class="lineNum"> 162 </span> : {
<span class="lineNum"> 163 </span><span class="lineCov"> 101881 : struct snapraid_state* state = scan-&gt;state;</span>
<span class="lineNum"> 164 </span><span class="lineCov"> 101881 : struct snapraid_disk* disk = scan-&gt;disk;</span>
<span class="lineNum"> 165 </span> : block_off_t i;
<span class="lineNum"> 166 </span> : block_off_t parity_pos;
<span class="lineNum"> 167 </span> :
<span class="lineNum"> 168 </span> : /* state changed */
<span class="lineNum"> 169 </span><span class="lineCov"> 101881 : state-&gt;need_write = 1;</span>
<span class="lineNum"> 170 </span> :
<span class="lineNum"> 171 </span> : /* allocate the blocks of the file */
<span class="lineNum"> 172 </span><span class="lineCov"> 101881 : parity_pos = disk-&gt;first_free_block;</span>
<span class="lineNum"> 173 </span><span class="lineCov"> 353073 : for (i = 0; i &lt; file-&gt;blockmax; ++i) {</span>
<span class="lineNum"> 174 </span> : struct snapraid_block* block;
<span class="lineNum"> 175 </span> : struct snapraid_block* over_block;
<span class="lineNum"> 176 </span> : snapraid_info info;
<span class="lineNum"> 177 </span> :
<span class="lineNum"> 178 </span> : /* increment the position until the first really free block */
<span class="lineNum"> 179 </span><span class="lineCov"> 1022715 : while (block_has_file(fs_par2block_find(disk, parity_pos)))</span>
<span class="lineNum"> 180 </span><span class="lineCov"> 520331 : ++parity_pos;</span>
<span class="lineNum"> 181 </span> :
<span class="lineNum"> 182 </span> : /* get block we are going to overwrite, if any */
<span class="lineNum"> 183 </span><span class="lineCov"> 251192 : over_block = fs_par2block_find(disk, parity_pos);</span>
<span class="lineNum"> 184 </span> :
<span class="lineNum"> 185 </span> : /* deallocate it */
<span class="lineNum"> 186 </span><span class="lineCov"> 251192 : if (over_block != BLOCK_NULL)</span>
<span class="lineNum"> 187 </span><span class="lineCov"> 95279 : fs_deallocate(disk, parity_pos);</span>
<span class="lineNum"> 188 </span> :
<span class="lineNum"> 189 </span> : /* get block specific info */
<span class="lineNum"> 190 </span><span class="lineCov"> 251192 : info = info_get(&amp;state-&gt;infoarr, parity_pos);</span>
<span class="lineNum"> 191 </span> :
<span class="lineNum"> 192 </span> : /* get the new block we are going to write */
<span class="lineNum"> 193 </span><span class="lineCov"> 251192 : block = fs_file2block_get(file, i);</span>
<span class="lineNum"> 194 </span> :
<span class="lineNum"> 195 </span> : /* if the file block already has an updated hash without rehash */
<span class="lineNum"> 196 </span><span class="lineCov"> 251192 : if (block_has_updated_hash(block) &amp;&amp; !info_get_rehash(info)) {</span>
<span class="lineNum"> 197 </span> : /* the only possible case is for REP blocks */
<span class="lineNum"> 198 </span><span class="lineCov"> 86215 : assert(block_state_get(block) == BLOCK_STATE_REP);</span>
<span class="lineNum"> 199 </span> :
<span class="lineNum"> 200 </span> : /* convert to a REP block */
<span class="lineNum"> 201 </span><span class="lineCov"> 86215 : block_state_set(block, BLOCK_STATE_REP);</span>
<span class="lineNum"> 202 </span> :
<span class="lineNum"> 203 </span> : /* and keep the hash as it's */
<span class="lineNum"> 204 </span> : } else {
<span class="lineNum"> 205 </span> : unsigned over_state;
<span class="lineNum"> 206 </span> :
<span class="lineNum"> 207 </span> : /* convert to a CHG block */
<span class="lineNum"> 208 </span><span class="lineCov"> 164977 : block_state_set(block, BLOCK_STATE_CHG);</span>
<span class="lineNum"> 209 </span> :
<span class="lineNum"> 210 </span> : /* state of the block we are going to overwrite */
<span class="lineNum"> 211 </span><span class="lineCov"> 164977 : over_state = block_state_get(over_block);</span>
<span class="lineNum"> 212 </span> :
<span class="lineNum"> 213 </span> : /* if the block is an empty one */
<span class="lineNum"> 214 </span><span class="lineCov"> 164977 : if (over_state == BLOCK_STATE_EMPTY) {</span>
<span class="lineNum"> 215 </span> : /* the block was empty and filled with zeros */
<span class="lineNum"> 216 </span> : /* set the hash to the special ZERO value */
<span class="lineNum"> 217 </span><span class="lineCov"> 115543 : hash_zero_set(block-&gt;hash);</span>
<span class="lineNum"> 218 </span> : } else {
<span class="lineNum"> 219 </span> : /* otherwise it's a DELETED one */
<span class="lineNum"> 220 </span><span class="lineCov"> 49434 : assert(over_state == BLOCK_STATE_DELETED);</span>
<span class="lineNum"> 221 </span> :
<span class="lineNum"> 222 </span> : /* copy the past hash of the block */
<span class="lineNum"> 223 </span><span class="lineCov"> 49434 : memcpy(block-&gt;hash, over_block-&gt;hash, BLOCK_HASH_SIZE);</span>
<span class="lineNum"> 224 </span> :
<span class="lineNum"> 225 </span> : /* if we have not already cleared the past hash */
<span class="lineNum"> 226 </span><span class="lineCov"> 49434 : if (!state-&gt;clear_past_hash) {</span>
<span class="lineNum"> 227 </span> : /* in this case we don't know if the old state is still the one */
<span class="lineNum"> 228 </span> : /* stored inside the parity, because after an aborted sync, the parity */
<span class="lineNum"> 229 </span> : /* may be or may be not have been updated with the new data */
<span class="lineNum"> 230 </span> : /* Then we reset the hash to a bogus value */
<span class="lineNum"> 231 </span> : /* For example: */
<span class="lineNum"> 232 </span> : /* - One file is deleted */
<span class="lineNum"> 233 </span> : /* - Sync aborted after, updating the parity to the new state, */
<span class="lineNum"> 234 </span> : /* but without saving the content file representing this new state. */
<span class="lineNum"> 235 </span> : /* - Another file is added again (exactly here) */
<span class="lineNum"> 236 </span> : /* with the hash of DELETED block not representing the real parity state */
<span class="lineNum"> 237 </span><span class="lineCov"> 421 : hash_invalid_set(block-&gt;hash);</span>
<span class="lineNum"> 238 </span> : }
<span class="lineNum"> 239 </span> : }
<span class="lineNum"> 240 </span> : }
<span class="lineNum"> 241 </span> :
<span class="lineNum"> 242 </span> : /* store in the disk map, after invalidating all the other blocks */
<span class="lineNum"> 243 </span><span class="lineCov"> 251192 : fs_allocate(disk, parity_pos, file, i);</span>
<span class="lineNum"> 244 </span> :
<span class="lineNum"> 245 </span> : /* set the new free position */
<span class="lineNum"> 246 </span><span class="lineCov"> 251192 : disk-&gt;first_free_block = parity_pos + 1;</span>
<span class="lineNum"> 247 </span> : }
<span class="lineNum"> 248 </span> :
<span class="lineNum"> 249 </span> : /* insert in the list of contained files */
<span class="lineNum"> 250 </span><span class="lineCov"> 101881 : tommy_list_insert_tail(&amp;disk-&gt;filelist, &amp;file-&gt;nodelist, file);</span>
<span class="lineNum"> 251 </span><span class="lineCov"> 101881 : }</span>
<span class="lineNum"> 252 </span> :
<span class="lineNum"> 253 </span> : /**
<span class="lineNum"> 254 </span> : * Delete the specified file from the parity.
<span class="lineNum"> 255 </span> : *
<span class="lineNum"> 256 </span> : * Note that the parity remains allocated, but the blocks and the file are marked as DELETED.
<span class="lineNum"> 257 </span> : * The file is then inserted in the deleted set, and it should not be deallocated,
<a name="258"><span class="lineNum"> 258 </span> : * as the parity still references it.</a>
<span class="lineNum"> 259 </span> : */
<span class="lineNum"> 260 </span><span class="lineCov"> 57015 : static void scan_file_deallocate(struct snapraid_scan* scan, struct snapraid_file* file)</span>
<span class="lineNum"> 261 </span> : {
<span class="lineNum"> 262 </span><span class="lineCov"> 57015 : struct snapraid_state* state = scan-&gt;state;</span>
<span class="lineNum"> 263 </span><span class="lineCov"> 57015 : struct snapraid_disk* disk = scan-&gt;disk;</span>
<span class="lineNum"> 264 </span> : block_off_t i;
<span class="lineNum"> 265 </span> :
<span class="lineNum"> 266 </span> : /* remove from the list of contained files */
<span class="lineNum"> 267 </span><span class="lineCov"> 57015 : tommy_list_remove_existing(&amp;disk-&gt;filelist, &amp;file-&gt;nodelist);</span>
<span class="lineNum"> 268 </span> :
<span class="lineNum"> 269 </span> : /* state changed */
<span class="lineNum"> 270 </span><span class="lineCov"> 57015 : state-&gt;need_write = 1;</span>
<span class="lineNum"> 271 </span> :
<span class="lineNum"> 272 </span> : /* here we are supposed to adjust the ::first_free_block position */
<span class="lineNum"> 273 </span> : /* with the parity position we are deleting */
<span class="lineNum"> 274 </span> : /* but we also know that we do only delayed insert, after all the deletion, */
<span class="lineNum"> 275 </span> : /* so at this point ::first_free_block is always at 0, and we don't need to update it */
<span class="lineNum"> 276 </span><span class="lineCov"> 57015 : if (disk-&gt;first_free_block != 0) {</span>
<span class="lineNum"> 277 </span> : /* LCOV_EXCL_START */
<span class="lineNum"> 278 </span> : log_fatal(&quot;Internal inconsistency for first free position at '%u' deallocating file '%s'\n&quot;, disk-&gt;first_free_block, file-&gt;sub);
<span class="lineNum"> 279 </span> : os_abort();
<span class="lineNum"> 280 </span> : /* LCOV_EXCL_STOP */
<span class="lineNum"> 281 </span> : }
<span class="lineNum"> 282 </span> :
<span class="lineNum"> 283 </span> : /* free all the blocks of the file */
<span class="lineNum"> 284 </span><span class="lineCov"> 197592 : for (i = 0; i &lt; file-&gt;blockmax; ++i) {</span>
<span class="lineNum"> 285 </span><span class="lineCov"> 140577 : struct snapraid_block* block = fs_file2block_get(file, i);</span>
<span class="lineNum"> 286 </span> : unsigned block_state;
<span class="lineNum"> 287 </span> :
<span class="lineNum"> 288 </span> : /* in case we scan after an aborted sync, */
<span class="lineNum"> 289 </span> : /* we could get also intermediate states */
<span class="lineNum"> 290 </span><span class="lineCov"> 140577 : block_state = block_state_get(block);</span>
<span class="lineNum"> 291 </span><span class="lineCov"> 140577 : switch (block_state) {</span>
<span class="lineNum"> 292 </span> : case BLOCK_STATE_BLK :
<span class="lineNum"> 293 </span> : /* we keep the hash making it an &quot;old&quot; hash, because the parity is still containing data for it */
<span class="lineNum"> 294 </span><span class="lineCov"> 35580 : break;</span>
<span class="lineNum"> 295 </span> : case BLOCK_STATE_CHG :
<span class="lineNum"> 296 </span> : /* if we have not already cleared the past hash */
<span class="lineNum"> 297 </span><span class="lineCov"> 28040 : if (!state-&gt;clear_past_hash) {</span>
<span class="lineNum"> 298 </span> : /* in these cases we don't know if the old state is still the one */
<span class="lineNum"> 299 </span> : /* stored inside the parity, because after an aborted sync, the parity */
<span class="lineNum"> 300 </span> : /* may be or may be not have been updated with the data that it's now */
<span class="lineNum"> 301 </span> : /* deleted. Then we reset the hash to a bogus value. */
<span class="lineNum"> 302 </span> : /* For example: */
<span class="lineNum"> 303 </span> : /* - One file is added */
<span class="lineNum"> 304 </span> : /* - Sync aborted after updating the parity to the new state, */
<span class="lineNum"> 305 </span> : /* but without saving the content file representing this new state. */
<span class="lineNum"> 306 </span> : /* - File is now deleted after the aborted sync */
<span class="lineNum"> 307 </span> : /* - Sync again, deleting the blocks (exactly here) */
<span class="lineNum"> 308 </span> : /* with the hash of CHG block not representing the real parity state */
<span class="lineNum"> 309 </span><span class="lineCov"> 40 : hash_invalid_set(block-&gt;hash);</span>
<span class="lineNum"> 310 </span> : }
<span class="lineNum"> 311 </span><span class="lineCov"> 28040 : break;</span>
<span class="lineNum"> 312 </span> : case BLOCK_STATE_REP :
<span class="lineNum"> 313 </span> : /* we just don't know the old hash, and then we set it to invalid */
<span class="lineNum"> 314 </span><span class="lineCov"> 76957 : hash_invalid_set(block-&gt;hash);</span>
<span class="lineNum"> 315 </span><span class="lineCov"> 76957 : break;</span>
<span class="lineNum"> 316 </span> : default :
<span class="lineNum"> 317 </span> : /* LCOV_EXCL_START */
<span class="lineNum"> 318 </span> : log_fatal(&quot;Internal inconsistency in file '%s' deallocating block '%u:%u' state %u\n&quot;, file-&gt;sub, i, file-&gt;blockmax, block_state);
<span class="lineNum"> 319 </span> : os_abort();
<span class="lineNum"> 320 </span> : /* LCOV_EXCL_STOP */
<span class="lineNum"> 321 </span> : }
<span class="lineNum"> 322 </span> :
<span class="lineNum"> 323 </span> : /* set the block as deleted */
<span class="lineNum"> 324 </span><span class="lineCov"> 140577 : block_state_set(block, BLOCK_STATE_DELETED);</span>
<span class="lineNum"> 325 </span> : }
<span class="lineNum"> 326 </span> :
<span class="lineNum"> 327 </span> : /* mark the file as deleted */
<span class="lineNum"> 328 </span><span class="lineCov"> 57015 : file_flag_set(file, FILE_IS_DELETED);</span>
<span class="lineNum"> 329 </span> :
<span class="lineNum"> 330 </span> : /* insert it in the list of deleted blocks */
<span class="lineNum"> 331 </span><span class="lineCov"> 57015 : tommy_list_insert_tail(&amp;disk-&gt;deletedlist, &amp;file-&gt;nodelist, file);</span>
<a name="332"><span class="lineNum"> 332 </span><span class="lineCov"> 57015 : }</span></a>
<span class="lineNum"> 333 </span> :
<span class="lineNum"> 334 </span><span class="lineCov"> 101881 : static void scan_file_delayed_allocate(struct snapraid_scan* scan, struct snapraid_file* file)</span>
<span class="lineNum"> 335 </span> : {
<span class="lineNum"> 336 </span><span class="lineCov"> 101881 : struct snapraid_state* state = scan-&gt;state;</span>
<span class="lineNum"> 337 </span><span class="lineCov"> 101881 : struct snapraid_disk* disk = scan-&gt;disk;</span>
<span class="lineNum"> 338 </span> :
<span class="lineNum"> 339 </span> : /* if we sort for physical offsets we have to read them for new files */
<span class="lineNum"> 340 </span><span class="lineCov"> 101881 : if (state-&gt;opt.force_order == SORT_PHYSICAL</span>
<span class="lineNum"> 341 </span><span class="lineCov"> 11432 : &amp;&amp; file-&gt;physical == FILEPHY_UNREAD_OFFSET</span>
<span class="lineNum"> 342 </span> : ) {
<span class="lineNum"> 343 </span> : char path_next[PATH_MAX];
<span class="lineNum"> 344 </span> :
<span class="lineNum"> 345 </span><span class="lineCov"> 11432 : pathprint(path_next, sizeof(path_next), &quot;%s%s&quot;, disk-&gt;dir, file-&gt;sub);</span>
<span class="lineNum"> 346 </span> :
<span class="lineNum"> 347 </span><span class="lineCov"> 11432 : if (filephy(path_next, file-&gt;size, &amp;file-&gt;physical) != 0) {</span>
<span class="lineNum"> 348 </span> : /* LCOV_EXCL_START */
<span class="lineNum"> 349 </span> : log_fatal(&quot;Error in getting the physical offset of file '%s'. %s.\n&quot;, path_next, strerror(errno));
<span class="lineNum"> 350 </span> : exit(EXIT_FAILURE);
<span class="lineNum"> 351 </span> : /* LCOV_EXCL_STOP */
<span class="lineNum"> 352 </span> : }
<span class="lineNum"> 353 </span> : }
<span class="lineNum"> 354 </span> :
<span class="lineNum"> 355 </span> : /* insert in the delayed list */
<span class="lineNum"> 356 </span><span class="lineCov"> 101881 : tommy_list_insert_tail(&amp;scan-&gt;file_insert_list, &amp;file-&gt;nodelist, file);</span>
<span class="lineNum"> 357 </span><span class="lineCov"> 101881 : }</span>
<span class="lineNum"> 358 </span> :
<span class="lineNum"> 359 </span> : /**
<span class="lineNum"> 360 </span> : * Check if a file is completely formed of blocks with invalid parity,
<a name="361"><span class="lineNum"> 361 </span> : * and no rehash is tagged, and if it has at least one block.</a>
<span class="lineNum"> 362 </span> : */
<span class="lineNum"> 363 </span><span class="lineCov"> 1025550 : static int file_is_full_invalid_parity_and_stable(struct snapraid_state* state, struct snapraid_disk* disk, struct snapraid_file* file)</span>
<span class="lineNum"> 364 </span> : {
<span class="lineNum"> 365 </span> : block_off_t i;
<span class="lineNum"> 366 </span> :
<span class="lineNum"> 367 </span> : /* with no block, it never has an invalid parity */
<span class="lineNum"> 368 </span><span class="lineCov"> 1025550 : if (file-&gt;blockmax == 0)</span>
<span class="lineNum"> 369 </span><span class="lineCov"> 1439 : return 0;</span>
<span class="lineNum"> 370 </span> :
<span class="lineNum"> 371 </span> : /* check all blocks */
<span class="lineNum"> 372 </span><span class="lineCov"> 1080079 : for (i = 0; i &lt; file-&gt;blockmax; ++i) {</span>
<span class="lineNum"> 373 </span> : snapraid_info info;
<span class="lineNum"> 374 </span><span class="lineCov"> 1057392 : struct snapraid_block* block = fs_file2block_get(file, i);</span>
<span class="lineNum"> 375 </span> : block_off_t parity_pos;
<span class="lineNum"> 376 </span> :
<span class="lineNum"> 377 </span> : /* exclude blocks with parity */
<span class="lineNum"> 378 </span><span class="lineCov"> 1057392 : if (!block_has_invalid_parity(block))</span>
<span class="lineNum"> 379 </span><span class="lineCov"> 1001424 : return 0;</span>
<span class="lineNum"> 380 </span> :
<span class="lineNum"> 381 </span> : /*
<span class="lineNum"> 382 </span> : * Get the parity position.
<span class="lineNum"> 383 </span> : *
<span class="lineNum"> 384 </span> : * Note that here we expect to always have mapped
<span class="lineNum"> 385 </span> : * parity, because kept files always have it.
<span class="lineNum"> 386 </span> : *
<span class="lineNum"> 387 </span> : * Anyway, checking for POS_NULL doesn't hurt.
<span class="lineNum"> 388 </span> : */
<span class="lineNum"> 389 </span><span class="lineCov"> 55968 : parity_pos = fs_file2par_find(disk, file, i);</span>
<span class="lineNum"> 390 </span> :
<span class="lineNum"> 391 </span> : /* if it's not mapped, it cannot have rehash */
<span class="lineNum"> 392 </span><span class="lineCov"> 55968 : if (parity_pos != POS_NULL) {</span>
<span class="lineNum"> 393 </span> : /* get block specific info */
<span class="lineNum"> 394 </span><span class="lineCov"> 55968 : info = info_get(&amp;state-&gt;infoarr, parity_pos);</span>
<span class="lineNum"> 395 </span> :
<span class="lineNum"> 396 </span> : /* if rehash fails */
<span class="lineNum"> 397 </span><span class="lineCov"> 55968 : if (info_get_rehash(info))</span>
<span class="lineNum"> 398 </span><span class="lineNoCov"> 0 : return 0;</span>
<span class="lineNum"> 399 </span> : }
<span class="lineNum"> 400 </span> : }
<span class="lineNum"> 401 </span> :
<span class="lineNum"> 402 </span><span class="lineCov"> 22687 : return 1;</span>
<span class="lineNum"> 403 </span> : }
<span class="lineNum"> 404 </span> :
<span class="lineNum"> 405 </span> : /**
<span class="lineNum"> 406 </span> : * Check if a file is completely formed of blocks with an updated hash,
<a name="407"><span class="lineNum"> 407 </span> : * and no rehash is tagged, and if it has at least one block.</a>
<span class="lineNum"> 408 </span> : */
<span class="lineNum"> 409 </span><span class="lineCov"> 23670 : static int file_is_full_hashed_and_stable(struct snapraid_state* state, struct snapraid_disk* disk, struct snapraid_file* file)</span>
<span class="lineNum"> 410 </span> : {
<span class="lineNum"> 411 </span> : block_off_t i;
<span class="lineNum"> 412 </span> :
<span class="lineNum"> 413 </span> : /* with no block, it never has a hash */
<span class="lineNum"> 414 </span><span class="lineCov"> 23670 : if (file-&gt;blockmax == 0)</span>
<span class="lineNum"> 415 </span><span class="lineCov"> 27 : return 0;</span>
<span class="lineNum"> 416 </span> :
<span class="lineNum"> 417 </span> : /* check all blocks */
<span class="lineNum"> 418 </span><span class="lineCov"> 81886 : for (i = 0; i &lt; file-&gt;blockmax; ++i) {</span>
<span class="lineNum"> 419 </span> : snapraid_info info;
<span class="lineNum"> 420 </span><span class="lineCov"> 58250 : struct snapraid_block* block = fs_file2block_get(file, i);</span>
<span class="lineNum"> 421 </span> : block_off_t parity_pos;
<span class="lineNum"> 422 </span> :
<span class="lineNum"> 423 </span> : /* exclude blocks without hash */
<span class="lineNum"> 424 </span><span class="lineCov"> 58250 : if (!block_has_updated_hash(block))</span>
<span class="lineNum"> 425 </span><span class="lineCov"> 7 : return 0;</span>
<span class="lineNum"> 426 </span> :
<span class="lineNum"> 427 </span> : /*
<span class="lineNum"> 428 </span> : * Get the parity position.
<span class="lineNum"> 429 </span> : *
<span class="lineNum"> 430 </span> : * Note that it's possible to have files
<span class="lineNum"> 431 </span> : * not mapped into the parity, even if they
<span class="lineNum"> 432 </span> : * have a valid hash.
<span class="lineNum"> 433 </span> : *
<span class="lineNum"> 434 </span> : * This happens for example, for 'copied' files
<span class="lineNum"> 435 </span> : * that have REP blocks, but not yet mapped.
<span class="lineNum"> 436 </span> : *
<span class="lineNum"> 437 </span> : * If there are multiple copies, it's also possible
<span class="lineNum"> 438 </span> : * that such files are used as 'source' to copy
<span class="lineNum"> 439 </span> : * hashes, and then to get them inside this function.
<span class="lineNum"> 440 </span> : */
<span class="lineNum"> 441 </span><span class="lineCov"> 58243 : parity_pos = fs_file2par_find(disk, file, i);</span>
<span class="lineNum"> 442 </span> :
<span class="lineNum"> 443 </span> : /* if it's not mapped, it cannot have rehash */
<span class="lineNum"> 444 </span><span class="lineCov"> 58243 : if (parity_pos != POS_NULL) {</span>
<span class="lineNum"> 445 </span> : /* get block specific info */
<span class="lineNum"> 446 </span><span class="lineCov"> 58235 : info = info_get(&amp;state-&gt;infoarr, parity_pos);</span>
<span class="lineNum"> 447 </span> :
<span class="lineNum"> 448 </span> : /* exclude blocks needing a rehash */
<span class="lineNum"> 449 </span><span class="lineCov"> 58235 : if (info_get_rehash(info))</span>
<span class="lineNum"> 450 </span><span class="lineNoCov"> 0 : return 0;</span>
<span class="lineNum"> 451 </span> : }
<span class="lineNum"> 452 </span> : }
<span class="lineNum"> 453 </span> :
<span class="lineNum"> 454 </span><span class="lineCov"> 23636 : return 1;</span>
<span class="lineNum"> 455 </span> : }
<span class="lineNum"> 456 </span> :
<span class="lineNum"> 457 </span> : /**
<span class="lineNum"> 458 </span> : * Refresh the file info.
<span class="lineNum"> 459 </span> : *
<span class="lineNum"> 460 </span> : * This is needed by Windows as the normal way to list directories may report not
<span class="lineNum"> 461 </span> : * updated info. Only the GetFileInformationByHandle() func, called file-by-file,
<span class="lineNum"> 462 </span> : * really ensures to return synced info.
<span class="lineNum"> 463 </span> : *
<a name="464"><span class="lineNum"> 464 </span> : * If this happens, we read also the physical offset, to avoid to read it later.</a>
<span class="lineNum"> 465 </span> : */
<span class="lineNum"> 466 </span><span class="lineCov"> 79194 : static void scan_file_refresh(struct snapraid_scan* scan, const char* sub, struct stat* st, uint64_t* physical)</span>
<span class="lineNum"> 467 </span> : {
<span class="lineNum"> 468 </span> : #if HAVE_LSTAT_SYNC
<span class="lineNum"> 469 </span> : struct snapraid_state* state = scan-&gt;state;
<span class="lineNum"> 470 </span> : struct snapraid_disk* disk = scan-&gt;disk;
<span class="lineNum"> 471 </span> :
<span class="lineNum"> 472 </span> : /* if the st_sync is not set, ensure to get synced info */
<span class="lineNum"> 473 </span> : if (st-&gt;st_sync == 0) {
<span class="lineNum"> 474 </span> : char path_next[PATH_MAX];
<span class="lineNum"> 475 </span> : struct stat synced_st;
<span class="lineNum"> 476 </span> :
<span class="lineNum"> 477 </span> : pathprint(path_next, sizeof(path_next), &quot;%s%s&quot;, disk-&gt;dir, sub);
<span class="lineNum"> 478 </span> :
<span class="lineNum"> 479 </span> : /* if we sort for physical offsets we have to read them for new files */
<span class="lineNum"> 480 </span> : if (state-&gt;opt.force_order == SORT_PHYSICAL
<span class="lineNum"> 481 </span> : &amp;&amp; *physical == FILEPHY_UNREAD_OFFSET
<span class="lineNum"> 482 </span> : ) {
<span class="lineNum"> 483 </span> : /* do nothing, leave the pointer to read the physical offset */
<span class="lineNum"> 484 </span> : } else {
<span class="lineNum"> 485 </span> : physical = 0; /* set the pointer to 0 to read nothing */
<span class="lineNum"> 486 </span> : }
<span class="lineNum"> 487 </span> :
<span class="lineNum"> 488 </span> : if (lstat_sync(path_next, &amp;synced_st, physical) != 0) {
<span class="lineNum"> 489 </span> : /* LCOV_EXCL_START */
<span class="lineNum"> 490 </span> : log_fatal(&quot;Error in stat file '%s'. %s.\n&quot;, path_next, strerror(errno));
<span class="lineNum"> 491 </span> : exit(EXIT_FAILURE);
<span class="lineNum"> 492 </span> : /* LCOV_EXCL_STOP */
<span class="lineNum"> 493 </span> : }
<span class="lineNum"> 494 </span> :
<span class="lineNum"> 495 </span> : if (st-&gt;st_mtime != synced_st.st_mtime
<span class="lineNum"> 496 </span> : || st-&gt;st_mtimensec != synced_st.st_mtimensec
<span class="lineNum"> 497 </span> : ) {
<span class="lineNum"> 498 </span> : #ifndef _WIN32
<span class="lineNum"> 499 </span> : /*
<span class="lineNum"> 500 </span> : * In Windows having different metadata is expected with open files
<span class="lineNum"> 501 </span> : * because the metadata in the directory is updated only when the file
<span class="lineNum"> 502 </span> : * is closed.
<span class="lineNum"> 503 </span> : *
<span class="lineNum"> 504 </span> : * See also:
<span class="lineNum"> 505 </span> : * Why is the file size reported incorrectly for files that are still being written to?
<span class="lineNum"> 506 </span> : * http://blogs.msdn.com/b/oldnewthing/archive/2011/12/26/10251026.aspx
<span class="lineNum"> 507 </span> : */
<span class="lineNum"> 508 </span> : log_fatal(&quot;WARNING! Detected uncached time change for file '%s'\n&quot;, sub);
<span class="lineNum"> 509 </span> : log_fatal(&quot;It's better if you run SnapRAID without other processes running.\n&quot;);
<span class="lineNum"> 510 </span> : #endif
<span class="lineNum"> 511 </span> : st-&gt;st_mtime = synced_st.st_mtime;
<span class="lineNum"> 512 </span> : st-&gt;st_mtimensec = synced_st.st_mtimensec;
<span class="lineNum"> 513 </span> : }
<span class="lineNum"> 514 </span> :
<span class="lineNum"> 515 </span> : if (st-&gt;st_size != synced_st.st_size) {
<span class="lineNum"> 516 </span> : #ifndef _WIN32
<span class="lineNum"> 517 </span> : log_fatal(&quot;WARNING! Detected uncached size change for file '%s'\n&quot;, sub);
<span class="lineNum"> 518 </span> : log_fatal(&quot;It's better if you run SnapRAID without other processes running.\n&quot;);
<span class="lineNum"> 519 </span> : #endif
<span class="lineNum"> 520 </span> : st-&gt;st_size = synced_st.st_size;
<span class="lineNum"> 521 </span> : }
<span class="lineNum"> 522 </span> :
<span class="lineNum"> 523 </span> : if (st-&gt;st_ino != synced_st.st_ino) {
<span class="lineNum"> 524 </span> : log_fatal(&quot;DANGER! Detected uncached inode change for file '%s'\n&quot;, sub);
<span class="lineNum"> 525 </span> : log_fatal(&quot;Please ensure to run SnapRAID without other processes running.\n&quot;);
<span class="lineNum"> 526 </span> : /* at this point, it's too late to change inode */
<span class="lineNum"> 527 </span> : /* and having inconsistent inodes may result to internal failures */
<span class="lineNum"> 528 </span> : /* so, it's better to abort */
<span class="lineNum"> 529 </span> : exit(EXIT_FAILURE);
<span class="lineNum"> 530 </span> : }
<span class="lineNum"> 531 </span> : }
<span class="lineNum"> 532 </span> : #else
<span class="lineNum"> 533 </span> : (void)scan;
<span class="lineNum"> 534 </span> : (void)sub;
<span class="lineNum"> 535 </span> : (void)st;
<span class="lineNum"> 536 </span> : (void)physical;
<span class="lineNum"> 537 </span> : #endif
<span class="lineNum"> 538 </span><span class="lineCov"> 79194 : }</span>
<span class="lineNum"> 539 </span> :
<span class="lineNum"> 540 </span> : /**
<a name="541"><span class="lineNum"> 541 </span> : * Insert the file in the data set.</a>
<span class="lineNum"> 542 </span> : */
<span class="lineNum"> 543 </span><span class="lineCov"> 101881 : static void scan_file_insert(struct snapraid_scan* scan, struct snapraid_file* file)</span>
<span class="lineNum"> 544 </span> : {
<span class="lineNum"> 545 </span><span class="lineCov"> 101881 : struct snapraid_disk* disk = scan-&gt;disk;</span>
<span class="lineNum"> 546 </span> :
<span class="lineNum"> 547 </span> : /* insert the file in the containers */
<span class="lineNum"> 548 </span><span class="lineCov"> 101881 : if (!file_flag_has(file, FILE_IS_WITHOUT_INODE))</span>
<span class="lineNum"> 549 </span><span class="lineCov"> 101881 : tommy_hashdyn_insert(&amp;disk-&gt;inodeset, &amp;file-&gt;nodeset, file, file_inode_hash(file-&gt;inode));</span>
<span class="lineNum"> 550 </span><span class="lineCov"> 101881 : tommy_hashdyn_insert(&amp;disk-&gt;pathset, &amp;file-&gt;pathset, file, file_path_hash(file-&gt;sub));</span>
<span class="lineNum"> 551 </span><span class="lineCov"> 101881 : tommy_hashdyn_insert(&amp;disk-&gt;stampset, &amp;file-&gt;stampset, file, file_stamp_hash(file-&gt;size, file-&gt;mtime_sec, file-&gt;mtime_nsec));</span>
<span class="lineNum"> 552 </span> :
<span class="lineNum"> 553 </span> : /* delayed allocation of the parity */
<span class="lineNum"> 554 </span><span class="lineCov"> 101881 : scan_file_delayed_allocate(scan, file);</span>
<span class="lineNum"> 555 </span><span class="lineCov"> 101881 : }</span>
<span class="lineNum"> 556 </span> :
<span class="lineNum"> 557 </span> : /**
<span class="lineNum"> 558 </span> : * Remove the file from the data set.
<span class="lineNum"> 559 </span> : *
<a name="560"><span class="lineNum"> 560 </span> : * File is then deleted.</a>
<span class="lineNum"> 561 </span> : */
<span class="lineNum"> 562 </span><span class="lineCov"> 57015 : static void scan_file_remove(struct snapraid_scan* scan, struct snapraid_file* file)</span>
<span class="lineNum"> 563 </span> : {
<span class="lineNum"> 564 </span><span class="lineCov"> 57015 : struct snapraid_disk* disk = scan-&gt;disk;</span>
<span class="lineNum"> 565 </span> :
<span class="lineNum"> 566 </span> : /* remove the file from the containers */
<span class="lineNum"> 567 </span><span class="lineCov"> 57015 : if (!file_flag_has(file, FILE_IS_WITHOUT_INODE))</span>
<span class="lineNum"> 568 </span><span class="lineCov"> 56941 : tommy_hashdyn_remove_existing(&amp;disk-&gt;inodeset, &amp;file-&gt;nodeset);</span>
<span class="lineNum"> 569 </span><span class="lineCov"> 57015 : tommy_hashdyn_remove_existing(&amp;disk-&gt;pathset, &amp;file-&gt;pathset);</span>
<span class="lineNum"> 570 </span><span class="lineCov"> 57015 : tommy_hashdyn_remove_existing(&amp;disk-&gt;stampset, &amp;file-&gt;stampset);</span>
<span class="lineNum"> 571 </span> :
<span class="lineNum"> 572 </span> : /* deallocate the file from the parity */
<span class="lineNum"> 573 </span><span class="lineCov"> 57015 : scan_file_deallocate(scan, file);</span>
<span class="lineNum"> 574 </span><span class="lineCov"> 57015 : }</span>
<span class="lineNum"> 575 </span> :
<span class="lineNum"> 576 </span> : /**
<span class="lineNum"> 577 </span> : * Keep the file as it's (or with only a name/inode modification).
<span class="lineNum"> 578 </span> : *
<span class="lineNum"> 579 </span> : * If the file is kept, nothing has to be done.
<span class="lineNum"> 580 </span> : *
<span class="lineNum"> 581 </span> : * But if a file contains only blocks with invalid parity, it's reallocated to ensure
<span class="lineNum"> 582 </span> : * to always minimize the space used in the parity.
<span class="lineNum"> 583 </span> : *
<span class="lineNum"> 584 </span> : * This could happen after a failed sync, when some other files are deleted,
<a name="585"><span class="lineNum"> 585 </span> : * and then new ones can be moved backward to fill the hole created.</a>
<span class="lineNum"> 586 </span> : */
<span class="lineNum"> 587 </span><span class="lineCov"> 1025550 : static void scan_file_keep(struct snapraid_scan* scan, struct snapraid_file* file)</span>
<span class="lineNum"> 588 </span> : {
<span class="lineNum"> 589 </span><span class="lineCov"> 1025550 : struct snapraid_disk* disk = scan-&gt;disk;</span>
<span class="lineNum"> 590 </span> :
<span class="lineNum"> 591 </span> : /* if the file is full invalid, schedule a reinsert at later stage */
<span class="lineNum"> 592 </span><span class="lineCov"> 1025550 : if (file_is_full_invalid_parity_and_stable(scan-&gt;state, disk, file)) {</span>
<span class="lineNum"> 593 </span><span class="lineCov"> 22687 : struct snapraid_file* copy = file_dup(file);</span>
<span class="lineNum"> 594 </span> :
<span class="lineNum"> 595 </span> : /* remove the file */
<span class="lineNum"> 596 </span><span class="lineCov"> 22687 : scan_file_remove(scan, file);</span>
<span class="lineNum"> 597 </span> :
<span class="lineNum"> 598 </span> : /* reinsert the copy in the delayed list */
<span class="lineNum"> 599 </span><span class="lineCov"> 22687 : scan_file_insert(scan, copy);</span>
<span class="lineNum"> 600 </span> : }
<span class="lineNum"> 601 </span><span class="lineCov"> 1025550 : }</span>
<span class="lineNum"> 602 </span> :
<span class="lineNum"> 603 </span> : /**
<a name="604"><span class="lineNum"> 604 </span> : * Process a file.</a>
<span class="lineNum"> 605 </span> : */
<span class="lineNum"> 606 </span><span class="lineCov"> 1104939 : static void scan_file(struct snapraid_scan* scan, int is_diff, const char* sub, struct stat* st, uint64_t physical)</span>
<span class="lineNum"> 607 </span> : {
<span class="lineNum"> 608 </span><span class="lineCov"> 1104939 : struct snapraid_state* state = scan-&gt;state;</span>
<span class="lineNum"> 609 </span><span class="lineCov"> 1104939 : struct snapraid_disk* disk = scan-&gt;disk;</span>
<span class="lineNum"> 610 </span> : struct snapraid_file* file;
<span class="lineNum"> 611 </span> : tommy_node* i;
<span class="lineNum"> 612 </span> : int is_original_file_size_different_than_zero;
<span class="lineNum"> 613 </span> : int is_file_already_present;
<span class="lineNum"> 614 </span> : data_off_t file_already_present_size;
<span class="lineNum"> 615 </span> : int64_t file_already_present_mtime_sec;
<span class="lineNum"> 616 </span> : int file_already_present_mtime_nsec;
<span class="lineNum"> 617 </span> : int is_file_reported;
<span class="lineNum"> 618 </span> : char esc_buffer[ESC_MAX];
<span class="lineNum"> 619 </span> : char esc_buffer_alt[ESC_MAX];
<span class="lineNum"> 620 </span> :
<span class="lineNum"> 621 </span> : /*
<span class="lineNum"> 622 </span> : * If the disk has persistent inodes and UUID, try a search on the past inodes,
<span class="lineNum"> 623 </span> : * to detect moved files.
<span class="lineNum"> 624 </span> : *
<span class="lineNum"> 625 </span> : * For persistent inodes we mean inodes that keep their values when the file-system
<span class="lineNum"> 626 </span> : * is unmounted and remounted. This don't always happen.
<span class="lineNum"> 627 </span> : *
<span class="lineNum"> 628 </span> : * Cases found are:
<span class="lineNum"> 629 </span> : * - Linux FUSE with exFAT driver from https://code.google.com/p/exfat/.
<span class="lineNum"> 630 </span> : * Inodes are reassigned at every mount restarting from 1 and incrementing.
<span class="lineNum"> 631 </span> : * As worse, the exFAT support in FUSE doesn't use sub-second precision in timestamps
<span class="lineNum"> 632 </span> : * making inode collision more easy (exFAT by design supports 10ms precision).
<span class="lineNum"> 633 </span> : * - Linux VFAT kernel (3.2) driver. Inodes are fully reassigned at every mount.
<span class="lineNum"> 634 </span> : *
<span class="lineNum"> 635 </span> : * In such cases, to avoid possible random collisions, it's better to disable the moved
<span class="lineNum"> 636 </span> : * file recognition.
<span class="lineNum"> 637 </span> : *
<span class="lineNum"> 638 </span> : * For persistent UUID we mean that it has the same UUID as before.
<span class="lineNum"> 639 </span> : * Otherwise, if the UUID is changed, likely it's a new recreated file-system,
<span class="lineNum"> 640 </span> : * and then the inode have no meaning.
<span class="lineNum"> 641 </span> : *
<span class="lineNum"> 642 </span> : * Note that to disable the search by past inode, we do this implicitly
<span class="lineNum"> 643 </span> : * removing all the past inode before searching for files.
<span class="lineNum"> 644 </span> : * This ensures that no file is found with a past inode, but at the same time,
<span class="lineNum"> 645 </span> : * it allows to find new files with the same inode, to identify them as hardlinks.
<span class="lineNum"> 646 </span> : */
<span class="lineNum"> 647 </span><span class="lineCov"> 1104939 : int has_past_inodes = !disk-&gt;has_volatile_inodes &amp;&amp; !disk-&gt;has_different_uuid &amp;&amp; !disk-&gt;has_unsupported_uuid;</span>
<span class="lineNum"> 648 </span> :
<span class="lineNum"> 649 </span> : /* always search with the new inode, in the all new inodes found until now, */
<span class="lineNum"> 650 </span> : /* with the eventual presence of also the past inodes */
<span class="lineNum"> 651 </span><span class="lineCov"> 1104939 : uint64_t inode = st-&gt;st_ino;</span>
<span class="lineNum"> 652 </span> :
<span class="lineNum"> 653 </span><span class="lineCov"> 1104939 : file = tommy_hashdyn_search(&amp;disk-&gt;inodeset, file_inode_compare_to_arg, &amp;inode, file_inode_hash(inode));</span>
<span class="lineNum"> 654 </span> :
<span class="lineNum"> 655 </span> : /* identify moved files with past inodes and hardlinks with the new inodes */
<span class="lineNum"> 656 </span><span class="lineCov"> 1104939 : if (file) {</span>
<span class="lineNum"> 657 </span> : /* check if the file is not changed */
<span class="lineNum"> 658 </span><span class="lineCov"> 943901 : if (file-&gt;size == st-&gt;st_size</span>
<span class="lineNum"> 659 </span><span class="lineCov"> 935613 : &amp;&amp; file-&gt;mtime_sec == st-&gt;st_mtime</span>
<span class="lineNum"> 660 </span><span class="lineCov"> 932556 : &amp;&amp; (file-&gt;mtime_nsec == STAT_NSEC(st)</span>
<span class="lineNum"> 661 </span> : /* always accept the stored value if it's STAT_NSEC_INVALID */
<span class="lineNum"> 662 </span> : /* it happens when upgrading from an old version of SnapRAID */
<span class="lineNum"> 663 </span> : /* not yet supporting the nanosecond field */
<span class="lineNum"> 664 </span><span class="lineCov"> 1 : || file-&gt;mtime_nsec == STAT_NSEC_INVALID</span>
<span class="lineNum"> 665 </span> : )
<span class="lineNum"> 666 </span> : ) {
<span class="lineNum"> 667 </span> : /* check if multiple files have the same inode */
<span class="lineNum"> 668 </span><span class="lineCov"> 932555 : if (file_flag_has(file, FILE_IS_PRESENT)) {</span>
<span class="lineNum"> 669 </span> : #if HAVE_STRUCT_STAT_ST_NLINK
<span class="lineNum"> 670 </span><span class="lineCov"> 195 : if (st-&gt;st_nlink &lt;= 1) {</span>
<span class="lineNum"> 671 </span> : /* LCOV_EXCL_START */
<span class="lineNum"> 672 </span> : log_fatal(&quot;Internal inode '%&quot; PRIu64 &quot;' inconsistency for file '%s%s' already present\n&quot;, (uint64_t)st-&gt;st_ino, disk-&gt;dir, sub);
<span class="lineNum"> 673 </span> : os_abort();
<span class="lineNum"> 674 </span> : /* LCOV_EXCL_STOP */
<span class="lineNum"> 675 </span> : }
<span class="lineNum"> 676 </span> : #endif
<span class="lineNum"> 677 </span> : /* it's a hardlink */
<span class="lineNum"> 678 </span><span class="lineCov"> 195 : scan_link(scan, is_diff, sub, file-&gt;sub, FILE_IS_HARDLINK);</span>
<span class="lineNum"> 679 </span><span class="lineCov"> 195 : return;</span>
<span class="lineNum"> 680 </span> : }
<span class="lineNum"> 681 </span> :
<span class="lineNum"> 682 </span> : /* mark as present */
<span class="lineNum"> 683 </span><span class="lineCov"> 932360 : file_flag_set(file, FILE_IS_PRESENT);</span>
<span class="lineNum"> 684 </span> :
<span class="lineNum"> 685 </span> : /* update the nanoseconds mtime only if different */
<span class="lineNum"> 686 </span> : /* to avoid unneeded updates */
<span class="lineNum"> 687 </span><span class="lineCov"> 932360 : if (file-&gt;mtime_nsec == STAT_NSEC_INVALID</span>
<span class="lineNum"> 688 </span><span class="lineNoCov"> 0 : &amp;&amp; STAT_NSEC(st) != file-&gt;mtime_nsec</span>
<span class="lineNum"> 689 </span> : ) {
<span class="lineNum"> 690 </span><span class="lineNoCov"> 0 : file-&gt;mtime_nsec = STAT_NSEC(st);</span>
<span class="lineNum"> 691 </span> :
<span class="lineNum"> 692 </span> : /* we have to save the new mtime */
<span class="lineNum"> 693 </span><span class="lineNoCov"> 0 : state-&gt;need_write = 1;</span>
<span class="lineNum"> 694 </span> : }
<span class="lineNum"> 695 </span> :
<span class="lineNum"> 696 </span><span class="lineCov"> 932360 : if (strcmp(file-&gt;sub, sub) != 0) {</span>
<span class="lineNum"> 697 </span> : /* if the path is different, it means a moved file with the same inode */
<span class="lineNum"> 698 </span><span class="lineCov"> 155 : ++scan-&gt;count_move;</span>
<span class="lineNum"> 699 </span> :
<span class="lineNum"> 700 </span><span class="lineCov"> 155 : log_tag(&quot;scan:move:%s:%s:%s\n&quot;, disk-&gt;name, esc_tag(file-&gt;sub, esc_buffer), esc_tag(sub, esc_buffer_alt));</span>
<span class="lineNum"> 701 </span><span class="lineCov"> 155 : if (is_diff) {</span>
<span class="lineNum"> 702 </span><span class="lineNoCov"> 0 : printf(&quot;move %s -&gt; %s\n&quot;, fmt_term(disk, file-&gt;sub, esc_buffer), fmt_term(disk, sub, esc_buffer_alt));</span>
<span class="lineNum"> 703 </span> : }
<span class="lineNum"> 704 </span> :
<span class="lineNum"> 705 </span> : /* remove from the name set */
<span class="lineNum"> 706 </span><span class="lineCov"> 155 : tommy_hashdyn_remove_existing(&amp;disk-&gt;pathset, &amp;file-&gt;pathset);</span>
<span class="lineNum"> 707 </span> :
<span class="lineNum"> 708 </span> : /* save the new name */
<span class="lineNum"> 709 </span><span class="lineCov"> 155 : file_rename(file, sub);</span>
<span class="lineNum"> 710 </span> :
<span class="lineNum"> 711 </span> : /* reinsert in the name set */
<span class="lineNum"> 712 </span><span class="lineCov"> 155 : tommy_hashdyn_insert(&amp;disk-&gt;pathset, &amp;file-&gt;pathset, file, file_path_hash(file-&gt;sub));</span>
<span class="lineNum"> 713 </span> :
<span class="lineNum"> 714 </span> : /* we have to save the new name */
<span class="lineNum"> 715 </span><span class="lineCov"> 155 : state-&gt;need_write = 1;</span>
<span class="lineNum"> 716 </span> : } else {
<span class="lineNum"> 717 </span> : /* otherwise it's equal */
<span class="lineNum"> 718 </span><span class="lineCov"> 932205 : ++scan-&gt;count_equal;</span>
<span class="lineNum"> 719 </span> :
<span class="lineNum"> 720 </span><span class="lineCov"> 932205 : if (state-&gt;opt.gui) {</span>
<span class="lineNum"> 721 </span><span class="lineCov"> 22611 : log_tag(&quot;scan:equal:%s:%s\n&quot;, disk-&gt;name, esc_tag(file-&gt;sub, esc_buffer));</span>
<span class="lineNum"> 722 </span> : }
<span class="lineNum"> 723 </span> : }
<span class="lineNum"> 724 </span> :
<span class="lineNum"> 725 </span> : /* mark the file as kept */
<span class="lineNum"> 726 </span><span class="lineCov"> 932360 : scan_file_keep(scan, file);</span>
<span class="lineNum"> 727 </span> :
<span class="lineNum"> 728 </span> : /* nothing more to do */
<span class="lineNum"> 729 </span><span class="lineCov"> 932360 : return;</span>
<span class="lineNum"> 730 </span> : }
<span class="lineNum"> 731 </span> :
<span class="lineNum"> 732 </span> : /* here the file matches the inode, but not the other info */
<span class="lineNum"> 733 </span> : /* if could be a modified file with the same name, */
<span class="lineNum"> 734 </span> : /* or a restored/copied file that get assigned a previously used inode, */
<span class="lineNum"> 735 </span> : /* or a file-system with not persistent inodes */
<span class="lineNum"> 736 </span> :
<span class="lineNum"> 737 </span> : /* for sure it cannot be already present */
<span class="lineNum"> 738 </span><span class="lineCov"> 11346 : if (file_flag_has(file, FILE_IS_PRESENT)) {</span>
<span class="lineNum"> 739 </span> : /* LCOV_EXCL_START */
<span class="lineNum"> 740 </span> : log_fatal(&quot;Internal inode '%&quot; PRIu64 &quot;' inconsistency for files '%s%s' and '%s%s' matching and already present but different\n&quot;, file-&gt;inode, disk-&gt;dir, sub, disk-&gt;dir, file-&gt;sub);
<span class="lineNum"> 741 </span> : os_abort();
<span class="lineNum"> 742 </span> : /* LCOV_EXCL_STOP */
<span class="lineNum"> 743 </span> : }
<span class="lineNum"> 744 </span> :
<span class="lineNum"> 745 </span> : /* assume a previously used inode, it's the worst case */
<span class="lineNum"> 746 </span> : /* and we handle it removing the duplicate stored inode. */
<span class="lineNum"> 747 </span> : /* If the file is found by name later, it will have the inode restored, */
<span class="lineNum"> 748 </span> : /* otherwise, it will get removed */
<span class="lineNum"> 749 </span> :
<span class="lineNum"> 750 </span> : /* remove from the inode set */
<span class="lineNum"> 751 </span><span class="lineCov"> 11346 : tommy_hashdyn_remove_existing(&amp;disk-&gt;inodeset, &amp;file-&gt;nodeset);</span>
<span class="lineNum"> 752 </span> :
<span class="lineNum"> 753 </span> : /* clear the inode */
<span class="lineNum"> 754 </span> : /* this is not really needed for correct functionality */
<span class="lineNum"> 755 </span> : /* because we are going to set FILE_IS_WITHOUT_INODE */
<span class="lineNum"> 756 </span> : /* but it's easier for debugging to have invalid inodes set to 0 */
<span class="lineNum"> 757 </span><span class="lineCov"> 11346 : file-&gt;inode = 0;</span>
<span class="lineNum"> 758 </span> :
<span class="lineNum"> 759 </span> : /* mark as missing inode */
<span class="lineNum"> 760 </span><span class="lineCov"> 11346 : file_flag_set(file, FILE_IS_WITHOUT_INODE);</span>
<span class="lineNum"> 761 </span> :
<span class="lineNum"> 762 </span> : /* go further to find it by name */
<span class="lineNum"> 763 </span> : }
<span class="lineNum"> 764 </span> :
<span class="lineNum"> 765 </span> : /* initialize for later overwrite */
<span class="lineNum"> 766 </span><span class="lineCov"> 172384 : is_file_reported = 0;</span>
<span class="lineNum"> 767 </span><span class="lineCov"> 172384 : is_original_file_size_different_than_zero = 0;</span>
<span class="lineNum"> 768 </span> :
<span class="lineNum"> 769 </span> : /* then try finding it by name */
<span class="lineNum"> 770 </span><span class="lineCov"> 172384 : file = tommy_hashdyn_search(&amp;disk-&gt;pathset, file_path_compare_to_arg, sub, file_path_hash(sub));</span>
<span class="lineNum"> 771 </span> :
<span class="lineNum"> 772 </span> : /* keep track if the file already exists */
<span class="lineNum"> 773 </span><span class="lineCov"> 172384 : is_file_already_present = file != 0;</span>
<span class="lineNum"> 774 </span> :
<span class="lineNum"> 775 </span><span class="lineCov"> 172384 : if (is_file_already_present) {</span>
<span class="lineNum"> 776 </span> : /* if the file is without an inode */
<span class="lineNum"> 777 </span><span class="lineCov"> 97871 : if (file_flag_has(file, FILE_IS_WITHOUT_INODE)) {</span>
<span class="lineNum"> 778 </span> : /* set it now */
<span class="lineNum"> 779 </span><span class="lineCov"> 11286 : file-&gt;inode = st-&gt;st_ino;</span>
<span class="lineNum"> 780 </span> :
<span class="lineNum"> 781 </span> : /* insert in the set */
<span class="lineNum"> 782 </span><span class="lineCov"> 11286 : tommy_hashdyn_insert(&amp;disk-&gt;inodeset, &amp;file-&gt;nodeset, file, file_inode_hash(file-&gt;inode));</span>
<span class="lineNum"> 783 </span> :
<span class="lineNum"> 784 </span> : /* unmark as missing inode */
<span class="lineNum"> 785 </span><span class="lineCov"> 11286 : file_flag_clear(file, FILE_IS_WITHOUT_INODE);</span>
<span class="lineNum"> 786 </span> : } else {
<span class="lineNum"> 787 </span> : /* here the inode has to be different, otherwise we would have found it before */
<span class="lineNum"> 788 </span><span class="lineCov"> 86585 : if (file-&gt;inode == st-&gt;st_ino) {</span>
<span class="lineNum"> 789 </span> : /* LCOV_EXCL_START */
<span class="lineNum"> 790 </span> : log_fatal(&quot;Internal inconsistency in inode '%&quot; PRIu64 &quot;' for files '%s%s' as unexpected matching\n&quot;, file-&gt;inode, disk-&gt;dir, sub);
<span class="lineNum"> 791 </span> : os_abort();
<span class="lineNum"> 792 </span> : /* LCOV_EXCL_STOP */
<span class="lineNum"> 793 </span> : }
<span class="lineNum"> 794 </span> : }
<span class="lineNum"> 795 </span> :
<span class="lineNum"> 796 </span> : /* for sure it cannot be already present */
<span class="lineNum"> 797 </span><span class="lineCov"> 97871 : if (file_flag_has(file, FILE_IS_PRESENT)) {</span>
<span class="lineNum"> 798 </span> : /* LCOV_EXCL_START */
<span class="lineNum"> 799 </span> : log_fatal(&quot;Internal inconsistency in path for file '%s%s' matching and already present\n&quot;, disk-&gt;dir, sub);
<span class="lineNum"> 800 </span> : os_abort();
<span class="lineNum"> 801 </span> : /* LCOV_EXCL_STOP */
<span class="lineNum"> 802 </span> : }
<span class="lineNum"> 803 </span> :
<span class="lineNum"> 804 </span> : /* check if the file is not changed */
<span class="lineNum"> 805 </span><span class="lineCov"> 97871 : if (file-&gt;size == st-&gt;st_size</span>
<span class="lineNum"> 806 </span><span class="lineCov"> 97275 : &amp;&amp; file-&gt;mtime_sec == st-&gt;st_mtime</span>
<span class="lineNum"> 807 </span><span class="lineCov"> 93190 : &amp;&amp; (file-&gt;mtime_nsec == STAT_NSEC(st)</span>
<span class="lineNum"> 808 </span> : /* always accept the stored value if it's STAT_NSEC_INVALID */
<span class="lineNum"> 809 </span> : /* it happens when upgrading from an old version of SnapRAID */
<span class="lineNum"> 810 </span> : /* not yet supporting the nanosecond field */
<span class="lineNum"> 811 </span><span class="lineNoCov"> 0 : || file-&gt;mtime_nsec == STAT_NSEC_INVALID</span>
<span class="lineNum"> 812 </span> : )
<span class="lineNum"> 813 </span> : ) {
<span class="lineNum"> 814 </span> : /* mark as present */
<span class="lineNum"> 815 </span><span class="lineCov"> 93190 : file_flag_set(file, FILE_IS_PRESENT);</span>
<span class="lineNum"> 816 </span> :
<span class="lineNum"> 817 </span> : /* update the nano seconds mtime only if different */
<span class="lineNum"> 818 </span> : /* to avoid unneeded updates */
<span class="lineNum"> 819 </span><span class="lineCov"> 93190 : if (file-&gt;mtime_nsec == STAT_NSEC_INVALID</span>
<span class="lineNum"> 820 </span><span class="lineNoCov"> 0 : &amp;&amp; STAT_NSEC(st) != STAT_NSEC_INVALID</span>
<span class="lineNum"> 821 </span> : ) {
<span class="lineNum"> 822 </span><span class="lineNoCov"> 0 : file-&gt;mtime_nsec = STAT_NSEC(st);</span>
<span class="lineNum"> 823 </span> :
<span class="lineNum"> 824 </span> : /* we have to save the new mtime */
<span class="lineNum"> 825 </span><span class="lineNoCov"> 0 : state-&gt;need_write = 1;</span>
<span class="lineNum"> 826 </span> : }
<span class="lineNum"> 827 </span> :
<span class="lineNum"> 828 </span> : /* if when processing the disk we used the past inodes values */
<span class="lineNum"> 829 </span><span class="lineCov"> 93190 : if (has_past_inodes) {</span>
<span class="lineNum"> 830 </span> : /* if persistent inodes are supported, we are sure that the inode number */
<span class="lineNum"> 831 </span> : /* is now different, because otherwise the file would have been found */
<span class="lineNum"> 832 </span> : /* when searching by inode. */
<span class="lineNum"> 833 </span> : /* if the inode is different, it means a rewritten file with the same path */
<span class="lineNum"> 834 </span> : /* like when restoring a backup that restores also the timestamp */
<span class="lineNum"> 835 </span><span class="lineCov"> 93176 : ++scan-&gt;count_restore;</span>
<span class="lineNum"> 836 </span> :
<span class="lineNum"> 837 </span><span class="lineCov"> 93176 : log_tag(&quot;scan:restore:%s:%s\n&quot;, disk-&gt;name, esc_tag(sub, esc_buffer));</span>
<span class="lineNum"> 838 </span><span class="lineCov"> 93176 : if (is_diff) {</span>
<span class="lineNum"> 839 </span><span class="lineNoCov"> 0 : printf(&quot;restore %s\n&quot;, fmt_term(disk, sub, esc_buffer));</span>
<span class="lineNum"> 840 </span> : }
<span class="lineNum"> 841 </span> :
<span class="lineNum"> 842 </span> : /* remove from the inode set */
<span class="lineNum"> 843 </span><span class="lineCov"> 93176 : tommy_hashdyn_remove_existing(&amp;disk-&gt;inodeset, &amp;file-&gt;nodeset);</span>
<span class="lineNum"> 844 </span> :
<span class="lineNum"> 845 </span> : /* save the new inode */
<span class="lineNum"> 846 </span><span class="lineCov"> 93176 : file-&gt;inode = st-&gt;st_ino;</span>
<span class="lineNum"> 847 </span> :
<span class="lineNum"> 848 </span> : /* reinsert in the inode set */
<span class="lineNum"> 849 </span><span class="lineCov"> 93176 : tommy_hashdyn_insert(&amp;disk-&gt;inodeset, &amp;file-&gt;nodeset, file, file_inode_hash(file-&gt;inode));</span>
<span class="lineNum"> 850 </span> :
<span class="lineNum"> 851 </span> : /* we have to save the new inode */
<span class="lineNum"> 852 </span><span class="lineCov"> 93176 : state-&gt;need_write = 1;</span>
<span class="lineNum"> 853 </span> : } else {
<span class="lineNum"> 854 </span> : /* otherwise it's the case of not persistent inode, where doesn't */
<span class="lineNum"> 855 </span> : /* matter if the inode is different or equal, because they have no */
<span class="lineNum"> 856 </span> : /* meaning, and then we don't even save them */
<span class="lineNum"> 857 </span><span class="lineCov"> 14 : ++scan-&gt;count_equal;</span>
<span class="lineNum"> 858 </span> :
<span class="lineNum"> 859 </span><span class="lineCov"> 14 : if (state-&gt;opt.gui) {</span>
<span class="lineNum"> 860 </span><span class="lineNoCov"> 0 : log_tag(&quot;scan:equal:%s:%s\n&quot;, disk-&gt;name, esc_tag(file-&gt;sub, esc_buffer));</span>
<span class="lineNum"> 861 </span> : }
<span class="lineNum"> 862 </span> : }
<span class="lineNum"> 863 </span> :
<span class="lineNum"> 864 </span> : /* mark the file as kept */
<span class="lineNum"> 865 </span><span class="lineCov"> 93190 : scan_file_keep(scan, file);</span>
<span class="lineNum"> 866 </span> :
<span class="lineNum"> 867 </span> : /* nothing more to do */
<span class="lineNum"> 868 </span><span class="lineCov"> 93190 : return;</span>
<span class="lineNum"> 869 </span> : }
<span class="lineNum"> 870 </span> :
<span class="lineNum"> 871 </span> : /* here if the file is changed but with the correct name */
<span class="lineNum"> 872 </span> :
<span class="lineNum"> 873 </span> : /* save the info for later printout */
<span class="lineNum"> 874 </span><span class="lineCov"> 4681 : file_already_present_size = file-&gt;size;</span>
<span class="lineNum"> 875 </span><span class="lineCov"> 4681 : file_already_present_mtime_sec = file-&gt;mtime_sec;</span>
<span class="lineNum"> 876 </span><span class="lineCov"> 4681 : file_already_present_mtime_nsec = file-&gt;mtime_nsec;</span>
<span class="lineNum"> 877 </span> :
<span class="lineNum"> 878 </span> : /* keep track if the original file was not of zero size */
<span class="lineNum"> 879 </span><span class="lineCov"> 4681 : is_original_file_size_different_than_zero = file-&gt;size != 0;</span>
<span class="lineNum"> 880 </span> :
<span class="lineNum"> 881 </span> : /* remove it, and continue to insert it again */
<span class="lineNum"> 882 </span><span class="lineCov"> 4681 : scan_file_remove(scan, file);</span>
<span class="lineNum"> 883 </span> :
<span class="lineNum"> 884 </span> : /* and continue to insert it again */
<span class="lineNum"> 885 </span> : } else {
<span class="lineNum"> 886 </span><span class="lineCov"> 74513 : file_already_present_size = 0;</span>
<span class="lineNum"> 887 </span><span class="lineCov"> 74513 : file_already_present_mtime_sec = 0;</span>
<span class="lineNum"> 888 </span><span class="lineCov"> 74513 : file_already_present_mtime_nsec = 0;</span>
<span class="lineNum"> 889 </span> : }
<span class="lineNum"> 890 </span> :
<span class="lineNum"> 891 </span> : /* refresh the info, to ensure that they are synced, */
<span class="lineNum"> 892 </span> : /* note that we refresh only the info of the new or modified files */
<span class="lineNum"> 893 </span> : /* because this is slow operation */
<span class="lineNum"> 894 </span><span class="lineCov"> 79194 : scan_file_refresh(scan, sub, st, &amp;physical);</span>
<span class="lineNum"> 895 </span> :
<span class="lineNum"> 896 </span> : #ifndef _WIN32
<span class="lineNum"> 897 </span> : /* do a safety check to ensure that the common ext4 case of zeroing */
<span class="lineNum"> 898 </span> : /* the size of a file after a crash doesn't propagate to the backup */
<span class="lineNum"> 899 </span> : /* this check is specific for Linux, so we disable it on Windows */
<span class="lineNum"> 900 </span><span class="lineCov"> 79194 : if (is_original_file_size_different_than_zero &amp;&amp; st-&gt;st_size == 0) {</span>
<span class="lineNum"> 901 </span><span class="lineNoCov"> 0 : if (!state-&gt;opt.force_zero) {</span>
<span class="lineNum"> 902 </span> : /* LCOV_EXCL_START */
<span class="lineNum"> 903 </span> : log_fatal(&quot;The file '%s%s' has unexpected zero size!\n&quot;, disk-&gt;dir, sub);
<span class="lineNum"> 904 </span> : log_fatal(&quot;It's possible that after a kernel crash this file was lost,\n&quot;);
<span class="lineNum"> 905 </span> : log_fatal(&quot;and you can use 'snapraid fix -f /%s' to recover it.\n&quot;, fmt_poll(disk, sub, esc_buffer));
<span class="lineNum"> 906 </span> : if (!is_diff) {
<span class="lineNum"> 907 </span> : log_fatal(&quot;If this an expected condition you can '%s' anyway using 'snapraid --force-zero %s'\n&quot;, state-&gt;command, state-&gt;command);
<span class="lineNum"> 908 </span> : exit(EXIT_FAILURE);
<span class="lineNum"> 909 </span> : }
<span class="lineNum"> 910 </span> : /* LCOV_EXCL_STOP */
<span class="lineNum"> 911 </span> : }
<span class="lineNum"> 912 </span> : }
<span class="lineNum"> 913 </span> : #else
<span class="lineNum"> 914 </span> : /* avoid the unused warning in Windows */
<span class="lineNum"> 915 </span> : (void)is_original_file_size_different_than_zero;
<span class="lineNum"> 916 </span> : #endif
<span class="lineNum"> 917 </span> :
<span class="lineNum"> 918 </span> : /* insert it */
<span class="lineNum"> 919 </span><span class="lineCov"> 79194 : file = file_alloc(state-&gt;block_size, sub, st-&gt;st_size, st-&gt;st_mtime, STAT_NSEC(st), st-&gt;st_ino, physical);</span>
<span class="lineNum"> 920 </span> :
<span class="lineNum"> 921 </span> : /* mark it as present */
<span class="lineNum"> 922 </span><span class="lineCov"> 79194 : file_flag_set(file, FILE_IS_PRESENT);</span>
<span class="lineNum"> 923 </span> :
<span class="lineNum"> 924 </span> : /* if copy detection is enabled */
<span class="lineNum"> 925 </span> : /* note that the copy detection is tried also for updated files */
<span class="lineNum"> 926 </span> : /* this makes sense because it may happen to have two different copies */
<span class="lineNum"> 927 </span> : /* of the same file, and we move the right one over the wrong one */
<span class="lineNum"> 928 </span> : /* in such case we have a &quot;copy&quot; over an &quot;update&quot; */
<span class="lineNum"> 929 </span><span class="lineCov"> 79194 : if (!state-&gt;opt.force_nocopy) {</span>
<span class="lineNum"> 930 </span><span class="lineCov"> 79194 : tommy_uint32_t hash = file_stamp_hash(file-&gt;size, file-&gt;mtime_sec, file-&gt;mtime_nsec);</span>
<span class="lineNum"> 931 </span> :
<span class="lineNum"> 932 </span> : /* search for a file with the same name and stamp in all the disks */
<span class="lineNum"> 933 </span><span class="lineCov"> 423410 : for (i = state-&gt;disklist; i != 0; i = i-&gt;next) {</span>
<span class="lineNum"> 934 </span><span class="lineCov"> 367852 : struct snapraid_disk* other_disk = i-&gt;data;</span>
<span class="lineNum"> 935 </span> : struct snapraid_file* other_file;
<span class="lineNum"> 936 </span> :
<span class="lineNum"> 937 </span> : /* if the nanosecond part of the time stamp is valid, search */
<span class="lineNum"> 938 </span> : /* for name and stamp, otherwise for path and stamp */
<span class="lineNum"> 939 </span><span class="lineCov"> 367852 : if (file-&gt;mtime_nsec != 0 &amp;&amp; file-&gt;mtime_nsec != STAT_NSEC_INVALID)</span>
<span class="lineNum"> 940 </span><span class="lineCov"> 367744 : other_file = tommy_hashdyn_search(&amp;other_disk-&gt;stampset, file_namestamp_compare, file, hash);</span>
<span class="lineNum"> 941 </span> : else
<span class="lineNum"> 942 </span><span class="lineCov"> 108 : other_file = tommy_hashdyn_search(&amp;other_disk-&gt;stampset, file_pathstamp_compare, file, hash);</span>
<span class="lineNum"> 943 </span> :
<span class="lineNum"> 944 </span> : /* if found, and it's a fully hashed file */
<span class="lineNum"> 945 </span><span class="lineCov"> 367852 : if (other_file &amp;&amp; file_is_full_hashed_and_stable(scan-&gt;state, other_disk, other_file)) {</span>
<span class="lineNum"> 946 </span> : /* assume that the file is a copy, and reuse the hash */
<span class="lineNum"> 947 </span><span class="lineCov"> 23636 : file_copy(other_file, file);</span>
<span class="lineNum"> 948 </span> :
<span class="lineNum"> 949 </span> : /* revert old counter and use the copy one */
<span class="lineNum"> 950 </span><span class="lineCov"> 23636 : ++scan-&gt;count_copy;</span>
<span class="lineNum"> 951 </span> :
<span class="lineNum"> 952 </span><span class="lineCov"> 23636 : log_tag(&quot;scan:copy:%s:%s:%s:%s\n&quot;, other_disk-&gt;name, esc_tag(other_file-&gt;sub, esc_buffer), disk-&gt;name, esc_tag(file-&gt;sub, esc_buffer_alt));</span>
<span class="lineNum"> 953 </span><span class="lineCov"> 23636 : if (is_diff) {</span>
<span class="lineNum"> 954 </span><span class="lineCov"> 31 : printf(&quot;copy %s -&gt; %s\n&quot;, fmt_term(other_disk, other_file-&gt;sub, esc_buffer), fmt_term(disk, file-&gt;sub, esc_buffer_alt));</span>
<span class="lineNum"> 955 </span> : }
<span class="lineNum"> 956 </span> :
<span class="lineNum"> 957 </span> : /* mark it as reported */
<span class="lineNum"> 958 </span><span class="lineCov"> 23636 : is_file_reported = 1;</span>
<span class="lineNum"> 959 </span> :
<span class="lineNum"> 960 </span> : /* no need to continue the search */
<span class="lineNum"> 961 </span><span class="lineCov"> 23636 : break;</span>
<span class="lineNum"> 962 </span> : }
<span class="lineNum"> 963 </span> : }
<span class="lineNum"> 964 </span> : }
<span class="lineNum"> 965 </span> :
<span class="lineNum"> 966 </span> : /* if not yet reported, do it now */
<span class="lineNum"> 967 </span> : /* we postpone this to avoid to print two times the copied files */
<span class="lineNum"> 968 </span><span class="lineCov"> 79194 : if (!is_file_reported) {</span>
<span class="lineNum"> 969 </span><span class="lineCov"> 55558 : if (is_file_already_present) {</span>
<span class="lineNum"> 970 </span><span class="lineCov"> 4681 : ++scan-&gt;count_change;</span>
<span class="lineNum"> 971 </span> :
<span class="lineNum"> 972 </span><span class="lineCov"> 14043 : log_tag(&quot;scan:update:%s:%s: %&quot; PRIu64 &quot; %&quot; PRIu64 &quot;.%d -&gt; %&quot; PRIu64 &quot; %&quot; PRIu64 &quot;.%d\n&quot;, disk-&gt;name, esc_tag(sub, esc_buffer),</span>
<span class="lineNum"> 973 </span> : (uint64_t)file_already_present_size, (uint64_t)file_already_present_mtime_sec, file_already_present_mtime_nsec,
<span class="lineNum"> 974 </span><span class="lineCov"> 9362 : (uint64_t)file-&gt;size, (uint64_t)file-&gt;mtime_sec, file-&gt;mtime_nsec</span>
<span class="lineNum"> 975 </span> : );
<span class="lineNum"> 976 </span> :
<span class="lineNum"> 977 </span><span class="lineCov"> 4681 : if (is_diff) {</span>
<span class="lineNum"> 978 </span><span class="lineCov"> 118 : printf(&quot;update %s\n&quot;, fmt_term(disk, sub, esc_buffer));</span>
<span class="lineNum"> 979 </span> : }
<span class="lineNum"> 980 </span> : } else {
<span class="lineNum"> 981 </span><span class="lineCov"> 50877 : ++scan-&gt;count_insert;</span>
<span class="lineNum"> 982 </span> :
<span class="lineNum"> 983 </span><span class="lineCov"> 50877 : log_tag(&quot;scan:add:%s:%s\n&quot;, disk-&gt;name, esc_tag(sub, esc_buffer));</span>
<span class="lineNum"> 984 </span><span class="lineCov"> 50877 : if (is_diff) {</span>
<span class="lineNum"> 985 </span><span class="lineCov"> 17054 : printf(&quot;add %s\n&quot;, fmt_term(disk, sub, esc_buffer));</span>
<span class="lineNum"> 986 </span> : }
<span class="lineNum"> 987 </span> : }
<span class="lineNum"> 988 </span> : }
<span class="lineNum"> 989 </span> :
<span class="lineNum"> 990 </span> : /* insert the file in the delayed list */
<span class="lineNum"> 991 </span><span class="lineCov"> 79194 : scan_file_insert(scan, file);</span>
<span class="lineNum"> 992 </span> : }
<span class="lineNum"> 993 </span> :
<span class="lineNum"> 994 </span> : /**
<a name="995"><span class="lineNum"> 995 </span> : * Remove the specified dir from the data set.</a>
<span class="lineNum"> 996 </span> : */
<span class="lineNum"> 997 </span><span class="lineCov"> 2 : static void scan_emptydir_remove(struct snapraid_scan* scan, struct snapraid_dir* dir)</span>
<span class="lineNum"> 998 </span> : {
<span class="lineNum"> 999 </span><span class="lineCov"> 2 : struct snapraid_state* state = scan-&gt;state;</span>
<span class="lineNum"> 1000 </span><span class="lineCov"> 2 : struct snapraid_disk* disk = scan-&gt;disk;</span>
<span class="lineNum"> 1001 </span> :
<span class="lineNum"> 1002 </span> : /* state changed */
<span class="lineNum"> 1003 </span><span class="lineCov"> 2 : state-&gt;need_write = 1;</span>
<span class="lineNum"> 1004 </span> :
<span class="lineNum"> 1005 </span> : /* remove the file from the dir containers */
<span class="lineNum"> 1006 </span><span class="lineCov"> 2 : tommy_hashdyn_remove_existing(&amp;disk-&gt;dirset, &amp;dir-&gt;nodeset);</span>
<span class="lineNum"> 1007 </span><span class="lineCov"> 2 : tommy_list_remove_existing(&amp;disk-&gt;dirlist, &amp;dir-&gt;nodelist);</span>
<span class="lineNum"> 1008 </span> :
<span class="lineNum"> 1009 </span> : /* deallocate */
<span class="lineNum"> 1010 </span><span class="lineCov"> 2 : dir_free(dir);</span>
<span class="lineNum"> 1011 </span><span class="lineCov"> 2 : }</span>
<span class="lineNum"> 1012 </span> :
<span class="lineNum"> 1013 </span> : /**
<a name="1014"><span class="lineNum"> 1014 </span> : * Insert the specified dir in the data set.</a>
<span class="lineNum"> 1015 </span> : */
<span class="lineNum"> 1016 </span><span class="lineCov"> 10 : static void scan_emptydir_insert(struct snapraid_scan* scan, struct snapraid_dir* dir)</span>
<span class="lineNum"> 1017 </span> : {
<span class="lineNum"> 1018 </span><span class="lineCov"> 10 : struct snapraid_state* state = scan-&gt;state;</span>
<span class="lineNum"> 1019 </span><span class="lineCov"> 10 : struct snapraid_disk* disk = scan-&gt;disk;</span>
<span class="lineNum"> 1020 </span> :
<span class="lineNum"> 1021 </span> : /* state changed */
<span class="lineNum"> 1022 </span><span class="lineCov"> 10 : state-&gt;need_write = 1;</span>
<span class="lineNum"> 1023 </span> :
<span class="lineNum"> 1024 </span> : /* insert the dir in the dir containers */
<span class="lineNum"> 1025 </span><span class="lineCov"> 10 : tommy_hashdyn_insert(&amp;disk-&gt;dirset, &amp;dir-&gt;nodeset, dir, dir_name_hash(dir-&gt;sub));</span>
<span class="lineNum"> 1026 </span><span class="lineCov"> 10 : tommy_list_insert_tail(&amp;disk-&gt;dirlist, &amp;dir-&gt;nodelist, dir);</span>
<span class="lineNum"> 1027 </span><span class="lineCov"> 10 : }</span>
<span class="lineNum"> 1028 </span> :
<span class="lineNum"> 1029 </span> : /**
<a name="1030"><span class="lineNum"> 1030 </span> : * Process a dir.</a>
<span class="lineNum"> 1031 </span> : */
<span class="lineNum"> 1032 </span><span class="lineCov"> 259 : static void scan_emptydir(struct snapraid_scan* scan, const char* sub)</span>
<span class="lineNum"> 1033 </span> : {
<span class="lineNum"> 1034 </span><span class="lineCov"> 259 : struct snapraid_disk* disk = scan-&gt;disk;</span>
<span class="lineNum"> 1035 </span> : struct snapraid_dir* dir;
<span class="lineNum"> 1036 </span> :
<span class="lineNum"> 1037 </span> : /* check if the dir already exists */
<span class="lineNum"> 1038 </span><span class="lineCov"> 259 : dir = tommy_hashdyn_search(&amp;disk-&gt;dirset, dir_name_compare, sub, dir_name_hash(sub));</span>
<span class="lineNum"> 1039 </span><span class="lineCov"> 259 : if (dir) {</span>
<span class="lineNum"> 1040 </span> : /* check if multiple files have the same name */
<span class="lineNum"> 1041 </span><span class="lineCov"> 249 : if (dir_flag_has(dir, FILE_IS_PRESENT)) {</span>
<span class="lineNum"> 1042 </span> : /* LCOV_EXCL_START */
<span class="lineNum"> 1043 </span> : log_fatal(&quot;Internal inconsistency for dir '%s%s'\n&quot;, disk-&gt;dir, sub);
<span class="lineNum"> 1044 </span> : os_abort();
<span class="lineNum"> 1045 </span> : /* LCOV_EXCL_STOP */
<span class="lineNum"> 1046 </span> : }
<span class="lineNum"> 1047 </span> :
<span class="lineNum"> 1048 </span> : /* mark as present */
<span class="lineNum"> 1049 </span><span class="lineCov"> 249 : dir_flag_set(dir, FILE_IS_PRESENT);</span>
<span class="lineNum"> 1050 </span> :
<span class="lineNum"> 1051 </span> : /* nothing more to do */
<span class="lineNum"> 1052 </span><span class="lineCov"> 508 : return;</span>
<span class="lineNum"> 1053 </span> : } else {
<span class="lineNum"> 1054 </span> : /* and continue to insert it */
<span class="lineNum"> 1055 </span> : }
<span class="lineNum"> 1056 </span> :
<span class="lineNum"> 1057 </span> : /* insert it */
<span class="lineNum"> 1058 </span><span class="lineCov"> 10 : dir = dir_alloc(sub);</span>
<span class="lineNum"> 1059 </span> :
<span class="lineNum"> 1060 </span> : /* mark it as present */
<span class="lineNum"> 1061 </span><span class="lineCov"> 10 : dir_flag_set(dir, FILE_IS_PRESENT);</span>
<span class="lineNum"> 1062 </span> :
<span class="lineNum"> 1063 </span> : /* insert it in the delayed insert list */
<span class="lineNum"> 1064 </span><span class="lineCov"> 10 : tommy_list_insert_tail(&amp;scan-&gt;dir_insert_list, &amp;dir-&gt;nodelist, dir);</span>
<span class="lineNum"> 1065 </span> : }
<span class="lineNum"> 1066 </span> :
<span class="lineNum"> 1067 </span> : struct dirent_sorted {
<span class="lineNum"> 1068 </span> : /* node for data structures */
<span class="lineNum"> 1069 </span> : tommy_node node;
<span class="lineNum"> 1070 </span> :
<span class="lineNum"> 1071 </span> : #if HAVE_STRUCT_DIRENT_D_INO
<span class="lineNum"> 1072 </span> : uint64_t d_ino; /**&lt; Inode number. */
<span class="lineNum"> 1073 </span> : #endif
<span class="lineNum"> 1074 </span> : #if HAVE_STRUCT_DIRENT_D_TYPE
<span class="lineNum"> 1075 </span> : uint32_t d_type; /**&lt; File type. */
<span class="lineNum"> 1076 </span> : #endif
<span class="lineNum"> 1077 </span> : #if HAVE_STRUCT_DIRENT_D_STAT
<span class="lineNum"> 1078 </span> : struct stat d_stat; /**&lt; Stat result. */
<span class="lineNum"> 1079 </span> : #endif
<span class="lineNum"> 1080 </span> : char d_name[]; /**&lt; Variable length name. It must be the last field. */
<span class="lineNum"> 1081 </span> : };
<a name="1082"><span class="lineNum"> 1082 </span> : </a>
<span class="lineNum"> 1083 </span> : #if HAVE_STRUCT_DIRENT_D_INO
<span class="lineNum"> 1084 </span><span class="lineCov"> 103390 : static int dd_ino_compare(const void* void_a, const void* void_b)</span>
<span class="lineNum"> 1085 </span> : {
<span class="lineNum"> 1086 </span><span class="lineCov"> 103390 : const struct dirent_sorted* a = void_a;</span>
<span class="lineNum"> 1087 </span><span class="lineCov"> 103390 : const struct dirent_sorted* b = void_b;</span>
<span class="lineNum"> 1088 </span> :
<span class="lineNum"> 1089 </span><span class="lineCov"> 103390 : if (a-&gt;d_ino &lt; b-&gt;d_ino)</span>
<span class="lineNum"> 1090 </span><span class="lineCov"> 49438 : return -1;</span>
<span class="lineNum"> 1091 </span><span class="lineCov"> 53952 : if (a-&gt;d_ino &gt; b-&gt;d_ino)</span>
<span class="lineNum"> 1092 </span><span class="lineCov"> 53952 : return 1;</span>
<span class="lineNum"> 1093 </span> :
<span class="lineNum"> 1094 </span><span class="lineNoCov"> 0 : return 0;</span>
<span class="lineNum"> 1095 </span> : }
<a name="1096"><span class="lineNum"> 1096 </span> : #endif</a>
<span class="lineNum"> 1097 </span> :
<span class="lineNum"> 1098 </span><span class="lineCov"> 11526118 : static int dd_name_compare(const void* void_a, const void* void_b)</span>
<span class="lineNum"> 1099 </span> : {
<span class="lineNum"> 1100 </span><span class="lineCov"> 11526118 : const struct dirent_sorted* a = void_a;</span>
<span class="lineNum"> 1101 </span><span class="lineCov"> 11526118 : const struct dirent_sorted* b = void_b;</span>
<span class="lineNum"> 1102 </span> :
<span class="lineNum"> 1103 </span><span class="lineCov"> 11526118 : return strcmp(a-&gt;d_name, b-&gt;d_name);</span>
<span class="lineNum"> 1104 </span> : }
<span class="lineNum"> 1105 </span> :
<span class="lineNum"> 1106 </span> : /**
<span class="lineNum"> 1107 </span> : * Return the stat info of a dir entry.
<span class="lineNum"> 1108 </span> : */
<span class="lineNum"> 1109 </span> : #if HAVE_STRUCT_DIRENT_D_STAT
<span class="lineNum"> 1110 </span> : #define DSTAT(file, dd, buf) dstat(dd)
<span class="lineNum"> 1111 </span> : struct stat* dstat(struct dirent_sorted* dd)
<span class="lineNum"> 1112 </span> : {
<span class="lineNum"> 1113 </span> : return &amp;dd-&gt;d_stat;
<span class="lineNum"> 1114 </span> : }
<a name="1115"><span class="lineNum"> 1115 </span> : #else</a>
<span class="lineNum"> 1116 </span> : #define DSTAT(file, dd, buf) dstat(file, buf)
<span class="lineNum"> 1117 </span><span class="lineCov"> 1106210 : struct stat* dstat(const char* file, struct stat* st)</span>
<span class="lineNum"> 1118 </span> : {
<span class="lineNum"> 1119 </span><span class="lineCov"> 1106210 : if (lstat(file, st) != 0) {</span>
<span class="lineNum"> 1120 </span> : /* LCOV_EXCL_START */
<span class="lineNum"> 1121 </span> : log_fatal(&quot;Error in stat file/directory '%s'. %s.\n&quot;, file, strerror(errno));
<span class="lineNum"> 1122 </span> : exit(EXIT_FAILURE);
<span class="lineNum"> 1123 </span> : /* LCOV_EXCL_STOP */
<span class="lineNum"> 1124 </span> : }
<span class="lineNum"> 1125 </span><span class="lineCov"> 1106210 : return st;</span>
<span class="lineNum"> 1126 </span> : }
<span class="lineNum"> 1127 </span> : #endif
<span class="lineNum"> 1128 </span> :
<span class="lineNum"> 1129 </span> : /**
<span class="lineNum"> 1130 </span> : * Process a directory.
<a name="1131"><span class="lineNum"> 1131 </span> : * Return != 0 if at least one file or link is processed.</a>
<span class="lineNum"> 1132 </span> : */
<span class="lineNum"> 1133 </span><span class="lineCov"> 1846 : static int scan_dir(struct snapraid_scan* scan, int level, int is_diff, const char* dir, const char* sub)</span>
<span class="lineNum"> 1134 </span> : {
<span class="lineNum"> 1135 </span><span class="lineCov"> 1846 : struct snapraid_state* state = scan-&gt;state;</span>
<span class="lineNum"> 1136 </span><span class="lineCov"> 1846 : struct snapraid_disk* disk = scan-&gt;disk;</span>
<span class="lineNum"> 1137 </span><span class="lineCov"> 1846 : int processed = 0;</span>
<span class="lineNum"> 1138 </span> : DIR* d;
<span class="lineNum"> 1139 </span> : tommy_list list;
<span class="lineNum"> 1140 </span> : tommy_node* node;
<span class="lineNum"> 1141 </span> :
<span class="lineNum"> 1142 </span><span class="lineCov"> 1846 : tommy_list_init(&amp;list);</span>
<span class="lineNum"> 1143 </span> :
<span class="lineNum"> 1144 </span><span class="lineCov"> 1846 : d = opendir(dir);</span>
<span class="lineNum"> 1145 </span><span class="lineCov"> 1846 : if (!d) {</span>
<span class="lineNum"> 1146 </span> : /* LCOV_EXCL_START */
<span class="lineNum"> 1147 </span> : log_fatal(&quot;Error opening directory '%s'. %s.\n&quot;, dir, strerror(errno));
<span class="lineNum"> 1148 </span> : if (level == 0)
<span class="lineNum"> 1149 </span> : log_fatal(&quot;If this is the disk mount point, remember to create it manually\n&quot;);
<span class="lineNum"> 1150 </span> : else
<span class="lineNum"> 1151 </span> : log_fatal(&quot;If it's a permission problem, you can exclude it in the config file with:\n\texclude /%s\n&quot;, sub);
<span class="lineNum"> 1152 </span> : exit(EXIT_FAILURE);
<span class="lineNum"> 1153 </span> : /* LCOV_EXCL_STOP */
<span class="lineNum"> 1154 </span> : }
<span class="lineNum"> 1155 </span> :
<span class="lineNum"> 1156 </span> : /* read the full directory */
<span class="lineNum"> 1157 </span> : while (1) {
<span class="lineNum"> 1158 </span> : char path_next[PATH_MAX];
<span class="lineNum"> 1159 </span> : char sub_next[PATH_MAX];
<span class="lineNum"> 1160 </span> : struct dirent_sorted* entry;
<span class="lineNum"> 1161 </span> : const char* name;
<span class="lineNum"> 1162 </span> : struct dirent* dd;
<span class="lineNum"> 1163 </span> : size_t name_len;
<span class="lineNum"> 1164 </span> :
<span class="lineNum"> 1165 </span> : /*
<span class="lineNum"> 1166 </span> : * Clear errno to differentiate the end of the stream and an error condition
<span class="lineNum"> 1167 </span> : *
<span class="lineNum"> 1168 </span> : * From the Linux readdir() manpage:
<span class="lineNum"> 1169 </span> : * &quot;If the end of the directory stream is reached, NULL is returned and errno is not changed.
<span class="lineNum"> 1170 </span> : * If an error occurs, NULL is returned and errno is set appropriately.&quot;
<span class="lineNum"> 1171 </span> : */
<span class="lineNum"> 1172 </span><span class="lineCov"> 1147737 : errno = 0;</span>
<span class="lineNum"> 1173 </span><span class="lineCov"> 1147737 : dd = readdir(d);</span>
<span class="lineNum"> 1174 </span><span class="lineCov"> 1147737 : if (dd == 0 &amp;&amp; errno != 0) {</span>
<span class="lineNum"> 1175 </span> : /* LCOV_EXCL_START */
<span class="lineNum"> 1176 </span> : log_fatal(&quot;Error reading directory '%s'. %s.\n&quot;, dir, strerror(errno));
<span class="lineNum"> 1177 </span> : log_fatal(&quot;You can exclude it in the config file with:\n\texclude /%s\n&quot;, sub);
<span class="lineNum"> 1178 </span> : exit(EXIT_FAILURE);
<span class="lineNum"> 1179 </span> : /* LCOV_EXCL_STOP */
<span class="lineNum"> 1180 </span> : }
<span class="lineNum"> 1181 </span><span class="lineCov"> 1147737 : if (dd == 0) {</span>
<span class="lineNum"> 1182 </span><span class="lineCov"> 1846 : break; /* finished */</span>
<span class="lineNum"> 1183 </span> : }
<span class="lineNum"> 1184 </span> :
<span class="lineNum"> 1185 </span> : /* skip &quot;.&quot; and &quot;..&quot; files */
<span class="lineNum"> 1186 </span><span class="lineCov"> 1145891 : name = dd-&gt;d_name;</span>
<span class="lineNum"> 1187 </span><span class="lineCov"> 1145891 : if (name[0] == '.' &amp;&amp; (name[1] == 0 || (name[1] == '.' &amp;&amp; name[2] == 0)))</span>
<span class="lineNum"> 1188 </span><span class="lineCov"> 7384 : continue;</span>
<span class="lineNum"> 1189 </span> :
<span class="lineNum"> 1190 </span><span class="lineCov"> 1142199 : pathprint(path_next, sizeof(path_next), &quot;%s%s&quot;, dir, name);</span>
<span class="lineNum"> 1191 </span><span class="lineCov"> 1142199 : pathprint(sub_next, sizeof(sub_next), &quot;%s%s&quot;, sub, name);</span>
<span class="lineNum"> 1192 </span> :
<span class="lineNum"> 1193 </span> : /* check for not supported file names */
<span class="lineNum"> 1194 </span><span class="lineCov"> 1142199 : if (name[0] == 0) {</span>
<span class="lineNum"> 1195 </span> : /* LCOV_EXCL_START */
<span class="lineNum"> 1196 </span> : log_fatal(&quot;Unsupported name '%s' in file '%s'.\n&quot;, name, path_next);
<span class="lineNum"> 1197 </span> : exit(EXIT_FAILURE);
<span class="lineNum"> 1198 </span> : /* LCOV_EXCL_STOP */
<span class="lineNum"> 1199 </span> : }
<span class="lineNum"> 1200 </span> :
<span class="lineNum"> 1201 </span> : /* exclude hidden files even before calling lstat() */
<span class="lineNum"> 1202 </span><span class="lineCov"> 1142199 : if (filter_hidden(state-&gt;filter_hidden, dd) != 0) {</span>
<span class="lineNum"> 1203 </span><span class="lineNoCov"> 0 : msg_verbose(&quot;Excluding hidden '%s'\n&quot;, path_next);</span>
<span class="lineNum"> 1204 </span><span class="lineNoCov"> 0 : continue;</span>
<span class="lineNum"> 1205 </span> : }
<span class="lineNum"> 1206 </span> :
<span class="lineNum"> 1207 </span> : /* exclude content files even before calling lstat() */
<span class="lineNum"> 1208 </span><span class="lineCov"> 1142199 : if (filter_content(&amp;state-&gt;contentlist, path_next) != 0) {</span>
<span class="lineNum"> 1209 </span><span class="lineNoCov"> 0 : msg_verbose(&quot;Excluding content '%s'\n&quot;, path_next);</span>
<span class="lineNum"> 1210 </span><span class="lineNoCov"> 0 : continue;</span>
<span class="lineNum"> 1211 </span> : }
<span class="lineNum"> 1212 </span> :
<span class="lineNum"> 1213 </span><span class="lineCov"> 1142199 : name_len = strlen(dd-&gt;d_name);</span>
<span class="lineNum"> 1214 </span><span class="lineCov"> 1142199 : entry = malloc_nofail(sizeof(struct dirent_sorted) + name_len + 1);</span>
<span class="lineNum"> 1215 </span> :
<span class="lineNum"> 1216 </span> : /* copy the dir entry */
<span class="lineNum"> 1217 </span> : #if HAVE_STRUCT_DIRENT_D_INO
<span class="lineNum"> 1218 </span><span class="lineCov"> 1142199 : entry-&gt;d_ino = dd-&gt;d_ino;</span>
<span class="lineNum"> 1219 </span> : #endif
<span class="lineNum"> 1220 </span> : #if HAVE_STRUCT_DIRENT_D_TYPE
<span class="lineNum"> 1221 </span><span class="lineCov"> 1142199 : entry-&gt;d_type = dd-&gt;d_type;</span>
<span class="lineNum"> 1222 </span> : #endif
<span class="lineNum"> 1223 </span> : #if HAVE_STRUCT_DIRENT_D_STAT
<span class="lineNum"> 1224 </span> : /* convert dirent to lstat result */
<span class="lineNum"> 1225 </span> : dirent_lstat(dd, &amp;entry-&gt;d_stat);
<span class="lineNum"> 1226 </span> :
<span class="lineNum"> 1227 </span> : /* note that at this point the st_mode may be 0 */
<span class="lineNum"> 1228 </span> : #endif
<span class="lineNum"> 1229 </span><span class="lineCov"> 1142199 : memcpy(entry-&gt;d_name, dd-&gt;d_name, name_len + 1);</span>
<span class="lineNum"> 1230 </span> :
<span class="lineNum"> 1231 </span> : /* insert in the list */
<span class="lineNum"> 1232 </span><span class="lineCov"> 1142199 : tommy_list_insert_tail(&amp;list, &amp;entry-&gt;node, entry);</span>
<span class="lineNum"> 1233 </span><span class="lineCov"> 1145891 : }</span>
<span class="lineNum"> 1234 </span> :
<span class="lineNum"> 1235 </span><span class="lineCov"> 1846 : if (closedir(d) != 0) {</span>
<span class="lineNum"> 1236 </span> : /* LCOV_EXCL_START */
<span class="lineNum"> 1237 </span> : log_fatal(&quot;Error closing directory '%s'. %s.\n&quot;, dir, strerror(errno));
<span class="lineNum"> 1238 </span> : exit(EXIT_FAILURE);
<span class="lineNum"> 1239 </span> : /* LCOV_EXCL_STOP */
<span class="lineNum"> 1240 </span> : }
<span class="lineNum"> 1241 </span> :
<span class="lineNum"> 1242 </span><span class="lineCov"> 1846 : if (state-&gt;opt.force_order == SORT_ALPHA) {</span>
<span class="lineNum"> 1243 </span> : /* if requested sort alphabetically */
<span class="lineNum"> 1244 </span> : /* this is mainly done for testing to ensure to always */
<span class="lineNum"> 1245 </span> : /* process in the same way in different platforms */
<span class="lineNum"> 1246 </span><span class="lineCov"> 1810 : tommy_list_sort(&amp;list, dd_name_compare);</span>
<span class="lineNum"> 1247 </span> : }
<span class="lineNum"> 1248 </span> : #if HAVE_STRUCT_DIRENT_D_INO
<span class="lineNum"> 1249 </span><span class="lineCov"> 36 : else if (!disk-&gt;has_volatile_inodes) {</span>
<span class="lineNum"> 1250 </span> : /* if inodes are persistent */
<span class="lineNum"> 1251 </span> : /* sort the list of dir entries by inodes */
<span class="lineNum"> 1252 </span><span class="lineCov"> 36 : tommy_list_sort(&amp;list, dd_ino_compare);</span>
<span class="lineNum"> 1253 </span> : }
<span class="lineNum"> 1254 </span> : /* otherwise just keep the insertion order */
<span class="lineNum"> 1255 </span> : #endif
<span class="lineNum"> 1256 </span> :
<span class="lineNum"> 1257 </span> : /* process the sorted dir entries */
<span class="lineNum"> 1258 </span><span class="lineCov"> 1846 : node = list;</span>
<span class="lineNum"> 1259 </span><span class="lineCov"> 1145891 : while (node != 0) {</span>
<span class="lineNum"> 1260 </span> : char path_next[PATH_MAX];
<span class="lineNum"> 1261 </span> : char sub_next[PATH_MAX];
<span class="lineNum"> 1262 </span> : char out[PATH_MAX];
<span class="lineNum"> 1263 </span><span class="lineCov"> 1142199 : struct snapraid_filter* reason = 0;</span>
<span class="lineNum"> 1264 </span><span class="lineCov"> 1142199 : struct dirent_sorted* dd = node-&gt;data;</span>
<span class="lineNum"> 1265 </span><span class="lineCov"> 1142199 : const char* name = dd-&gt;d_name;</span>
<span class="lineNum"> 1266 </span> : struct stat* st;
<span class="lineNum"> 1267 </span> : int type;
<span class="lineNum"> 1268 </span> : #if !HAVE_STRUCT_DIRENT_D_STAT
<span class="lineNum"> 1269 </span> : struct stat st_buf;
<span class="lineNum"> 1270 </span> : #endif
<span class="lineNum"> 1271 </span> :
<span class="lineNum"> 1272 </span><span class="lineCov"> 1142199 : pathprint(path_next, sizeof(path_next), &quot;%s%s&quot;, dir, name);</span>
<span class="lineNum"> 1273 </span><span class="lineCov"> 1142199 : pathprint(sub_next, sizeof(sub_next), &quot;%s%s&quot;, sub, name);</span>
<span class="lineNum"> 1274 </span> :
<span class="lineNum"> 1275 </span> : /* start with an unknown type */
<span class="lineNum"> 1276 </span><span class="lineCov"> 1142199 : type = -1;</span>
<span class="lineNum"> 1277 </span><span class="lineCov"> 1142199 : st = 0;</span>
<span class="lineNum"> 1278 </span> :
<span class="lineNum"> 1279 </span> : /* if dirent has the type, use it */
<span class="lineNum"> 1280 </span> : #if HAVE_STRUCT_DIRENT_D_TYPE
<span class="lineNum"> 1281 </span><span class="lineCov"> 1142199 : switch (dd-&gt;d_type) {</span>
<span class="lineNum"> 1282 </span><span class="lineNoCov"> 0 : case DT_UNKNOWN : break;</span>
<span class="lineNum"> 1283 </span><span class="lineCov"> 1104939 : case DT_REG : type = 0; break;</span>
<span class="lineNum"> 1284 </span><span class="lineCov"> 35989 : case DT_LNK : type = 1; break;</span>
<span class="lineNum"> 1285 </span><span class="lineCov"> 1271 : case DT_DIR : type = 2; break;</span>
<span class="lineNum"> 1286 </span><span class="lineNoCov"> 0 : default : type = 3; break;</span>
<span class="lineNum"> 1287 </span> : }
<span class="lineNum"> 1288 </span> : #endif
<span class="lineNum"> 1289 </span> :
<span class="lineNum"> 1290 </span> : /* if type is still unknown */
<span class="lineNum"> 1291 </span><span class="lineCov"> 1142199 : if (type &lt; 0) {</span>
<span class="lineNum"> 1292 </span> : /* get the type from stat */
<span class="lineNum"> 1293 </span><span class="lineNoCov"> 0 : st = DSTAT(path_next, dd, &amp;st_buf);</span>
<span class="lineNum"> 1294 </span> :
<span class="lineNum"> 1295 </span> : #if HAVE_STRUCT_DIRENT_D_STAT
<span class="lineNum"> 1296 </span> : /* if the st_mode field is missing, takes care to fill it using normal lstat() */
<span class="lineNum"> 1297 </span> : /* at now this can happen only in Windows (with HAVE_STRUCT_DIRENT_D_STAT defined), */
<span class="lineNum"> 1298 </span> : /* because we use a directory reading method that doesn't read info about ReparsePoint. */
<span class="lineNum"> 1299 </span> : /* Note that here we cannot call here lstat_sync(), because we don't know what kind */
<span class="lineNum"> 1300 </span> : /* of file is it, and lstat_sync() doesn't always work */
<span class="lineNum"> 1301 </span> : if (st-&gt;st_mode == 0) {
<span class="lineNum"> 1302 </span> : if (lstat(path_next, st) != 0) {
<span class="lineNum"> 1303 </span> : /* LCOV_EXCL_START */
<span class="lineNum"> 1304 </span> : log_fatal(&quot;Error in stat file/directory '%s'. %s.\n&quot;, path_next, strerror(errno));
<span class="lineNum"> 1305 </span> : exit(EXIT_FAILURE);
<span class="lineNum"> 1306 </span> : /* LCOV_EXCL_STOP */
<span class="lineNum"> 1307 </span> : }
<span class="lineNum"> 1308 </span> : }
<span class="lineNum"> 1309 </span> : #endif
<span class="lineNum"> 1310 </span> :
<span class="lineNum"> 1311 </span><span class="lineNoCov"> 0 : if (S_ISREG(st-&gt;st_mode))</span>
<span class="lineNum"> 1312 </span><span class="lineNoCov"> 0 : type = 0;</span>
<span class="lineNum"> 1313 </span><span class="lineNoCov"> 0 : else if (S_ISLNK(st-&gt;st_mode))</span>
<span class="lineNum"> 1314 </span><span class="lineNoCov"> 0 : type = 1;</span>
<span class="lineNum"> 1315 </span><span class="lineNoCov"> 0 : else if (S_ISDIR(st-&gt;st_mode))</span>
<span class="lineNum"> 1316 </span><span class="lineNoCov"> 0 : type = 2;</span>
<span class="lineNum"> 1317 </span> : else
<span class="lineNum"> 1318 </span><span class="lineNoCov"> 0 : type = 3;</span>
<span class="lineNum"> 1319 </span> : }
<span class="lineNum"> 1320 </span> :
<span class="lineNum"> 1321 </span><span class="lineCov"> 1142199 : if (type == 0) { /* REG */</span>
<span class="lineNum"> 1322 </span><span class="lineCov"> 1104939 : if (filter_path(&amp;state-&gt;filterlist, &amp;reason, disk-&gt;name, sub_next) == 0) {</span>
<span class="lineNum"> 1323 </span> :
<span class="lineNum"> 1324 </span> : /* late stat, if not yet called */
<span class="lineNum"> 1325 </span><span class="lineCov"> 1104939 : if (!st)</span>
<span class="lineNum"> 1326 </span><span class="lineCov"> 1104939 : st = DSTAT(path_next, dd, &amp;st_buf);</span>
<span class="lineNum"> 1327 </span> :
<span class="lineNum"> 1328 </span> : #if HAVE_LSTAT_SYNC
<span class="lineNum"> 1329 </span> : /* if the st_ino field is missing, takes care to fill it using the extended lstat() */
<span class="lineNum"> 1330 </span> : /* this can happen only in Windows */
<span class="lineNum"> 1331 </span> : if (st-&gt;st_ino == 0) {
<span class="lineNum"> 1332 </span> : if (lstat_sync(path_next, st, 0) != 0) {
<span class="lineNum"> 1333 </span> : /* LCOV_EXCL_START */
<span class="lineNum"> 1334 </span> : log_fatal(&quot;Error in stat file '%s'. %s.\n&quot;, path_next, strerror(errno));
<span class="lineNum"> 1335 </span> : exit(EXIT_FAILURE);
<span class="lineNum"> 1336 </span> : /* LCOV_EXCL_STOP */
<span class="lineNum"> 1337 </span> : }
<span class="lineNum"> 1338 </span> : }
<span class="lineNum"> 1339 </span> : #endif
<span class="lineNum"> 1340 </span> :
<span class="lineNum"> 1341 </span><span class="lineCov"> 1104939 : scan_file(scan, is_diff, sub_next, st, FILEPHY_UNREAD_OFFSET);</span>
<span class="lineNum"> 1342 </span><span class="lineCov"> 1104939 : processed = 1;</span>
<span class="lineNum"> 1343 </span> : } else {
<span class="lineNum"> 1344 </span><span class="lineNoCov"> 0 : msg_verbose(&quot;Excluding file '%s' for rule '%s'\n&quot;, path_next, filter_type(reason, out, sizeof(out)));</span>
<span class="lineNum"> 1345 </span> : }
<span class="lineNum"> 1346 </span><span class="lineCov"> 37260 : } else if (type == 1) { /* LNK */</span>
<span class="lineNum"> 1347 </span><span class="lineCov"> 35989 : if (filter_path(&amp;state-&gt;filterlist, &amp;reason, disk-&gt;name, sub_next) == 0) {</span>
<span class="lineNum"> 1348 </span> : char subnew[PATH_MAX];
<span class="lineNum"> 1349 </span> : int ret;
<span class="lineNum"> 1350 </span> :
<span class="lineNum"> 1351 </span><span class="lineCov"> 35989 : ret = readlink(path_next, subnew, sizeof(subnew));</span>
<span class="lineNum"> 1352 </span><span class="lineCov"> 35989 : if (ret &gt;= PATH_MAX) {</span>
<span class="lineNum"> 1353 </span> : /* LCOV_EXCL_START */
<span class="lineNum"> 1354 </span> : log_fatal(&quot;Error in readlink file '%s'. Symlink too long.\n&quot;, path_next);
<span class="lineNum"> 1355 </span> : exit(EXIT_FAILURE);
<span class="lineNum"> 1356 </span> : /* LCOV_EXCL_STOP */
<span class="lineNum"> 1357 </span> : }
<span class="lineNum"> 1358 </span><span class="lineCov"> 35989 : if (ret &lt; 0) {</span>
<span class="lineNum"> 1359 </span> : /* LCOV_EXCL_START */
<span class="lineNum"> 1360 </span> : log_fatal(&quot;Error in readlink file '%s'. %s.\n&quot;, path_next, strerror(errno));
<span class="lineNum"> 1361 </span> : exit(EXIT_FAILURE);
<span class="lineNum"> 1362 </span> : /* LCOV_EXCL_STOP */
<span class="lineNum"> 1363 </span> : }
<span class="lineNum"> 1364 </span><span class="lineCov"> 35989 : if (ret == 0)</span>
<span class="lineNum"> 1365 </span><span class="lineNoCov"> 0 : log_fatal(&quot;WARNING! Empty symbolic link '%s'.\n&quot;, path_next);</span>
<span class="lineNum"> 1366 </span> :
<span class="lineNum"> 1367 </span> : /* readlink doesn't put the final 0 */
<span class="lineNum"> 1368 </span><span class="lineCov"> 35989 : subnew[ret] = 0;</span>
<span class="lineNum"> 1369 </span> :
<span class="lineNum"> 1370 </span> : /* process as a symbolic link */
<span class="lineNum"> 1371 </span><span class="lineCov"> 35989 : scan_link(scan, is_diff, sub_next, subnew, FILE_IS_SYMLINK);</span>
<span class="lineNum"> 1372 </span><span class="lineCov"> 35989 : processed = 1;</span>
<span class="lineNum"> 1373 </span> : } else {
<span class="lineNum"> 1374 </span><span class="lineNoCov"> 0 : msg_verbose(&quot;Excluding link '%s' for rule '%s'\n&quot;, path_next, filter_type(reason, out, sizeof(out)));</span>
<span class="lineNum"> 1375 </span> : }
<span class="lineNum"> 1376 </span><span class="lineCov"> 1271 : } else if (type == 2) { /* DIR */</span>
<span class="lineNum"> 1377 </span><span class="lineCov"> 1271 : if (filter_subdir(&amp;state-&gt;filterlist, &amp;reason, disk-&gt;name, sub_next) == 0) {</span>
<span class="lineNum"> 1378 </span> : #ifndef _WIN32
<span class="lineNum"> 1379 </span> : /* late stat, if not yet called */
<span class="lineNum"> 1380 </span><span class="lineCov"> 1271 : if (!st)</span>
<span class="lineNum"> 1381 </span><span class="lineCov"> 1271 : st = DSTAT(path_next, dd, &amp;st_buf);</span>
<span class="lineNum"> 1382 </span> :
<span class="lineNum"> 1383 </span> : /* in Unix don't follow mount points in different devices */
<span class="lineNum"> 1384 </span> : /* in Windows we are already skipping them reporting them as special files */
<span class="lineNum"> 1385 </span><span class="lineCov"> 1271 : if ((uint64_t)st-&gt;st_dev != disk-&gt;device) {</span>
<span class="lineNum"> 1386 </span><span class="lineNoCov"> 0 : log_fatal(&quot;WARNING! Ignoring mount point '%s' because it appears to be in a different device\n&quot;, path_next);</span>
<span class="lineNum"> 1387 </span> : } else
<span class="lineNum"> 1388 </span> : #endif
<span class="lineNum"> 1389 </span> : {
<span class="lineNum"> 1390 </span> : char sub_dir[PATH_MAX];
<span class="lineNum"> 1391 </span> :
<span class="lineNum"> 1392 </span> : /* recurse */
<span class="lineNum"> 1393 </span><span class="lineCov"> 1271 : pathslash(path_next, sizeof(path_next));</span>
<span class="lineNum"> 1394 </span><span class="lineCov"> 1271 : pathcpy(sub_dir, sizeof(sub_dir), sub_next);</span>
<span class="lineNum"> 1395 </span><span class="lineCov"> 1271 : pathslash(sub_dir, sizeof(sub_dir));</span>
<span class="lineNum"> 1396 </span><span class="lineCov"> 1271 : if (scan_dir(scan, level + 1, is_diff, path_next, sub_dir) == 0) {</span>
<span class="lineNum"> 1397 </span> : /* scan the directory as empty dir */
<span class="lineNum"> 1398 </span><span class="lineCov"> 259 : scan_emptydir(scan, sub_next);</span>
<span class="lineNum"> 1399 </span> : }
<span class="lineNum"> 1400 </span> : /* or we processed something internally, or we have added the empty dir */
<span class="lineNum"> 1401 </span><span class="lineCov"> 1271 : processed = 1;</span>
<span class="lineNum"> 1402 </span> : }
<span class="lineNum"> 1403 </span> : } else {
<span class="lineNum"> 1404 </span><span class="lineNoCov"> 0 : msg_verbose(&quot;Excluding directory '%s' for rule '%s'\n&quot;, path_next, filter_type(reason, out, sizeof(out)));</span>
<span class="lineNum"> 1405 </span> : }
<span class="lineNum"> 1406 </span> : } else {
<span class="lineNum"> 1407 </span><span class="lineNoCov"> 0 : if (filter_path(&amp;state-&gt;filterlist, &amp;reason, disk-&gt;name, sub_next) == 0) {</span>
<span class="lineNum"> 1408 </span> : /* late stat, if not yet called */
<span class="lineNum"> 1409 </span><span class="lineNoCov"> 0 : if (!st)</span>
<span class="lineNum"> 1410 </span><span class="lineNoCov"> 0 : st = DSTAT(path_next, dd, &amp;st_buf);</span>
<span class="lineNum"> 1411 </span> :
<span class="lineNum"> 1412 </span><span class="lineNoCov"> 0 : log_fatal(&quot;WARNING! Ignoring special '%s' file '%s'\n&quot;, stat_desc(st), path_next);</span>
<span class="lineNum"> 1413 </span> : } else {
<span class="lineNum"> 1414 </span><span class="lineNoCov"> 0 : msg_verbose(&quot;Excluding special file '%s' for rule '%s'\n&quot;, path_next, filter_type(reason, out, sizeof(out)));</span>
<span class="lineNum"> 1415 </span> : }
<span class="lineNum"> 1416 </span> : }
<span class="lineNum"> 1417 </span> :
<span class="lineNum"> 1418 </span> : /* next entry */
<span class="lineNum"> 1419 </span><span class="lineCov"> 1142199 : node = node-&gt;next;</span>
<span class="lineNum"> 1420 </span> :
<span class="lineNum"> 1421 </span> : /* free the present one */
<span class="lineNum"> 1422 </span><span class="lineCov"> 1142199 : free(dd);</span>
<span class="lineNum"> 1423 </span> : }
<span class="lineNum"> 1424 </span> :
<span class="lineNum"> 1425 </span><span class="lineCov"> 1846 : return processed;</span>
<a name="1426"><span class="lineNum"> 1426 </span> : }</a>
<span class="lineNum"> 1427 </span> :
<span class="lineNum"> 1428 </span><span class="lineCov"> 96 : static int state_diffscan(struct snapraid_state* state, int is_diff)</span>
<span class="lineNum"> 1429 </span> : {
<span class="lineNum"> 1430 </span> : tommy_node* i;
<span class="lineNum"> 1431 </span> : tommy_node* j;
<span class="lineNum"> 1432 </span> : tommy_list scanlist;
<span class="lineNum"> 1433 </span> : int done;
<span class="lineNum"> 1434 </span> : fptr* msg;
<span class="lineNum"> 1435 </span> : struct snapraid_scan total;
<span class="lineNum"> 1436 </span> : int no_difference;
<span class="lineNum"> 1437 </span> : char esc_buffer[ESC_MAX];
<span class="lineNum"> 1438 </span> :
<span class="lineNum"> 1439 </span><span class="lineCov"> 96 : tommy_list_init(&amp;scanlist);</span>
<span class="lineNum"> 1440 </span> :
<span class="lineNum"> 1441 </span><span class="lineCov"> 96 : if (is_diff)</span>
<span class="lineNum"> 1442 </span><span class="lineCov"> 8 : msg_progress(&quot;Comparing...\n&quot;);</span>
<span class="lineNum"> 1443 </span> :
<span class="lineNum"> 1444 </span> : /* first scan all the directory and find new and deleted files */
<span class="lineNum"> 1445 </span><span class="lineCov"> 671 : for (i = state-&gt;disklist; i != 0; i = i-&gt;next) {</span>
<span class="lineNum"> 1446 </span><span class="lineCov"> 575 : struct snapraid_disk* disk = i-&gt;data;</span>
<span class="lineNum"> 1447 </span> : struct snapraid_scan* scan;
<span class="lineNum"> 1448 </span> : tommy_node* node;
<span class="lineNum"> 1449 </span> : int ret;
<span class="lineNum"> 1450 </span> : int has_persistent_inode;
<span class="lineNum"> 1451 </span> :
<span class="lineNum"> 1452 </span><span class="lineCov"> 575 : scan = malloc_nofail(sizeof(struct snapraid_scan));</span>
<span class="lineNum"> 1453 </span><span class="lineCov"> 575 : scan-&gt;state = state;</span>
<span class="lineNum"> 1454 </span><span class="lineCov"> 575 : scan-&gt;disk = disk;</span>
<span class="lineNum"> 1455 </span><span class="lineCov"> 575 : scan-&gt;count_equal = 0;</span>
<span class="lineNum"> 1456 </span><span class="lineCov"> 575 : scan-&gt;count_move = 0;</span>
<span class="lineNum"> 1457 </span><span class="lineCov"> 575 : scan-&gt;count_copy = 0;</span>
<span class="lineNum"> 1458 </span><span class="lineCov"> 575 : scan-&gt;count_restore = 0;</span>
<span class="lineNum"> 1459 </span><span class="lineCov"> 575 : scan-&gt;count_change = 0;</span>
<span class="lineNum"> 1460 </span><span class="lineCov"> 575 : scan-&gt;count_remove = 0;</span>
<span class="lineNum"> 1461 </span><span class="lineCov"> 575 : scan-&gt;count_insert = 0;</span>
<span class="lineNum"> 1462 </span><span class="lineCov"> 575 : tommy_list_init(&amp;scan-&gt;file_insert_list);</span>
<span class="lineNum"> 1463 </span><span class="lineCov"> 575 : tommy_list_init(&amp;scan-&gt;link_insert_list);</span>
<span class="lineNum"> 1464 </span><span class="lineCov"> 575 : tommy_list_init(&amp;scan-&gt;dir_insert_list);</span>
<span class="lineNum"> 1465 </span> :
<span class="lineNum"> 1466 </span><span class="lineCov"> 575 : tommy_list_insert_tail(&amp;scanlist, &amp;scan-&gt;node, scan);</span>
<span class="lineNum"> 1467 </span> :
<span class="lineNum"> 1468 </span><span class="lineCov"> 575 : if (!is_diff)</span>
<span class="lineNum"> 1469 </span><span class="lineCov"> 527 : msg_progress(&quot;Scanning disk %s...\n&quot;, disk-&gt;name);</span>
<span class="lineNum"> 1470 </span> :
<span class="lineNum"> 1471 </span> : /* check if the disk supports persistent inodes */
<span class="lineNum"> 1472 </span><span class="lineCov"> 575 : ret = fsinfo(disk-&gt;dir, &amp;has_persistent_inode, 0, 0);</span>
<span class="lineNum"> 1473 </span><span class="lineCov"> 575 : if (ret &lt; 0) {</span>
<span class="lineNum"> 1474 </span> : /* LCOV_EXCL_START */
<span class="lineNum"> 1475 </span> : log_fatal(&quot;Error accessing disk '%s' to get file-system info. %s.\n&quot;, disk-&gt;dir, strerror(errno));
<span class="lineNum"> 1476 </span> : exit(EXIT_FAILURE);
<span class="lineNum"> 1477 </span> : /* LCOV_EXCL_STOP */
<span class="lineNum"> 1478 </span> : }
<span class="lineNum"> 1479 </span><span class="lineCov"> 575 : if (!has_persistent_inode) {</span>
<span class="lineNum"> 1480 </span><span class="lineNoCov"> 0 : disk-&gt;has_volatile_inodes = 1;</span>
<span class="lineNum"> 1481 </span> : }
<span class="lineNum"> 1482 </span> :
<span class="lineNum"> 1483 </span> : /* if inodes or UUID are not persistent/changed/unsupported */
<span class="lineNum"> 1484 </span><span class="lineCov"> 575 : if (disk-&gt;has_volatile_inodes || disk-&gt;has_different_uuid || disk-&gt;has_unsupported_uuid) {</span>
<span class="lineNum"> 1485 </span> : /* remove all the inodes from the inode collection */
<span class="lineNum"> 1486 </span> : /* if they are not persistent, all of them could be changed now */
<span class="lineNum"> 1487 </span> : /* and we don't want to find false matching ones */
<span class="lineNum"> 1488 </span> : /* see scan_file() for more details */
<span class="lineNum"> 1489 </span><span class="lineCov"> 94 : node = disk-&gt;filelist;</span>
<span class="lineNum"> 1490 </span><span class="lineCov"> 202 : while (node) {</span>
<span class="lineNum"> 1491 </span><span class="lineCov"> 14 : struct snapraid_file* file = node-&gt;data;</span>
<span class="lineNum"> 1492 </span> :
<span class="lineNum"> 1493 </span><span class="lineCov"> 14 : node = node-&gt;next;</span>
<span class="lineNum"> 1494 </span> :
<span class="lineNum"> 1495 </span> : /* remove from the inode set */
<span class="lineNum"> 1496 </span><span class="lineCov"> 14 : tommy_hashdyn_remove_existing(&amp;disk-&gt;inodeset, &amp;file-&gt;nodeset);</span>
<span class="lineNum"> 1497 </span> :
<span class="lineNum"> 1498 </span> : /* clear the inode */
<span class="lineNum"> 1499 </span><span class="lineCov"> 14 : file-&gt;inode = 0;</span>
<span class="lineNum"> 1500 </span> :
<span class="lineNum"> 1501 </span> : /* mark as missing inode */
<span class="lineNum"> 1502 </span><span class="lineCov"> 14 : file_flag_set(file, FILE_IS_WITHOUT_INODE);</span>
<span class="lineNum"> 1503 </span> : }
<span class="lineNum"> 1504 </span> : }
<span class="lineNum"> 1505 </span> :
<span class="lineNum"> 1506 </span><span class="lineCov"> 575 : scan_dir(scan, 0, is_diff, disk-&gt;dir, &quot;&quot;);</span>
<span class="lineNum"> 1507 </span> : }
<span class="lineNum"> 1508 </span> :
<span class="lineNum"> 1509 </span> : /* we split the search in two phases because to detect files */
<span class="lineNum"> 1510 </span> : /* moved from one disk to another we have to start deletion */
<span class="lineNum"> 1511 </span> : /* only when all disks have all the new files found */
<span class="lineNum"> 1512 </span> :
<span class="lineNum"> 1513 </span> : /* now process all the new and deleted files */
<span class="lineNum"> 1514 </span><span class="lineCov"> 671 : for (i = scanlist; i != 0; i = i-&gt;next) {</span>
<span class="lineNum"> 1515 </span><span class="lineCov"> 575 : struct snapraid_scan* scan = i-&gt;data;</span>
<span class="lineNum"> 1516 </span><span class="lineCov"> 575 : struct snapraid_disk* disk = scan-&gt;disk;</span>
<span class="lineNum"> 1517 </span> : tommy_node* node;
<span class="lineNum"> 1518 </span> : unsigned phy_count;
<span class="lineNum"> 1519 </span> : unsigned phy_dup;
<span class="lineNum"> 1520 </span> : uint64_t phy_last;
<span class="lineNum"> 1521 </span> : struct snapraid_file* phy_file_last;
<span class="lineNum"> 1522 </span> :
<span class="lineNum"> 1523 </span> : /* check for removed files */
<span class="lineNum"> 1524 </span><span class="lineCov"> 575 : node = disk-&gt;filelist;</span>
<span class="lineNum"> 1525 </span><span class="lineCov"> 1033660 : while (node) {</span>
<span class="lineNum"> 1526 </span><span class="lineCov"> 1032510 : struct snapraid_file* file = node-&gt;data;</span>
<span class="lineNum"> 1527 </span> :
<span class="lineNum"> 1528 </span> : /* next node */
<span class="lineNum"> 1529 </span><span class="lineCov"> 1032510 : node = node-&gt;next;</span>
<span class="lineNum"> 1530 </span> :
<span class="lineNum"> 1531 </span> : /* remove if not present */
<span class="lineNum"> 1532 </span><span class="lineCov"> 1032510 : if (!file_flag_has(file, FILE_IS_PRESENT)) {</span>
<span class="lineNum"> 1533 </span><span class="lineCov"> 29647 : ++scan-&gt;count_remove;</span>
<span class="lineNum"> 1534 </span> :
<span class="lineNum"> 1535 </span><span class="lineCov"> 29647 : log_tag(&quot;scan:remove:%s:%s\n&quot;, disk-&gt;name, esc_tag(file-&gt;sub, esc_buffer));</span>
<span class="lineNum"> 1536 </span><span class="lineCov"> 29647 : if (is_diff) {</span>
<span class="lineNum"> 1537 </span><span class="lineCov"> 97 : printf(&quot;remove %s\n&quot;, fmt_term(disk, file-&gt;sub, esc_buffer));</span>
<span class="lineNum"> 1538 </span> : }
<span class="lineNum"> 1539 </span> :
<span class="lineNum"> 1540 </span><span class="lineCov"> 29647 : scan_file_remove(scan, file);</span>
<span class="lineNum"> 1541 </span> : }
<span class="lineNum"> 1542 </span> : }
<span class="lineNum"> 1543 </span> :
<span class="lineNum"> 1544 </span> : /* check for removed links */
<span class="lineNum"> 1545 </span><span class="lineCov"> 575 : node = disk-&gt;linklist;</span>
<span class="lineNum"> 1546 </span><span class="lineCov"> 35833 : while (node) {</span>
<span class="lineNum"> 1547 </span><span class="lineCov"> 34683 : struct snapraid_link* slink = node-&gt;data;</span>
<span class="lineNum"> 1548 </span> :
<span class="lineNum"> 1549 </span> : /* next node */
<span class="lineNum"> 1550 </span><span class="lineCov"> 34683 : node = node-&gt;next;</span>
<span class="lineNum"> 1551 </span> :
<span class="lineNum"> 1552 </span> : /* remove if not present */
<span class="lineNum"> 1553 </span><span class="lineCov"> 34683 : if (!link_flag_has(slink, FILE_IS_PRESENT)) {</span>
<span class="lineNum"> 1554 </span><span class="lineCov"> 956 : ++scan-&gt;count_remove;</span>
<span class="lineNum"> 1555 </span> :
<span class="lineNum"> 1556 </span><span class="lineCov"> 956 : log_tag(&quot;scan:remove:%s:%s\n&quot;, disk-&gt;name, esc_tag(slink-&gt;sub, esc_buffer));</span>
<span class="lineNum"> 1557 </span><span class="lineCov"> 956 : if (is_diff) {</span>
<span class="lineNum"> 1558 </span><span class="lineCov"> 10 : printf(&quot;remove %s\n&quot;, fmt_term(disk, slink-&gt;sub, esc_buffer));</span>
<span class="lineNum"> 1559 </span> : }
<span class="lineNum"> 1560 </span> :
<span class="lineNum"> 1561 </span><span class="lineCov"> 956 : scan_link_remove(scan, slink);</span>
<span class="lineNum"> 1562 </span> : }
<span class="lineNum"> 1563 </span> : }
<span class="lineNum"> 1564 </span> :
<span class="lineNum"> 1565 </span> : /* check for removed dirs */
<span class="lineNum"> 1566 </span><span class="lineCov"> 575 : node = disk-&gt;dirlist;</span>
<span class="lineNum"> 1567 </span><span class="lineCov"> 1401 : while (node) {</span>
<span class="lineNum"> 1568 </span><span class="lineCov"> 251 : struct snapraid_dir* dir = node-&gt;data;</span>
<span class="lineNum"> 1569 </span> :
<span class="lineNum"> 1570 </span> : /* next node */
<span class="lineNum"> 1571 </span><span class="lineCov"> 251 : node = node-&gt;next;</span>
<span class="lineNum"> 1572 </span> :
<span class="lineNum"> 1573 </span> : /* remove if not present */
<span class="lineNum"> 1574 </span><span class="lineCov"> 251 : if (!dir_flag_has(dir, FILE_IS_PRESENT)) {</span>
<span class="lineNum"> 1575 </span><span class="lineCov"> 2 : scan_emptydir_remove(scan, dir);</span>
<span class="lineNum"> 1576 </span> : }
<span class="lineNum"> 1577 </span> : }
<span class="lineNum"> 1578 </span> :
<span class="lineNum"> 1579 </span> : /* sort the files before inserting them */
<span class="lineNum"> 1580 </span> : /* we use a stable sort to ensure that if the reported physical offset/inode */
<span class="lineNum"> 1581 </span> : /* are always 0, we keep at least the directory order */
<span class="lineNum"> 1582 </span><span class="lineCov"> 575 : switch (state-&gt;opt.force_order) {</span>
<span class="lineNum"> 1583 </span> : case SORT_PHYSICAL :
<span class="lineNum"> 1584 </span><span class="lineCov"> 12 : tommy_list_sort(&amp;scan-&gt;file_insert_list, file_physical_compare);</span>
<span class="lineNum"> 1585 </span><span class="lineCov"> 12 : break;</span>
<span class="lineNum"> 1586 </span> : case SORT_INODE :
<span class="lineNum"> 1587 </span><span class="lineNoCov"> 0 : tommy_list_sort(&amp;scan-&gt;file_insert_list, file_inode_compare);</span>
<span class="lineNum"> 1588 </span><span class="lineNoCov"> 0 : break;</span>
<span class="lineNum"> 1589 </span> : case SORT_ALPHA :
<span class="lineNum"> 1590 </span><span class="lineCov"> 563 : tommy_list_sort(&amp;scan-&gt;file_insert_list, file_path_compare);</span>
<span class="lineNum"> 1591 </span><span class="lineCov"> 563 : break;</span>
<span class="lineNum"> 1592 </span> : case SORT_DIR :
<span class="lineNum"> 1593 </span> : /* already in order */
<span class="lineNum"> 1594 </span><span class="lineNoCov"> 0 : break;</span>
<span class="lineNum"> 1595 </span> : }
<span class="lineNum"> 1596 </span> :
<span class="lineNum"> 1597 </span> : /* insert all the new files, we insert them only after the deletion */
<span class="lineNum"> 1598 </span> : /* to reuse the just freed space */
<span class="lineNum"> 1599 </span> : /* also check if the physical offset reported are fakes or not */
<span class="lineNum"> 1600 </span><span class="lineCov"> 575 : node = scan-&gt;file_insert_list;</span>
<span class="lineNum"> 1601 </span><span class="lineCov"> 575 : phy_count = 0;</span>
<span class="lineNum"> 1602 </span><span class="lineCov"> 575 : phy_dup = 0;</span>
<span class="lineNum"> 1603 </span><span class="lineCov"> 575 : phy_last = FILEPHY_UNREAD_OFFSET;</span>
<span class="lineNum"> 1604 </span><span class="lineCov"> 575 : phy_file_last = 0;</span>
<span class="lineNum"> 1605 </span><span class="lineCov"> 103031 : while (node) {</span>
<span class="lineNum"> 1606 </span><span class="lineCov"> 101881 : struct snapraid_file* file = node-&gt;data;</span>
<span class="lineNum"> 1607 </span> :
<span class="lineNum"> 1608 </span> : /* if the file is not empty, count duplicate physical offsets */
<span class="lineNum"> 1609 </span><span class="lineCov"> 101881 : if (state-&gt;opt.force_order == SORT_PHYSICAL &amp;&amp; file-&gt;size != 0) {</span>
<span class="lineNum"> 1610 </span><span class="lineCov"> 11418 : if (phy_file_last != 0 &amp;&amp; file-&gt;physical == phy_last</span>
<span class="lineNum"> 1611 </span> : /* files without offset are expected to have duplicates */
<span class="lineNum"> 1612 </span><span class="lineNoCov"> 0 : &amp;&amp; phy_last != FILEPHY_WITHOUT_OFFSET</span>
<span class="lineNum"> 1613 </span> : ) {
<span class="lineNum"> 1614 </span> : /* if verbose, print the list of duplicates real offsets */
<span class="lineNum"> 1615 </span> : /* other cases are for offsets not supported, so we don't need to report them file by file */
<span class="lineNum"> 1616 </span><span class="lineNoCov"> 0 : if (phy_last &gt;= FILEPHY_REAL_OFFSET) {</span>
<span class="lineNum"> 1617 </span><span class="lineNoCov"> 0 : log_fatal(&quot;WARNING! Files '%s%s' and '%s%s' have the same physical offset %&quot; PRId64 &quot;.\n&quot;, disk-&gt;dir, phy_file_last-&gt;sub, disk-&gt;dir, file-&gt;sub, phy_last);</span>
<span class="lineNum"> 1618 </span> : }
<span class="lineNum"> 1619 </span><span class="lineNoCov"> 0 : ++phy_dup;</span>
<span class="lineNum"> 1620 </span> : }
<span class="lineNum"> 1621 </span><span class="lineCov"> 11418 : phy_file_last = file;</span>
<span class="lineNum"> 1622 </span><span class="lineCov"> 11418 : phy_last = file-&gt;physical;</span>
<span class="lineNum"> 1623 </span><span class="lineCov"> 11418 : ++phy_count;</span>
<span class="lineNum"> 1624 </span> : }
<span class="lineNum"> 1625 </span> :
<span class="lineNum"> 1626 </span> : /* next node */
<span class="lineNum"> 1627 </span><span class="lineCov"> 101881 : node = node-&gt;next;</span>
<span class="lineNum"> 1628 </span> :
<span class="lineNum"> 1629 </span> : /* insert in the parity */
<span class="lineNum"> 1630 </span><span class="lineCov"> 101881 : scan_file_allocate(scan, file);</span>
<span class="lineNum"> 1631 </span> : }
<span class="lineNum"> 1632 </span> :
<span class="lineNum"> 1633 </span> : /* mark the disk without reliable physical offset if it has duplicates */
<span class="lineNum"> 1634 </span> : /* here it should never happen because we already sorted out hardlinks */
<span class="lineNum"> 1635 </span><span class="lineCov"> 575 : if (state-&gt;opt.force_order == SORT_PHYSICAL &amp;&amp; phy_dup &gt; 0) {</span>
<span class="lineNum"> 1636 </span><span class="lineNoCov"> 0 : disk-&gt;has_unreliable_physical = 1;</span>
<span class="lineNum"> 1637 </span> : }
<span class="lineNum"> 1638 </span> :
<span class="lineNum"> 1639 </span> : /* insert all the new links */
<span class="lineNum"> 1640 </span><span class="lineCov"> 575 : node = scan-&gt;link_insert_list;</span>
<span class="lineNum"> 1641 </span><span class="lineCov"> 3607 : while (node) {</span>
<span class="lineNum"> 1642 </span><span class="lineCov"> 2457 : struct snapraid_link* slink = node-&gt;data;</span>
<span class="lineNum"> 1643 </span> :
<span class="lineNum"> 1644 </span> : /* next node */
<span class="lineNum"> 1645 </span><span class="lineCov"> 2457 : node = node-&gt;next;</span>
<span class="lineNum"> 1646 </span> :
<span class="lineNum"> 1647 </span> : /* insert it */
<span class="lineNum"> 1648 </span><span class="lineCov"> 2457 : scan_link_insert(scan, slink);</span>
<span class="lineNum"> 1649 </span> : }
<span class="lineNum"> 1650 </span> :
<span class="lineNum"> 1651 </span> : /* insert all the new dirs */
<span class="lineNum"> 1652 </span><span class="lineCov"> 575 : node = scan-&gt;dir_insert_list;</span>
<span class="lineNum"> 1653 </span><span class="lineCov"> 1160 : while (node) {</span>
<span class="lineNum"> 1654 </span><span class="lineCov"> 10 : struct snapraid_dir* dir = node-&gt;data;</span>
<span class="lineNum"> 1655 </span> :
<span class="lineNum"> 1656 </span> : /* next node */
<span class="lineNum"> 1657 </span><span class="lineCov"> 10 : node = node-&gt;next;</span>
<span class="lineNum"> 1658 </span> :
<span class="lineNum"> 1659 </span> : /* insert it */
<span class="lineNum"> 1660 </span><span class="lineCov"> 10 : scan_emptydir_insert(scan, dir);</span>
<span class="lineNum"> 1661 </span> : }
<span class="lineNum"> 1662 </span> : }
<span class="lineNum"> 1663 </span> :
<span class="lineNum"> 1664 </span> : /* check for disks where all the previously existing files where removed */
<span class="lineNum"> 1665 </span><span class="lineCov"> 96 : if (!state-&gt;opt.force_empty) {</span>
<span class="lineNum"> 1666 </span><span class="lineCov"> 90 : int all_missing = 0;</span>
<span class="lineNum"> 1667 </span><span class="lineCov"> 90 : int all_rewritten = 0;</span>
<span class="lineNum"> 1668 </span><span class="lineCov"> 90 : done = 0;</span>
<span class="lineNum"> 1669 </span><span class="lineCov"> 629 : for (i = state-&gt;disklist, j = scanlist; i != 0; i = i-&gt;next, j = j-&gt;next) {</span>
<span class="lineNum"> 1670 </span><span class="lineCov"> 539 : struct snapraid_disk* disk = i-&gt;data;</span>
<span class="lineNum"> 1671 </span><span class="lineCov"> 539 : struct snapraid_scan* scan = j-&gt;data;</span>
<span class="lineNum"> 1672 </span> :
<span class="lineNum"> 1673 </span><span class="lineCov"> 539 : if (scan-&gt;count_equal == 0</span>
<span class="lineNum"> 1674 </span><span class="lineCov"> 74 : &amp;&amp; scan-&gt;count_move == 0</span>
<span class="lineNum"> 1675 </span><span class="lineCov"> 74 : &amp;&amp; scan-&gt;count_restore == 0</span>
<span class="lineNum"> 1676 </span><span class="lineCov"> 74 : &amp;&amp; (scan-&gt;count_remove != 0 || scan-&gt;count_change != 0)</span>
<span class="lineNum"> 1677 </span> : ) {
<span class="lineNum"> 1678 </span><span class="lineCov"> 1 : if (!done) {</span>
<span class="lineNum"> 1679 </span><span class="lineCov"> 1 : done = 1;</span>
<span class="lineNum"> 1680 </span><span class="lineCov"> 1 : log_fatal(&quot;WARNING! All the files previously present in disk '%s' at dir '%s'&quot;, disk-&gt;name, disk-&gt;dir);</span>
<span class="lineNum"> 1681 </span> : } else {
<span class="lineNum"> 1682 </span><span class="lineNoCov"> 0 : log_fatal(&quot;, disk '%s' at dir '%s'&quot;, disk-&gt;name, disk-&gt;dir);</span>
<span class="lineNum"> 1683 </span> : }
<span class="lineNum"> 1684 </span> :
<span class="lineNum"> 1685 </span> : /* detect the special condition of all files missing */
<span class="lineNum"> 1686 </span><span class="lineCov"> 1 : if (scan-&gt;count_change == 0)</span>
<span class="lineNum"> 1687 </span><span class="lineCov"> 1 : all_missing = 1;</span>
<span class="lineNum"> 1688 </span> :
<span class="lineNum"> 1689 </span> : /* detect the special condition of all files rewritten */
<span class="lineNum"> 1690 </span><span class="lineCov"> 1 : if (scan-&gt;count_remove == 0)</span>
<span class="lineNum"> 1691 </span><span class="lineNoCov"> 0 : all_rewritten = 1;</span>
<span class="lineNum"> 1692 </span> : }
<span class="lineNum"> 1693 </span> : }
<span class="lineNum"> 1694 </span><span class="lineCov"> 90 : if (done) {</span>
<span class="lineNum"> 1695 </span><span class="lineCov"> 1 : log_fatal(&quot;\nare now missing or rewritten!\n&quot;);</span>
<span class="lineNum"> 1696 </span><span class="lineCov"> 1 : if (all_rewritten) {</span>
<span class="lineNum"> 1697 </span><span class="lineNoCov"> 0 : log_fatal(&quot;This could happen when restoring a disk with a backup\n&quot;);</span>
<span class="lineNum"> 1698 </span><span class="lineNoCov"> 0 : log_fatal(&quot;program that is not setting correctly the timestamps.\n&quot;);</span>
<span class="lineNum"> 1699 </span> : }
<span class="lineNum"> 1700 </span><span class="lineCov"> 1 : if (all_missing) {</span>
<span class="lineNum"> 1701 </span><span class="lineCov"> 1 : log_fatal(&quot;This could happen when some disks are not mounted\n&quot;);</span>
<span class="lineNum"> 1702 </span><span class="lineCov"> 1 : log_fatal(&quot;in the expected directory.\n&quot;);</span>
<span class="lineNum"> 1703 </span> : }
<span class="lineNum"> 1704 </span><span class="lineCov"> 1 : if (!is_diff) {</span>
<span class="lineNum"> 1705 </span><span class="lineCov"> 1 : log_fatal(&quot;If you want to '%s' anyway, use 'snapraid --force-empty %s'.\n&quot;, state-&gt;command, state-&gt;command);</span>
<span class="lineNum"> 1706 </span><span class="lineCov"> 1 : exit(EXIT_FAILURE);</span>
<span class="lineNum"> 1707 </span> : }
<span class="lineNum"> 1708 </span> : }
<span class="lineNum"> 1709 </span> : }
<span class="lineNum"> 1710 </span> :
<span class="lineNum"> 1711 </span> : /* check for disks without the physical offset support */
<span class="lineNum"> 1712 </span><span class="lineCov"> 95 : if (state-&gt;opt.force_order == SORT_PHYSICAL) {</span>
<span class="lineNum"> 1713 </span><span class="lineCov"> 2 : done = 0;</span>
<span class="lineNum"> 1714 </span><span class="lineCov"> 14 : for (i = state-&gt;disklist; i != 0; i = i-&gt;next) {</span>
<span class="lineNum"> 1715 </span><span class="lineCov"> 12 : struct snapraid_disk* disk = i-&gt;data;</span>
<span class="lineNum"> 1716 </span> :
<span class="lineNum"> 1717 </span><span class="lineCov"> 12 : if (disk-&gt;has_unreliable_physical) {</span>
<span class="lineNum"> 1718 </span><span class="lineNoCov"> 0 : if (!done) {</span>
<span class="lineNum"> 1719 </span><span class="lineNoCov"> 0 : done = 1;</span>
<span class="lineNum"> 1720 </span><span class="lineNoCov"> 0 : log_fatal(&quot;WARNING! Physical offsets not supported for disk '%s'&quot;, disk-&gt;name);</span>
<span class="lineNum"> 1721 </span> : } else {
<span class="lineNum"> 1722 </span><span class="lineNoCov"> 0 : log_fatal(&quot;, '%s'&quot;, disk-&gt;name);</span>
<span class="lineNum"> 1723 </span> : }
<span class="lineNum"> 1724 </span> : }
<span class="lineNum"> 1725 </span> : }
<span class="lineNum"> 1726 </span><span class="lineCov"> 2 : if (done) {</span>
<span class="lineNum"> 1727 </span><span class="lineNoCov"> 0 : log_fatal(&quot;. Files order won't be optimal.\n&quot;);</span>
<span class="lineNum"> 1728 </span> : }
<span class="lineNum"> 1729 </span> : }
<span class="lineNum"> 1730 </span> :
<span class="lineNum"> 1731 </span> : /* check for disks without persistent inodes */
<span class="lineNum"> 1732 </span><span class="lineCov"> 95 : done = 0;</span>
<span class="lineNum"> 1733 </span><span class="lineCov"> 664 : for (i = state-&gt;disklist; i != 0; i = i-&gt;next) {</span>
<span class="lineNum"> 1734 </span><span class="lineCov"> 569 : struct snapraid_disk* disk = i-&gt;data;</span>
<span class="lineNum"> 1735 </span> :
<span class="lineNum"> 1736 </span><span class="lineCov"> 569 : if (disk-&gt;has_volatile_inodes) {</span>
<span class="lineNum"> 1737 </span><span class="lineNoCov"> 0 : if (!done) {</span>
<span class="lineNum"> 1738 </span><span class="lineNoCov"> 0 : done = 1;</span>
<span class="lineNum"> 1739 </span><span class="lineNoCov"> 0 : log_fatal(&quot;WARNING! Inodes are not persistent for disks: '%s'&quot;, disk-&gt;name);</span>
<span class="lineNum"> 1740 </span> : } else {
<span class="lineNum"> 1741 </span><span class="lineNoCov"> 0 : log_fatal(&quot;, '%s'&quot;, disk-&gt;name);</span>
<span class="lineNum"> 1742 </span> : }
<span class="lineNum"> 1743 </span> : }
<span class="lineNum"> 1744 </span> : }
<span class="lineNum"> 1745 </span><span class="lineCov"> 95 : if (done) {</span>
<span class="lineNum"> 1746 </span><span class="lineNoCov"> 0 : log_fatal(&quot;. Not using inodes to detect move operations.\n&quot;);</span>
<span class="lineNum"> 1747 </span> : }
<span class="lineNum"> 1748 </span> :
<span class="lineNum"> 1749 </span> : /* check for disks with changed UUID */
<span class="lineNum"> 1750 </span><span class="lineCov"> 95 : done = 0;</span>
<span class="lineNum"> 1751 </span><span class="lineCov"> 664 : for (i = state-&gt;disklist; i != 0; i = i-&gt;next) {</span>
<span class="lineNum"> 1752 </span><span class="lineCov"> 569 : struct snapraid_disk* disk = i-&gt;data;</span>
<span class="lineNum"> 1753 </span> :
<span class="lineNum"> 1754 </span> : /* don't print the message if the UUID changed because before */
<span class="lineNum"> 1755 </span> : /* it was no set. */
<span class="lineNum"> 1756 </span> : /* this is the normal condition for an empty disk because it */
<span class="lineNum"> 1757 </span> : /* isn't stored */
<span class="lineNum"> 1758 </span><span class="lineCov"> 569 : if (disk-&gt;has_different_uuid &amp;&amp; !disk-&gt;had_empty_uuid) {</span>
<span class="lineNum"> 1759 </span><span class="lineCov"> 4 : if (!done) {</span>
<span class="lineNum"> 1760 </span><span class="lineCov"> 2 : done = 1;</span>
<span class="lineNum"> 1761 </span><span class="lineCov"> 2 : log_fatal(&quot;WARNING! UUID is changed for disks: '%s'&quot;, disk-&gt;name);</span>
<span class="lineNum"> 1762 </span> : } else {
<span class="lineNum"> 1763 </span><span class="lineCov"> 2 : log_fatal(&quot;, '%s'&quot;, disk-&gt;name);</span>
<span class="lineNum"> 1764 </span> : }
<span class="lineNum"> 1765 </span> : }
<span class="lineNum"> 1766 </span> : }
<span class="lineNum"> 1767 </span><span class="lineCov"> 95 : if (done) {</span>
<span class="lineNum"> 1768 </span><span class="lineCov"> 2 : log_fatal(&quot;. Not using inodes to detect move operations.\n&quot;);</span>
<span class="lineNum"> 1769 </span> : }
<span class="lineNum"> 1770 </span> :
<span class="lineNum"> 1771 </span> : /* check for disks with unsupported UUID */
<span class="lineNum"> 1772 </span><span class="lineCov"> 95 : done = 0;</span>
<span class="lineNum"> 1773 </span><span class="lineCov"> 664 : for (i = state-&gt;disklist; i != 0; i = i-&gt;next) {</span>
<span class="lineNum"> 1774 </span><span class="lineCov"> 569 : struct snapraid_disk* disk = i-&gt;data;</span>
<span class="lineNum"> 1775 </span> :
<span class="lineNum"> 1776 </span><span class="lineCov"> 569 : if (disk-&gt;has_unsupported_uuid) {</span>
<span class="lineNum"> 1777 </span><span class="lineNoCov"> 0 : if (!done) {</span>
<span class="lineNum"> 1778 </span><span class="lineNoCov"> 0 : done = 1;</span>
<span class="lineNum"> 1779 </span><span class="lineNoCov"> 0 : log_fatal(&quot;WARNING! UUID is unsupported for disks: '%s'&quot;, disk-&gt;name);</span>
<span class="lineNum"> 1780 </span> : } else {
<span class="lineNum"> 1781 </span><span class="lineNoCov"> 0 : log_fatal(&quot;, '%s'&quot;, disk-&gt;name);</span>
<span class="lineNum"> 1782 </span> : }
<span class="lineNum"> 1783 </span> : }
<span class="lineNum"> 1784 </span> : }
<span class="lineNum"> 1785 </span><span class="lineCov"> 95 : if (done) {</span>
<span class="lineNum"> 1786 </span><span class="lineNoCov"> 0 : log_fatal(&quot;. Not using inodes to detect move operations.\n&quot;);</span>
<span class="lineNum"> 1787 </span> : #if defined(_linux) &amp;&amp; !HAVE_BLKID
<span class="lineNum"> 1788 </span> : log_fatal(&quot;The 'blkid' library is not linked in SnapRAID!\n&quot;);
<span class="lineNum"> 1789 </span> : log_fatal(&quot;Try rebuilding it after installing the libblkid-dev or libblkid-devel package.\n&quot;);
<span class="lineNum"> 1790 </span> : #endif
<span class="lineNum"> 1791 </span> : }
<span class="lineNum"> 1792 </span> :
<span class="lineNum"> 1793 </span><span class="lineCov"> 95 : total.count_equal = 0;</span>
<span class="lineNum"> 1794 </span><span class="lineCov"> 95 : total.count_move = 0;</span>
<span class="lineNum"> 1795 </span><span class="lineCov"> 95 : total.count_copy = 0;</span>
<span class="lineNum"> 1796 </span><span class="lineCov"> 95 : total.count_restore = 0;</span>
<span class="lineNum"> 1797 </span><span class="lineCov"> 95 : total.count_change = 0;</span>
<span class="lineNum"> 1798 </span><span class="lineCov"> 95 : total.count_remove = 0;</span>
<span class="lineNum"> 1799 </span><span class="lineCov"> 95 : total.count_insert = 0;</span>
<span class="lineNum"> 1800 </span> :
<span class="lineNum"> 1801 </span><span class="lineCov"> 664 : for (i = scanlist; i != 0; i = i-&gt;next) {</span>
<span class="lineNum"> 1802 </span><span class="lineCov"> 569 : struct snapraid_scan* scan = i-&gt;data;</span>
<span class="lineNum"> 1803 </span><span class="lineCov"> 569 : total.count_equal += scan-&gt;count_equal;</span>
<span class="lineNum"> 1804 </span><span class="lineCov"> 569 : total.count_move += scan-&gt;count_move;</span>
<span class="lineNum"> 1805 </span><span class="lineCov"> 569 : total.count_copy += scan-&gt;count_copy;</span>
<span class="lineNum"> 1806 </span><span class="lineCov"> 569 : total.count_restore += scan-&gt;count_restore;</span>
<span class="lineNum"> 1807 </span><span class="lineCov"> 569 : total.count_change += scan-&gt;count_change;</span>
<span class="lineNum"> 1808 </span><span class="lineCov"> 569 : total.count_remove += scan-&gt;count_remove;</span>
<span class="lineNum"> 1809 </span><span class="lineCov"> 569 : total.count_insert += scan-&gt;count_insert;</span>
<span class="lineNum"> 1810 </span> : }
<span class="lineNum"> 1811 </span> :
<span class="lineNum"> 1812 </span><span class="lineCov"> 95 : if (is_diff) {</span>
<span class="lineNum"> 1813 </span><span class="lineCov"> 8 : msg_status(&quot;\n&quot;);</span>
<span class="lineNum"> 1814 </span><span class="lineCov"> 8 : msg = msg_status;</span>
<span class="lineNum"> 1815 </span> : } else {
<span class="lineNum"> 1816 </span><span class="lineCov"> 87 : msg = msg_verbose;</span>
<span class="lineNum"> 1817 </span> : }
<span class="lineNum"> 1818 </span> :
<span class="lineNum"> 1819 </span><span class="lineCov"> 95 : msg(&quot;%8u equal\n&quot;, total.count_equal);</span>
<span class="lineNum"> 1820 </span><span class="lineCov"> 95 : msg(&quot;%8u added\n&quot;, total.count_insert);</span>
<span class="lineNum"> 1821 </span><span class="lineCov"> 95 : msg(&quot;%8u removed\n&quot;, total.count_remove);</span>
<span class="lineNum"> 1822 </span><span class="lineCov"> 95 : msg(&quot;%8u updated\n&quot;, total.count_change);</span>
<span class="lineNum"> 1823 </span><span class="lineCov"> 95 : msg(&quot;%8u moved\n&quot;, total.count_move);</span>
<span class="lineNum"> 1824 </span><span class="lineCov"> 95 : msg(&quot;%8u copied\n&quot;, total.count_copy);</span>
<span class="lineNum"> 1825 </span><span class="lineCov"> 95 : msg(&quot;%8u restored\n&quot;, total.count_restore);</span>
<span class="lineNum"> 1826 </span> :
<span class="lineNum"> 1827 </span><span class="lineCov"> 95 : log_tag(&quot;summary:equal:%u\n&quot;, total.count_equal);</span>
<span class="lineNum"> 1828 </span><span class="lineCov"> 95 : log_tag(&quot;summary:added:%u\n&quot;, total.count_insert);</span>
<span class="lineNum"> 1829 </span><span class="lineCov"> 95 : log_tag(&quot;summary:removed:%u\n&quot;, total.count_remove);</span>
<span class="lineNum"> 1830 </span><span class="lineCov"> 95 : log_tag(&quot;summary:updated:%u\n&quot;, total.count_change);</span>
<span class="lineNum"> 1831 </span><span class="lineCov"> 95 : log_tag(&quot;summary:moved:%u\n&quot;, total.count_move);</span>
<span class="lineNum"> 1832 </span><span class="lineCov"> 95 : log_tag(&quot;summary:copied:%u\n&quot;, total.count_copy);</span>
<span class="lineNum"> 1833 </span><span class="lineCov"> 95 : log_tag(&quot;summary:restored:%u\n&quot;, total.count_restore);</span>
<span class="lineNum"> 1834 </span> :
<span class="lineNum"> 1835 </span><span class="lineCov"> 284 : no_difference = !total.count_move &amp;&amp; !total.count_copy &amp;&amp; !total.count_restore</span>
<span class="lineNum"> 1836 </span><span class="lineCov"> 159 : &amp;&amp; !total.count_change &amp;&amp; !total.count_remove &amp;&amp; !total.count_insert;</span>
<span class="lineNum"> 1837 </span> :
<span class="lineNum"> 1838 </span><span class="lineCov"> 95 : if (is_diff) {</span>
<span class="lineNum"> 1839 </span><span class="lineCov"> 8 : if (no_difference) {</span>
<span class="lineNum"> 1840 </span><span class="lineCov"> 2 : msg_status(&quot;No differences\n&quot;);</span>
<span class="lineNum"> 1841 </span> : } else {
<span class="lineNum"> 1842 </span><span class="lineCov"> 6 : msg_status(&quot;There are differences!\n&quot;);</span>
<span class="lineNum"> 1843 </span> : }
<span class="lineNum"> 1844 </span> : }
<span class="lineNum"> 1845 </span> :
<span class="lineNum"> 1846 </span><span class="lineCov"> 95 : if (no_difference) {</span>
<span class="lineNum"> 1847 </span><span class="lineCov"> 20 : log_tag(&quot;summary:exit:equal\n&quot;);</span>
<span class="lineNum"> 1848 </span> : } else {
<span class="lineNum"> 1849 </span><span class="lineCov"> 75 : log_tag(&quot;summary:exit:diff\n&quot;);</span>
<span class="lineNum"> 1850 </span> : }
<span class="lineNum"> 1851 </span><span class="lineCov"> 95 : log_flush();</span>
<span class="lineNum"> 1852 </span> :
<span class="lineNum"> 1853 </span><span class="lineCov"> 95 : tommy_list_foreach(&amp;scanlist, (tommy_foreach_func*)free);</span>
<span class="lineNum"> 1854 </span> :
<span class="lineNum"> 1855 </span> : /* check the file-system on all disks */
<span class="lineNum"> 1856 </span><span class="lineCov"> 95 : state_fscheck(state, &quot;after scan&quot;);</span>
<span class="lineNum"> 1857 </span> :
<span class="lineNum"> 1858 </span><span class="lineCov"> 95 : if (is_diff) {</span>
<span class="lineNum"> 1859 </span> : /* check for file difference */
<span class="lineNum"> 1860 </span><span class="lineCov"> 8 : if (!no_difference)</span>
<span class="lineNum"> 1861 </span><span class="lineCov"> 6 : return 1;</span>
<span class="lineNum"> 1862 </span> :
<span class="lineNum"> 1863 </span> : /* check also for incomplete &quot;sync&quot; */
<span class="lineNum"> 1864 </span><span class="lineCov"> 2 : if (parity_is_invalid(state))</span>
<span class="lineNum"> 1865 </span><span class="lineCov"> 1 : return 1;</span>
<span class="lineNum"> 1866 </span> : }
<span class="lineNum"> 1867 </span> :
<span class="lineNum"> 1868 </span><span class="lineCov"> 88 : return 0;</span>
<a name="1869"><span class="lineNum"> 1869 </span> : }</a>
<span class="lineNum"> 1870 </span> :
<span class="lineNum"> 1871 </span><span class="lineCov"> 8 : int state_diff(struct snapraid_state* state)</span>
<span class="lineNum"> 1872 </span> : {
<span class="lineNum"> 1873 </span><span class="lineCov"> 8 : return state_diffscan(state, 1);</span>
<a name="1874"><span class="lineNum"> 1874 </span> : }</a>
<span class="lineNum"> 1875 </span> :
<span class="lineNum"> 1876 </span><span class="lineCov"> 88 : void state_scan(struct snapraid_state* state)</span>
<span class="lineNum"> 1877 </span> : {
<span class="lineNum"> 1878 </span><span class="lineCov"> 88 : (void)state_diffscan(state, 0); /* ignore return value */</span>
<span class="lineNum"> 1879 </span><span class="lineCov"> 87 : }</span>
<span class="lineNum"> 1880 </span> :
</pre>
</td>
</tr>
</table>
<br>
<table width="100%" border=0 cellspacing=0 cellpadding=0>
<tr><td class="ruler"><img src="../glass.png" width=3 height=3 alt=""></td></tr>
<tr><td class="versionInfo">Generated by: <a href="http://ltp.sourceforge.net/coverage/lcov.php" target="_parent">LCOV version 1.10</a></td></tr>
</table>
<br>
</body>
</html>