#include "stat-util.h"
#include "string-util.h"
#include "time-util.h"
-#include "util.h"
/* WARNING: Be careful with file system ioctls! When we get an fd, we
* need to make sure it either refers to only a regular file or
}
int btrfs_is_subvol(const char *path) {
- _cleanup_close_ int fd = -1;
+ _cleanup_close_ int fd = -EBADF;
assert(path);
int btrfs_subvol_make_fd(int fd, const char *subvolume) {
struct btrfs_ioctl_vol_args args = {};
- _cleanup_close_ int real_fd = -1;
+ _cleanup_close_ int real_fd = -EBADF;
int r;
assert(subvolume);
if (r < 0)
return r;
- r = fcntl(fd, F_GETFL);
- if (r < 0)
- return -errno;
- if (FLAGS_SET(r, O_PATH)) {
- /* An O_PATH fd was specified, let's convert here to a proper one, as btrfs ioctl's can't deal with
- * O_PATH. */
-
- real_fd = fd_reopen(fd, O_RDONLY|O_CLOEXEC|O_DIRECTORY);
- if (real_fd < 0)
- return real_fd;
-
- fd = real_fd;
- }
+ /* If an O_PATH fd was specified, let's convert here to a proper one, as btrfs ioctl's can't deal
+ * with O_PATH. */
+ fd = fd_reopen_condition(fd, O_RDONLY|O_CLOEXEC|O_DIRECTORY, O_PATH|O_DIRECTORY, &real_fd);
+ if (fd < 0)
+ return fd;
strncpy(args.name, subvolume, sizeof(args.name)-1);
- if (ioctl(fd, BTRFS_IOC_SUBVOL_CREATE, &args) < 0)
- return -errno;
-
- return 0;
+ return RET_NERRNO(ioctl(fd, BTRFS_IOC_SUBVOL_CREATE, &args));
}
int btrfs_subvol_make(const char *path) {
- _cleanup_close_ int fd = -1;
+ _cleanup_close_ int fd = -EBADF;
const char *subvolume;
int r;
if (flags == nflags)
return 0;
- if (ioctl(fd, BTRFS_IOC_SUBVOL_SETFLAGS, &nflags) < 0)
- return -errno;
-
- return 0;
+ return RET_NERRNO(ioctl(fd, BTRFS_IOC_SUBVOL_SETFLAGS, &nflags));
}
int btrfs_subvol_set_read_only(const char *path, bool b) {
- _cleanup_close_ int fd = -1;
+ _cleanup_close_ int fd = -EBADF;
fd = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
if (fd < 0)
if (r < 0)
return r;
- if (ioctl(outfd, BTRFS_IOC_CLONE, infd) < 0)
- return -errno;
-
- return 0;
+ return RET_NERRNO(ioctl(outfd, BTRFS_IOC_CLONE, infd));
}
int btrfs_clone_range(int infd, uint64_t in_offset, int outfd, uint64_t out_offset, uint64_t sz) {
assert(infd >= 0);
assert(outfd >= 0);
- assert(sz > 0);
r = fd_verify_regular(outfd);
if (r < 0)
return r;
- if (ioctl(outfd, BTRFS_IOC_CLONE_RANGE, &args) < 0)
- return -errno;
-
- return 0;
+ return RET_NERRNO(ioctl(outfd, BTRFS_IOC_CLONE_RANGE, &args));
}
int btrfs_get_block_device_fd(int fd, dev_t *dev) {
struct btrfs_ioctl_fs_info_args fsi = {};
+ _cleanup_close_ int regfd = -EBADF;
uint64_t id;
int r;
assert(fd >= 0);
assert(dev);
+ fd = fd_reopen_condition(fd, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY, O_PATH, ®fd);
+ if (fd < 0)
+ return fd;
+
r = fd_is_fs_type(fd, BTRFS_SUPER_MAGIC);
if (r < 0)
return r;
}
int btrfs_get_block_device(const char *path, dev_t *dev) {
- _cleanup_close_ int fd = -1;
+ _cleanup_close_ int fd = -EBADF;
assert(path);
assert(dev);
}
int btrfs_subvol_get_id(int fd, const char *subvol, uint64_t *ret) {
- _cleanup_close_ int subvol_fd = -1;
+ _cleanup_close_ int subvol_fd = -EBADF;
assert(fd >= 0);
assert(ret);
}
finish:
- if (!found)
- return -ENODATA;
-
- return 0;
+ return found ? 0 : -ENODATA;
}
int btrfs_qgroup_get_quota_fd(int fd, uint64_t qgroupid, BtrfsQuotaInfo *ret) {
}
int btrfs_qgroup_get_quota(const char *path, uint64_t qgroupid, BtrfsQuotaInfo *ret) {
- _cleanup_close_ int fd = -1;
+ _cleanup_close_ int fd = -EBADF;
fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
if (fd < 0)
* prepared with btrfs_subvol_auto_qgroup_fd() with
* insert_intermediary_qgroup=true (or equivalent). For others
* it will return the leaf qgroup instead. The two cases may
- * be distuingished via the return value, which is 1 in case
+ * be distinguished via the return value, which is 1 in case
* an appropriate "subtree" qgroup was found, and 0
* otherwise. */
}
int btrfs_subvol_get_subtree_quota(const char *path, uint64_t subvol_id, BtrfsQuotaInfo *ret) {
- _cleanup_close_ int fd = -1;
+ _cleanup_close_ int fd = -EBADF;
fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
if (fd < 0)
return btrfs_subvol_get_subtree_quota_fd(fd, subvol_id, ret);
}
+int btrfs_defrag_fd(int fd) {
+ int r;
+
+ assert(fd >= 0);
+
+ r = fd_verify_regular(fd);
+ if (r < 0)
+ return r;
+
+ return RET_NERRNO(ioctl(fd, BTRFS_IOC_DEFRAG, NULL));
+}
+
int btrfs_defrag(const char *p) {
- _cleanup_close_ int fd = -1;
+ _cleanup_close_ int fd = -EBADF;
fd = open(p, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
if (fd < 0)
if (!r)
return -ENOTTY;
- if (ioctl(fd, BTRFS_IOC_QUOTA_CTL, &args) < 0)
- return -errno;
-
- return 0;
+ return RET_NERRNO(ioctl(fd, BTRFS_IOC_QUOTA_CTL, &args));
}
int btrfs_quota_enable(const char *path, bool b) {
- _cleanup_close_ int fd = -1;
+ _cleanup_close_ int fd = -EBADF;
fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
if (fd < 0)
}
int btrfs_qgroup_set_limit(const char *path, uint64_t qgroupid, uint64_t referenced_max) {
- _cleanup_close_ int fd = -1;
+ _cleanup_close_ int fd = -EBADF;
fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
if (fd < 0)
}
int btrfs_subvol_set_subtree_quota_limit(const char *path, uint64_t subvol_id, uint64_t referenced_max) {
- _cleanup_close_ int fd = -1;
+ _cleanup_close_ int fd = -EBADF;
fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
if (fd < 0)
assert(fd >= 0);
- if (ioctl(fd, BTRFS_IOC_QUOTA_RESCAN, &args) < 0)
- return -errno;
-
- return 0;
+ return RET_NERRNO(ioctl(fd, BTRFS_IOC_QUOTA_RESCAN, &args));
}
int btrfs_quota_scan_wait(int fd) {
assert(fd >= 0);
- if (ioctl(fd, BTRFS_IOC_QUOTA_RESCAN_WAIT) < 0)
- return -errno;
-
- return 0;
+ return RET_NERRNO(ioctl(fd, BTRFS_IOC_QUOTA_RESCAN_WAIT));
}
int btrfs_quota_scan_ongoing(int fd) {
};
struct btrfs_ioctl_vol_args vol_args = {};
- _cleanup_close_ int subvol_fd = -1;
+ _cleanup_close_ int subvol_fd = -EBADF;
struct stat st;
bool made_writable = false;
int r;
* directory of the subvolume. */
r = subvol_remove_children(subvol_fd, p, sh->objectid, flags);
else {
- _cleanup_close_ int child_fd = -1;
+ _cleanup_close_ int child_fd = -EBADF;
/* Subvolume is somewhere further down,
* hence we need to open the
}
int btrfs_subvol_remove(const char *path, BtrfsRemoveFlags flags) {
- _cleanup_close_ int fd = -1;
+ _cleanup_close_ int fd = -EBADF;
const char *subvolume;
int r;
.flags = flags & BTRFS_SNAPSHOT_READ_ONLY ? BTRFS_SUBVOL_RDONLY : 0,
.fd = old_fd,
};
- _cleanup_close_ int subvolume_fd = -1;
+ _cleanup_close_ int subvolume_fd = -EBADF;
uint64_t new_subvol_id;
int r;
FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
_cleanup_free_ char *p = NULL, *c = NULL, *np = NULL;
const struct btrfs_root_ref *ref;
- _cleanup_close_ int old_child_fd = -1, new_child_fd = -1;
+ _cleanup_close_ int old_child_fd = -EBADF, new_child_fd = -EBADF;
btrfs_ioctl_search_args_set(&args, sh);
copy_progress_bytes_t progress_bytes,
void *userdata) {
- _cleanup_close_ int new_fd = -1;
+ _cleanup_close_ int new_fd = -EBADF;
const char *subvolume;
int r;
copy_progress_bytes_t progress_bytes,
void *userdata) {
- _cleanup_close_ int old_fd = -1;
+ _cleanup_close_ int old_fd = -EBADF;
assert(old_path);
assert(new_path);
int btrfs_subvol_auto_qgroup_fd(int fd, uint64_t subvol_id, bool insert_intermediary_qgroup) {
_cleanup_free_ uint64_t *qgroups = NULL;
+ _cleanup_close_ int real_fd = -EBADF;
uint64_t parent_subvol;
bool changed = false;
int n = 0, r;
* qgroup that then includes all its own child subvolumes.
*/
+ /* Turn this into a proper fd, if it is currently O_PATH */
+ fd = fd_reopen_condition(fd, O_RDONLY|O_CLOEXEC, O_PATH, &real_fd);
+ if (fd < 0)
+ return fd;
+
if (subvol_id == 0) {
r = btrfs_is_subvol_fd(fd);
if (r < 0)
}
int btrfs_subvol_auto_qgroup(const char *path, uint64_t subvol_id, bool create_intermediary_qgroup) {
- _cleanup_close_ int fd = -1;
+ _cleanup_close_ int fd = -EBADF;
fd = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
if (fd < 0)