From d44d81dcd15345b099357721024dc1cd76cfceab Mon Sep 17 00:00:00 2001 From: Luca BRUNO Date: Fri, 10 Jun 2022 12:00:51 +0000 Subject: [PATCH] libpriv/importer: move tmpfiles.d entries buffering to Rust This moves the RPM importer buffering logic for tmpfiles.d entries to Rust. --- rust/src/importer.rs | 42 +++++++++++++++++++++++++++++- rust/src/lib.rs | 10 ++++++- src/libpriv/rpmostree-importer.cxx | 23 +++++----------- 3 files changed, 57 insertions(+), 18 deletions(-) diff --git a/rust/src/importer.rs b/rust/src/importer.rs index eb10acd1f3..81ae02fc3f 100644 --- a/rust/src/importer.rs +++ b/rust/src/importer.rs @@ -61,6 +61,8 @@ pub struct RpmImporter { /// - [K] absolute full path of the file /// - [V] iterator index in RPM header for this file rpmfi_overrides: HashMap, + /// Filepaths translated to tmpfiles.d entries. + tmpfiles_entries: Vec, } /// Build a new RPM importer for a given package. @@ -102,6 +104,7 @@ impl RpmImporter { pkg_name: pkg_name.to_string(), varlib_direntries: BTreeSet::new(), rpmfi_overrides: HashMap::new(), + tmpfiles_entries: vec![], }; Ok(importer) } @@ -176,7 +179,7 @@ impl RpmImporter { /// Format tmpfiles.d lines for symlinked entries. // NOTE(lucab): destinations (dirname) can't be quoted as systemd just // parses the remainder of the line, and doesn't expand quotes. - pub fn tmpfiles_symlink_entries(&self) -> Vec { + fn tmpfiles_symlink_entries(&self) -> Vec { // /opt/ symlinks let opt_entries = self.opt_direntries.iter().map(|dirname| { let quoted = crate::maybe_shell_quote(&format!("/opt/{dirname}")); @@ -251,6 +254,43 @@ impl RpmImporter { x => unreachable!("unknown commit result '{}' for path '{}'", x, path), } } + + /// Translate a filepath to an equivalent tmpfiles.d line. + pub fn translate_to_tmpfiles_entry( + &mut self, + abs_path: &str, + mut file_info: Pin<&mut crate::FFIGFileInfo>, + username: &str, + groupname: &str, + ) -> CxxResult<()> { + let file_info = file_info.gobj_wrap(); + let entry = translate_to_tmpfiles_d(abs_path, &file_info, username, groupname)?; + self.tmpfiles_entries.push(entry); + Ok(()) + } + + /// Return whether this RPM has any auto-translated tmpfiles.d entries. + pub fn has_tmpfiles_entries(&self) -> bool { + self.tmpfiles_entries + .len() + .saturating_add(self.opt_direntries.len()) + .saturating_add(self.varlib_direntries.len()) + > 0 + } + + /// Serialize all tmpfiles.d entries as a single configuration fragment. + pub fn serialize_tmpfiles_content(&self) -> String { + let mut buf = String::new(); + + let symlink_entries = self.tmpfiles_symlink_entries(); + let all_entries = symlink_entries.iter().chain(self.tmpfiles_entries.iter()); + + for entry in all_entries { + buf.push_str(&entry); + buf.push('\n'); + } + buf + } } /// Canonicalize a path, e.g. replace `//` with `/` and `././` with `./`. diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 57b0d89e66..6abfabbbbe 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -349,7 +349,6 @@ pub mod ffi { fn handle_translate_pathname(self: &mut RpmImporter, path: &str) -> String; fn ostree_branch(self: &RpmImporter) -> String; fn pkg_name(self: &RpmImporter) -> String; - fn tmpfiles_symlink_entries(self: &RpmImporter) -> Vec; fn doc_files_are_filtered(self: &RpmImporter) -> bool; fn doc_files_insert(self: &mut RpmImporter, path: &str); fn doc_files_contains(self: &RpmImporter, path: &str) -> bool; @@ -363,6 +362,15 @@ pub mod ffi { path: &str, mut file_info: Pin<&mut GFileInfo>, ) -> Result; + fn translate_to_tmpfiles_entry( + self: &mut RpmImporter, + abs_path: &str, + mut file_info: Pin<&mut GFileInfo>, + username: &str, + groupname: &str, + ) -> Result<()>; + fn has_tmpfiles_entries(self: &RpmImporter) -> bool; + fn serialize_tmpfiles_content(self: &RpmImporter) -> String; fn tmpfiles_translate( abs_path: &str, diff --git a/src/libpriv/rpmostree-importer.cxx b/src/libpriv/rpmostree-importer.cxx index a25efda7c1..3a7f7a0205 100644 --- a/src/libpriv/rpmostree-importer.cxx +++ b/src/libpriv/rpmostree-importer.cxx @@ -61,7 +61,6 @@ struct RpmOstreeImporter Header hdr; rpmfi fi; off_t cpio_offset; - GString *tmpfiles_d; DnfPackage *pkg; std::optional > importer_rs; @@ -80,7 +79,6 @@ rpmostree_importer_finalize (GObject *object) if (self->fi) (void)rpmfiFree (self->fi); glnx_close_fd (&self->fd); - g_string_free (self->tmpfiles_d, TRUE); g_clear_object (&self->repo); g_clear_object (&self->sepolicy); @@ -101,7 +99,6 @@ static void rpmostree_importer_init (RpmOstreeImporter *self) { self->fd = -1; - self->tmpfiles_d = g_string_new (""); self->importer_rs = std::nullopt; } @@ -497,13 +494,9 @@ compose_filter_cb (OstreeRepo *repo, const char *path, GFileInfo *file_info, gpo const char *group = NULL; get_rpmfi_override (self, path, &user, &group, NULL, NULL); - auto entry = ROSCXX_VAL ( - tmpfiles_translate (path, *file_info, user ?: "root", group ?: "root"), error); - if (entry.has_value ()) - { - g_string_append (self->tmpfiles_d, entry.value ().c_str ()); - g_string_append_c (self->tmpfiles_d, '\n'); - } + CXX ((*self->importer_rs) + ->translate_to_tmpfiles_entry (path, *file_info, user ?: "root", group ?: "root"), + error); return OSTREE_REPO_COMMIT_FILTER_SKIP; } @@ -607,9 +600,6 @@ import_rpm_to_repo (RpmOstreeImporter *self, char **out_csum, char **out_metadat return FALSE; } - for (auto &line : (*self->importer_rs)->tmpfiles_symlink_entries ()) - g_string_append_printf (self->tmpfiles_d, "%s\n", line.c_str ()); - /* Handle any data we've accumulated to write to tmpfiles.d. * I originally tried to do this entirely in memory but things * like selinux labeling only happen as callbacks out of using @@ -618,8 +608,9 @@ import_rpm_to_repo (RpmOstreeImporter *self, char **out_csum, char **out_metadat g_auto (GLnxTmpDir) tmpdir = { 0, }; - if (self->tmpfiles_d->len > 0) + if ((*self->importer_rs)->has_tmpfiles_entries ()) { + auto content = (*self->importer_rs)->serialize_tmpfiles_content (); auto pkg_name = (*self->importer_rs)->pkg_name (); if (!glnx_mkdtemp ("rpm-ostree-import.XXXXXX", 0700, &tmpdir, error)) @@ -628,8 +619,8 @@ import_rpm_to_repo (RpmOstreeImporter *self, char **out_csum, char **out_metadat return FALSE; if (!glnx_file_replace_contents_at ( tmpdir.fd, glnx_strjoina ("usr/lib/tmpfiles.d/", "pkg-", pkg_name.c_str (), ".conf"), - (guint8 *)self->tmpfiles_d->str, self->tmpfiles_d->len, GLNX_FILE_REPLACE_NODATASYNC, - cancellable, error)) + (guint8 *)content.data (), content.size (), GLNX_FILE_REPLACE_NODATASYNC, cancellable, + error)) return FALSE; if (!ostree_repo_write_dfd_to_mtree (repo, tmpdir.fd, ".", mtree, modifier, cancellable,