From 6583897fcf23797febbf78200103ecce4241e124 Mon Sep 17 00:00:00 2001 From: Andrea Mazzoleni Date: Wed, 26 Aug 2026 00:37:52 +0200 Subject: [PATCH] Reserve snapraid- prefix for native ZFS snapshots and introduce fssnapshot_path --- cmdline/app.h | 11 +++++++++++ cmdline/mingwapp.c | 10 ++++++++++ cmdline/state.c | 13 +++++-------- cmdline/unixapp.c | 36 ++++++++++++++++++++++++++++++------ 4 files changed, 56 insertions(+), 14 deletions(-) diff --git a/cmdline/app.h b/cmdline/app.h index 751c7d6c..b5af88ba 100644 --- a/cmdline/app.h +++ b/cmdline/app.h @@ -166,6 +166,17 @@ int fssnapshot_delete(const struct fssnapshot_struct* fss, const char* name); */ int fssnapshot_rename(const struct fssnapshot_struct* fss, const char* old_name, const char* new_name); +/** + * Get the path where a logical snapshot is accessible. + * + * @param fss Snapshot context + * @param name Logical snapshot name + * @param path Output path + * @param path_size Size of path + * @return 0 on success, -1 on failure + */ +int fssnapshot_path(const struct fssnapshot_struct* fss, const char* name, char* path, size_t path_size); + /* * Log file. * diff --git a/cmdline/mingwapp.c b/cmdline/mingwapp.c index 9c35b37c..1762886c 100644 --- a/cmdline/mingwapp.c +++ b/cmdline/mingwapp.c @@ -743,6 +743,16 @@ int fssnapshot_rename(const struct fssnapshot_struct* fss, const char* old_name, return 0; } +int fssnapshot_path(const struct fssnapshot_struct* fss, const char* name, char* path, size_t path_size) +{ + pathcpy(path, path_size, fss->snapshot_dir); + pathcat(path, path_size, name); + pathcatc(path, path_size, '/'); + pathcat(path, path_size, fss->sub_dir); + + return 0; +} + void fssnapshot_unmount(const struct fssnapshot_struct* fss) { /* diff --git a/cmdline/state.c b/cmdline/state.c index 23bc8928..93aa652a 100644 --- a/cmdline/state.c +++ b/cmdline/state.c @@ -6036,10 +6036,9 @@ static int state_snapshot_dir(struct fssnapshot_struct* fss, const char* name, s if (disk) { char vol[PATH_MAX]; - pathcpy(vol, sizeof(vol), fss->snapshot_dir); - pathcat(vol, sizeof(vol), name); - pathcatc(vol, sizeof(vol), '/'); - pathcat(vol, sizeof(vol), fss->sub_dir); + + if (fssnapshot_path(fss, name, vol, sizeof(vol)) != 0) + return -1; pathcpy(disk->dir, sizeof(disk->dir), vol); disk->dir_device = st.st_dev; @@ -6245,10 +6244,8 @@ void state_snapshot_write(struct snapraid_state* state, tommy_list* filterlist_d /* set where to find deallocated files */ char vol[PATH_MAX]; - pathcpy(vol, sizeof(vol), disk->fss.snapshot_dir); - pathcat(vol, sizeof(vol), SNAPSHOT_STABLE "/"); - pathcat(vol, sizeof(vol), disk->fss.sub_dir); - state_dealloc(state, vol, &disk->dealloclist); + if (fssnapshot_path(&disk->fss, SNAPSHOT_STABLE, vol, sizeof(vol)) == 0) + state_dealloc(state, vol, &disk->dealloclist); } } } else { diff --git a/cmdline/unixapp.c b/cmdline/unixapp.c index 3044a51b..ba07895a 100644 --- a/cmdline/unixapp.c +++ b/cmdline/unixapp.c @@ -2294,13 +2294,24 @@ static int fssnapshot_stat_fs(const struct fssnapshot_struct* fss, const char* n } #endif +/* + * Native ZFS snapshots use a SnapRAID-specific prefix to avoid + * deleting or renaming unrelated user snapshots with generic + * names such as @scan, @pending, or @stable. + */ +#define ZFS_SNAPSHOT_PREFIX "snapraid-" + #if HAVE_LINUX_DEVICE static int fssnapshot_stat_zfs(const struct fssnapshot_struct* fss, const char* name, struct stat* st) { + char native_name[PATH_MAX]; char target_path[PATH_MAX]; + pathcpy(native_name, sizeof(native_name), ZFS_SNAPSHOT_PREFIX); + pathcat(native_name, sizeof(native_name), name); + pathcpy(target_path, sizeof(target_path), fss->snapshot_dir); - pathcat(target_path, sizeof(target_path), name); + pathcat(target_path, sizeof(target_path), native_name); /* * Ensure to get into into the snapshot @@ -2351,7 +2362,7 @@ static int fssnapshot_stat_zfs(const struct fssnapshot_struct* fss, const char* if (!entry) break; - if (strcmp(entry->d_name, name) == 0) { + if (strcmp(entry->d_name, native_name) == 0) { closedir(d); return 0; } @@ -2480,7 +2491,7 @@ static int fssnapshot_zfs_create(const struct fssnapshot_struct* fss, const char /* LCOV_EXCL_STOP */ } - snprintf(snapshot, sizeof(snapshot), "%s@%s", fss->dataset, name); + snprintf(snapshot, sizeof(snapshot), "%s@" ZFS_SNAPSHOT_PREFIX "%s", fss->dataset, name); if (os_validate_exec_input(snapshot) != 0) { /* LCOV_EXCL_START */ @@ -2609,7 +2620,7 @@ static int fssnapshot_zfs_delete(const struct fssnapshot_struct* fss, const char /* LCOV_EXCL_STOP */ } - snprintf(snapshot, sizeof(snapshot), "%s@%s", fss->dataset, name); + snprintf(snapshot, sizeof(snapshot), "%s@" ZFS_SNAPSHOT_PREFIX "%s", fss->dataset, name); if (os_validate_exec_input(snapshot) != 0) { /* LCOV_EXCL_START */ @@ -2689,8 +2700,8 @@ static int fssnapshot_zfs_rename(const struct fssnapshot_struct* fss, const char /* LCOV_EXCL_STOP */ } - snprintf(old_snapshot, sizeof(old_snapshot), "%s@%s", fss->dataset, old_name); - snprintf(new_snapshot, sizeof(new_snapshot), "%s@%s", fss->dataset, new_name); + snprintf(old_snapshot, sizeof(old_snapshot), "%s@" ZFS_SNAPSHOT_PREFIX "%s", fss->dataset, old_name); + snprintf(new_snapshot, sizeof(new_snapshot), "%s@" ZFS_SNAPSHOT_PREFIX "%s", fss->dataset, new_name); if (os_validate_exec_input(old_snapshot) != 0 || os_validate_exec_input(new_snapshot) != 0) { /* LCOV_EXCL_START */ @@ -2735,11 +2746,24 @@ int fssnapshot_rename(const struct fssnapshot_struct* fss, const char* old_name, #endif } +int fssnapshot_path(const struct fssnapshot_struct* fss, const char* name, char* path, size_t path_size) +{ + pathcpy(path, path_size, fss->snapshot_dir); + if (fss->magic == ZFS_SUPER_MAGIC) + pathcat(path, path_size, ZFS_SNAPSHOT_PREFIX); + pathcat(path, path_size, name); + pathcatc(path, path_size, '/'); + pathcat(path, path_size, fss->sub_dir); + + return 0; +} + void fssnapshot_unmount(const struct fssnapshot_struct* fss) { (void)fss; } + /****************************************************************************/ /* dev */