Files
flatpak/builder/builder-utils.c
Sam Thursfield d5c176f440 builder: Don't delete the APPDIR directory
A new user might think that APPDIR is the location of the app to be
built, and run something like `xdg-app-builder . ./manifest`. This
could silently the user's entire project that they are trying to
package, which is not acceptable at all! Even if you think it is their
fault for not reading the manual first!

This commit means that APPDIR is no longer deleted. Instead,
xdg-app-builder checks whether it is empty and, if it is not, it asks
the user to delete the contents and then rerun it.

This means you now have to do `rm -Rf APPDIR; xdg-app-builder APPDIR
MANIFEST` when developing your manifest, but I think that's better than
having a build tool that can optionally delete your whole project.
2016-01-17 18:16:05 +00:00

238 lines
5.3 KiB
C

/* builder-utils.c
*
* Copyright (C) 2015 Red Hat, Inc
*
* This file is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Authors:
* Alexander Larsson <alexl@redhat.com>
*/
#include "config.h"
#include <libelf.h>
#include <gelf.h>
#include <sys/mman.h>
#include <string.h>
#include "xdg-app-utils.h"
#include "builder-utils.h"
char *
builder_uri_to_filename (const char *uri)
{
GString *s;
const char *p;
s = g_string_new ("");
for (p = uri; *p != 0; p++)
{
if (*p == '/' || *p == ':')
{
while (p[1] == '/' || p[1] == ':')
p++;
g_string_append_c (s, '_');
}
else
g_string_append_c (s, *p);
}
return g_string_free (s, FALSE);
}
const char *
inplace_basename (const char *path)
{
const char *last_slash;
last_slash = strrchr (path, '/');
if (last_slash)
path = last_slash + 1;
return path;
}
/* Adds all matches of path to prefix. There can be multiple, because
* e.g matching "a/b/c" against "/a" matches both "a/b" and "a/b/c"
*
* If pattern starts with a slash, then match on the entire
* path, otherwise just the basename.
*/
void
xdg_app_collect_matches_for_path_pattern (const char *path,
const char *pattern,
const char *add_prefix,
GHashTable *to_remove_ht)
{
const char *rest;
if (pattern[0] != '/')
{
rest = xdg_app_path_match_prefix (pattern, inplace_basename (path));
if (rest != NULL)
g_hash_table_insert (to_remove_ht, g_strconcat (add_prefix ? add_prefix : "", path, NULL), GINT_TO_POINTER (1));
}
else
{
/* Absolute pathname match. This can actually match multiple
* files, as a prefix match should remove all files below that
* (in this module) */
rest = xdg_app_path_match_prefix (pattern, path);
while (rest != NULL)
{
const char *slash;
g_autofree char *prefix = g_strndup (path, rest-path);
g_hash_table_insert (to_remove_ht, g_strconcat (add_prefix ? add_prefix : "", prefix, NULL), GINT_TO_POINTER (1));
while (*rest == '/')
rest++;
if (*rest == 0)
break;
slash = strchr (rest, '/');
rest = slash ? slash : rest + strlen (rest);
}
}
}
gboolean
xdg_app_matches_path_pattern (const char *path,
const char *pattern)
{
if (pattern[0] != '/')
path = inplace_basename (path);
return xdg_app_path_match_prefix (pattern, path) != NULL;
}
gboolean
strip (GError **error,
...)
{
gboolean res;
va_list ap;
va_start (ap, error);
res = xdg_app_spawn (NULL, NULL, error, "strip", ap);
va_end (ap);
return res;
}
gboolean
eu_strip (GError **error,
...)
{
gboolean res;
va_list ap;
va_start (ap, error);
res = xdg_app_spawn (NULL, NULL, error, "eu-strip", ap);
va_end (ap);
return res;
}
static gboolean elf_has_symtab (Elf *elf)
{
Elf_Scn *scn;
GElf_Shdr shdr;
scn = NULL;
while ((scn = elf_nextscn(elf, scn)) != NULL)
{
if (gelf_getshdr (scn, &shdr) == NULL)
continue;
if (shdr.sh_type != SHT_SYMTAB)
continue;
return TRUE;
}
return FALSE;
}
gboolean is_elf_file (const char *path,
gboolean *is_shared,
gboolean *is_stripped)
{
g_autofree char *filename = g_path_get_basename (path);
struct stat stbuf;
if (lstat (path, &stbuf) == -1)
return FALSE;
if (!S_ISREG (stbuf.st_mode))
return FALSE;
if ((strstr (filename, ".so.") != NULL ||
g_str_has_suffix (filename, ".so")) ||
(stbuf.st_mode & 0111) != 0)
{
glnx_fd_close int fd = -1;
fd = open (path, O_RDONLY|O_NOFOLLOW|O_CLOEXEC);
if (fd >= 0)
{
Elf *elf;
GElf_Ehdr ehdr;
gboolean res = FALSE;
if (elf_version (EV_CURRENT) == EV_NONE )
return FALSE;
elf = elf_begin (fd, ELF_C_READ, NULL);
if (elf == NULL)
return FALSE;
if (elf_kind (elf) == ELF_K_ELF &&
gelf_getehdr (elf, &ehdr))
{
if (is_shared)
*is_shared = ehdr.e_type == ET_DYN;
if (is_stripped)
*is_stripped = !elf_has_symtab (elf);
res = TRUE;
}
elf_end (elf);
return res;
}
}
return FALSE;
}
gboolean directory_is_empty (const char *path)
{
GDir *dir;
gboolean empty;
dir = g_dir_open (path, 0, NULL);
if (g_dir_read_name (dir) == NULL)
empty = TRUE;
else
empty = FALSE;
g_dir_close (dir);
return empty;
}