LCOV - code coverage report
Current view: top level - cmdline - elem.h (source / functions) Hit Total Coverage
Test: lcov.info Lines: 130 137 94.9 %
Date: 2026-04-29 15:04:44 Functions: 40 40 100.0 %

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

Generated by: LCOV version 1.0