* it: the IMMUTABLE bit. Let's use this here, if this is requested. */
if (flags & BTRFS_SNAPSHOT_FALLBACK_IMMUTABLE)
- (void) chattr_path(new_path, FS_IMMUTABLE_FL, FS_IMMUTABLE_FL);
+ (void) chattr_path(new_path, FS_IMMUTABLE_FL, FS_IMMUTABLE_FL, NULL);
} else {
r = btrfs_subvol_set_read_only(new_path, true);
if (r < 0)
#include "fd-util.h"
#include "macro.h"
-int chattr_fd(int fd, unsigned value, unsigned mask) {
+int chattr_fd(int fd, unsigned value, unsigned mask, unsigned *previous) {
unsigned old_attr, new_attr;
struct stat st;
if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode))
return -ENOTTY;
- if (mask == 0)
+ if (mask == 0 && !previous)
return 0;
if (ioctl(fd, FS_IOC_GETFLAGS, &old_attr) < 0)
return -errno;
new_attr = (old_attr & ~mask) | (value & mask);
- if (new_attr == old_attr)
+ if (new_attr == old_attr) {
+ if (previous)
+ *previous = old_attr;
return 0;
+ }
if (ioctl(fd, FS_IOC_SETFLAGS, &new_attr) < 0)
return -errno;
+ if (previous)
+ *previous = old_attr;
+
return 1;
}
-int chattr_path(const char *p, unsigned value, unsigned mask) {
+int chattr_path(const char *p, unsigned value, unsigned mask, unsigned *previous) {
_cleanup_close_ int fd = -1;
assert(p);
if (fd < 0)
return -errno;
- return chattr_fd(fd, value, mask);
+ return chattr_fd(fd, value, mask, previous);
}
int read_attr_fd(int fd, unsigned *ret) {
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-int chattr_fd(int fd, unsigned value, unsigned mask);
-int chattr_path(const char *p, unsigned value, unsigned mask);
+int chattr_fd(int fd, unsigned value, unsigned mask, unsigned *previous);
+int chattr_path(const char *p, unsigned value, unsigned mask, unsigned *previous);
int read_attr_fd(int fd, unsigned *ret);
int read_attr_path(const char *p, unsigned *ret);
}
if (chattr_flags != 0)
- (void) chattr_fd(fdt, chattr_flags, (unsigned) -1);
+ (void) chattr_fd(fdt, chattr_flags, (unsigned) -1, NULL);
r = copy_file_fd(from, fdt, copy_flags);
if (r < 0) {
}
if (chattr_flags != 0)
- (void) chattr_fd(fdt, chattr_flags, (unsigned) -1);
+ (void) chattr_fd(fdt, chattr_flags, (unsigned) -1, NULL);
r = copy_file_fd(from, fdt, copy_flags);
if (r < 0)
if (converted_fd < 0)
return log_error_errno(errno, "Failed to create %s: %m", t);
- r = chattr_fd(converted_fd, FS_NOCOW_FL, FS_NOCOW_FL);
+ r = chattr_fd(converted_fd, FS_NOCOW_FL, FS_NOCOW_FL, NULL);
if (r < 0)
log_warning_errno(r, "Failed to set file attributes on %s: %m", t);
if (i->output_fd < 0)
return log_error_errno(errno, "Failed to open destination %s: %m", i->temp_path);
- r = chattr_fd(i->output_fd, FS_NOCOW_FL, FS_NOCOW_FL);
+ r = chattr_fd(i->output_fd, FS_NOCOW_FL, FS_NOCOW_FL, NULL);
if (r < 0)
log_warning_errno(r, "Failed to set file attributes on %s: %m", i->temp_path);
if (converted_fd < 0)
return log_error_errno(errno, "Failed to create %s: %m", t);
- r = chattr_fd(converted_fd, FS_NOCOW_FL, FS_NOCOW_FL);
+ r = chattr_fd(converted_fd, FS_NOCOW_FL, FS_NOCOW_FL, NULL);
if (r < 0)
log_warning_errno(r, "Failed to set file attributes on %s: %m", t);
* performance on COW file systems like btrfs, since it
* reduces fragmentation caused by not allowing in-place
* writes. */
- r = chattr_fd(dfd, FS_NOCOW_FL, FS_NOCOW_FL);
+ r = chattr_fd(dfd, FS_NOCOW_FL, FS_NOCOW_FL, NULL);
if (r < 0)
log_warning_errno(r, "Failed to set file attributes on %s: %m", tp);
if (r < 0)
return r;
- r = chattr_fd(j->disk_fd, FS_NOCOW_FL, FS_NOCOW_FL);
+ r = chattr_fd(j->disk_fd, FS_NOCOW_FL, FS_NOCOW_FL, NULL);
if (r < 0)
log_warning_errno(r, "Failed to set file attributes on %s, ignoring: %m", i->temp_path);
* reenable all the good bits COW usually provides
* (such as data checksumming). */
- (void) chattr_fd(f->fd, 0, FS_NOCOW_FL);
+ (void) chattr_fd(f->fd, 0, FS_NOCOW_FL, NULL);
(void) btrfs_defrag_fd(f->fd);
}
/* btrfs doesn't cope well with our write pattern and
* fragments heavily. Let's defrag all files we rotate */
- (void) chattr_path(p, 0, FS_NOCOW_FL);
+ (void) chattr_path(p, 0, FS_NOCOW_FL, NULL);
(void) btrfs_defrag(p);
log_warning_errno(r, "File %s corrupted or uncleanly shut down, renaming and replacing.", fname);
/* Enable secure remove, exclusion from dump, synchronous
* writing and in-place updating */
- r = chattr_fd(fd, FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL, FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL);
+ r = chattr_fd(fd, FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL, FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL, NULL);
if (r < 0)
log_warning_errno(r, "Failed to set file attributes: %m");
case IMAGE_DIRECTORY:
/* Allow deletion of read-only directories */
- (void) chattr_path(i->path, 0, FS_IMMUTABLE_FL);
+ (void) chattr_path(i->path, 0, FS_IMMUTABLE_FL, NULL);
r = rm_rf(i->path, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
if (r < 0)
return r;
(void) read_attr_path(i->path, &file_attr);
if (file_attr & FS_IMMUTABLE_FL)
- (void) chattr_path(i->path, 0, FS_IMMUTABLE_FL);
+ (void) chattr_path(i->path, 0, FS_IMMUTABLE_FL, NULL);
_fallthrough_;
case IMAGE_SUBVOLUME:
/* Restore the immutable bit, if it was set before */
if (file_attr & FS_IMMUTABLE_FL)
- (void) chattr_path(new_path, FS_IMMUTABLE_FL, FS_IMMUTABLE_FL);
+ (void) chattr_path(new_path, FS_IMMUTABLE_FL, FS_IMMUTABLE_FL, NULL);
free_and_replace(i->path, new_path);
free_and_replace(i->name, nn);
a read-only subvolume, but at least something, and
we can read the value back. */
- r = chattr_path(i->path, b ? FS_IMMUTABLE_FL : 0, FS_IMMUTABLE_FL);
+ r = chattr_path(i->path, b ? FS_IMMUTABLE_FL : 0, FS_IMMUTABLE_FL, NULL);
if (r < 0)
return r;
if (procfs_fd < 0)
return log_error_errno(procfs_fd, "Failed to re-open '%s': %m", path);
- r = chattr_fd(procfs_fd, f, item->attribute_mask);
+ r = chattr_fd(procfs_fd, f, item->attribute_mask, NULL);
if (r < 0)
log_full_errno(IN_SET(r, -ENOTTY, -EOPNOTSUPP) ? LOG_DEBUG : LOG_WARNING,
r,