/** * as_utils_delete_dir_recursive: * @dirname: Directory to remove * * Remove directory and all its children (like rm -r does). * * Returns: %TRUE if operation was successful */ gboolean as_utils_delete_dir_recursive (const gchar* dirname) { GError *error = NULL; gboolean ret = FALSE; GFile *dir; GFileEnumerator *enr; GFileInfo *info; g_return_val_if_fail (dirname != NULL, FALSE); if (!g_file_test (dirname, G_FILE_TEST_IS_DIR)) return TRUE; dir = g_file_new_for_path (dirname); enr = g_file_enumerate_children (dir, "standard::name", G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &error); if (error != NULL) goto out; if (enr == NULL) goto out; info = g_file_enumerator_next_file (enr, NULL, &error); if (error != NULL) goto out; while (info != NULL) { gchar *path; path = g_build_filename (dirname, g_file_info_get_name (info), NULL); if (g_file_test (path, G_FILE_TEST_IS_DIR)) { as_utils_delete_dir_recursive (path); } else { g_remove (path); } g_object_unref (info); info = g_file_enumerator_next_file (enr, NULL, &error); if (error != NULL) goto out; } if (g_file_test (dirname, G_FILE_TEST_EXISTS)) { g_rmdir (dirname); } ret = TRUE; out: g_object_unref (dir); if (enr != NULL) g_object_unref (enr); if (error != NULL) { g_critical ("Could not remove directory: %s", error->message); g_error_free (error); } return ret; }
/** * as_pool_scan_apt: * * Scan for additional metadata in 3rd-party directories and move it to the right place. */ void as_pool_scan_apt (AsPool *pool, gboolean force, GError **error) { const gchar *apt_lists_dir = "/var/lib/apt/lists/"; const gchar *appstream_yml_target = "/var/lib/app-info/yaml"; const gchar *appstream_icons_target = "/var/lib/app-info/icons"; g_autoptr(GPtrArray) yml_files = NULL; g_autoptr(GError) tmp_error = NULL; gboolean data_changed = FALSE; guint i; /* skip this step if the APT lists directory doesn't exist */ if (!g_file_test (apt_lists_dir, G_FILE_TEST_IS_DIR)) { g_debug ("APT lists directory (%s) not found!", apt_lists_dir); return; } if (g_file_test (appstream_yml_target, G_FILE_TEST_IS_DIR)) { g_autoptr(GPtrArray) ytfiles = NULL; /* we can't modify the files here if we don't have write access */ if (!as_utils_is_writable (appstream_yml_target)) { g_debug ("Unable to write to '%s': Can't add AppStream data from APT to the pool.", appstream_yml_target); return; } ytfiles = as_utils_find_files_matching (appstream_yml_target, "*", FALSE, &tmp_error); if (tmp_error != NULL) { g_warning ("Could not scan for broken symlinks in DEP-11 target: %s", tmp_error->message); return; } for (i = 0; i < ytfiles->len; i++) { const gchar *fname = (const gchar*) g_ptr_array_index (ytfiles, i); if (!g_file_test (fname, G_FILE_TEST_EXISTS)) { g_remove (fname); data_changed = TRUE; } } } yml_files = as_utils_find_files_matching (apt_lists_dir, "*Components-*.yml.gz", FALSE, &tmp_error); if (tmp_error != NULL) { g_warning ("Could not scan for APT-downloaded DEP-11 files: %s", tmp_error->message); return; } /* no data found? skip scan step */ if (yml_files->len <= 0) { g_debug ("Couldn't find DEP-11 data in APT directories."); return; } /* We have to check if our metadata is in the target directory at all, and - if not - trigger a cache refresh. * This is needed because APT is putting files with the *server* ctime/mtime into it's lists directory, * and that time might be lower than the time the metadata cache was last updated, which may result * in no cache update being triggered at all. */ for (i = 0; i < yml_files->len; i++) { g_autofree gchar *fbasename = NULL; g_autofree gchar *dest_fname = NULL; const gchar *fname = (const gchar*) g_ptr_array_index (yml_files, i); fbasename = g_path_get_basename (fname); dest_fname = g_build_filename (appstream_yml_target, fbasename, NULL); if (!g_file_test (dest_fname, G_FILE_TEST_EXISTS)) { data_changed = TRUE; g_debug ("File '%s' missing, cache update is needed.", dest_fname); break; } } /* get the last time we touched the database */ if (!data_changed) { for (i = 0; i < yml_files->len; i++) { struct stat sb; const gchar *fname = (const gchar*) g_ptr_array_index (yml_files, i); if (stat (fname, &sb) < 0) continue; if (sb.st_ctime > as_pool_get_cache_age (pool)) { /* we need to update the cache */ data_changed = TRUE; break; } } } /* no changes means nothing to do here */ if ((!data_changed) && (!force)) return; /* this is not really great, but we simply can't detect if we should remove an icons folder or not, * or which specific icons we should drop from a folder. * So, we hereby simply "own" the icons directory and all it's contents, anything put in there by 3rd-parties will * be deleted. * (And there should actually be no cases 3rd-parties put icons there on a Debian machine, since metadata in packages * will land in /usr/share/app-info anyway) */ as_utils_delete_dir_recursive (appstream_icons_target); if (g_mkdir_with_parents (appstream_yml_target, 0755) > 0) { g_debug ("Unable to create '%s': %s", appstream_yml_target, g_strerror (errno)); return; } for (i = 0; i < yml_files->len; i++) { g_autofree gchar *fbasename = NULL; g_autofree gchar *dest_fname = NULL; g_autofree gchar *origin = NULL; g_autofree gchar *file_baseprefix = NULL; const gchar *fname = (const gchar*) g_ptr_array_index (yml_files, i); fbasename = g_path_get_basename (fname); dest_fname = g_build_filename (appstream_yml_target, fbasename, NULL); if (!g_file_test (fname, G_FILE_TEST_EXISTS)) { /* broken symlinks in the dest will have been removed earlier */ g_debug ("File %s is a broken symlink, skipping.", fname); continue; } else if (!g_file_test (dest_fname, G_FILE_TEST_EXISTS)) { /* file not found, let's symlink */ if (symlink (fname, dest_fname) != 0) { g_debug ("Unable to set symlink (%s -> %s): %s", fname, dest_fname, g_strerror (errno)); continue; } } else if (!g_file_test (dest_fname, G_FILE_TEST_IS_SYMLINK)) { /* file found, but it isn't a symlink, try to rescue */ g_debug ("Regular file '%s' found, which doesn't belong there. Removing it.", dest_fname); g_remove (dest_fname); continue; } /* get DEP-11 data origin */ origin = as_get_yml_data_origin (dest_fname); if (origin == NULL) { g_warning ("No origin found for file %s", fbasename); continue; } /* get base prefix for this file in the APT download cache */ file_baseprefix = g_strndup (fbasename, strlen (fbasename) - strlen (g_strrstr (fbasename, "_") + 1)); /* extract icons to their destination (if they exist at all */ as_extract_icon_cache_tarball (appstream_icons_target, origin, file_baseprefix, apt_lists_dir, "64x64"); as_extract_icon_cache_tarball (appstream_icons_target, origin, file_baseprefix, apt_lists_dir, "128x128"); } /* ensure the cache-rebuild process notices these changes */ as_touch_location (appstream_yml_target); }