mirror of
https://github.com/amadvance/snapraid.git
synced 2026-10-26 10:51:54 -04:00
Fix snapshot path resolution and aliased paths by storing sub_dir in fssnapshot_struct
This commit is contained in:
parent
abcdd688dd
commit
ebb199de3d
4 changed files with 68 additions and 26 deletions
|
|
@ -76,8 +76,9 @@ struct fssnapshot_struct {
|
|||
/**
|
||||
* Root directory of the volume/dataset mountpoint.
|
||||
* It ALWAYS terminates with /
|
||||
* - Btrfs/Bcachefs: subvolume root
|
||||
* - ZFS: dataset mountpoint
|
||||
* - Btrfs/Bcachefs: subvolume root (canonical path via realpath)
|
||||
* - ZFS: dataset mountpoint (canonical path via realpath)
|
||||
* - Windows: volume mountpoint (via GetVolumePathName)
|
||||
*/
|
||||
char root_dir[PATH_MAX];
|
||||
|
||||
|
|
@ -86,12 +87,24 @@ struct fssnapshot_struct {
|
|||
* It ALWAYS terminates with /
|
||||
* - Btrfs/Bcachefs: real directory (e.g. <root>/.snapraid/)
|
||||
* - ZFS: virtual directory (e.g. <root>/.zfs/snapshot/)
|
||||
* - Windows: symlink container directory (e.g. <root>/.snapraid/)
|
||||
*/
|
||||
char snapshot_dir[PATH_MAX];
|
||||
|
||||
/**
|
||||
* Data directory relative to root_dir in snapshots.
|
||||
*
|
||||
* It NEVER starts with '/'.
|
||||
* It is empty if the configured data directory is exactly root_dir.
|
||||
* If non-empty, it ALWAYS terminates with '/'.
|
||||
* - Unix: relative suffix computed from the realpath() canonical representation
|
||||
* - Windows: relative suffix computed from the configured path
|
||||
*/
|
||||
char sub_dir[PATH_MAX];
|
||||
|
||||
/*
|
||||
* Dataset name for ZFS (e.g. "pool/data")
|
||||
* or VolumeName in Windows.
|
||||
* or VolumeName in Windows (e.g. "\\?\Volume{guid}\").
|
||||
* Empty string for filesystems where not applicable.
|
||||
*/
|
||||
char dataset[PATH_MAX];
|
||||
|
|
|
|||
|
|
@ -532,6 +532,9 @@ int fssnapshot_mount(const char* dir, struct fssnapshot_struct* fss)
|
|||
return -1;
|
||||
}
|
||||
|
||||
size_t root_len = strlen(fss->root_dir);
|
||||
pathcpy(fss->sub_dir, sizeof(fss->sub_dir), dir + root_len);
|
||||
|
||||
pathcpy(fss->snapshot_dir, sizeof(fss->snapshot_dir), fss->root_dir);
|
||||
pathcat(fss->snapshot_dir, sizeof(fss->snapshot_dir), SNAPSHOT_CONTAINER "/");
|
||||
|
||||
|
|
|
|||
|
|
@ -6026,7 +6026,7 @@ void state_load_ignore_file(tommy_list* filter_list, const char* path, const cha
|
|||
sclose(f);
|
||||
}
|
||||
|
||||
static int state_snapshot_dir(struct fssnapshot_struct* fss, const char* name, const char* dir, struct snapraid_disk* disk)
|
||||
static int state_snapshot_dir(struct fssnapshot_struct* fss, const char* name, struct snapraid_disk* disk)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
|
|
@ -6039,7 +6039,7 @@ static int state_snapshot_dir(struct fssnapshot_struct* fss, const char* name, c
|
|||
pathcpy(vol, sizeof(vol), fss->snapshot_dir);
|
||||
pathcat(vol, sizeof(vol), name);
|
||||
pathcatc(vol, sizeof(vol), '/');
|
||||
pathcat(vol, sizeof(vol), dir);
|
||||
pathcat(vol, sizeof(vol), fss->sub_dir);
|
||||
|
||||
pathcpy(disk->dir, sizeof(disk->dir), vol);
|
||||
disk->dir_device = st.st_dev;
|
||||
|
|
@ -6065,10 +6065,8 @@ int state_snapshot_scan(struct snapraid_state* state)
|
|||
return -1;
|
||||
}
|
||||
|
||||
size_t root_len = strlen(disk->fss.root_dir);
|
||||
|
||||
/* delete a potential previous scan snapshot */
|
||||
if (state_snapshot_dir(&disk->fss, SNAPSHOT_SCAN, 0, 0) == 0) {
|
||||
if (state_snapshot_dir(&disk->fss, SNAPSHOT_SCAN, 0) == 0) {
|
||||
if (fssnapshot_delete(&disk->fss, SNAPSHOT_SCAN) != 0) {
|
||||
log_fatal(errno, "Failed to delete scan snapshot in '%s'. %s.\n", disk->fss.snapshot_dir, strerror(errno));
|
||||
return -1;
|
||||
|
|
@ -6084,7 +6082,7 @@ int state_snapshot_scan(struct snapraid_state* state)
|
|||
msg_progress("Created disk %s scan snapshot...\n", disk->name);
|
||||
|
||||
/* setup the snapshot in use */
|
||||
if (state_snapshot_dir(&disk->fss, SNAPSHOT_SCAN, disk->mount_point + root_len, disk) != 0) {
|
||||
if (state_snapshot_dir(&disk->fss, SNAPSHOT_SCAN, disk) != 0) {
|
||||
log_error(errno, "Error stating scan snapshot '%s'. %s.\n", disk->fss.snapshot_dir, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -6107,10 +6105,8 @@ int state_snapshot_pending(struct snapraid_state* state)
|
|||
if (disk->fss.magic == 0)
|
||||
continue;
|
||||
|
||||
size_t root_len = strlen(disk->fss.root_dir);
|
||||
|
||||
/* delete the pending snapshot only after the content state was saved */
|
||||
if (state_snapshot_dir(&disk->fss, SNAPSHOT_PENDING, 0, 0) == 0) {
|
||||
if (state_snapshot_dir(&disk->fss, SNAPSHOT_PENDING, 0) == 0) {
|
||||
if (fssnapshot_delete(&disk->fss, SNAPSHOT_PENDING) != 0) {
|
||||
log_fatal(errno, "Failed to delete pending snapshot in '%s'. %s.\n", disk->fss.snapshot_dir, strerror(errno));
|
||||
error = -1;
|
||||
|
|
@ -6128,7 +6124,7 @@ int state_snapshot_pending(struct snapraid_state* state)
|
|||
msg_progress("Created disk %s pending snapshot...\n", disk->name);
|
||||
|
||||
/* setup the snapshot in use */
|
||||
if (state_snapshot_dir(&disk->fss, SNAPSHOT_PENDING, disk->mount_point + root_len, disk) != 0) {
|
||||
if (state_snapshot_dir(&disk->fss, SNAPSHOT_PENDING, disk) != 0) {
|
||||
log_error(errno, "Error stating pending snapshot '%s'. %s.\n", disk->fss.snapshot_dir, strerror(errno));
|
||||
error = -1;
|
||||
continue;
|
||||
|
|
@ -6153,7 +6149,7 @@ int state_snapshot_commit(struct snapraid_state* state)
|
|||
continue;
|
||||
|
||||
/* delete a potential previous stable snapshot */
|
||||
if (state_snapshot_dir(&disk->fss, SNAPSHOT_STABLE, 0, 0) == 0) {
|
||||
if (state_snapshot_dir(&disk->fss, SNAPSHOT_STABLE, 0) == 0) {
|
||||
if (fssnapshot_delete(&disk->fss, SNAPSHOT_STABLE) != 0) {
|
||||
log_fatal(errno, "Failed to delete stable snapshot in '%s'. %s.\n", disk->fss.snapshot_dir, strerror(errno));
|
||||
error = -1;
|
||||
|
|
@ -6192,12 +6188,10 @@ void state_snapshot_read(struct snapraid_state* state)
|
|||
continue;
|
||||
}
|
||||
|
||||
size_t root_len = strlen(disk->fss.root_dir);
|
||||
|
||||
if (state_snapshot_dir(&disk->fss, SNAPSHOT_PENDING, disk->mount_point + root_len, disk) == 0) {
|
||||
if (state_snapshot_dir(&disk->fss, SNAPSHOT_PENDING, disk) == 0) {
|
||||
msg_progress("Using disk %s pending snapshot...\n", disk->name);
|
||||
} else {
|
||||
if (state_snapshot_dir(&disk->fss, SNAPSHOT_STABLE, disk->mount_point + root_len, disk) == 0) {
|
||||
if (state_snapshot_dir(&disk->fss, SNAPSHOT_STABLE, disk) == 0) {
|
||||
msg_progress("Using disk %s stable snapshot...\n", disk->name);
|
||||
} else {
|
||||
/* fallback to standard mount point */
|
||||
|
|
@ -6233,34 +6227,32 @@ void state_snapshot_write(struct snapraid_state* state, tommy_list* filterlist_d
|
|||
continue;
|
||||
}
|
||||
|
||||
size_t root_len = strlen(disk->fss.root_dir);
|
||||
|
||||
/* if the disk is filtered in, it could be written, then we cannot use the snapshot */
|
||||
if (filter_path(filterlist_disk, 0, disk->name, 0) == 0) {
|
||||
msg_progress("Using disk %s live filesystem...\n", disk->name);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (state_snapshot_dir(&disk->fss, SNAPSHOT_PENDING, disk->mount_point + root_len, disk) == 0) {
|
||||
if (state_snapshot_dir(&disk->fss, SNAPSHOT_PENDING, disk) == 0) {
|
||||
msg_progress("Using disk %s pending snapshot...\n", disk->name);
|
||||
|
||||
/* if there is a dealloc list */
|
||||
if (!tommy_list_empty(&disk->dealloclist)) {
|
||||
|
||||
/* if there is a previous snapshot */
|
||||
if (state_snapshot_dir(&disk->fss, SNAPSHOT_STABLE, disk->mount_point + root_len, 0) == 0) {
|
||||
if (state_snapshot_dir(&disk->fss, SNAPSHOT_STABLE, 0) == 0) {
|
||||
msg_progress("Importing disk %s stable snapshot %" PRIu64 " deallocated files...\n", disk->name, (uint64_t)tommy_list_count(&disk->dealloclist));
|
||||
|
||||
/* 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->mount_point + root_len);
|
||||
pathcat(vol, sizeof(vol), disk->fss.sub_dir);
|
||||
state_dealloc(state, vol, &disk->dealloclist);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (state_snapshot_dir(&disk->fss, SNAPSHOT_STABLE, disk->mount_point + root_len, disk) == 0) {
|
||||
if (state_snapshot_dir(&disk->fss, SNAPSHOT_STABLE, disk) == 0) {
|
||||
msg_progress("Using disk %s stable snapshot...\n", disk->name);
|
||||
} else {
|
||||
/* fallback to standard mount point */
|
||||
|
|
|
|||
|
|
@ -2144,9 +2144,14 @@ int fsinfo(const char* path, int* has_persistent_inode, int* has_syncronized_har
|
|||
#if HAVE_LINUX_DEVICE
|
||||
static int fssnapshot_inode(const char* path, uint32_t magic, uint64_t root_inode, struct fssnapshot_struct* fss)
|
||||
{
|
||||
char resolved[PATH_MAX];
|
||||
char current_path[PATH_MAX];
|
||||
|
||||
pathcpy(current_path, sizeof(current_path), path);
|
||||
if (realpath(path, resolved) == 0)
|
||||
return -1;
|
||||
|
||||
pathslash(resolved, sizeof(resolved));
|
||||
pathcpy(current_path, sizeof(current_path), resolved);
|
||||
|
||||
/* walk up the directory tree to find the subvolume root (Inode 256) */
|
||||
while (1) {
|
||||
|
|
@ -2171,6 +2176,15 @@ static int fssnapshot_inode(const char* path, uint32_t magic, uint64_t root_inod
|
|||
return -1;
|
||||
}
|
||||
|
||||
size_t root_len = strlen(fss->root_dir);
|
||||
|
||||
if (pathncmp(fss->root_dir, resolved, root_len) != 0) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
pathcpy(fss->sub_dir, sizeof(fss->sub_dir), resolved + root_len);
|
||||
|
||||
fss->magic = magic;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -2191,10 +2205,30 @@ static int fssnapshot_inode(const char* path, uint32_t magic, uint64_t root_inod
|
|||
#if HAVE_LINUX_DEVICE
|
||||
static int fssnapshot_zfs(const char* dir, uint32_t magic, struct fssnapshot_struct* fss)
|
||||
{
|
||||
char resolved[PATH_MAX];
|
||||
char root[PATH_MAX];
|
||||
|
||||
if (realpath(dir, resolved) == 0)
|
||||
return -1;
|
||||
|
||||
if (extract_zfs(dir, fss->dataset, sizeof(fss->dataset), 0, 0, fss->root_dir, sizeof(fss->root_dir)) != 0)
|
||||
return -1;
|
||||
|
||||
pathslash(fss->root_dir, sizeof(fss->root_dir));
|
||||
if (realpath(fss->root_dir, root) == 0)
|
||||
return -1;
|
||||
|
||||
pathslash(resolved, sizeof(resolved));
|
||||
pathslash(root, sizeof(root));
|
||||
|
||||
size_t root_len = strlen(root);
|
||||
if (pathncmp(root, resolved, root_len) != 0) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
pathcpy(fss->sub_dir, sizeof(fss->sub_dir), resolved + root_len);
|
||||
pathcpy(fss->root_dir, sizeof(fss->root_dir), root);
|
||||
|
||||
pathcpy(fss->snapshot_dir, sizeof(fss->snapshot_dir), fss->root_dir);
|
||||
pathcat(fss->snapshot_dir, sizeof(fss->snapshot_dir), ".zfs/snapshot/");
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue