static gboolean enumerate_refs_recurse (OstreeRepo *repo, const char *remote, int base_dfd, GString *base_path, int child_dfd, const char *path, GHashTable *refs, GCancellable *cancellable, GError **error) { g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; if (!glnx_dirfd_iterator_init_at (child_dfd, path, FALSE, &dfd_iter, error)) return FALSE; while (TRUE) { guint len = base_path->len; struct dirent *dent = NULL; if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error)) return FALSE; if (dent == NULL) break; g_string_append (base_path, dent->d_name); if (dent->d_type == DT_DIR) { g_string_append_c (base_path, '/'); if (!enumerate_refs_recurse (repo, remote, base_dfd, base_path, dfd_iter.fd, dent->d_name, refs, cancellable, error)) return FALSE; } else if (dent->d_type == DT_REG) { if (!add_ref_to_set (remote, base_dfd, base_path->str, refs, cancellable, error)) return FALSE; } g_string_truncate (base_path, len); } return TRUE; }
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; }
/** * 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 _ostree_repo_list_refs_internal (OstreeRepo *self, gboolean cut_prefix, const char *refspec_prefix, GHashTable **out_all_refs, GCancellable *cancellable, GError **error) { 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) { struct stat stbuf; const char *prefix_path; const char *path; if (!ostree_parse_refspec (refspec_prefix, &remote, &ref_prefix, error)) return FALSE; if (remote) { prefix_path = glnx_strjoina ("refs/remotes/", remote, "/"); path = glnx_strjoina (prefix_path, ref_prefix); } else { prefix_path = "refs/heads/"; path = glnx_strjoina (prefix_path, ref_prefix); } if (fstatat (self->repo_dir_fd, path, &stbuf, 0) < 0) { if (errno != ENOENT) return glnx_throw_errno (error); } else { if (S_ISDIR (stbuf.st_mode)) { glnx_fd_close int base_fd = -1; g_autoptr(GString) base_path = g_string_new (""); if (!cut_prefix) g_string_printf (base_path, "%s/", ref_prefix); if (!glnx_opendirat (self->repo_dir_fd, cut_prefix ? path : prefix_path, TRUE, &base_fd, error)) return FALSE; if (!enumerate_refs_recurse (self, remote, base_fd, base_path, base_fd, cut_prefix ? "." : ref_prefix, ret_all_refs, cancellable, error)) return FALSE; } else { glnx_fd_close int prefix_dfd = -1; if (!glnx_opendirat (self->repo_dir_fd, prefix_path, TRUE, &prefix_dfd, error)) return FALSE; if (!add_ref_to_set (remote, prefix_dfd, ref_prefix, ret_all_refs, cancellable, error)) return FALSE; } } } else { g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; g_autoptr(GString) base_path = g_string_new (""); glnx_fd_close int refs_heads_dfd = -1; if (!glnx_opendirat (self->repo_dir_fd, "refs/heads", TRUE, &refs_heads_dfd, error)) return FALSE; if (!enumerate_refs_recurse (self, NULL, refs_heads_dfd, base_path, refs_heads_dfd, ".", ret_all_refs, cancellable, error)) return FALSE; g_string_truncate (base_path, 0); if (!glnx_dirfd_iterator_init_at (self->repo_dir_fd, "refs/remotes", TRUE, &dfd_iter, error)) return FALSE; while (TRUE) { struct dirent *dent; glnx_fd_close int remote_dfd = -1; if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error)) return FALSE; if (!dent) break; if (dent->d_type != DT_DIR) continue; if (!glnx_opendirat (dfd_iter.fd, dent->d_name, TRUE, &remote_dfd, error)) return FALSE; if (!enumerate_refs_recurse (self, dent->d_name, remote_dfd, base_path, remote_dfd, ".", ret_all_refs, cancellable, error)) return FALSE; } } ot_transfer_out_value (out_all_refs, &ret_all_refs); return TRUE; }