LCOV - code coverage report
Current view: top level - cmdline - elem.h (source / functions) Hit Total Coverage
Test: lcov.info Lines: 129 133 97.0 %
Date: 2017-11-06 22:14:04 Functions: 41 41 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (C) 2011 Andrea Mazzoleni
       3             :  *
       4             :  * This program is free software: you can redistribute it and/or modify
       5             :  * it under the terms of the GNU General Public License as published by
       6             :  * the Free Software Foundation, either version 3 of the License, or
       7             :  * (at your option) any later version.
       8             :  *
       9             :  * This program is distributed in the hope that it will be useful,
      10             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             :  * GNU General Public License for more details.
      13             :  *
      14             :  * You should have received a copy of the GNU General Public License
      15             :  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
      16             :  */
      17             : 
      18             : #ifndef __ELEM_H
      19             : #define __ELEM_H
      20             : 
      21             : #include "util.h"
      22             : #include "support.h"
      23             : #include "tommyds/tommyhash.h"
      24             : #include "tommyds/tommylist.h"
      25             : #include "tommyds/tommytree.h"
      26             : #include "tommyds/tommyhashdyn.h"
      27             : #include "tommyds/tommyarray.h"
      28             : #include "tommyds/tommyarrayblkof.h"
      29             : 
      30             : /****************************************************************************/
      31             : /* snapraid */
      32             : 
      33             : /**
      34             :  * Number of measures of the operation progress.
      35             :  */
      36             : #define PROGRESS_MAX 100
      37             : 
      38             : /**
      39             :  * Max UUID length.
      40             :  */
      41             : #define UUID_MAX 128
      42             : 
      43             : /**
      44             :  * Invalid position.
      45             :  */
      46             : #define POS_NULL ((block_off_t)-1)
      47             : 
      48             : /**
      49             :  * Content file specification.
      50             :  */
      51             : struct snapraid_content {
      52             :         char content[PATH_MAX]; /**< Path of the content file. */
      53             :         uint64_t device; /**< Device identifier. */
      54             :         void* context; /**< Context used for multithread operations. */
      55             :         tommy_node node; /**< Next node in the list. */
      56             : };
      57             : 
      58             : /**
      59             :  * Filter for paths.
      60             :  */
      61             : struct snapraid_filter {
      62             :         char pattern[PATH_MAX]; /**< Filter pattern. */
      63             :         int is_disk; /**< If the pattern is a disk one. */
      64             :         int is_path; /**< If the pattern is only for the complete path. */
      65             :         int is_dir; /**< If the pattern is only for dir. */
      66             :         int direction; /**< If it's an inclusion (=1) or an exclusion (=-1). */
      67             :         tommy_node node; /**< Next node in the list. */
      68             : };
      69             : 
      70             : /**
      71             :  * Block pointer used to represent unused blocks.
      72             :  */
      73             : #define BLOCK_NULL 0
      74             : 
      75             : /**
      76             :  * This block is an empty one.
      77             :  * Note that an empty block is represent with ::BLOCK_NULL.
      78             :  */
      79             : #define BLOCK_STATE_EMPTY 0
      80             : 
      81             : /**
      82             :  * The block has both the hash and the parity computed.
      83             :  * This is the normal state of a saved block.
      84             :  *
      85             :  * The block hash field IS set.
      86             :  * The parity for this disk is updated.
      87             :  */
      88             : #define BLOCK_STATE_BLK 1
      89             : 
      90             : /**
      91             :  * The block is new and not yet hashed.
      92             :  * This happens when a new block overwrite a just removed block, or an empty space.
      93             :  *
      94             :  * The block hash field MAY be set and it represents the hash of the OLD data.
      95             :  * The hash may be also INVALID or ZERO.
      96             :  *
      97             :  * If the OLD block was empty, the hash is set to the special ZERO value.
      98             :  * If the OLD block was lost, the hash is set to the special INVALID value.
      99             :  *
     100             :  * The parity for this disk is not updated, but it contains the old data referenced by the hash.
     101             :  *
     102             :  * If the state is read from an incomplete sync, we don't really know if the hash is referring at the
     103             :  * data used to compute the parity, because the sync process was interrupted at an unknown point,
     104             :  * and the parity may or may not be updated.
     105             :  *
     106             :  * For this reason we clear all such hashes when reading the state from an incomplete sync before
     107             :  * starting a new sync, because sync is affected by such hashes, as sync updates the parity, only
     108             :  * if the new data read for CHG blocks has a mismatching hash.
     109             :  * Clearing is done setting the ::clear_past_hash flag before reading the state.
     110             :  * No clearing is done in other commands, as check and fix are instead able to work with unsynced
     111             :  * hashes, and scrub ignores CHG/DELETED blocks.
     112             :  */
     113             : #define BLOCK_STATE_CHG 2
     114             : 
     115             : /**
     116             :  * The block is new and hashed.
     117             :  * This happens when a new block overwrite a just removed block, or an empty space.
     118             :  *
     119             :  * Note that when the file copy heuristic is enabled, the REP blocks may be set
     120             :  * using this heuristic, meaning that the hash may be wrong.
     121             :  *
     122             :  * For this reason, when the ::force_nocopy flag is enabled in sync, we convert all the REP blocks
     123             :  * to CHG, invalidating the stored hash.
     124             :  * Clearing is done setting the ::clear_past_hash flag before reading the state.
     125             :  * No clearing is done in other commands, as they don't stop the process like in sync
     126             :  * when there is a false silent error.
     127             :  *
     128             :  * The block hash field IS set, and it represents the hash of the new data.
     129             :  * The parity for this disk is not updated.
     130             :  */
     131             : #define BLOCK_STATE_REP 3
     132             : 
     133             : /**
     134             :  * This block is a deleted one.
     135             :  * This happens when a file is deleted.
     136             :  *
     137             :  * The block hash field IS set, and it represents the hash of the previous data,
     138             :  * but only if it's different by all 0.
     139             :  * The parity for this disk is not updated, but it contains the old data referenced by the hash.
     140             :  *
     141             :  * If the state is read from an incomplete sync, we don't really know if the hash is referring at the
     142             :  * data used to compute the parity, because the sync process was interrupted at an unknown point,
     143             :  * and the parity may or may not be updated.
     144             :  *
     145             :  * A now the sync process is not affected by DELETED hash, so clearing won't be really needed,
     146             :  * but considering that we have to do it for CHG blocks, we do it also for DELETED ones,
     147             :  * clearing all the past hashes.
     148             :  * Clearing is done setting the ::clear_past_hash flag before reading the state.
     149             :  * No clearing is done in other commands, as check and fix are instead able to work with unsynced
     150             :  * hashes, and scrub ignores CHG/DELETED blocks.
     151             :  */
     152             : #define BLOCK_STATE_DELETED 4
     153             : 
     154             : /**
     155             :  * Block hash size.
     156             :  *
     157             :  * At max HASH_MAX.
     158             :  */
     159             : extern int BLOCK_HASH_SIZE;
     160             : 
     161             : /**
     162             :  * Block of a file.
     163             :  */
     164             : struct snapraid_block {
     165             :         unsigned char state; /**< State of the block. */
     166             : 
     167             :         /**
     168             :          * Hash of the block.
     169             :          *
     170             :          * The effective stored size is BLOCK_HASH_SIZE.
     171             :          */
     172             :         unsigned char hash[HASH_MAX];
     173             : };
     174             : 
     175             : /**
     176             :  * If a file is present in the disk.
     177             :  * It's used only in scan to detect present and missing files.
     178             :  */
     179             : #define FILE_IS_PRESENT 0x01
     180             : 
     181             : /**
     182             :  * If it's an excluded file from the processing.
     183             :  * It's used in both check and fix to mark files to exclude from the processing.
     184             :  */
     185             : #define FILE_IS_EXCLUDED 0x02
     186             : 
     187             : /**
     188             :  * If a fix was attempted but it failed.
     189             :  * It's used only in fix to mark that some data is unrecoverable.
     190             :  */
     191             : #define FILE_IS_DAMAGED 0x04
     192             : 
     193             : /**
     194             :  * If a fix was done.
     195             :  * It's used only in fix to mark that some data was recovered.
     196             :  */
     197             : #define FILE_IS_FIXED 0x08
     198             : 
     199             : /**
     200             :  * If the file was originally missing, and it was created in the fix process.
     201             :  * It's used only in fix to mark files recovered from scratch,
     202             :  * meaning that they don't have any previous content.
     203             :  * This is important because it means that deleting them, you are not going
     204             :  * to lose something that cannot be recovered.
     205             :  * Note that excluded files won't ever get this flag.
     206             :  */
     207             : #define FILE_IS_CREATED 0x10
     208             : 
     209             : /**
     210             :  * If the file has completed its processing, meaning that it won't be opened anymore.
     211             :  * It's used only in fix to mark when we finish processing one file.
     212             :  * Note that excluded files won't ever get this flag.
     213             :  */
     214             : #define FILE_IS_FINISHED 0x20
     215             : 
     216             : /**
     217             :  * If the file hash was obtained from a file copy
     218             :  * identified by the same name, size and stamp.
     219             :  */
     220             : #define FILE_IS_COPY 0x40
     221             : 
     222             : /**
     223             :  * If the file was opened.
     224             :  * It's used in fix to detect if it's the first time a file is opened.
     225             :  */
     226             : #define FILE_IS_OPENED 0x80
     227             : 
     228             : /**
     229             :  * If the file is modified from the latest sync.
     230             :  * It's used in fix to store if the state of the file before being modified.
     231             :  */
     232             : #define FILE_IS_UNSYNCED 0x100
     233             : 
     234             : /**
     235             :  * If the file is without inode.
     236             :  * It could happen in file-system where inodes are not persistent,
     237             :  * or when restoring a full disk with "fix".
     238             :  * In such cases we have to clear any stored duplicate inode.
     239             :  * After the scan process completes, no file should have this flag set.
     240             :  */
     241             : #define FILE_IS_WITHOUT_INODE 0x200
     242             : 
     243             : /**
     244             :  * The file is deleted.
     245             :  * This happens when a file is deleted from the array,
     246             :  * but it's keep inside the parity until the next sync.
     247             :  *
     248             :  * During the file-system check we needs this information,
     249             :  * because deleted files may be present only partially.
     250             :  */
     251             : #define FILE_IS_DELETED 0x400
     252             : 
     253             : /**
     254             :  * The file is missing.
     255             :  * This happens in fix/check when a file is cannot be opened,
     256             :  * and marking it as such prevents to retry to open it again.
     257             :  */
     258             : #define FILE_IS_MISSING 0x800
     259             : 
     260             : #define FILE_IS_HARDLINK 0x1000 /**< If it's an hardlink. */
     261             : #define FILE_IS_SYMLINK 0x2000 /**< If it's a file symlink. */
     262             : #define FILE_IS_SYMDIR 0x4000 /**< If it's a dir symlink for Windows. Not yet supported. */
     263             : #define FILE_IS_JUNCTION 0x8000 /**< If it's a junction for Windows. Not yet supported. */
     264             : #define FILE_IS_LINK_MASK 0xF000 /**< Mask for link type. */
     265             : 
     266             : /**
     267             :  * File.
     268             :  */
     269             : struct snapraid_file {
     270             :         int64_t mtime_sec; /**< Modification time. */
     271             :         uint64_t inode; /**< Inode. */
     272             :         uint64_t physical; /**< Physical offset of the file. */
     273             :         data_off_t size; /**< Size of the file. */
     274             :         struct snapraid_block* blockvec; /**< All the blocks of the file. */
     275             :         int mtime_nsec; /**< Modification time nanoseconds. In the range 0 <= x < 1,000,000,000, or STAT_NSEC_INVALID if not present. */
     276             :         block_off_t blockmax; /**< Number of blocks. */
     277             :         unsigned flag; /**< FILE_IS_* flags. */
     278             :         char* sub; /**< Sub path of the file. Without the disk dir. The disk is implicit. */
     279             : 
     280             :         /* nodes for data structures */
     281             :         tommy_node nodelist;
     282             :         tommy_hashdyn_node nodeset;
     283             :         tommy_hashdyn_node pathset;
     284             :         tommy_hashdyn_node stampset;
     285             : };
     286             : 
     287             : /**
     288             :  * Symbolic Link.
     289             :  */
     290             : struct snapraid_link {
     291             :         unsigned flag; /**< FILE_IS_* flags. */
     292             :         char* sub; /**< Sub path of the file. Without the disk dir. The disk is implicit. */
     293             :         char* linkto; /**< Link to. */
     294             : 
     295             :         /* nodes for data structures */
     296             :         tommy_node nodelist;
     297             :         tommy_hashdyn_node nodeset;
     298             : };
     299             : 
     300             : /**
     301             :  * Dir.
     302             :  */
     303             : struct snapraid_dir {
     304             :         unsigned flag; /**< FILE_IS_* flags. */
     305             :         char* sub; /**< Sub path of the file. Without the disk dir. The disk is implicit. */
     306             : 
     307             :         /* nodes for data structures */
     308             :         tommy_node nodelist;
     309             :         tommy_hashdyn_node nodeset;
     310             : };
     311             : 
     312             : /**
     313             :  * Chunk.
     314             :  *
     315             :  * A extent represents a fragment of a file mapped into the parity.
     316             :  */
     317             : struct snapraid_extent {
     318             :         struct snapraid_file* file; /**< File containing this extent. */
     319             :         block_off_t parity_pos; /**< Parity position. */
     320             :         block_off_t file_pos; /**< Position in the file. */
     321             :         block_off_t count; /**< Number of sequential blocks in the file and parity. */
     322             :         tommy_tree_node parity_node; /**< Tree sorted by <parity_pos>. */
     323             :         tommy_tree_node file_node; /**< Tree sorter by <file,file_pos>. */
     324             : };
     325             : 
     326             : /**
     327             :  * Disk.
     328             :  */
     329             : struct snapraid_disk {
     330             :         char name[PATH_MAX]; /**< Name of the disk. */
     331             :         char dir[PATH_MAX]; /**< Mount point of the disk. It always terminates with /. */
     332             :         char smartctl[PATH_MAX]; /**< Custom command for smartctl. Empty means auto. */
     333             :         char uuid[UUID_MAX]; /**< UUID of the disk. */
     334             : 
     335             :         uint64_t device; /**< Device identifier. */
     336             :         block_off_t total_blocks; /**< Number of total blocks. */
     337             :         block_off_t free_blocks; /**< Number of free blocks at the last sync. */
     338             : 
     339             :         uint64_t tick; /**< Usage time. */
     340             :         uint64_t progress_tick[PROGRESS_MAX]; /**< Last ticks of progress. */
     341             :         unsigned cached; /**< Number of IO blocks cached. */
     342             : 
     343             :         /**
     344             :          * First free searching block.
     345             :          * Note that it doesn't necessarily point at the first free block,
     346             :          * but it just tell you that no free block is present before this position.
     347             :          */
     348             :         block_off_t first_free_block;
     349             : 
     350             :         int has_volatile_inodes; /**< If the underline file-system has not persistent inodes. */
     351             :         int has_volatile_hardlinks; /**< If the underline file-system has not syncronized metadata for hardlink (NTFS). */
     352             :         int has_unreliable_physical; /**< If the physical offset of files has duplicates. */
     353             :         int has_different_uuid; /**< If the disk has a different UUID, meaning that it is not the same file-system. */
     354             :         int has_unsupported_uuid; /**< If the disk doesn't report UUID, meaning it's not supported. */
     355             :         int had_empty_uuid; /**< If the disk had an empty UUID, meaning that it's a new disk. */
     356             :         int mapping_idx; /**< Index in the mapping vector. Used only as buffer when writing the content file. */
     357             :         int skip_access; /**< If the disk is inaccessible and it should be skipped. */
     358             : 
     359             : #if HAVE_PTHREAD
     360             :         /**
     361             :          * Mutex for protecting the filesystem structure.
     362             :          *
     363             :          * Specifically, this protects ::fs_parity, ::fs_file, and ::fs_last,
     364             :          * meaning that it protects only extents.
     365             :          *
     366             :          * Files, links and dirs are not protected as they are not expected to
     367             :          * change during multithread processing.
     368             :          */
     369             :         pthread_mutex_t fs_mutex;
     370             : #endif
     371             : 
     372             :         /**
     373             :          * Mapping of extents in the parity.
     374             :          * Sorted by <parity_pos> and by <file,file_pos>
     375             :          */
     376             :         tommy_tree fs_parity;
     377             :         tommy_tree fs_file;
     378             : 
     379             :         /**
     380             :          * Last extent we accessed.
     381             :          * It's used to optimize access of sequential blocks.
     382             :          */
     383             :         struct snapraid_extent* fs_last;
     384             : 
     385             :         /**
     386             :          * List of all the snapraid_file for the disk.
     387             :          */
     388             :         tommy_list filelist;
     389             : 
     390             :         /**
     391             :          * List of all the deleted file for the disk.
     392             :          *
     393             :          * These files are kept allocated, because the blocks are still referenced in
     394             :          * the ::blockarr.
     395             :          */
     396             :         tommy_list deletedlist;
     397             : 
     398             :         tommy_hashdyn inodeset; /**< Hashtable by inode of all the files. */
     399             :         tommy_hashdyn pathset; /**< Hashtable by path of all the files. */
     400             :         tommy_hashdyn stampset; /**< Hashtable by stamp (size and time) of all the files. */
     401             :         tommy_list linklist; /**< List of all the links. */
     402             :         tommy_hashdyn linkset; /**< Hashtable by name of all the links. */
     403             :         tommy_list dirlist; /**< List of all the empty dirs. */
     404             :         tommy_hashdyn dirset; /**< Hashtable by name of all the empty dirs. */
     405             : 
     406             :         /* nodes for data structures */
     407             :         tommy_node node;
     408             : };
     409             : 
     410             : /**
     411             :  * Disk mapping.
     412             :  */
     413             : struct snapraid_map {
     414             :         char name[PATH_MAX]; /**< Name of the disk. */
     415             :         char uuid[UUID_MAX]; /**< UUID of the disk. Empty if unknown. */
     416             :         block_off_t total_blocks; /**< Number of total blocks. */
     417             :         block_off_t free_blocks; /**< Number of free blocks at last 'sync'. */
     418             :         unsigned position; /**< Position of the disk in the parity. */
     419             : 
     420             :         /* nodes for data structures */
     421             :         tommy_node node;
     422             : };
     423             : 
     424             : /**
     425             :  * Max number of parity split.
     426             :  */
     427             : #define SPLIT_MAX 8
     428             : 
     429             : /**
     430             :  * Invalid parity size.
     431             :  *
     432             :  * This value is used to identify new parities,
     433             :  * like when you alter the configuration adding
     434             :  * a new parity level, creating it with 'fix'.
     435             :  * Given that 'fix' doesn't write the content file,
     436             :  * the new size will be written only at the next
     437             :  * 'sync'.
     438             :  */
     439             : #define PARITY_SIZE_INVALID -1LL
     440             : 
     441             : /**
     442             :  * Parity split.
     443             :  */
     444             : struct snapraid_split {
     445             :         char path[PATH_MAX]; /**< Path of the parity file. */
     446             :         char uuid[UUID_MAX]; /**< UUID of the disk. Empty if unknown. */
     447             : 
     448             :         /**
     449             :          * Size of the parity split.
     450             :          * Only the latest not zero size is allowed to grow.
     451             :          * If the value is unset, it's PARITY_SIZE_INVALID.
     452             :          */
     453             :         data_off_t size;
     454             : 
     455             :         uint64_t device; /**< Device identifier of the parity. */
     456             : };
     457             : 
     458             : /**
     459             :  * Parity.
     460             :  */
     461             : struct snapraid_parity {
     462             :         struct snapraid_split split_map[SPLIT_MAX]; /**< Parity splits. */
     463             :         unsigned split_mac; /**< Number of parity splits. */
     464             :         char smartctl[PATH_MAX]; /**< Custom command for smartctl. Empty means auto. */
     465             :         block_off_t total_blocks; /**< Number of total blocks. */
     466             :         block_off_t free_blocks; /**< Number of free blocks at the last sync. */
     467             :         int is_excluded_by_filter; /**< If the parity is excluded by filters. */
     468             :         int skip_access; /**< If at least one of the parity disk is inaccessible and it should be skipped. */
     469             :         uint64_t tick; /**< Usage time. */
     470             :         uint64_t progress_tick[PROGRESS_MAX]; /**< Last cpu ticks of progress. */
     471             :         unsigned cached; /**< Number of IO blocks cached. */
     472             : };
     473             : 
     474             : /**
     475             :  * Info.
     476             :  */
     477             : typedef uint32_t snapraid_info;
     478             : 
     479             : /**
     480             :  * Allocate a content.
     481             :  */
     482             : struct snapraid_content* content_alloc(const char* path, uint64_t dev);
     483             : 
     484             : /**
     485             :  * Deallocate a content.
     486             :  */
     487             : void content_free(struct snapraid_content* content);
     488             : 
     489             : /**
     490             :  * Allocate a filter pattern for files and directories.
     491             :  */
     492             : struct snapraid_filter* filter_alloc_file(int is_include, const char* pattern);
     493             : 
     494             : /**
     495             :  * Allocate a filter pattern for disks.
     496             :  */
     497             : struct snapraid_filter* filter_alloc_disk(int is_include, const char* pattern);
     498             : 
     499             : /**
     500             :  * Deallocate an exclusion.
     501             :  */
     502             : void filter_free(struct snapraid_filter* filter);
     503             : 
     504             : /**
     505             :  * Filter type description.
     506             :  */
     507             : const char* filter_type(struct snapraid_filter* filter, char* out, size_t out_size);
     508             : 
     509             : /**
     510             :  * Filter hidden files.
     511             :  * Return !=0 if it matches and it should be excluded.
     512             :  */
     513     3173014 : static inline int filter_hidden(int enable, struct dirent* dd)
     514             : {
     515     3173014 :         if (enable && dirent_hidden(dd)) {
     516           0 :                 return 1; /* filter out */
     517             :         }
     518             : 
     519     3173014 :         return 0;
     520             : }
     521             : 
     522             : /**
     523             :  * Filter a path using a list of filters.
     524             :  * For each element of the path all the filters are applied, until the first one that matches.
     525             :  * Return !=0 if it should be excluded.
     526             :  */
     527             : int filter_path(tommy_list* filterlist, struct snapraid_filter** reason, const char* disk, const char* sub);
     528             : 
     529             : /**
     530             :  * Filter a file/link/dir if missing.
     531             :  * This call imply a disk check for the file presence.
     532             :  * Return !=0 if the file is present and it should be excluded.
     533             :  */
     534             : int filter_existence(int filter_missing, const char* dir, const char* sub);
     535             : 
     536             : /**
     537             :  * Filter a file if bad.
     538             :  * Return !=0 if the file is correct and it should be excluded.
     539             :  */
     540             : int filter_correctness(int filter_error, tommy_arrayblkof* infoarr, struct snapraid_disk* disk, struct snapraid_file* file);
     541             : 
     542             : /**
     543             :  * Filter a dir using a list of filters.
     544             :  * For each element of the path all the filters are applied, until the first one that matches.
     545             :  * Thesesdir are always by included by default, to allow to apply rules at the contained files.
     546             :  * Return !=0 if should be excluded.
     547             :  */
     548             : int filter_subdir(tommy_list* filterlist, struct snapraid_filter** reason, const char* disk, const char* sub);
     549             : 
     550             : /**
     551             :  * Filter a dir using a list of filters.
     552             :  * For each element of the path all the filters are applied, until the first one that matches.
     553             :  * Return !=0 if should be excluded.
     554             :  */
     555             : int filter_emptydir(tommy_list* filterlist, struct snapraid_filter** reason, const char* disk, const char* sub);
     556             : 
     557             : /**
     558             :  * Filter a path if it's a content file.
     559             :  * Return !=0 if should be excluded.
     560             :  */
     561             : int filter_content(tommy_list* contentlist, const char* path);
     562             : 
     563             : /**
     564             :  * Check if the specified hash is invalid.
     565             :  *
     566             :  * An invalid hash is represented with all bytes at 0x00.
     567             :  *
     568             :  * If working with reduced hash lengths, this function always return 0.
     569             :  */
     570      759521 : static inline int hash_is_invalid(const unsigned char* hash)
     571             : {
     572             :         int i;
     573             : 
     574             :         /* if the hash is reduced, we cannot grant that it's a specific kind of hash */
     575      759521 :         if (BLOCK_HASH_SIZE != HASH_MAX)
     576           0 :                 return 0;
     577             : 
     578     1179390 :         for (i = 0; i < BLOCK_HASH_SIZE; ++i)
     579     1153326 :                 if (hash[i] != 0x00)
     580      733457 :                         return 0;
     581             : 
     582       26064 :         return 1;
     583             : }
     584             : 
     585             : /**
     586             :  * Check if the specified hash represent the zero block.
     587             :  *
     588             :  * A zero hash is represented with all bytes at 0xFF.
     589             :  *
     590             :  * If working with reduced hash lengths, this function always return 0.
     591             :  */
     592      760984 : static inline int hash_is_zero(const unsigned char* hash)
     593             : {
     594             :         int i;
     595             : 
     596             :         /* if the hash is reduced, we cannot grant that it's a specific kind of hash */
     597      760984 :         if (BLOCK_HASH_SIZE != HASH_MAX)
     598           0 :                 return 0;
     599             : 
     600      995194 :         for (i = 0; i < BLOCK_HASH_SIZE; ++i)
     601      980725 :                 if (hash[i] != 0xFF)
     602      746515 :                         return 0;
     603             : 
     604       14469 :         return 1;
     605             : }
     606             : 
     607             : /**
     608             :  * Check if the specified hash is unequivocally representing the data.
     609             :  *
     610             :  * If working with reduced hash lengths, this function always return 0.
     611             :  */
     612       44272 : static inline int hash_is_unique(const unsigned char* hash)
     613             : {
     614             :         /* if the hash is reduced, we cannot grant that it's a specific kind of hash */
     615       44272 :         if (BLOCK_HASH_SIZE != HASH_MAX)
     616           0 :                 return 0;
     617             : 
     618       44272 :         return !hash_is_zero(hash) && !hash_is_invalid(hash);
     619             : }
     620             : 
     621             : /**
     622             :  * Set the hash to the special INVALID value.
     623             :  */
     624     9234056 : static inline void hash_invalid_set(unsigned char* hash)
     625             : {
     626     9234056 :         memset(hash, 0x00, BLOCK_HASH_SIZE);
     627     9234056 : }
     628             : 
     629             : /**
     630             :  * Set the hash to the special ZERO value.
     631             :  */
     632      115543 : static inline void hash_zero_set(unsigned char* hash)
     633             : {
     634      115543 :         memset(hash, 0xFF, BLOCK_HASH_SIZE);
     635      115543 : }
     636             : 
     637             : /**
     638             :  * Allocated space for block.
     639             :  */
     640    58061578 : static inline size_t block_sizeof(void)
     641             : {
     642    58061578 :         return 1 + BLOCK_HASH_SIZE;
     643             : }
     644             : 
     645             : /**
     646             :  * Get the state of the block.
     647             :  *
     648             :  * For this function, it's allowed to pass a NULL block
     649             :  * pointer than results in the BLOCK_STATE_EMPTY state.
     650             :  */
     651    52302812 : static inline unsigned block_state_get(const struct snapraid_block* block)
     652             : {
     653    52302812 :         if (block == BLOCK_NULL)
     654     1721787 :                 return BLOCK_STATE_EMPTY;
     655             : 
     656    50581025 :         return block->state;
     657             : }
     658             : 
     659             : /**
     660             :  * Set the state of the block.
     661             :  */
     662    19117243 : static inline void block_state_set(struct snapraid_block* block, unsigned state)
     663             : {
     664    19117243 :         block->state = state;
     665    19117243 : }
     666             : 
     667             : /**
     668             :  * Check if the specified block has an updated hash.
     669             :  *
     670             :  * Note that EMPTY / CHG / DELETED return 0.
     671             :  */
     672     2218840 : static inline int block_has_updated_hash(const struct snapraid_block* block)
     673             : {
     674     2218840 :         unsigned state = block_state_get(block);
     675             : 
     676     2218840 :         return state == BLOCK_STATE_BLK || state == BLOCK_STATE_REP;
     677             : }
     678             : 
     679             : /**
     680             :  * Check if the specified block has a past hash,
     681             :  * i.e. the hash of the data that it's now overwritten or lost.
     682             :  *
     683             :  * Note that EMPTY / BLK / REP return 0.
     684             :  */
     685     2542004 : static inline int block_has_past_hash(const struct snapraid_block* block)
     686             : {
     687     2542004 :         unsigned state = block_state_get(block);
     688             : 
     689     2542004 :         return state == BLOCK_STATE_CHG || state == BLOCK_STATE_DELETED;
     690             : }
     691             : 
     692             : /**
     693             :  * Check if the specified block is part of a file.
     694             :  *
     695             :  * Note that EMPTY / DELETED return 0.
     696             :  */
     697    14585890 : static inline int block_has_file(const struct snapraid_block* block)
     698             : {
     699    14585890 :         unsigned state = block_state_get(block);
     700             : 
     701    14587920 :         return state == BLOCK_STATE_BLK
     702    14587920 :                || state == BLOCK_STATE_CHG || state == BLOCK_STATE_REP;
     703             : }
     704             : 
     705             : /**
     706             :  * Check if the block has an invalid parity than needs to be updated.
     707             :  *
     708             :  * Note that EMPTY / BLK return 0.
     709             :  */
     710    12320776 : static inline int block_has_invalid_parity(const struct snapraid_block* block)
     711             : {
     712    12320776 :         unsigned state = block_state_get(block);
     713             : 
     714    12320776 :         return state == BLOCK_STATE_DELETED
     715    12320776 :                || state == BLOCK_STATE_CHG || state == BLOCK_STATE_REP;
     716             : }
     717             : 
     718             : /**
     719             :  * Check if the block is part of a file with valid parity.
     720             :  *
     721             :  * Note that anything different than BLK return 0.
     722             :  */
     723      220963 : static inline int block_has_file_and_valid_parity(const struct snapraid_block* block)
     724             : {
     725      220963 :         unsigned state = block_state_get(block);
     726             : 
     727      220963 :         return state == BLOCK_STATE_BLK;
     728             : }
     729             : 
     730    34101473 : static inline int file_flag_has(const struct snapraid_file* file, unsigned mask)
     731             : {
     732    34101473 :         return (file->flag & mask) == mask;
     733             : }
     734             : 
     735     5303517 : static inline void file_flag_set(struct snapraid_file* file, unsigned mask)
     736             : {
     737     5303517 :         file->flag |= mask;
     738     5303517 : }
     739             : 
     740       18459 : static inline void file_flag_clear(struct snapraid_file* file, unsigned mask)
     741             : {
     742       18459 :         file->flag &= ~mask;
     743       18459 : }
     744             : 
     745             : /**
     746             :  * Allocate a file.
     747             :  */
     748             : struct snapraid_file* file_alloc(unsigned block_size, const char* sub, data_off_t size, uint64_t mtime_sec, int mtime_nsec, uint64_t inode, uint64_t physical);
     749             : 
     750             : /**
     751             :  * Duplicate a file.
     752             :  */
     753             : struct snapraid_file* file_dup(struct snapraid_file* copy);
     754             : 
     755             : /**
     756             :  * Deallocate a file.
     757             :  */
     758             : void file_free(struct snapraid_file* file);
     759             : 
     760             : /**
     761             :  * Rename a file.
     762             :  */
     763             : void file_rename(struct snapraid_file* file, const char* sub);
     764             : 
     765             : /**
     766             :  * Copy a file.
     767             :  */
     768             : void file_copy(struct snapraid_file* src_file, struct snapraid_file* dest_file);
     769             : 
     770             : /**
     771             :  * Return the block at the specified position.
     772             :  *
     773             :  * Note that the block size if a runtime value.
     774             :  */
     775    54348022 : static inline struct snapraid_block* file_block(struct snapraid_file* file, size_t pos)
     776             : {
     777    54348022 :         unsigned char* ptr = (unsigned char*)file->blockvec;
     778             : 
     779    54348022 :         return (struct snapraid_block*)(ptr + pos * block_sizeof());
     780             : }
     781             : 
     782             : /**
     783             :  * Return the name of the file, without the dir.
     784             :  */
     785             : const char* file_name(const struct snapraid_file* file);
     786             : 
     787             : /**
     788             :  * Check if the block is the last in the file.
     789             :  */
     790             : int file_block_is_last(struct snapraid_file* file, block_off_t file_pos);
     791             : 
     792             : /**
     793             :  * Get the size in bytes of the block.
     794             :  * If it's the last block of a file it could be less than block_size.
     795             :  */
     796             : unsigned file_block_size(struct snapraid_file* file, block_off_t file_pos, unsigned block_size);
     797             : 
     798             : /**
     799             :  * Compare a file with an inode.
     800             :  */
     801             : int file_inode_compare_to_arg(const void* void_arg, const void* void_data);
     802             : 
     803             : /**
     804             :  * Compare files by inode.
     805             :  */
     806             : int file_inode_compare(const void* void_a, const void* void_b);
     807             : 
     808             : /**
     809             :  * Compare files by path.
     810             :  */
     811             : int file_path_compare(const void* void_a, const void* void_b);
     812             : 
     813             : /**
     814             :  * Compare files by physical address.
     815             :  */
     816             : int file_physical_compare(const void* void_a, const void* void_b);
     817             : 
     818             : /**
     819             :  * Compute the hash of a file inode.
     820             :  */
     821     5055426 : static inline tommy_uint32_t file_inode_hash(uint64_t inode)
     822             : {
     823     5055426 :         return (tommy_uint32_t)tommy_inthash_u64(inode);
     824             : }
     825             : 
     826             : /**
     827             :  * Compare a file with a path.
     828             :  */
     829             : int file_path_compare_to_arg(const void* void_arg, const void* void_data);
     830             : 
     831             : /**
     832             :  * Compare a file with another file for name, stamp, and both.
     833             :  */
     834             : int file_name_compare(const void* void_a, const void* void_b);
     835             : int file_stamp_compare(const void* void_a, const void* void_b);
     836             : int file_namestamp_compare(const void* void_a, const void* void_b);
     837             : int file_pathstamp_compare(const void* void_a, const void* void_b);
     838             : 
     839             : /**
     840             :  * Compute the hash of a file path.
     841             :  */
     842     3891909 : static inline tommy_uint32_t file_path_hash(const char* sub)
     843             : {
     844     3891909 :         return tommy_hash_u32(0, sub, strlen(sub));
     845             : }
     846             : 
     847             : /**
     848             :  * Compute the hash of a file stamp.
     849             :  */
     850     6275848 : static inline tommy_uint32_t file_stamp_hash(data_off_t size, int64_t mtime_sec, int mtime_nsec)
     851             : {
     852     6275848 :         return tommy_inthash_u32((tommy_uint32_t)size ^ tommy_inthash_u32(mtime_sec ^ tommy_inthash_u32(mtime_nsec)));
     853             : }
     854             : 
     855             : /**
     856             :  * Allocate a extent.
     857             :  */
     858             : struct snapraid_extent* extent_alloc(block_off_t parity_pos, struct snapraid_file* file, block_off_t file_pos, block_off_t count);
     859             : 
     860             : /**
     861             :  * Deallocate a extent.
     862             :  */
     863             : void extent_free(struct snapraid_extent* extent);
     864             : 
     865             : /**
     866             :  * Compare extent by parity position.
     867             :  */
     868             : int extent_parity_compare(const void* void_a, const void* void_b);
     869             : 
     870             : /**
     871             :  * Compare extent by file and file position.
     872             :  */
     873             : int extent_file_compare(const void* void_a, const void* void_b);
     874             : 
     875      209328 : static inline int link_flag_has(const struct snapraid_link* slink, unsigned mask)
     876             : {
     877      209328 :         return (slink->flag & mask) == mask;
     878             : }
     879             : 
     880       39461 : static inline void link_flag_set(struct snapraid_link* slink, unsigned mask)
     881             : {
     882       39461 :         slink->flag |= mask;
     883       39461 : }
     884             : 
     885             : static inline void link_flag_clear(struct snapraid_link* slink, unsigned mask)
     886             : {
     887             :         slink->flag &= ~mask;
     888             : }
     889             : 
     890           6 : static inline void link_flag_let(struct snapraid_link* slink, unsigned flag, unsigned mask)
     891             : {
     892           6 :         slink->flag &= ~mask;
     893           6 :         slink->flag |= flag & mask;
     894           6 : }
     895             : 
     896       91794 : static inline unsigned link_flag_get(struct snapraid_link* slink, unsigned mask)
     897             : {
     898       91794 :         return slink->flag & mask;
     899             : }
     900             : 
     901             : /**
     902             :  * Allocate a link.
     903             :  */
     904             : struct snapraid_link* link_alloc(const char* name, const char* slink, unsigned link_flag);
     905             : 
     906             : /**
     907             :  * Deallocate a link.
     908             :  */
     909             : void link_free(struct snapraid_link* slink);
     910             : 
     911             : /**
     912             :  * Compare a link with a name.
     913             :  */
     914             : int link_name_compare_to_arg(const void* void_arg, const void* void_data);
     915             : 
     916             : /**
     917             :  * Compare links by path.
     918             :  */
     919             : int link_alpha_compare(const void* void_a, const void* void_b);
     920             : 
     921             : /**
     922             :  * Compute the hash of a link name.
     923             :  */
     924      155706 : static inline tommy_uint32_t link_name_hash(const char* name)
     925             : {
     926      155706 :         return tommy_hash_u32(0, name, strlen(name));
     927             : }
     928             : 
     929         940 : static inline int dir_flag_has(const struct snapraid_dir* dir, unsigned mask)
     930             : {
     931         940 :         return (dir->flag & mask) == mask;
     932             : }
     933             : 
     934         278 : static inline void dir_flag_set(struct snapraid_dir* dir, unsigned mask)
     935             : {
     936         278 :         dir->flag |= mask;
     937         278 : }
     938             : 
     939             : static inline void dir_flag_clear(struct snapraid_dir* dir, unsigned mask)
     940             : {
     941             :         dir->flag &= ~mask;
     942             : }
     943             : 
     944             : /**
     945             :  * Allocate a dir.
     946             :  */
     947             : struct snapraid_dir* dir_alloc(const char* name);
     948             : 
     949             : /**
     950             :  * Deallocate a dir.
     951             :  */
     952             : void dir_free(struct snapraid_dir* dir);
     953             : 
     954             : /**
     955             :  * Compare a dir with a name.
     956             :  */
     957             : int dir_name_compare(const void* void_arg, const void* void_data);
     958             : 
     959             : /**
     960             :  * Compute the hash of a dir name.
     961             :  */
     962        1059 : static inline tommy_uint32_t dir_name_hash(const char* name)
     963             : {
     964        1059 :         return tommy_hash_u32(0, name, strlen(name));
     965             : }
     966             : 
     967             : /**
     968             :  * Allocate a disk.
     969             :  */
     970             : struct snapraid_disk* disk_alloc(const char* name, const char* dir, uint64_t dev, const char* uuid, int skip);
     971             : 
     972             : /**
     973             :  * Deallocate a disk.
     974             :  */
     975             : void disk_free(struct snapraid_disk* disk);
     976             : 
     977             : /**
     978             :  * Get the size of the disk in blocks.
     979             :  */
     980             : block_off_t fs_size(struct snapraid_disk* disk);
     981             : 
     982             : /**
     983             :  * Check if a disk is totally empty and can be discarded from the content file.
     984             :  * A disk is empty if it doesn't contain any file, symlink, hardlink or dir
     985             :  * and without any DELETED block.
     986             :  * The blockmax is used to limit the search of DELETED block up to blockmax.
     987             :  */
     988             : int fs_is_empty(struct snapraid_disk* disk, block_off_t blockmax);
     989             : 
     990             : /**
     991             :  * Check the file-system for errors.
     992             :  * Return 0 if it's OK.
     993             :  */
     994             : int fs_check(struct snapraid_disk* disk);
     995             : 
     996             : /**
     997             :  * Allocate a parity position for the specified file position.
     998             :  *
     999             :  * After this call you can use the par2file/par2block operations
    1000             :  * to query the relation.
    1001             :  *
    1002             :  * \note This function is NOT thread-safe as it uses the the disk cache. +
    1003             :  */
    1004             : void fs_allocate(struct snapraid_disk* disk, block_off_t parity_pos, struct snapraid_file* file, block_off_t file_pos);
    1005             : 
    1006             : /**
    1007             :  * Deallocate the parity position.
    1008             :  *
    1009             :  * After this call the par2file/par2block operations
    1010             :  * won't find anymore the parity association.
    1011             :  *
    1012             :  * \note This function is NOT thread-safe as it uses the the disk cache.
    1013             :  */
    1014             : void fs_deallocate(struct snapraid_disk* disk, block_off_t pos);
    1015             : 
    1016             : /**
    1017             :  * Get the block from the file position.
    1018             :  */
    1019             : struct snapraid_block* fs_file2block_get(struct snapraid_file* file, block_off_t file_pos);
    1020             : 
    1021             : /**
    1022             :  * Get the file position from the parity position.
    1023             :  * Return 0 if no file is using it.
    1024             :  */
    1025             : struct snapraid_file* fs_par2file_find(struct snapraid_disk* disk, block_off_t parity_pos, block_off_t* file_pos);
    1026             : 
    1027             : /**
    1028             :  * Get the file position from the parity position.
    1029             :  */
    1030    11721014 : static inline struct snapraid_file* fs_par2file_get(struct snapraid_disk* disk, block_off_t parity_pos, block_off_t* file_pos)
    1031             : {
    1032             :         struct snapraid_file* ret;
    1033             : 
    1034    11721014 :         ret = fs_par2file_find(disk, parity_pos, file_pos);
    1035    11723751 :         if (ret == 0) {
    1036             :                 /* LCOV_EXCL_START */
    1037             :                 log_fatal("Internal inconsistency when deresolving parity to file at position '%u' in disk '%s'\n", parity_pos, disk->name);
    1038             :                 os_abort();
    1039             :                 /* LCOV_EXCL_STOP */
    1040             :         }
    1041             : 
    1042    11723751 :         return ret;
    1043             : }
    1044             : 
    1045             : /**
    1046             :  * Get the parity position from the file position.
    1047             :  * Return POS_NULL if no parity is allocated.
    1048             :  */
    1049             : block_off_t fs_file2par_find(struct snapraid_disk* disk, struct snapraid_file* file, block_off_t file_pos);
    1050             : 
    1051             : /**
    1052             :  * Get the parity position from the file position.
    1053             :  */
    1054     4755439 : static inline block_off_t fs_file2par_get(struct snapraid_disk* disk, struct snapraid_file* file, block_off_t file_pos)
    1055             : {
    1056             :         block_off_t ret;
    1057             : 
    1058     4755439 :         ret = fs_file2par_find(disk, file, file_pos);
    1059     4755439 :         if (ret == POS_NULL) {
    1060             :                 /* LCOV_EXCL_START */
    1061             :                 log_fatal("Internal inconsistency when resolving file '%s' at position '%u/%u' in disk '%s'\n", file->sub, file_pos, file->blockmax, disk->name);
    1062             :                 os_abort();
    1063             :                 /* LCOV_EXCL_STOP */
    1064             :         }
    1065             : 
    1066     4755439 :         return ret;
    1067             : }
    1068             : 
    1069             : /**
    1070             :  * Get the block from the parity position.
    1071             :  * Return BLOCK_NULL==0 if the block is over the end of the disk or not used.
    1072             :  */
    1073             : struct snapraid_block* fs_par2block_find(struct snapraid_disk* disk, block_off_t parity_pos);
    1074             : 
    1075             : /**
    1076             :  * Get the block from the parity position.
    1077             :  */
    1078       15867 : static inline struct snapraid_block* fs_par2block_get(struct snapraid_disk* disk, block_off_t parity_pos)
    1079             : {
    1080             :         struct snapraid_block* ret;
    1081             : 
    1082       15867 :         ret = fs_par2block_find(disk, parity_pos);
    1083       15867 :         if (ret == BLOCK_NULL) {
    1084             :                 /* LCOV_EXCL_START */
    1085             :                 log_fatal("Internal inconsistency when deresolving parity to block at position '%u' in disk '%s'\n", parity_pos, disk->name);
    1086             :                 os_abort();
    1087             :                 /* LCOV_EXCL_STOP */
    1088             :         }
    1089             : 
    1090       15867 :         return ret;
    1091             : }
    1092             : 
    1093             : /**
    1094             :  * Allocate a disk mapping.
    1095             :  * Uses uuid="" if not available.
    1096             :  */
    1097             : struct snapraid_map* map_alloc(const char* name, unsigned position, block_off_t total_blocks, block_off_t free_blocks, const char* uuid);
    1098             : 
    1099             : /**
    1100             :  * Deallocate a disk mapping.
    1101             :  */
    1102             : void map_free(struct snapraid_map* map);
    1103             : 
    1104             : /**
    1105             :  * Mask used to store additional information in the info bits.
    1106             :  *
    1107             :  * These bits reduce the granularity of the time in the memory representation.
    1108             :  */
    1109             : #define INFO_MASK 0x7
    1110             : 
    1111             : /**
    1112             :  * Make an info.
    1113             :  */
    1114      194355 : static inline snapraid_info info_make(time_t last_access, int error, int rehash, int justsynced)
    1115             : {
    1116             :         /* clear the lowest bits as reserved for other information */
    1117      194355 :         snapraid_info info = last_access & ~INFO_MASK;
    1118             : 
    1119      194355 :         if (error != 0)
    1120        5273 :                 info |= 0x1;
    1121      194355 :         if (rehash != 0)
    1122       14426 :                 info |= 0x2;
    1123      194355 :         if (justsynced != 0)
    1124      142804 :                 info |= 0x4;
    1125      194355 :         return info;
    1126             : }
    1127             : 
    1128             : /**
    1129             :  * Extract the time information.
    1130             :  * This is the last time when the block was know to be correct.
    1131             :  * The "scrubbed" info tells if the time is referreing at the latest sync or scrub.
    1132             :  */
    1133      883089 : static inline time_t info_get_time(snapraid_info info)
    1134             : {
    1135      883089 :         return info & ~INFO_MASK;
    1136             : }
    1137             : 
    1138             : /**
    1139             :  * Extract the error information.
    1140             :  * Report if the block address had some problem.
    1141             :  */
    1142      351938 : static inline int info_get_bad(snapraid_info info)
    1143             : {
    1144      351938 :         return (info & 0x1) != 0;
    1145             : }
    1146             : 
    1147             : /**
    1148             :  * Extract the rehash information.
    1149             :  * Report if the block address is using the old hash and needs to be rehashed.
    1150             :  */
    1151     2046765 : static inline int info_get_rehash(snapraid_info info)
    1152             : {
    1153     2046765 :         return (info & 0x2) != 0;
    1154             : }
    1155             : 
    1156             : /**
    1157             :  * Extract the scrubbed information.
    1158             :  * Report if the block address was never scrubbed.
    1159             :  */
    1160       68520 : static inline int info_get_justsynced(snapraid_info info)
    1161             : {
    1162       68520 :         return (info & 0x4) != 0;
    1163             : }
    1164             : 
    1165             : /**
    1166             :  * Mark the block address as with error.
    1167             :  */
    1168        1773 : static inline snapraid_info info_set_bad(snapraid_info info)
    1169             : {
    1170        1773 :         return info | 0x1;
    1171             : }
    1172             : 
    1173             : /**
    1174             :  * Mark the block address as with rehash.
    1175             :  */
    1176        9215 : static inline snapraid_info info_set_rehash(snapraid_info info)
    1177             : {
    1178        9215 :         return info | 0x2;
    1179             : }
    1180             : 
    1181             : /**
    1182             :  * Set the info at the specified position.
    1183             :  * The position is allocated if not yet done.
    1184             :  */
    1185     1698024 : static inline void info_set(tommy_arrayblkof* array, block_off_t pos, snapraid_info info)
    1186             : {
    1187     1698024 :         tommy_arrayblkof_grow(array, pos + 1);
    1188             : 
    1189     1698024 :         memcpy(tommy_arrayblkof_ref(array, pos), &info, sizeof(snapraid_info));
    1190     1698024 : }
    1191             : 
    1192             : /**
    1193             :  * Get the info at the specified position.
    1194             :  * For not allocated position, 0 is returned.
    1195             :  */
    1196     5098521 : static inline snapraid_info info_get(tommy_arrayblkof* array, block_off_t pos)
    1197             : {
    1198             :         snapraid_info info;
    1199             : 
    1200     5098521 :         if (pos >= tommy_arrayblkof_size(array))
    1201      262643 :                 return 0;
    1202             : 
    1203     4835878 :         memcpy(&info, tommy_arrayblkof_ref(array, pos), sizeof(snapraid_info));
    1204             : 
    1205     4835878 :         return info;
    1206             : }
    1207             : 
    1208             : /**
    1209             :  * Compare times
    1210             :  */
    1211             : int time_compare(const void* void_a, const void* void_b);
    1212             : 
    1213             : /****************************************************************************/
    1214             : /* format */
    1215             : 
    1216             : #define FMT_FILE 0 /**< Print only the file. */
    1217             : #define FMT_DISK 1 /**< Print the disk name and the file. */
    1218             : #define FMT_PATH 2 /**< Print the full path. */
    1219             : 
    1220             : extern int FMT_MODE;
    1221             : 
    1222             : /**
    1223             :  * Format a file path for poll reference
    1224             :  */
    1225             : const char* fmt_poll(const struct snapraid_disk* disk, const char* str, char* buffer);
    1226             : 
    1227             : /**
    1228             :  * Format a path name for terminal reference
    1229             :  */
    1230             : const char* fmt_term(const struct snapraid_disk* disk, const char* str, char* buffer);
    1231             : 
    1232             : #endif
    1233             : 

Generated by: LCOV version 1.13