mirror of
https://github.com/morgan9e/systemd
synced 2026-04-15 00:47:10 +09:00
Now that the necessary functions from log.h have been moved to macro.h, we can stop including log.h in macro.h. This requires modifying source files all over the tree to include log.h instead.
161 lines
5.0 KiB
C
161 lines
5.0 KiB
C
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
|
|
|
#include <fcntl.h>
|
|
#include <sys/stat.h>
|
|
|
|
#include "fd-util.h"
|
|
#include "fs-util.h"
|
|
#include "log.h"
|
|
#include "path-util.h"
|
|
#include "sync-util.h"
|
|
|
|
int fsync_directory_of_file(int fd) {
|
|
_cleanup_close_ int dfd = -EBADF;
|
|
struct stat st;
|
|
int r;
|
|
|
|
assert(fd >= 0);
|
|
|
|
/* We only reasonably can do this for regular files and directories, or for O_PATH fds, hence check
|
|
* for the inode type first */
|
|
if (fstat(fd, &st) < 0)
|
|
return -errno;
|
|
|
|
if (S_ISDIR(st.st_mode)) {
|
|
dfd = openat(fd, "..", O_RDONLY|O_DIRECTORY|O_CLOEXEC, 0);
|
|
if (dfd < 0)
|
|
return -errno;
|
|
|
|
} else if (!S_ISREG(st.st_mode)) { /* Regular files are OK regardless if O_PATH or not, for all other
|
|
* types check O_PATH flag */
|
|
r = fd_is_opath(fd);
|
|
if (r < 0)
|
|
return r;
|
|
if (!r) /* If O_PATH this refers to the inode in the fs, in which case we can sensibly do
|
|
* what is requested. Otherwise this refers to a socket, fifo or device node, where
|
|
* the concept of a containing directory doesn't make too much sense. */
|
|
return -ENOTTY;
|
|
}
|
|
|
|
if (dfd < 0) {
|
|
_cleanup_free_ char *path = NULL;
|
|
|
|
r = fd_get_path(fd, &path);
|
|
if (r < 0) {
|
|
log_debug_errno(r, "Failed to query /proc/self/fd/%d%s: %m",
|
|
fd,
|
|
r == -ENOSYS ? ", ignoring" : "");
|
|
|
|
if (r == -ENOSYS)
|
|
/* If /proc is not available, we're most likely running in some
|
|
* chroot environment, and syncing the directory is not very
|
|
* important in that case. Let's just silently do nothing. */
|
|
return 0;
|
|
|
|
return r;
|
|
}
|
|
|
|
if (!path_is_absolute(path))
|
|
return -EINVAL;
|
|
|
|
dfd = open_parent(path, O_CLOEXEC|O_NOFOLLOW, 0);
|
|
if (dfd < 0)
|
|
return dfd;
|
|
}
|
|
|
|
return RET_NERRNO(fsync(dfd));
|
|
}
|
|
|
|
int fsync_full(int fd) {
|
|
int r, q;
|
|
|
|
/* Sync both the file and the directory */
|
|
|
|
r = RET_NERRNO(fsync(fd));
|
|
|
|
q = fsync_directory_of_file(fd);
|
|
if (r < 0) /* Return earlier error */
|
|
return r;
|
|
if (q == -ENOTTY) /* Ignore if the 'fd' refers to a block device or so which doesn't really have a
|
|
* parent dir */
|
|
return 0;
|
|
return q;
|
|
}
|
|
|
|
int fsync_path_at(int at_fd, const char *path) {
|
|
_cleanup_close_ int opened_fd = -EBADF;
|
|
int fd;
|
|
|
|
if (isempty(path)) {
|
|
if (at_fd == AT_FDCWD) {
|
|
opened_fd = open(".", O_RDONLY|O_DIRECTORY|O_CLOEXEC);
|
|
if (opened_fd < 0)
|
|
return -errno;
|
|
|
|
fd = opened_fd;
|
|
} else
|
|
fd = at_fd;
|
|
} else {
|
|
opened_fd = openat(at_fd, path, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
|
|
if (opened_fd < 0)
|
|
return -errno;
|
|
|
|
fd = opened_fd;
|
|
}
|
|
|
|
return RET_NERRNO(fsync(fd));
|
|
}
|
|
|
|
int fsync_parent_at(int at_fd, const char *path) {
|
|
_cleanup_close_ int opened_fd = -EBADF;
|
|
|
|
if (isempty(path)) {
|
|
if (at_fd != AT_FDCWD)
|
|
return fsync_directory_of_file(at_fd);
|
|
|
|
opened_fd = open("..", O_RDONLY|O_DIRECTORY|O_CLOEXEC);
|
|
if (opened_fd < 0)
|
|
return -errno;
|
|
|
|
return RET_NERRNO(fsync(opened_fd));
|
|
}
|
|
|
|
opened_fd = openat(at_fd, path, O_PATH|O_CLOEXEC|O_NOFOLLOW);
|
|
if (opened_fd < 0)
|
|
return -errno;
|
|
|
|
return fsync_directory_of_file(opened_fd);
|
|
}
|
|
|
|
int fsync_path_and_parent_at(int at_fd, const char *path) {
|
|
_cleanup_close_ int opened_fd = -EBADF;
|
|
|
|
if (isempty(path)) {
|
|
if (at_fd != AT_FDCWD)
|
|
return fsync_full(at_fd);
|
|
|
|
opened_fd = open(".", O_RDONLY|O_DIRECTORY|O_CLOEXEC);
|
|
} else
|
|
opened_fd = openat(at_fd, path, O_RDONLY|O_NOFOLLOW|O_NONBLOCK|O_CLOEXEC);
|
|
if (opened_fd < 0)
|
|
return -errno;
|
|
|
|
return fsync_full(opened_fd);
|
|
}
|
|
|
|
int syncfs_path(int at_fd, const char *path) {
|
|
_cleanup_close_ int fd = -EBADF;
|
|
|
|
if (isempty(path)) {
|
|
if (at_fd != AT_FDCWD)
|
|
return RET_NERRNO(syncfs(at_fd));
|
|
|
|
fd = open(".", O_RDONLY|O_DIRECTORY|O_CLOEXEC);
|
|
} else
|
|
fd = openat(at_fd, path, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
|
|
if (fd < 0)
|
|
return -errno;
|
|
|
|
return RET_NERRNO(syncfs(fd));
|
|
}
|