#include "mkdir-label.h"
#include "path-util.h"
#include "process-util.h"
-#include "selinux-util.h"
-#include "stat-util.h"
#include "string-util.h"
#include "strv.h"
-#include "tmpfile-util.h"
+#include "tmpfile-util-label.h"
void edit_file_context_done(EditFileContext *context) {
int r;
static int create_edit_temp_file(EditFile *e) {
_cleanup_(unlink_and_freep) char *temp = NULL;
+ _cleanup_fclose_ FILE *f = NULL;
+ const char *source;
+ bool has_original, has_target;
unsigned line = 1;
int r;
if (e->temp)
return 0;
- r = tempfn_random(e->path, NULL, &temp);
+ r = mkdir_parents_label(e->path, 0755);
if (r < 0)
- return log_error_errno(r, "Failed to determine temporary filename for \"%s\": %m", e->path);
+ return log_error_errno(r, "Failed to create parent directories for '%s': %m", e->path);
- r = mkdir_parents_label(e->path, 0755);
+ r = fopen_temporary_label(e->path, e->path, &f, &temp);
if (r < 0)
- return log_error_errno(r, "Failed to create parent directories for \"%s\": %m", e->path);
+ return log_error_errno(r, "Failed to create temporary file for '%s': %m", e->path);
- if (!e->original_path && !e->comment_paths) {
- r = mac_selinux_create_file_prepare(e->path, S_IFREG);
- if (r < 0)
- return r;
+ if (fchmod(fileno(f), 0644) < 0)
+ return log_error_errno(errno, "Failed to change mode of temporary file '%s': %m", temp);
- r = touch(temp);
- mac_selinux_create_file_clear();
- if (r < 0)
- return log_error_errno(r, "Failed to create temporary file \"%s\": %m", temp);
- }
+ has_original = e->original_path && access(e->original_path, F_OK) >= 0;
+ has_target = access(e->path, F_OK) >= 0;
- if (e->original_path) {
- r = mac_selinux_create_file_prepare(e->path, S_IFREG);
- if (r < 0)
- return r;
-
- r = copy_file(e->original_path, temp, 0, 0644, COPY_REFLINK);
- if (r == -ENOENT) {
- r = touch(temp);
- mac_selinux_create_file_clear();
- if (r < 0)
- return log_error_errno(r, "Failed to create temporary file \"%s\": %m", temp);
- } else {
- mac_selinux_create_file_clear();
- if (r < 0)
- return log_error_errno(r, "Failed to create temporary file for \"%s\": %m", e->path);
- }
- }
+ if (has_original)
+ source = e->original_path;
+ else if (has_target)
+ source = e->path;
+ else
+ source = NULL;
if (e->comment_paths) {
- _cleanup_free_ char *target_contents = NULL;
- _cleanup_fclose_ FILE *f = NULL;
+ _cleanup_free_ char *source_contents = NULL;
- r = mac_selinux_create_file_prepare(e->path, S_IFREG);
- if (r < 0)
- return r;
-
- f = fopen(temp, "we");
- mac_selinux_create_file_clear();
- if (!f)
- return log_error_errno(errno, "Failed to open temporary file \"%s\": %m", temp);
-
- if (fchmod(fileno(f), 0644) < 0)
- return log_error_errno(errno, "Failed to change mode of temporary file \"%s\": %m", temp);
-
- r = read_full_file(e->path, &target_contents, NULL);
- if (r < 0 && r != -ENOENT)
- return log_error_errno(r, "Failed to read target file \"%s\": %m", e->path);
+ if (source) {
+ r = read_full_file(source, &source_contents, NULL);
+ if (r < 0)
+ return log_error_errno(r, "Failed to read source file '%s': %m", source);
+ }
fprintf(f,
"### Editing %s\n"
"%s\n",
e->path,
e->context->marker_start,
- strempty(target_contents),
- target_contents && endswith(target_contents, "\n") ? "" : "\n",
+ strempty(source_contents),
+ source_contents && endswith(source_contents, "\n") ? "" : "\n",
e->context->marker_end);
line = 4; /* Start editing at the contents area */
- /* Add a comment with the contents of the original files */
STRV_FOREACH(path, e->comment_paths) {
- _cleanup_free_ char *contents = NULL;
+ _cleanup_free_ char *comment = NULL;
- /* Skip the file that's being edited, already processed in above */
- if (path_equal(*path, e->path))
+ /* Skip the file which is being edited and the source file (can be the same) */
+ if (PATH_IN_SET(*path, e->path, source))
continue;
- r = read_full_file(*path, &contents, NULL);
+ r = read_full_file(*path, &comment, NULL);
if (r < 0)
- return log_error_errno(r, "Failed to read original file \"%s\": %m", *path);
+ return log_error_errno(r, "Failed to read comment file '%s': %m", *path);
fprintf(f, "\n\n### %s", *path);
- if (!isempty(contents)) {
- _cleanup_free_ char *commented_contents = NULL;
- commented_contents = strreplace(strstrip(contents), "\n", "\n# ");
- if (!commented_contents)
+ if (!isempty(comment)) {
+ _cleanup_free_ char *c = NULL;
+
+ c = strreplace(strstrip(comment), "\n", "\n# ");
+ if (!c)
return log_oom();
- fprintf(f, "\n# %s", commented_contents);
+ fprintf(f, "\n# %s", c);
}
}
-
- r = fflush_and_check(f);
- if (r < 0)
- return log_error_errno(r, "Failed to create temporary file \"%s\": %m", temp);
+ } else if (source) {
+ r = copy_file_fd(source, fileno(f), COPY_REFLINK);
+ if (r < 0) {
+ assert(r != -ENOENT);
+ return log_error_errno(r, "Failed to copy file '%s' to temporary file '%s': %m", source, temp);
+ }
}
+ r = fflush_and_check(f);
+ if (r < 0)
+ return log_error_errno(r, "Failed to write to temporary file '%s': %m", temp);
+
e->temp = TAKE_PTR(temp);
e->line = line;