diff options
Diffstat (limited to 'src/shared')
-rw-r--r-- | src/shared/rm-rf.c | 27 | ||||
-rw-r--r-- | src/shared/rm-rf.h | 1 |
2 files changed, 27 insertions, 1 deletions
diff --git a/src/shared/rm-rf.c b/src/shared/rm-rf.c index eeb2e39196..50112e3b5e 100644 --- a/src/shared/rm-rf.c +++ b/src/shared/rm-rf.c @@ -75,7 +75,8 @@ int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) { if (streq(de->d_name, ".") || streq(de->d_name, "..")) continue; - if (de->d_type == DT_UNKNOWN || (de->d_type == DT_DIR && root_dev)) { + if (de->d_type == DT_UNKNOWN || + (de->d_type == DT_DIR && (root_dev || (flags & REMOVE_SUBVOLUME)))) { if (fstatat(fd, de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) { if (ret == 0 && errno != ENOENT) ret = -errno; @@ -114,6 +115,30 @@ int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) { continue; } + if ((flags & REMOVE_SUBVOLUME) && st.st_ino == 256) { + struct btrfs_ioctl_vol_args args = {}; + + /* This could be a subvolume, try to remove it */ + + strncpy(args.name, de->d_name, sizeof(args.name)-1); + if (ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &args) < 0) { + + if (errno != ENOTTY && errno != EINVAL) { + if (ret == 0) + ret = -errno; + + safe_close(subdir_fd); + continue; + } + + /* ENOTTY, then it wasn't a btrfs subvolume */ + } else { + /* It was a subvolume, continue. */ + safe_close(subdir_fd); + continue; + } + } + /* We pass REMOVE_PHYSICAL here, to avoid * doing the fstatfs() to check the file * system type again for each directory */ diff --git a/src/shared/rm-rf.h b/src/shared/rm-rf.h index 769bbc853d..96579eb182 100644 --- a/src/shared/rm-rf.h +++ b/src/shared/rm-rf.h @@ -27,6 +27,7 @@ typedef enum RemoveFlags { REMOVE_ONLY_DIRECTORIES = 1, REMOVE_ROOT = 2, REMOVE_PHYSICAL = 4, /* if not set, only removes files on tmpfs, never physical file systems */ + REMOVE_SUBVOLUME = 8, } RemoveFlags; int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev); |