/** * ostree_repo_checkout_gc: * @self: Repo * @cancellable: Cancellable * @error: Error * * Call this after finishing a succession of checkout operations; it * will delete any currently-unused uncompressed objects from the * cache. */ gboolean ostree_repo_checkout_gc (OstreeRepo *self, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; g_autoptr(GHashTable) to_clean_dirs = NULL; GHashTableIter iter; gpointer key, value; g_mutex_lock (&self->cache_lock); to_clean_dirs = self->updated_uncompressed_dirs; self->updated_uncompressed_dirs = g_hash_table_new (NULL, NULL); g_mutex_unlock (&self->cache_lock); if (to_clean_dirs) g_hash_table_iter_init (&iter, to_clean_dirs); while (to_clean_dirs && g_hash_table_iter_next (&iter, &key, &value)) { g_autoptr(GFile) objdir = NULL; g_autoptr(GFileEnumerator) enumerator = NULL; g_autofree char *objdir_name = NULL; objdir_name = g_strdup_printf ("%02x", GPOINTER_TO_UINT (key)); objdir = g_file_get_child (self->uncompressed_objects_dir, objdir_name); enumerator = g_file_enumerate_children (objdir, "standard::name,standard::type,unix::inode,unix::nlink", G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, cancellable, error); if (!enumerator) goto out; while (TRUE) { GFileInfo *file_info; guint32 nlinks; if (!gs_file_enumerator_iterate (enumerator, &file_info, NULL, cancellable, error)) goto out; if (file_info == NULL) break; nlinks = g_file_info_get_attribute_uint32 (file_info, "unix::nlink"); if (nlinks == 1) { g_autoptr(GFile) objpath = NULL; objpath = g_file_get_child (objdir, g_file_info_get_name (file_info)); if (!gs_file_unlink (objpath, cancellable, error)) goto out; } } } ret = TRUE; out: return ret; }
static gboolean list_all_deployment_directories (OstreeSysroot *self, GPtrArray **out_deployments, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; gs_unref_object GFileEnumerator *dir_enum = NULL; gs_unref_object GFile *deploydir = NULL; gs_unref_ptrarray GPtrArray *ret_deployments = NULL; GError *temp_error = NULL; deploydir = g_file_resolve_relative_path (self->path, "ostree/deploy"); ret_deployments = g_ptr_array_new_with_free_func (g_object_unref); dir_enum = g_file_enumerate_children (deploydir, OSTREE_GIO_FAST_QUERYINFO, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, cancellable, &temp_error); if (!dir_enum) { if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) { g_clear_error (&temp_error); goto done; } else { g_propagate_error (error, temp_error); goto out; } } while (TRUE) { GFileInfo *file_info = NULL; GFile *child = NULL; if (!gs_file_enumerator_iterate (dir_enum, &file_info, &child, NULL, error)) goto out; if (file_info == NULL) break; if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_DIRECTORY) continue; if (!_ostree_sysroot_list_deployment_dirs_for_os (child, ret_deployments, cancellable, error)) goto out; } done: ret = TRUE; ot_transfer_out_value (out_deployments, &ret_deployments); out: return ret; }
static gboolean relabel_recursively (OstreeSePolicy *sepolicy, GFile *dir, GFileInfo *dir_info, GPtrArray *path_parts, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; g_autoptr(GFileEnumerator) direnum = NULL; if (!relabel_one_path (sepolicy, dir, dir_info, path_parts, cancellable, error)) goto out; direnum = g_file_enumerate_children (dir, OSTREE_GIO_FAST_QUERYINFO, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, cancellable, error); if (!direnum) goto out; while (TRUE) { GFileInfo *file_info; GFile *child; GFileType ftype; if (!gs_file_enumerator_iterate (direnum, &file_info, &child, cancellable, error)) goto out; if (file_info == NULL) break; g_ptr_array_add (path_parts, (char*)gs_file_get_basename_cached (child)); ftype = g_file_info_get_file_type (file_info); if (ftype == G_FILE_TYPE_DIRECTORY) { if (!relabel_recursively (sepolicy, child, file_info, path_parts, cancellable, error)) goto out; } else { if (!relabel_one_path (sepolicy, child, file_info, path_parts, cancellable, error)) goto out; } g_ptr_array_remove_index (path_parts, path_parts->len - 1); } ret = TRUE; out: return ret; }
static gboolean enumerate_refs_recurse (OstreeRepo *repo, const char *remote, GFile *base, GFile *dir, GHashTable *refs, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; g_autoptr(GFileEnumerator) enumerator = NULL; enumerator = g_file_enumerate_children (dir, OSTREE_GIO_FAST_QUERYINFO, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, cancellable, error); if (!enumerator) goto out; while (TRUE) { GFileInfo *file_info = NULL; GFile *child = NULL; if (!gs_file_enumerator_iterate (enumerator, &file_info, &child, NULL, error)) goto out; if (file_info == NULL) break; if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY) { if (!enumerate_refs_recurse (repo, remote, base, child, refs, cancellable, error)) goto out; } else if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR) { if (!add_ref_to_set (remote, base, child, refs, cancellable, error)) goto out; } } ret = TRUE; out: return ret; }
/* Given a directory @d, find the first child that is a directory, * returning it in @out_subdir. If there are multiple directories, * return an error. */ static gboolean find_ensure_one_subdirectory (GFile *d, GFile **out_subdir, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; gs_unref_object GFileEnumerator *direnum = NULL; gs_unref_object GFile *ret_subdir = NULL; direnum = g_file_enumerate_children (d, "standard::name,standard::type", 0, cancellable, error); if (!direnum) goto out; while (TRUE) { GFileInfo *file_info; GFile *child; if (!gs_file_enumerator_iterate (direnum, &file_info, &child, cancellable, error)) goto out; if (!file_info) break; if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY) { if (ret_subdir) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Multiple subdirectories found in: %s", gs_file_get_path_cached (d)); goto out; } ret_subdir = g_object_ref (child); } } ret = TRUE; gs_transfer_out_value (out_subdir, &ret_subdir); out: return ret; }
static gboolean clean_yumdb_extraneous_files (GFile *dir, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; gs_unref_object GFileEnumerator *direnum = NULL; direnum = g_file_enumerate_children (dir, "standard::name,standard::type", G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, cancellable, error); if (!direnum) goto out; while (TRUE) { GFileInfo *file_info; GFile *child; if (!gs_file_enumerator_iterate (direnum, &file_info, &child, cancellable, error)) goto out; if (!file_info) break; if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY) { if (!clean_yumdb_extraneous_files (child, cancellable, error)) goto out; } else if (strcmp (g_file_info_get_name (file_info), "var_uuid") == 0 || strcmp (g_file_info_get_name (file_info), "from_repo_timestamp") == 0 || strcmp (g_file_info_get_name (file_info), "from_repo_revision") == 0) { if (!g_file_delete (child, cancellable, error)) goto out; } } ret = TRUE; out: return ret; }
static gboolean find_ref_in_remotes (OstreeRepo *self, const char *rev, GFile **out_file, GError **error) { gboolean ret = FALSE; g_autoptr(GFileEnumerator) dir_enum = NULL; g_autoptr(GFile) ret_file = NULL; dir_enum = g_file_enumerate_children (self->remote_heads_dir, OSTREE_GIO_FAST_QUERYINFO, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, error); if (!dir_enum) goto out; while (TRUE) { GFileInfo *file_info; GFile *child; if (!gs_file_enumerator_iterate (dir_enum, &file_info, &child, NULL, error)) goto out; if (file_info == NULL) break; if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_DIRECTORY) continue; g_clear_object (&ret_file); ret_file = g_file_resolve_relative_path (child, rev); if (!g_file_query_exists (ret_file, NULL)) g_clear_object (&ret_file); else break; } ret = TRUE; ot_transfer_out_value (out_file, &ret_file); out: return ret; }
static gboolean dir_contains_uid_or_gid (GFile *root, guint32 id, const char *attr, gboolean *out_found_match, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; g_autoptr(GFileInfo) file_info = NULL; guint32 type; guint32 tid; gboolean found_match = FALSE; /* zero it out, just to be sure */ *out_found_match = found_match; file_info = g_file_query_info (root, OSTREE_GIO_FAST_QUERYINFO, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, cancellable, error); if (!file_info) goto out; type = g_file_info_get_file_type (file_info); switch (type) { case G_FILE_TYPE_DIRECTORY: case G_FILE_TYPE_SYMBOLIC_LINK: case G_FILE_TYPE_REGULAR: case G_FILE_TYPE_SPECIAL: tid = g_file_info_get_attribute_uint32 (file_info, attr); if (tid == id) found_match = TRUE; break; case G_FILE_TYPE_UNKNOWN: case G_FILE_TYPE_SHORTCUT: case G_FILE_TYPE_MOUNTABLE: g_assert_not_reached (); break; } /* Now recurse for dirs. */ if (!found_match && type == G_FILE_TYPE_DIRECTORY) { g_autoptr(GFileEnumerator) dir_enum = NULL; g_autoptr(GFileInfo) child_info = NULL; dir_enum = g_file_enumerate_children (root, OSTREE_GIO_FAST_QUERYINFO, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, error); if (!dir_enum) goto out; while (TRUE) { GFileInfo *file_info; GFile *child; if (!gs_file_enumerator_iterate (dir_enum, &file_info, &child, cancellable, error)) goto out; if (!file_info) break; if (!dir_contains_uid_or_gid (child, id, attr, &found_match, cancellable, error)) goto out; if (found_match) break; } } ret = TRUE; *out_found_match = found_match; out: return ret; }
static gboolean cp_internal (GFile *src, GFile *dest, GsCpMode mode, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; GFileEnumerator *enumerator = NULL; GFileInfo *src_info = NULL; GFile *dest_child = NULL; int dest_dfd = -1; int r; enumerator = g_file_enumerate_children (src, "standard::type,standard::name,unix::uid,unix::gid,unix::mode", G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, cancellable, error); if (!enumerator) goto out; src_info = g_file_query_info (src, "standard::name,unix::mode,unix::uid,unix::gid," \ "time::modified,time::modified-usec,time::access,time::access-usec", G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, cancellable, error); if (!src_info) goto out; do r = mkdir (gs_file_get_path_cached (dest), 0755); while (G_UNLIKELY (r == -1 && errno == EINTR)); if (r == -1) { gs_set_error_from_errno (error, errno); goto out; } if (mode != GS_CP_MODE_NONE) { if (!gs_file_open_dir_fd (dest, &dest_dfd, cancellable, error)) goto out; do r = fchown (dest_dfd, g_file_info_get_attribute_uint32 (src_info, "unix::uid"), g_file_info_get_attribute_uint32 (src_info, "unix::gid")); while (G_UNLIKELY (r == -1 && errno == EINTR)); if (r == -1) { gs_set_error_from_errno (error, errno); goto out; } do r = fchmod (dest_dfd, g_file_info_get_attribute_uint32 (src_info, "unix::mode")); while (G_UNLIKELY (r == -1 && errno == EINTR)); { GError *temp_error = NULL; if (!copy_xattrs_from_file_to_fd (src, dest_dfd, cancellable, &temp_error)) { if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED) || g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED)) { g_clear_error (&temp_error); } else { g_propagate_error (error, temp_error); goto out; } } } if (dest_dfd != -1) { (void) close (dest_dfd); dest_dfd = -1; } } while (TRUE) { GFileInfo *file_info = NULL; GFile *src_child = NULL; if (!gs_file_enumerator_iterate (enumerator, &file_info, &src_child, cancellable, error)) goto out; if (!file_info) break; if (dest_child) g_object_unref (dest_child); dest_child = g_file_get_child (dest, g_file_info_get_name (file_info)); if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY) { if (!cp_internal (src_child, dest_child, mode, cancellable, error)) goto out; } else { gboolean did_link = FALSE; (void) unlink (gs_file_get_path_cached (dest_child)); if (mode == GS_CP_MODE_HARDLINK) { if (link (gs_file_get_path_cached (src_child), gs_file_get_path_cached (dest_child)) == -1) { if (!(errno == EMLINK || errno == EXDEV || errno == EPERM)) { gs_set_error_from_errno (error, errno); goto out; } /* We failed to hardlink; fall back to copying all; this will * affect subsequent directory copies too. */ mode = GS_CP_MODE_COPY_ALL; } else did_link = TRUE; } if (!did_link) { GFileCopyFlags copyflags = G_FILE_COPY_OVERWRITE | G_FILE_COPY_NOFOLLOW_SYMLINKS; if (mode == GS_CP_MODE_COPY_ALL) copyflags |= G_FILE_COPY_ALL_METADATA; if (!g_file_copy (src_child, dest_child, copyflags, cancellable, NULL, NULL, error)) goto out; } } } ret = TRUE; out: if (dest_dfd != -1) (void) close (dest_dfd); g_clear_object (&src_info); g_clear_object (&enumerator); g_clear_object (&dest_child); return ret; }
static gboolean migrate_rpm_and_yumdb (GFile *targetroot, GFile *yumroot, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; gs_unref_object GFile *usrbin_rpm = g_file_resolve_relative_path (targetroot, "usr/bin/rpm"); gs_unref_object GFile *legacyrpm_path = g_file_resolve_relative_path (yumroot, "var/lib/rpm"); gs_unref_object GFile *newrpm_path = g_file_resolve_relative_path (targetroot, "usr/share/rpm"); gs_unref_object GFile *src_yum_rpmdb_indexes = g_file_resolve_relative_path (yumroot, "var/lib/yum"); gs_unref_object GFile *target_yum_rpmdb_indexes = g_file_resolve_relative_path (targetroot, "usr/share/yumdb"); gs_unref_object GFile *yumroot_yumlib = g_file_get_child (yumroot, "var/lib/yum"); gs_unref_object GFileEnumerator *direnum = NULL; direnum = g_file_enumerate_children (legacyrpm_path, "standard::name", G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, cancellable, error); if (!direnum) goto out; while (TRUE) { const char *name; GFileInfo *file_info; GFile *child; if (!gs_file_enumerator_iterate (direnum, &file_info, &child, cancellable, error)) goto out; if (!file_info) break; name = g_file_info_get_name (file_info); if (g_str_has_prefix (name, "__db.") || strcmp (name, ".dbenv.lock") == 0 || strcmp (name, ".rpm.lock") == 0) { if (!gs_file_unlink (child, cancellable, error)) goto out; } } (void) g_file_enumerator_close (direnum, cancellable, error); g_print ("Placing RPM db in /usr/share/rpm\n"); if (!gs_file_rename (legacyrpm_path, newrpm_path, cancellable, error)) goto out; /* Move the yum database to usr/share/yumdb; disabled for now due * to bad conflict with OSTree's current * one-http-request-per-file. */ #if 0 if (g_file_query_exists (src_yum_rpmdb_indexes, NULL)) { g_print ("Moving %s to %s\n", gs_file_get_path_cached (src_yum_rpmdb_indexes), gs_file_get_path_cached (target_yum_rpmdb_indexes)); if (!gs_file_rename (src_yum_rpmdb_indexes, target_yum_rpmdb_indexes, cancellable, error)) goto out; if (!clean_yumdb_extraneous_files (target_yum_rpmdb_indexes, cancellable, error)) goto out; } #endif /* Remove /var/lib/yum; we don't want it here. */ if (!gs_shutil_rm_rf (yumroot_yumlib, cancellable, error)) goto out; ret = TRUE; out: return ret; }
static gboolean workaround_selinux_cross_labeling_recurse (GFile *dir, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; gs_unref_object GFileEnumerator *direnum = NULL; direnum = g_file_enumerate_children (dir, "standard::name,standard::type,time::modified,time::access", G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, cancellable, error); if (!direnum) goto out; while (TRUE) { GFileInfo *file_info; GFile *child; const char *name; if (!gs_file_enumerator_iterate (direnum, &file_info, &child, cancellable, error)) goto out; if (!file_info) break; name = g_file_info_get_name (file_info); if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY) { if (!workaround_selinux_cross_labeling_recurse (child, cancellable, error)) goto out; } else if (g_str_has_suffix (name, ".bin")) { const char *lastdot; gs_free char *nonbin_name = NULL; gs_unref_object GFile *nonbin_path = NULL; guint64 mtime = g_file_info_get_attribute_uint64 (file_info, "time::modified"); guint64 atime = g_file_info_get_attribute_uint64 (file_info, "time::access"); struct utimbuf times; lastdot = strrchr (name, '.'); g_assert (lastdot); nonbin_name = g_strndup (name, lastdot - name); nonbin_path = g_file_get_child (dir, nonbin_name); times.actime = (time_t)atime; times.modtime = ((time_t)mtime) + 60; g_print ("Setting mtime of '%s' to newer than '%s'\n", gs_file_get_path_cached (nonbin_path), gs_file_get_path_cached (child)); if (utime (gs_file_get_path_cached (nonbin_path), ×) == -1) { int errsv = errno; g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "utime(%s): %s", gs_file_get_path_cached (nonbin_path), strerror (errsv)); goto out; } } } ret = TRUE; out: return ret; }
static gboolean convert_var_to_tmpfiles_d (GOutputStream *tmpfiles_out, GFile *yumroot, GFile *dir, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; gs_unref_object GFileEnumerator *direnum = NULL; gsize bytes_written; direnum = g_file_enumerate_children (dir, "standard::name,standard::type,unix::mode,standard::symlink-target,unix::uid,unix::gid", G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, cancellable, error); if (!direnum) { g_prefix_error (error, "Enumerating /var in '%s'", gs_file_get_path_cached (dir)); goto out; } while (TRUE) { GFileInfo *file_info; GFile *child; GString *tmpfiles_d_buf; gs_free char *tmpfiles_d_line = NULL; char filetype_c; gs_free char *relpath = NULL; if (!gs_file_enumerator_iterate (direnum, &file_info, &child, cancellable, error)) goto out; if (!file_info) break; switch (g_file_info_get_file_type (file_info)) { case G_FILE_TYPE_DIRECTORY: filetype_c = 'd'; break; case G_FILE_TYPE_SYMBOLIC_LINK: filetype_c = 'L'; break; default: g_print ("Ignoring non-directory/non-symlink '%s'\n", gs_file_get_path_cached (child)); continue; } tmpfiles_d_buf = g_string_new (""); g_string_append_c (tmpfiles_d_buf, filetype_c); g_string_append_c (tmpfiles_d_buf, ' '); relpath = g_file_get_relative_path (yumroot, child); g_assert (relpath); g_string_append_c (tmpfiles_d_buf, '/'); g_string_append (tmpfiles_d_buf, relpath); if (filetype_c == 'd') { guint mode = g_file_info_get_attribute_uint32 (file_info, "unix::mode"); mode &= ~S_IFMT; g_string_append_printf (tmpfiles_d_buf, " 0%02o", mode); g_string_append_printf (tmpfiles_d_buf, " %d %d - -", g_file_info_get_attribute_uint32 (file_info, "unix::uid"), g_file_info_get_attribute_uint32 (file_info, "unix::gid")); if (!convert_var_to_tmpfiles_d (tmpfiles_out, yumroot, child, cancellable, error)) goto out; } else { g_string_append (tmpfiles_d_buf, " - - - - "); g_string_append (tmpfiles_d_buf, g_file_info_get_symlink_target (file_info)); } g_string_append_c (tmpfiles_d_buf, '\n'); tmpfiles_d_line = g_string_free (tmpfiles_d_buf, FALSE); if (!g_output_stream_write_all (tmpfiles_out, tmpfiles_d_line, strlen (tmpfiles_d_line), &bytes_written, cancellable, error)) goto out; } ret = TRUE; out: return ret; }
static gboolean _ostree_bootloader_grub2_query (OstreeBootloader *bootloader, gboolean *out_is_active, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; OstreeBootloaderGrub2 *self = OSTREE_BOOTLOADER_GRUB2 (bootloader); gs_unref_object GFile* efi_basedir = NULL; gs_unref_object GFileInfo *file_info = NULL; if (g_file_query_exists (self->config_path_bios, NULL)) { *out_is_active = TRUE; ret = TRUE; goto out; } efi_basedir = g_file_resolve_relative_path (self->sysroot->path, "boot/efi/EFI"); g_clear_object (&self->config_path_efi); if (g_file_query_exists (efi_basedir, NULL)) { gs_unref_object GFileEnumerator *direnum = NULL; direnum = g_file_enumerate_children (efi_basedir, OSTREE_GIO_FAST_QUERYINFO, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, cancellable, error); if (!direnum) goto out; while (TRUE) { GFileInfo *file_info; const char *fname; gs_free char *subdir_grub_cfg = NULL; if (!gs_file_enumerator_iterate (direnum, &file_info, NULL, cancellable, error)) goto out; if (file_info == NULL) break; fname = g_file_info_get_name (file_info); if (strcmp (fname, "BOOT") == 0) continue; if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_DIRECTORY) continue; subdir_grub_cfg = g_build_filename (gs_file_get_path_cached (efi_basedir), fname, "grub.cfg", NULL); if (g_file_test (subdir_grub_cfg, G_FILE_TEST_EXISTS)) { self->config_path_efi = g_file_new_for_path (subdir_grub_cfg); break; } } if (self->config_path_efi) { self->is_efi = TRUE; *out_is_active = TRUE; ret = TRUE; goto out; } } else *out_is_active = FALSE; ret = TRUE; out: return ret; }
/* * checkout_tree_at: * @self: Repo * @mode: Options controlling all files * @overwrite_mode: Whether or not to overwrite files * @destination_parent_fd: Place tree here * @destination_name: Use this name for tree * @source: Source tree * @source_info: Source info * @cancellable: Cancellable * @error: Error * * Like ostree_repo_checkout_tree(), but check out @source into the * relative @destination_name, located by @destination_parent_fd. */ static gboolean checkout_tree_at (OstreeRepo *self, OstreeRepoCheckoutOptions *options, int destination_parent_fd, const char *destination_name, OstreeRepoFile *source, GFileInfo *source_info, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; gboolean did_exist = FALSE; int destination_dfd = -1; int res; g_autoptr(GVariant) xattrs = NULL; g_autoptr(GFileEnumerator) dir_enum = NULL; /* Create initially with mode 0700, then chown/chmod only when we're * done. This avoids anyone else being able to operate on partially * constructed dirs. */ do res = mkdirat (destination_parent_fd, destination_name, 0700); while (G_UNLIKELY (res == -1 && errno == EINTR)); if (res == -1) { if (errno == EEXIST && options->overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES) did_exist = TRUE; else { glnx_set_error_from_errno (error); goto out; } } if (!glnx_opendirat (destination_parent_fd, destination_name, TRUE, &destination_dfd, error)) goto out; /* Set the xattrs now, so any derived labeling works */ if (!did_exist && options->mode != OSTREE_REPO_CHECKOUT_MODE_USER) { if (!ostree_repo_file_get_xattrs (source, &xattrs, NULL, error)) goto out; if (xattrs) { if (!glnx_fd_set_all_xattrs (destination_dfd, xattrs, cancellable, error)) goto out; } } if (g_file_info_get_file_type (source_info) != G_FILE_TYPE_DIRECTORY) { ret = checkout_one_file_at (self, options, (GFile *) source, source_info, destination_dfd, g_file_info_get_name (source_info), cancellable, error); goto out; } dir_enum = g_file_enumerate_children ((GFile*)source, OSTREE_GIO_FAST_QUERYINFO, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, cancellable, error); if (!dir_enum) goto out; while (TRUE) { GFileInfo *file_info; GFile *src_child; const char *name; if (!gs_file_enumerator_iterate (dir_enum, &file_info, &src_child, cancellable, error)) goto out; if (file_info == NULL) break; name = g_file_info_get_name (file_info); if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY) { if (!checkout_tree_at (self, options, destination_dfd, name, (OstreeRepoFile*)src_child, file_info, cancellable, error)) goto out; } else { if (!checkout_one_file_at (self, options, src_child, file_info, destination_dfd, name, cancellable, error)) goto out; } } /* We do fchmod/fchown last so that no one else could access the * partially created directory and change content we're laying out. */ if (!did_exist) { do res = fchmod (destination_dfd, g_file_info_get_attribute_uint32 (source_info, "unix::mode")); while (G_UNLIKELY (res == -1 && errno == EINTR)); if (G_UNLIKELY (res == -1)) { glnx_set_error_from_errno (error); goto out; } } if (!did_exist && options->mode != OSTREE_REPO_CHECKOUT_MODE_USER) { do res = fchown (destination_dfd, g_file_info_get_attribute_uint32 (source_info, "unix::uid"), g_file_info_get_attribute_uint32 (source_info, "unix::gid")); while (G_UNLIKELY (res == -1 && errno == EINTR)); if (G_UNLIKELY (res == -1)) { glnx_set_error_from_errno (error); goto out; } } /* Set directory mtime to 0, so that it is constant for all checkouts. * Must be done after setting permissions and creating all children. */ if (!did_exist) { const struct timespec times[2] = { { 0, UTIME_OMIT }, { 0, } }; do res = futimens (destination_dfd, times); while (G_UNLIKELY (res == -1 && errno == EINTR)); if (G_UNLIKELY (res == -1)) { glnx_set_error_from_errno (error); goto out; } } if (fsync_is_enabled (self, options)) { if (fsync (destination_dfd) == -1) { glnx_set_error_from_errno (error); goto out; } } ret = TRUE; out: if (destination_dfd != -1) (void) close (destination_dfd); return ret; }
/** * ostree_repo_list_refs: * @self: Repo * @refspec_prefix: (allow-none): Only list refs which match this prefix * @out_all_refs: (out) (element-type utf8 utf8): Mapping from ref to checksum * @cancellable: Cancellable * @error: Error * * If @refspec_prefix is %NULL, list all local and remote refspecs, * with their current values in @out_all_refs. Otherwise, only list * refspecs which have @refspec_prefix as a prefix. */ gboolean ostree_repo_list_refs (OstreeRepo *self, const char *refspec_prefix, GHashTable **out_all_refs, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; g_autoptr(GHashTable) ret_all_refs = NULL; g_autofree char *remote = NULL; g_autofree char *ref_prefix = NULL; ret_all_refs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); if (refspec_prefix) { g_autoptr(GFile) dir = NULL; g_autoptr(GFile) child = NULL; g_autoptr(GFileInfo) info = NULL; if (!ostree_parse_refspec (refspec_prefix, &remote, &ref_prefix, error)) goto out; if (remote) dir = g_file_get_child (self->remote_heads_dir, remote); else dir = g_object_ref (self->local_heads_dir); child = g_file_resolve_relative_path (dir, ref_prefix); if (!ot_gfile_query_info_allow_noent (child, OSTREE_GIO_FAST_QUERYINFO, 0, &info, cancellable, error)) goto out; if (info) { if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) { if (!enumerate_refs_recurse (self, remote, child, child, ret_all_refs, cancellable, error)) goto out; } else { if (!add_ref_to_set (remote, dir, child, ret_all_refs, cancellable, error)) goto out; } } } else { g_autoptr(GFileEnumerator) remote_enumerator = NULL; if (!enumerate_refs_recurse (self, NULL, self->local_heads_dir, self->local_heads_dir, ret_all_refs, cancellable, error)) goto out; remote_enumerator = g_file_enumerate_children (self->remote_heads_dir, OSTREE_GIO_FAST_QUERYINFO, 0, cancellable, error); while (TRUE) { GFileInfo *info; GFile *child; const char *name; if (!gs_file_enumerator_iterate (remote_enumerator, &info, &child, cancellable, error)) goto out; if (!info) break; name = g_file_info_get_name (info); if (!enumerate_refs_recurse (self, name, child, child, ret_all_refs, cancellable, error)) goto out; } } ret = TRUE; ot_transfer_out_value (out_all_refs, &ret_all_refs); out: return ret; }
static gboolean list_all_boot_directories (OstreeSysroot *self, GPtrArray **out_bootdirs, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; gs_unref_object GFileEnumerator *dir_enum = NULL; gs_unref_object GFile *boot_ostree = NULL; gs_unref_ptrarray GPtrArray *ret_bootdirs = NULL; GError *temp_error = NULL; boot_ostree = g_file_resolve_relative_path (self->path, "boot/ostree"); ret_bootdirs = g_ptr_array_new_with_free_func (g_object_unref); dir_enum = g_file_enumerate_children (boot_ostree, OSTREE_GIO_FAST_QUERYINFO, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, cancellable, &temp_error); if (!dir_enum) { if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) { g_clear_error (&temp_error); goto done; } else { g_propagate_error (error, temp_error); goto out; } } while (TRUE) { GFileInfo *file_info = NULL; GFile *child = NULL; const char *name; if (!gs_file_enumerator_iterate (dir_enum, &file_info, &child, NULL, error)) goto out; if (file_info == NULL) break; if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_DIRECTORY) continue; /* Only look at directories ending in -CHECKSUM; nothing else * should be in here, but let's be conservative. */ name = g_file_info_get_name (file_info); if (!parse_bootdir_name (name, NULL, NULL)) continue; g_ptr_array_add (ret_bootdirs, g_object_ref (child)); } done: ret = TRUE; ot_transfer_out_value (out_bootdirs, &ret_bootdirs); out: return ret; }
static gboolean find_kernel_and_initramfs_in_bootdir (GFile *bootdir, GFile **out_kernel, GFile **out_initramfs, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; gs_unref_object GFileEnumerator *direnum = NULL; gs_unref_object GFile *ret_kernel = NULL; gs_unref_object GFile *ret_initramfs = NULL; direnum = g_file_enumerate_children (bootdir, "standard::name", 0, cancellable, error); if (!direnum) goto out; while (TRUE) { const char *name; GFileInfo *file_info; GFile *child; if (!gs_file_enumerator_iterate (direnum, &file_info, &child, cancellable, error)) goto out; if (!file_info) break; name = g_file_info_get_name (file_info); /* Current Fedora 23 kernel.spec installs as just vmlinuz */ if (strcmp (name, "vmlinuz") == 0 || g_str_has_prefix (name, "vmlinuz-")) { if (ret_kernel) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Multiple vmlinuz- in %s", gs_file_get_path_cached (bootdir)); goto out; } ret_kernel = g_object_ref (child); } else if (g_str_has_prefix (name, "initramfs-")) { if (ret_initramfs) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Multiple initramfs- in %s", gs_file_get_path_cached (bootdir)); goto out; } ret_initramfs = g_object_ref (child); } } ret = TRUE; gs_transfer_out_value (out_kernel, &ret_kernel); gs_transfer_out_value (out_initramfs, &ret_initramfs); out: return ret; }
gboolean _ostree_sysroot_list_deployment_dirs_for_os (GFile *osdir, GPtrArray *inout_deployments, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; const char *osname = gs_file_get_basename_cached (osdir); gs_unref_object GFileEnumerator *dir_enum = NULL; gs_unref_object GFile *osdeploy_dir = NULL; GError *temp_error = NULL; osdeploy_dir = g_file_get_child (osdir, "deploy"); dir_enum = g_file_enumerate_children (osdeploy_dir, OSTREE_GIO_FAST_QUERYINFO, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &temp_error); if (!dir_enum) { if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) { g_clear_error (&temp_error); goto done; } else { g_propagate_error (error, temp_error); goto out; } } while (TRUE) { const char *name; GFileInfo *file_info = NULL; GFile *child = NULL; gs_unref_object OstreeDeployment *deployment = NULL; gs_free char *csum = NULL; gint deployserial; if (!gs_file_enumerator_iterate (dir_enum, &file_info, &child, cancellable, error)) goto out; if (file_info == NULL) break; name = g_file_info_get_name (file_info); if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_DIRECTORY) continue; if (!_ostree_sysroot_parse_deploy_path_name (name, &csum, &deployserial, error)) goto out; deployment = ostree_deployment_new (-1, osname, csum, deployserial, NULL, -1); g_ptr_array_add (inout_deployments, g_object_ref (deployment)); } done: ret = TRUE; out: return ret; }
static gboolean migrate_rpm_and_yumdb (GFile *targetroot, GFile *yumroot, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; gs_unref_object GFile *usrbin_rpm = g_file_resolve_relative_path (targetroot, "usr/bin/rpm"); gs_unref_object GFile *legacyrpm_path = g_file_resolve_relative_path (yumroot, "var/lib/rpm"); gs_unref_object GFile *newrpm_path = g_file_resolve_relative_path (targetroot, "usr/share/rpm"); gs_unref_object GFile *src_yum_rpmdb_indexes = g_file_resolve_relative_path (yumroot, "var/lib/yum"); gs_unref_object GFile *target_yum_rpmdb_indexes = g_file_resolve_relative_path (targetroot, "usr/share/yumdb"); gs_unref_object GFile *yumroot_yumlib = g_file_get_child (yumroot, "var/lib/yum"); gs_unref_object GFileEnumerator *direnum = NULL; direnum = g_file_enumerate_children (legacyrpm_path, "standard::name", G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, cancellable, error); if (!direnum) goto out; while (TRUE) { const char *name; GFileInfo *file_info; GFile *child; if (!gs_file_enumerator_iterate (direnum, &file_info, &child, cancellable, error)) goto out; if (!file_info) break; name = g_file_info_get_name (file_info); if (g_str_has_prefix (name, "__db.") || strcmp (name, ".dbenv.lock") == 0 || strcmp (name, ".rpm.lock") == 0) { if (!gs_file_unlink (child, cancellable, error)) goto out; } } (void) g_file_enumerator_close (direnum, cancellable, error); g_print ("Placing RPM db in /usr/share/rpm\n"); if (!gs_file_rename (legacyrpm_path, newrpm_path, cancellable, error)) goto out; /* Remove /var/lib/yum; we don't want it here. */ if (!gs_shutil_rm_rf (yumroot_yumlib, cancellable, error)) goto out; ret = TRUE; out: return ret; }
/** * ostree_repo_list_static_delta_names: * @self: Repo * @out_deltas: (out) (element-type utf8): String name of deltas (checksum-checksum.delta) * @cancellable: Cancellable * @error: Error * * This function synchronously enumerates all static deltas in the * repository, returning its result in @out_deltas. */ gboolean ostree_repo_list_static_delta_names (OstreeRepo *self, GPtrArray **out_deltas, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; gs_unref_ptrarray GPtrArray *ret_deltas = NULL; gs_unref_object GFileEnumerator *dir_enum = NULL; ret_deltas = g_ptr_array_new_with_free_func (g_free); if (g_file_query_exists (self->deltas_dir, NULL)) { dir_enum = g_file_enumerate_children (self->deltas_dir, OSTREE_GIO_FAST_QUERYINFO, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, error); if (!dir_enum) goto out; while (TRUE) { gs_unref_object GFileEnumerator *dir_enum2 = NULL; GFileInfo *file_info; GFile *child; if (!gs_file_enumerator_iterate (dir_enum, &file_info, &child, NULL, error)) goto out; if (file_info == NULL) break; if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_DIRECTORY) continue; dir_enum2 = g_file_enumerate_children (child, OSTREE_GIO_FAST_QUERYINFO, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, error); if (!dir_enum2) goto out; while (TRUE) { GFileInfo *file_info2; GFile *child2; const char *name1; const char *name2; if (!gs_file_enumerator_iterate (dir_enum2, &file_info2, &child2, NULL, error)) goto out; if (file_info2 == NULL) break; if (g_file_info_get_file_type (file_info2) != G_FILE_TYPE_DIRECTORY) continue; name1 = gs_file_get_basename_cached (child); name2 = gs_file_get_basename_cached (child2); { gs_unref_object GFile *meta_path = g_file_get_child (child2, "superblock"); if (g_file_query_exists (meta_path, NULL)) { gs_free char *buf = g_strconcat (name1, name2, NULL); GString *out = g_string_new (""); char checksum[65]; guchar csum[32]; const char *dash = strchr (buf, '-'); ostree_checksum_b64_inplace_to_bytes (buf, csum); ostree_checksum_inplace_from_bytes (csum, checksum); g_string_append (out, checksum); if (dash) { g_string_append_c (out, '-'); ostree_checksum_b64_inplace_to_bytes (dash+1, csum); ostree_checksum_inplace_from_bytes (csum, checksum); g_string_append (out, checksum); } g_ptr_array_add (ret_deltas, g_string_free (out, FALSE)); } } } } } ret = TRUE; gs_transfer_out_value (out_deltas, &ret_deltas); out: return ret; }