1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
2  *
3  * Copyright (C) 2014 Fabien Bourigault <bourigaultfabien@gmail.com>
4  *
5  * SPDX-License-Identifier: LGPL-2.1+
6  */
7 
8 /**
9  * SECTION:asb-package-alpm
10  * @short_description: Object representing a .tar.xz (pacman) package file.
11  * @stability: Unstable
12  *
13  * This object represents one .tar.xz (pacman) package file.
14  */
15 
16 #include "config.h"
17 
18 #include <limits.h>
19 
20 #include <alpm.h>
21 
22 #include "asb-package-alpm.h"
23 #include "asb-plugin.h"
24 
25 typedef struct
26 {
27 	alpm_handle_t	*handle;
28 	alpm_pkg_t	*package;
29 } AsbPackageAlpmPrivate;
30 
G_DEFINE_TYPE_WITH_PRIVATE(AsbPackageAlpm,asb_package_alpm,ASB_TYPE_PACKAGE)31 G_DEFINE_TYPE_WITH_PRIVATE (AsbPackageAlpm, asb_package_alpm, ASB_TYPE_PACKAGE)
32 
33 #define GET_PRIVATE(o) (asb_package_alpm_get_instance_private (o))
34 
35 static void
36 asb_package_alpm_finalize (GObject *object)
37 {
38 	AsbPackageAlpm *pkg = ASB_PACKAGE_ALPM (object);
39 	AsbPackageAlpmPrivate *priv = GET_PRIVATE (pkg);
40 
41 	/* TODO: handle errors */
42 	alpm_pkg_free (priv->package);
43 	alpm_release (priv->handle);
44 
45 	G_OBJECT_CLASS (asb_package_alpm_parent_class)->finalize (object);
46 }
47 
48 static void
asb_package_alpm_init(AsbPackageAlpm * pkg)49 asb_package_alpm_init (AsbPackageAlpm *pkg)
50 {
51 }
52 
53 static GPtrArray *
asb_package_alpm_list_to_array(alpm_list_t * list)54 asb_package_alpm_list_to_array (alpm_list_t *list)
55 {
56 	alpm_list_t *current;
57 	GPtrArray *array = g_ptr_array_new_with_free_func (g_free);
58 
59 	for (current = list; current; current = alpm_list_next (current)) {
60 		g_ptr_array_add (array, g_strdup (current->data));
61 	}
62 	g_ptr_array_add (array, NULL);
63 
64 	return array;
65 }
66 
67 static gboolean
asb_package_alpm_ensure_license(AsbPackage * pkg,GError ** error)68 asb_package_alpm_ensure_license (AsbPackage *pkg, GError **error)
69 {
70 	AsbPackageAlpm *pkg_alpm = ASB_PACKAGE_ALPM (pkg);
71 	AsbPackageAlpmPrivate *priv = GET_PRIVATE (pkg_alpm);
72 
73 	alpm_list_t *alpm_licenses;
74 	GPtrArray *licenses;
75 	gchar *license;
76 
77 	alpm_licenses = alpm_pkg_get_licenses (priv->package);
78 	licenses = asb_package_alpm_list_to_array (alpm_licenses);
79 	/* TODO: translate licenses to SPDX licenses (makes licenses clickable
80 	 * is GNOME Software) */
81 	license = g_strjoinv (" AND ", (gchar **)(licenses->pdata));
82 
83 	asb_package_set_license (pkg, license);
84 
85 	g_ptr_array_free (licenses, TRUE);
86 	return TRUE;
87 }
88 
89 static void
asb_package_alpm_ensure_version(AsbPackage * pkg,GError ** error)90 asb_package_alpm_ensure_version (AsbPackage *pkg, GError **error)
91 {
92 	AsbPackageAlpm *pkg_alpm = ASB_PACKAGE_ALPM (pkg);
93 	AsbPackageAlpmPrivate *priv = GET_PRIVATE (pkg_alpm);
94 
95 	g_auto(GStrv) split = NULL;
96 
97 	split = g_strsplit (alpm_pkg_get_version (priv->package), ":-", 3);
98 
99 	/* epoch:version:release */
100 	if (g_strv_length (split) == 3) {
101 		asb_package_set_epoch (pkg, (guint) g_ascii_strtoull (split[0], NULL, 0));
102 		asb_package_set_version (pkg, split[1]);
103 		asb_package_set_release (pkg, split[2]);
104 	} else {/* version:release */
105 		asb_package_set_version (pkg, split[0]);
106 		asb_package_set_release (pkg, split[1]);
107 	}
108 }
109 
110 #if 0
111 static gboolean
112 asb_package_alpm_ensure_releases (AsbPackage *pkg, GError **error)
113 {
114 	AsbPackageAlpm *pkg_alpm = ASB_PACKAGE_ALPM (pkg);
115 	AsbPackageAlpmPrivate *priv = GET_PRIVATE (pkg_alpm);
116 	return TRUE;
117 }
118 #endif
119 
120 static gboolean
asb_package_alpm_ensure_depends(AsbPackage * pkg,GError ** error)121 asb_package_alpm_ensure_depends (AsbPackage *pkg, GError **error)
122 {
123 	AsbPackageAlpm *pkg_alpm = ASB_PACKAGE_ALPM (pkg);
124 	AsbPackageAlpmPrivate *priv = GET_PRIVATE (pkg_alpm);
125 	alpm_list_t *alpm_depends;
126 	alpm_list_t *current;
127 
128 	alpm_depends = alpm_pkg_get_depends (priv->package);
129 	for (current = alpm_depends; current; current = alpm_list_next (current))
130 		asb_package_add_dep (pkg, current->data);
131 
132 	return TRUE;
133 }
134 
135 static gboolean
asb_package_alpm_ensure_filelists(AsbPackage * pkg,GError ** error)136 asb_package_alpm_ensure_filelists (AsbPackage *pkg, GError **error)
137 {
138 	AsbPackageAlpm *pkg_alpm = ASB_PACKAGE_ALPM (pkg);
139 	AsbPackageAlpmPrivate *priv = GET_PRIVATE (pkg_alpm);
140 
141 	alpm_filelist_t *pkgfiles = alpm_pkg_get_files (priv->package);
142 	guint i;
143 	GPtrArray *filelist = g_ptr_array_new_with_free_func (g_free);
144 
145 	for (i = 0; i < pkgfiles->count; i++) {
146 		const alpm_file_t *file = pkgfiles->files + i;
147 		g_ptr_array_add (filelist, g_strconcat ("/", file->name, NULL));
148 	}
149 	g_ptr_array_add (filelist, NULL);
150 
151 	asb_package_set_filelist (pkg, (gchar **)(filelist->pdata));
152 
153 	g_ptr_array_free (filelist, TRUE);
154 	return TRUE;
155 }
156 
157 static gboolean
asb_package_alpm_open(AsbPackage * pkg,const gchar * filename,GError ** error)158 asb_package_alpm_open (AsbPackage *pkg, const gchar *filename, GError **error)
159 {
160 	AsbPackageAlpm *pkg_alpm = ASB_PACKAGE_ALPM (pkg);
161 	AsbPackageAlpmPrivate *priv = GET_PRIVATE (pkg_alpm);
162 
163 	alpm_errno_t alpm_error;
164 
165 	/* initialize the alpm library */
166 	priv->handle = alpm_initialize ("/", "/tmp", &alpm_error);
167 	if (priv->handle == NULL) {
168 		g_set_error (error,
169 		             ASB_PLUGIN_ERROR,
170 		             ASB_PLUGIN_ERROR_FAILED,
171 		             "libalpm initialization failed %s (%u) for %s",
172 		             alpm_strerror (alpm_error),
173 		             alpm_error,
174 		             filename);
175 		return FALSE;
176 	}
177 
178 	/* open the package */
179 	if (alpm_pkg_load (priv->handle, filename, TRUE, 0, &priv->package) == -1) {
180 		g_set_error (error,
181 		             ASB_PLUGIN_ERROR,
182 		             ASB_PLUGIN_ERROR_FAILED,
183 		             "Failed to load package %s : %s (%u)",
184 		             filename,
185 		             alpm_strerror (alpm_errno (priv->handle)),
186 		             alpm_errno (priv->handle));
187 		alpm_release (priv->handle);
188 		return FALSE;
189 	}
190 
191 	asb_package_set_name (pkg, alpm_pkg_get_name (priv->package));
192 	asb_package_set_url (pkg, alpm_pkg_get_url (priv->package));
193 	asb_package_set_arch (pkg, alpm_pkg_get_arch (priv->package));
194 	asb_package_alpm_ensure_version (pkg, error);
195 
196 	return TRUE;
197 }
198 
199 static gint
asb_package_alpm_compare(AsbPackage * pkg1,AsbPackage * pkg2)200 asb_package_alpm_compare (AsbPackage *pkg1, AsbPackage *pkg2)
201 {
202 	AsbPackageAlpm *pkg_alpm1 = ASB_PACKAGE_ALPM (pkg1);
203 	AsbPackageAlpmPrivate *priv1 = GET_PRIVATE (pkg_alpm1);
204 
205 	AsbPackageAlpm *pkg_alpm2 = ASB_PACKAGE_ALPM (pkg2);
206 	AsbPackageAlpmPrivate *priv2 = GET_PRIVATE (pkg_alpm2);
207 
208 	const gchar *pkg1_version = alpm_pkg_get_version (priv1->package);
209 	const gchar *pkg2_version = alpm_pkg_get_version (priv2->package);
210 
211 	return alpm_pkg_vercmp (pkg1_version, pkg2_version);
212 }
213 
214 static gboolean
asb_package_alpm_ensure(AsbPackage * pkg,AsbPackageEnsureFlags flags,GError ** error)215 asb_package_alpm_ensure (AsbPackage *pkg,
216 			 AsbPackageEnsureFlags flags,
217 			 GError **error)
218 {
219 	if ((flags & ASB_PACKAGE_ENSURE_DEPS) > 0) {
220 		if (!asb_package_alpm_ensure_depends (pkg, error))
221 			return FALSE;
222 	}
223 	if ((flags & ASB_PACKAGE_ENSURE_FILES) > 0) {
224 		if (!asb_package_alpm_ensure_filelists (pkg, error))
225 			return FALSE;
226 	}
227 	if ((flags & ASB_PACKAGE_ENSURE_LICENSE) > 0) {
228 		if (!asb_package_alpm_ensure_license (pkg, error))
229 			return FALSE;
230 	}
231 	return TRUE;
232 }
233 
234 static void
asb_package_alpm_class_init(AsbPackageAlpmClass * klass)235 asb_package_alpm_class_init (AsbPackageAlpmClass *klass)
236 {
237 	AsbPackageClass *package_class = ASB_PACKAGE_CLASS (klass);
238 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
239 
240 	object_class->finalize = asb_package_alpm_finalize;
241 	package_class->open = asb_package_alpm_open;
242 	package_class->ensure = asb_package_alpm_ensure;
243 	package_class->compare = asb_package_alpm_compare;
244 }
245 
246 AsbPackage *
asb_package_alpm_new(void)247 asb_package_alpm_new (void)
248 {
249 	AsbPackage *pkg;
250 	pkg = g_object_new (ASB_TYPE_PACKAGE_ALPM, NULL);
251 	return ASB_PACKAGE (pkg);
252 }
253