<commit_before>/*
 * Copyright © 2018 Red Hat, Inc
 *
 * This program 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.1 of the License, or (at your option) any later version.
 *
 * This library 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 library. If not, see <http://www.gnu.org/licenses/>.
 *
 * Authors:
 *       <NAME> <<EMAIL>>
 */

#include <gdk-pixbuf/gdk-pixbuf.h>
#include <glib/gstdio.h>
#include <errno.h>
#include <unistd.h>

static int
validate_icon (const char *arg_width,
               const char *arg_height,
               const char *filename)
{
  GdkPixbufFormat *format;
  int max_width, max_height;
  int width, height;
  const char *name;
  const char *allowed_formats[] = { "png", "jpeg", "svg", NULL };
  g_autoptr(GdkPixbuf) pixbuf = NULL;
  g_autoptr(GError) error = NULL;

  format = gdk_pixbuf_get_file_info (filename, &width, &height);
  if (format == NULL)
    {
      g_printerr ("Format not recognized\n");
      return 1;
    }

  name = gdk_pixbuf_format_get_name (format);
  if (!g_strv_contains (allowed_formats, name))
    {
      g_printerr ("Format %s not accepted\n", name);
      return 1;
    }

  if (!g_str_equal (name, "svg"))
    {
      max_width = g_ascii_strtoll (arg_width, NULL, 10);
      if (max_width < 16 || max_width > 4096)
        {
          g_printerr ("Bad width limit: %s\n", arg_width);
          return 1;
        }

      max_height = g_ascii_strtoll (arg_height, NULL, 10);
      if (max_height < 16 || max_height > 4096)
        {
          g_printerr ("Bad height limit: %s\n", arg_height);
          return 1;
        }
    }
  else
    {
      /* Sanity check for vector files */
      max_height = max_width = 4096;
    }

  if (width > max_width || height > max_height)
    {
      g_printerr ("Image too large (%dx%d). Max. size %dx%d\n", width, height, max_width, max_height);
      return 1;
    }

  pixbuf = gdk_pixbuf_new_from_file (filename, &error);
  if (pixbuf == NULL)
    {
      g_printerr ("Failed to load image: %s\n", error->message);
      return 1;
    }

  return 0;
}

G_GNUC_NULL_TERMINATED
static void
add_args (GPtrArray *argv_array, ...)
{
  va_list args;
  const char *arg;

  va_start (args, argv_array);
  while ((arg = va_arg (args, const gchar *)))
    g_ptr_array_add (argv_array, g_strdup (arg));
  va_end (args);
}

const char *
flatpak_get_bwrap (void)
{
  const char *e = g_getenv ("FLATPAK_BWRAP");

  if (e != NULL)
    return e;
  return HELPER;
}


static gboolean
path_is_usrmerged (const char *dir)
{
  /* does /dir point to /usr/dir? */
  g_autofree char *target = NULL;
  GStatBuf stat_buf_src, stat_buf_target;

  if (g_stat (dir, &stat_buf_src) < 0)
    return FALSE;

  target = g_strdup_printf ("/usr/%s", dir);

  if (g_stat (target, &stat_buf_target) < 0)
    return FALSE;

  return (stat_buf_src.st_dev == stat_buf_target.st_dev) &&
         (stat_buf_src.st_ino == stat_buf_target.st_ino);
}

static int
rerun_in_sandbox (const char *arg_width,
                  const char *arg_height,
                  const char *filename)
{
  const char * const usrmerged_dirs[] = { "bin", "lib64", "lib", "sbin" };
  int i;
  g_autoptr(GPtrArray) args = g_ptr_array_new_with_free_func (g_free);
  char validate_icon[PATH_MAX + 1];
  ssize_t symlink_size;

  symlink_size = readlink ("/proc/self/exe", validate_icon, sizeof (validate_icon) - 1);
  if (symlink_size < 0 || (size_t) symlink_size >= sizeof (validate_icon))
    {
      g_printerr ("Error: failed to read /proc/self/exe\n");
      return 1;
    }

  validate_icon[symlink_size] = 0;

  add_args (args,
            flatpak_get_bwrap (),
            "--unshare-ipc",
            "--unshare-net",
            "--unshare-pid",
            "--ro-bind", "/usr", "/usr",
            "--ro-bind", "/etc/ld.so.cache", "/etc/ld.so.cache",
            "--ro-bind", validate_icon, validate_icon,
            NULL);

  /* These directories might be symlinks into /usr/... */
  for (i = 0; i < G_N_ELEMENTS (usrmerged_dirs); i++)
    {
      g_autofree char *absolute_dir = g_strdup_printf ("/%s", usrmerged_dirs[i]);

      if (!g_file_test (absolute_dir, G_FILE_TEST_EXISTS))
        continue;<commit_msg>icon-validator: Add lib32 to usrmerged_dirs, for completeness<commit_after>/*
 * Copyright © 2018 Red Hat, Inc
 *
 * This program 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.1 of the License, or (at your option) any later version.
 *
 * This library 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 library. If not, see <http://www.gnu.org/licenses/>.
 *
 * Authors:
 *       <NAME> <<EMAIL>>
 */

#include <gdk-pixbuf/gdk-pixbuf.h>
#include <glib/gstdio.h>
#include <errno.h>
#include <unistd.h>

static int
validate_icon (const char *arg_width,
               const char *arg_height,
               const char *filename)
{
  GdkPixbufFormat *format;
  int max_width, max_height;
  int width, height;
  const char *name;
  const char *allowed_formats[] = { "png", "jpeg", "svg", NULL };
  g_autoptr(GdkPixbuf) pixbuf = NULL;
  g_autoptr(GError) error = NULL;

  format = gdk_pixbuf_get_file_info (filename, &width, &height);
  if (format == NULL)
    {
      g_printerr ("Format not recognized\n");
      return 1;
    }

  name = gdk_pixbuf_format_get_name (format);
  if (!g_strv_contains (allowed_formats, name))
    {
      g_printerr ("Format %s not accepted\n", name);
      return 1;
    }

  if (!g_str_equal (name, "svg"))
    {
      max_width = g_ascii_strtoll (arg_width, NULL, 10);
      if (max_width < 16 || max_width > 4096)
        {
          g_printerr ("Bad width limit: %s\n", arg_width);
          return 1;
        }

      max_height = g_ascii_strtoll (arg_height, NULL, 10);
      if (max_height < 16 || max_height > 4096)
        {
          g_printerr ("Bad height limit: %s\n", arg_height);
          return 1;
        }
    }
  else
    {
      /* Sanity check for vector files */
      max_height = max_width = 4096;
    }

  if (width > max_width || height > max_height)
    {
      g_printerr ("Image too large (%dx%d). Max. size %dx%d\n", width, height, max_width, max_height);
      return 1;
    }

  pixbuf = gdk_pixbuf_new_from_file (filename, &error);
  if (pixbuf == NULL)
    {
      g_printerr ("Failed to load image: %s\n", error->message);
      return 1;
    }

  return 0;
}

G_GNUC_NULL_TERMINATED
static void
add_args (GPtrArray *argv_array, ...)
{
  va_list args;
  const char *arg;

  va_start (args, argv_array);
  while ((arg = va_arg (args, const gchar *)))
    g_ptr_array_add (argv_array, g_strdup (arg));
  va_end (args);
}

const char *
flatpak_get_bwrap (void)
{
  const char *e = g_getenv ("FLATPAK_BWRAP");

  if (e != NULL)
    return e;
  return HELPER;
}


static gboolean
path_is_usrmerged (const char *dir)
{
  /* does /dir point to /usr/dir? */
  g_autofree char *target = NULL;
  GStatBuf stat_buf_src, stat_buf_target;

  if (g_stat (dir, &stat_buf_src) < 0)
    return FALSE;

  target = g_strdup_printf ("/usr/%s", dir);

  if (g_stat (target, &stat_buf_target) < 0)
    return FALSE;

  return (stat_buf_src.st_dev == stat_buf_target.st_dev) &&
         (stat_buf_src.st_ino == stat_buf_target.st_ino);
}

static int
rerun_in_sandbox (const char *arg_width,
                  const char *arg_height,
                  const char *filename)
{
  const char * const usrmerged_dirs[] = { "bin", "lib32", "lib64", "lib", "sbin" };
  int i;
  g_autoptr(GPtrArray) args = g_ptr_array_new_with_free_func (g_free);
  char validate_icon[PATH_MAX + 1];
  ssize_t symlink_size;

  symlink_size = readlink ("/proc/self/exe", validate_icon, sizeof (validate_icon) - 1);
  if (symlink_size < 0 || (size_t) symlink_size >= sizeof (validate_icon))
    {
      g_printerr ("Error: failed to read /proc/self/exe\n");
      return 1;
    }

  validate_icon[symlink_size] = 0;

  add_args (args,
            flatpak_get_bwrap (),
            "--unshare-ipc",
            "--unshare-net",
            "--unshare-pid",
            "--ro-bind", "/usr", "/usr",
            "--ro-bind", "/etc/ld.so.cache", "/etc/ld.so.cache",
            "--ro-bind", validate_icon, validate_icon,
            NULL);

  /* These directories might be symlinks into /usr/... */
  for (i = 0; i < G_N_ELEMENTS (usrmerged_dirs); i++)
    {
      g_autofree char *absolute_dir = g_strdup_printf ("/%s", usrmerged_dirs[i]);

      if (!g_file_test (absolute_dir, G_FILE_TEST_EXISTS))
        continue;
{'fraction_non_alphanumeric': 0.12514860045390683, 'fraction_numerical': 0.009726575164811412, 'mean_word_length': 2.7910692339205245, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 31, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3688220', 'n_tokens_mistral': 3393, 'n_tokens_neox': 3230, 'n_words': 906}