/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- Copyright © 2010 Kay Sievers
-***/
#include <errno.h>
#include <fcntl.h>
static int fd_set_perms(Item *i, int fd, const struct stat *st) {
_cleanup_free_ char *path = NULL;
+ struct stat stbuf;
int r;
assert(i);
if (!i->mode_set && !i->uid_set && !i->gid_set)
goto shortcut;
+ if (!st) {
+ if (fstat(fd, &stbuf) < 0)
+ return log_error_errno(errno, "fstat(%s) failed: %m", path);
+ st = &stbuf;
+ }
+
if (hardlink_vulnerable(st)) {
log_error("Refusing to set permissions on hardlinked file %s while the fs.protected_hardlinks sysctl is turned off.", path);
return -EPERM;
static int path_set_perms(Item *i, const char *path) {
_cleanup_close_ int fd = -1;
- struct stat st;
+ struct stat stbuf, *st = NULL;
assert(i);
assert(path);
return r;
}
- if (fstat(fd, &st) < 0)
- return log_error_errno(errno, "Failed to fstat() file %s: %m", path);
+ if (i->type == EMPTY_DIRECTORY) {
+ /* FIXME: introduce fd_is_dir() helper ? */
+ if (fstat(fd, &stbuf) < 0)
+ return log_error_errno(errno, "Failed to fstat() file %s: %m", path);
+
+ if (!S_ISDIR(stbuf.st_mode)) {
+ log_error("'%s' already exists and is not a directory. ", path);
+ return -EEXIST;
+ }
- if (i->type == EMPTY_DIRECTORY && !S_ISDIR(st.st_mode))
- return log_error_errno(EEXIST, "'%s' already exists and is not a directory. ", path);
+ st = &stbuf;
+ }
- return fd_set_perms(i, fd, &st);
+ return fd_set_perms(i, fd, st);
}
static int parse_xattrs_from_arg(Item *i) {
#if HAVE_ACL
char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
_cleanup_free_ char *path = NULL;
+ struct stat stbuf;
assert(item);
assert(fd);
- assert(st);
r = fd_get_path(fd, &path);
if (r < 0)
return r;
+ if (!st) {
+ if (fstat(fd, &stbuf) < 0)
+ return log_error_errno(errno, "fstat(%s) failed: %m", path);
+ st = &stbuf;
+ }
+
if (hardlink_vulnerable(st)) {
log_error("Refusing to set ACLs on hardlinked file %s while the fs.protected_hardlinks sysctl is turned off.", path);
return -EPERM;
if (item->acl_access)
r = path_set_acl(procfs_path, path, ACL_TYPE_ACCESS, item->acl_access, item->force);
- if (r == 0 && item->acl_default)
+ /* set only default acls to folders */
+ if (r == 0 && item->acl_default && S_ISDIR(st->st_mode))
r = path_set_acl(procfs_path, path, ACL_TYPE_DEFAULT, item->acl_default, item->force);
if (r > 0)
static int path_set_acls(Item *item, const char *path) {
int r = 0;
-#ifdef HAVE_ACL
+#if HAVE_ACL
_cleanup_close_ int fd = -1;
- struct stat st;
assert(item);
assert(path);
if (fd < 0)
return log_error_errno(errno, "Adjusting ACL of %s failed: %m", path);
- if (fstat(fd, &st) < 0)
- return log_error_errno(errno, "Failed to fstat() file %s: %m", path);
-
- r = fd_set_acls(item, fd, &st);
- #endif
- return r;
- }
+ r = fd_set_acls(item, fd, NULL);
+#endif
+ return r;
+}
#define ATTRIBUTES_ALL \
(FS_NOATIME_FL | \
static int fd_set_attribute(Item *item, int fd, const struct stat *st) {
_cleanup_close_ int procfs_fd = -1;
_cleanup_free_ char *path = NULL;
+ struct stat stbuf;
unsigned f;
int r;
if (r < 0)
return r;
+ if (!st) {
+ if (fstat(fd, &stbuf) < 0)
+ return log_error_errno(errno, "fstat(%s) failed: %m", path);
+ st = &stbuf;
+ }
+
/* Issuing the file attribute ioctls on device nodes is not
* safe, as that will be delivered to the drivers, not the
* file system containing the device node. */
static int path_set_attribute(Item *item, const char *path) {
_cleanup_close_ int fd = -1;
- struct stat st;
if (!item->attribute_set || item->attribute_mask == 0)
return 0;
if (fd < 0)
return log_error_errno(errno, "Cannot open '%s': %m", path);
- if (fstat(fd, &st) < 0)
- return log_error_errno(errno, "Cannot stat '%s': %m", path);
-
- return fd_set_attribute(item, fd, &st);
+ return fd_set_attribute(item, fd, NULL);
}
static int write_one_file(Item *i, const char *path) {
typedef int (*action_t)(Item *, const char *);
typedef int (*fdaction_t)(Item *, int fd, const struct stat *st);
-static int item_do(Item *i, int fd, const struct stat *st, fdaction_t action) {
+static int item_do(Item *i, int fd, fdaction_t action) {
+ struct stat st;
int r = 0, q;
assert(i);
assert(fd >= 0);
- assert(st);
+
+ if (fstat(fd, &st) < 0) {
+ r = -errno;
+ goto finish;
+ }
/* This returns the first error we run into, but nevertheless
* tries to go on */
- r = action(i, fd, st);
+ r = action(i, fd, &st);
- if (S_ISDIR(st->st_mode)) {
+ if (S_ISDIR(st.st_mode)) {
char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
_cleanup_closedir_ DIR *d = NULL;
struct dirent *de;
}
FOREACH_DIRENT_ALL(de, d, q = -errno; goto finish) {
- struct stat de_st;
int de_fd;
if (dot_or_dot_dot(de->d_name))
continue;
de_fd = openat(fd, de->d_name, O_NOFOLLOW|O_CLOEXEC|O_PATH);
- if (de_fd >= 0 && fstat(de_fd, &de_st) >= 0)
+ if (de_fd >= 0)
/* pass ownership of dirent fd over */
- q = item_do(i, de_fd, &de_st, action);
+ q = item_do(i, de_fd, action);
else
q = -errno;
STRV_FOREACH(fn, g.gl_pathv) {
_cleanup_close_ int fd = -1;
- struct stat st;
/* Make sure we won't trigger/follow file object (such as
* device nodes, automounts, ...) pointed out by 'fn' with
continue;
}
- if (fstat(fd, &st) < 0) {
- r = r ?: -errno;
- continue;
- }
-
- k = item_do(i, fd, &st, action);
+ k = item_do(i, fd, action);
if (k < 0 && r == 0)
r = k;