fix(win): tolerate tar/PS nonzero if files extracted; add path_tree_has_entries() to verify real output

This commit is contained in:
2026-03-08 10:40:20 -06:00
parent b47c45d4cc
commit a53802cfef

View File

@@ -55,6 +55,38 @@ remove_tree (const char *path)
g_rmdir (path); g_rmdir (path);
} }
static gboolean
path_tree_has_entries (const char *path)
{
GDir *dir;
const char *name;
if (!path || !g_file_test (path, G_FILE_TEST_EXISTS))
return FALSE;
if (!g_file_test (path, G_FILE_TEST_IS_DIR))
return TRUE;
dir = g_dir_open (path, 0, NULL);
if (!dir)
return FALSE;
while ((name = g_dir_read_name (dir)) != NULL)
{
char *child = g_build_filename (path, name, NULL);
gboolean has_entries = path_tree_has_entries (child);
g_free (child);
if (has_entries)
{
g_dir_close (dir);
return TRUE;
}
}
g_dir_close (dir);
return FALSE;
}
static gboolean static gboolean
gtk3_css_dir_parse_minor (const char *name, gint *minor) gtk3_css_dir_parse_minor (const char *name, gint *minor)
{ {
@@ -268,8 +300,8 @@ resolve_parent_theme_root (const char *child_theme_root, const char *parent_name
static void static void
build_inheritance_chain_recursive (const char *theme_root, build_inheritance_chain_recursive (const char *theme_root,
GPtrArray *ordered_roots, GPtrArray *ordered_roots,
GHashTable *visited) GHashTable *visited)
{ {
char **parents; char **parents;
guint i; guint i;
@@ -365,7 +397,7 @@ path_read_display_name (const char *root)
char *name = NULL; char *name = NULL;
if (g_file_test (index_theme, G_FILE_TEST_IS_REGULAR) && if (g_file_test (index_theme, G_FILE_TEST_IS_REGULAR) &&
g_key_file_load_from_file (keyfile, index_theme, G_KEY_FILE_NONE, NULL)) g_key_file_load_from_file (keyfile, index_theme, G_KEY_FILE_NONE, NULL))
{ {
name = g_key_file_get_string (keyfile, "Desktop Entry", "Name", NULL); name = g_key_file_get_string (keyfile, "Desktop Entry", "Name", NULL);
if (!name) if (!name)
@@ -475,8 +507,8 @@ path_normalize_theme_root (const char *path)
{ {
char *base = g_path_get_dirname (canonical); char *base = g_path_get_dirname (canonical);
char *resolved = g_path_is_absolute (target) char *resolved = g_path_is_absolute (target)
? g_strdup (target) ? g_strdup (target)
: g_build_filename (base, target, NULL); : g_build_filename (base, target, NULL);
g_free (canonical); g_free (canonical);
canonical = g_canonicalize_filename (resolved, NULL); canonical = g_canonicalize_filename (resolved, NULL);
g_free (resolved); g_free (resolved);
@@ -774,8 +806,8 @@ validate_theme_root_for_import (const char *theme_root, GError **error)
if (!g_file_test (index_theme, G_FILE_TEST_IS_REGULAR)) if (!g_file_test (index_theme, G_FILE_TEST_IS_REGULAR))
{ {
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_INVAL, g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_INVAL,
"Invalid GTK3 theme at '%s': missing required index.theme at '%s'.", "Invalid GTK3 theme at '%s': missing required index.theme at '%s'.",
theme_root, index_theme); theme_root, index_theme);
g_free (index_theme); g_free (index_theme);
return FALSE; return FALSE;
} }
@@ -784,8 +816,8 @@ validate_theme_root_for_import (const char *theme_root, GError **error)
if (!g_key_file_load_from_file (keyfile, index_theme, G_KEY_FILE_NONE, &load_error)) if (!g_key_file_load_from_file (keyfile, index_theme, G_KEY_FILE_NONE, &load_error))
{ {
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_INVAL, g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_INVAL,
"Invalid GTK3 theme at '%s': failed to parse index.theme '%s': %s.", "Invalid GTK3 theme at '%s': failed to parse index.theme '%s': %s.",
theme_root, index_theme, load_error->message); theme_root, index_theme, load_error->message);
g_error_free (load_error); g_error_free (load_error);
g_key_file_unref (keyfile); g_key_file_unref (keyfile);
g_free (index_theme); g_free (index_theme);
@@ -795,8 +827,8 @@ validate_theme_root_for_import (const char *theme_root, GError **error)
if (!g_key_file_has_group (keyfile, "Desktop Entry")) if (!g_key_file_has_group (keyfile, "Desktop Entry"))
{ {
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_INVAL, g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_INVAL,
"Invalid GTK3 theme at '%s': index.theme '%s' is missing the [Desktop Entry] section.", "Invalid GTK3 theme at '%s': index.theme '%s' is missing the [Desktop Entry] section.",
theme_root, index_theme); theme_root, index_theme);
g_key_file_unref (keyfile); g_key_file_unref (keyfile);
g_free (index_theme); g_free (index_theme);
return FALSE; return FALSE;
@@ -806,8 +838,8 @@ validate_theme_root_for_import (const char *theme_root, GError **error)
if (!css_dir) if (!css_dir)
{ {
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_INVAL, g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_INVAL,
"Invalid GTK3 theme at '%s': could not resolve a GTK CSS directory (expected gtk-3.x/gtk.css).", "Invalid GTK3 theme at '%s': could not resolve a GTK CSS directory (expected gtk-3.x/gtk.css).",
theme_root); theme_root);
g_key_file_unref (keyfile); g_key_file_unref (keyfile);
g_free (index_theme); g_free (index_theme);
return FALSE; return FALSE;
@@ -817,8 +849,8 @@ validate_theme_root_for_import (const char *theme_root, GError **error)
if (!g_file_test (css_path, G_FILE_TEST_IS_REGULAR)) if (!g_file_test (css_path, G_FILE_TEST_IS_REGULAR))
{ {
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_INVAL, g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_INVAL,
"Invalid GTK3 theme at '%s': missing primary gtk.css at '%s'.", "Invalid GTK3 theme at '%s': missing primary gtk.css at '%s'.",
theme_root, css_path); theme_root, css_path);
g_free (css_path); g_free (css_path);
g_free (css_dir); g_free (css_dir);
g_key_file_unref (keyfile); g_key_file_unref (keyfile);
@@ -849,8 +881,8 @@ validate_theme_root_for_import (const char *theme_root, GError **error)
if (!parent_root) if (!parent_root)
{ {
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_INVAL, g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_INVAL,
"Invalid GTK3 theme at '%s': parent theme '%s' from Inherits could not be resolved.", "Invalid GTK3 theme at '%s': parent theme '%s' from Inherits could not be resolved.",
theme_root, parent_name); theme_root, parent_name);
g_strfreev (inherits); g_strfreev (inherits);
return FALSE; return FALSE;
} }
@@ -865,7 +897,7 @@ static char *
extract_archive (const char *source, GError **error) extract_archive (const char *source, GError **error)
{ {
char *tmp = g_dir_make_tmp ("zoitechat-gtk3-theme-XXXXXX", error); char *tmp = g_dir_make_tmp ("zoitechat-gtk3-theme-XXXXXX", error);
#ifdef G_OS_WIN32 #ifdef G_OS_WIN32
char *stdout_text = NULL; char *stdout_text = NULL;
char *stderr_text = NULL; char *stderr_text = NULL;
char *system_tar = NULL; char *system_tar = NULL;
@@ -895,7 +927,7 @@ extract_archive (const char *source, GError **error)
}; };
extracted = g_spawn_sync (NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, extracted = g_spawn_sync (NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL,
&stdout_text, &stderr_text, &status, NULL); &stdout_text, &stderr_text, &status, NULL);
} }
else else
{ {
@@ -927,7 +959,7 @@ extract_archive (const char *source, GError **error)
}; };
extracted = g_spawn_sync (NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, extracted = g_spawn_sync (NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL,
&stdout_text, &stderr_text, &status, NULL); &stdout_text, &stderr_text, &status, NULL);
} }
else else
{ {
@@ -941,25 +973,37 @@ extract_archive (const char *source, GError **error)
}; };
extracted = g_spawn_sync (NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, extracted = g_spawn_sync (NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL,
&stdout_text, &stderr_text, &status, NULL); &stdout_text, &stderr_text, &status, NULL);
} }
} }
g_free (tar_program); if (!extracted || (status != 0 && !path_tree_has_entries (tmp)))
g_free (system_tar);
g_free (system_root);
g_free (stdout_text);
g_free (stderr_text);
if (!extracted || status != 0)
{ {
g_free (tar_program);
g_free (system_tar);
g_free (system_root);
g_free (stdout_text);
g_free (stderr_text);
remove_tree (tmp); remove_tree (tmp);
g_free (tmp); g_free (tmp);
g_set_error_literal (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, "Failed to extract theme archive."); g_set_error_literal (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, "Failed to extract theme archive.");
return NULL; return NULL;
} }
/*
* Windows archive tools often return a non-zero exit status for Unix-style
* symlink entries that cannot be materialized without extra privileges.
* If regular theme files were extracted, continue and let theme validation
* decide whether the imported theme is usable.
*/
g_free (tar_program);
g_free (system_tar);
g_free (system_root);
g_free (stdout_text);
g_free (stderr_text);
return tmp; return tmp;
#else #else
struct archive *archive = NULL; struct archive *archive = NULL;
struct archive *disk = NULL; struct archive *disk = NULL;
struct archive_entry *entry; struct archive_entry *entry;
@@ -1046,7 +1090,7 @@ extract_archive (const char *source, GError **error)
} }
return tmp; return tmp;
#endif #endif
} }
gboolean gboolean