Automatically exclude the snapshot .snapraid directory and content files

This commit is contained in:
Andrea Mazzoleni 2026-05-11 23:24:36 +02:00
parent 746a9b8940
commit cb6edc4335
10 changed files with 111 additions and 22 deletions

View file

@ -349,31 +349,54 @@ int filter_correctness(int filter_error, tommy_arrayblkof* infoarr, struct snapr
return 1;
}
int filter_content(tommy_list* contentlist, const char* path)
int filter_content(tommy_list* contentlist, const char* mount_point, size_t mount_point_len, const char* sub, size_t sub_len, const char* name)
{
tommy_node* i;
size_t name_len = strlen(name);
for (i = tommy_list_head(contentlist); i != 0; i = i->next) {
struct snapraid_content* content = i->data;
char tmp[PATH_MAX];
if (pathcmp(content->content, path) == 0)
/* if the mount point doesn't match, it's a different disk */
if (pathncmp(content->content, mount_point, mount_point_len) != 0)
continue;
/* if the sub dir doesn't match, it's a different dir */
if (pathncmp(content->content + mount_point_len, sub, sub_len) != 0)
continue;
/* if the name doesn't match, it's a different name */
if (pathncmp(content->content + mount_point_len + sub_len, name, name_len) != 0)
continue;
/* remaining part */
const char* postfix = content->content + mount_point_len + sub_len + name_len;
/* if it's an exact match */
if (*postfix == 0)
return -1;
/* exclude also the ".tmp" copy used to save it */
pathprint(tmp, sizeof(tmp), "%s.tmp", content->content);
if (pathcmp(tmp, path) == 0)
if (pathcmp(postfix, ".tmp") == 0)
return -1;
/* exclude also the ".lock" file */
pathprint(tmp, sizeof(tmp), "%s.lock", content->content);
if (pathcmp(tmp, path) == 0)
if (pathcmp(postfix, ".lock") == 0)
return -1;
}
return 0;
}
int filter_snapshot(const char* sub, const char* name)
{
if (*sub == 0 && pathcmp(name, SNAPSHOT_CONTAINER) == 0)
return -1;
return 0;
}
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)
{
struct snapraid_file* file;

View file

@ -632,7 +632,13 @@ int filter_emptydir(tommy_list* filterlist, struct snapraid_filter** reason, con
* Filter a path if it's a content file.
* Return !=0 if should be excluded.
*/
int filter_content(tommy_list* contentlist, const char* path);
int filter_content(tommy_list* contentlist, const char* mount_point, size_t mount_point_len, const char* sub, size_t sub_len, const char* name);
/**
* Filter a path that is in a snapshot
* Return !=0 if should be excluded.
*/
int filter_snapshot(const char* sub, const char* name);
/**
* Check if the specified hash is invalid.

View file

@ -385,7 +385,7 @@ int fsinfo(const char* path, int* has_persistent_inode, int* has_syncronized_har
#define SNAPSHOT_PENDING "pending"
#define SNAPSHOT_STABLE "stable"
/**
/*
* Snapshots context
*/
struct fssnapshot_struct {

View file

@ -1322,9 +1322,11 @@ static int scan_sub(struct snapraid_scan* scan, int level, int is_diff, char* pa
DIR* d;
tommy_list list;
tommy_node* node;
size_t mount_point_len;
size_t path_len;
size_t sub_len;
mount_point_len = strlen(disk->mount_point);
path_len = strlen(path_next);
sub_len = strlen(sub_next);
@ -1397,11 +1399,17 @@ static int scan_sub(struct snapraid_scan* scan, int level, int is_diff, char* pa
}
/* exclude content files even before calling lstat() */
if (filter_content(&state->contentlist, path_next) != 0) {
if (filter_content(&state->contentlist, disk->mount_point, mount_point_len, sub_next, sub_len, name) != 0) {
msg_verbose("Excluding content '%s'\n", path_next);
continue;
}
/* exclude snapshot container even before calling lstat() */
if (filter_snapshot(sub_next, name) != 0) {
msg_verbose("Excluding snapshots directory '%s'\n", path_next);
continue;
}
name_len = strlen(dd->d_name);
entry = malloc_nofail(sizeof(struct dirent_sorted) + name_len + 1);

View file

@ -138,6 +138,9 @@ static void search_dir(struct snapraid_state* state, struct snapraid_disk* disk,
{
DIR* d;
size_t mount_point_len = disk != 0 ? strlen(disk->mount_point) : 0;
size_t sub_len = strlen(sub);
d = opendir(dir);
if (!d) {
/* LCOV_EXCL_START */
@ -183,11 +186,17 @@ static void search_dir(struct snapraid_state* state, struct snapraid_disk* disk,
}
/* exclude content files even before calling lstat() */
if (disk != 0 && filter_content(&state->contentlist, path_next) != 0) {
if (disk != 0 && filter_content(&state->contentlist, disk->mount_point, mount_point_len, sub, sub_len, name) != 0) {
msg_verbose("Excluding content '%s'\n", path_next);
continue;
}
/* exclude snapshot container even before calling lstat() */
if (disk != 0 && filter_snapshot(sub, name) != 0) {
msg_verbose("Excluding snapshots directory '%s'\n", path_next);
continue;
}
#if HAVE_STRUCT_DIRENT_D_STAT
/* convert dirent to lstat result */
dirent_lstat(dd, &st);

View file

@ -1193,20 +1193,61 @@ void pathup(char* dst)
int pathcmp(const char* a, const char* b)
{
#ifdef _WIN32
char ai[PATH_MAX];
char bi[PATH_MAX];
while (1) {
char ca = *a++;
char cb = *b++;
/* import to convert \ to / */
pathimport(ai, sizeof(ai), a);
pathimport(bi, sizeof(bi), b);
if (ca == '/')
ca = '\\';
/* case insensitive compare in Windows */
return stricmp(ai, bi);
if (cb == '/')
cb = '\\';
int la = tolower((unsigned char)ca);
int lb = tolower((unsigned char)cb);
if (la != lb)
return la - lb;
if (la == 0)
return 0;
}
#else
return strcmp(a, b);
#endif
}
int pathncmp(const char* a, const char* b, size_t n)
{
#ifdef _WIN32
while (n > 0) {
char ca = *a++;
char cb = *b++;
if (ca == '/')
ca = '\\';
if (cb == '/')
cb = '\\';
int la = tolower((unsigned char)ca);
int lb = tolower((unsigned char)cb);
if (la != lb)
return la - lb;
if (la == '\0')
return 0;
--n;
}
return 0;
#else
return strncmp(a, b, n);
#endif
}
int path_is_root_of(const char* root, const char* path)
{
while (*root && *path) {

View file

@ -373,6 +373,12 @@ void pathup(char* dst);
*/
int pathcmp(const char* a, const char* b);
/**
* Compare two paths up to n chars.
* In Windows it's case insensitive and assumes \ equal at /.
*/
int pathncmp(const char* a, const char* b, size_t n);
/**
* Check if the root is matching the start of the specified path.
*

View file

@ -2490,8 +2490,6 @@ int fsinfo(const char* path, int* has_persistent_inode, int* has_syncronized_har
return 0;
}
#define SNAPSHOT_CONTAINER ".snapraid"
#if HAVE_LINUX_DEVICE
static int fssnapshot_inode(const char* path, uint32_t magic, uint64_t root_inode, struct fssnapshot_struct* fss)
{

View file

@ -84,7 +84,6 @@ extra boot /
exclude *.unrecoverable
exclude /tmp/
exclude /lost+found/
exclude .snapraid/
# Defines the block size in kibi bytes (1024 bytes) (uncomment to enable).
# WARNING: Changing this value is for experts only!

View file

@ -6,4 +6,3 @@ disk snap1 bench/snap1/
disk snap2 bench/snap2/
disk snap3 bench/snap3/
snapshot
exclude .snapraid/