test_full (void)
{
  g_autoptr(GError) error = NULL;
  g_autoptr(FlatpakBwrap) bwrap = flatpak_bwrap_new (NULL);
  g_autoptr(FlatpakExports) exports = flatpak_exports_new ();
  g_autofree gchar *subdir = g_build_filename (testdir, "test_full", NULL);
  g_autofree gchar *expose_rw = g_build_filename (subdir, "expose-rw", NULL);
  g_autofree gchar *in_expose_rw = g_build_filename (subdir, "expose-rw",
                                                     "file", NULL);
  g_autofree gchar *dangling_link_in_expose_rw = g_build_filename (subdir,
                                                                   "expose-rw",
                                                                   "dangling",
                                                                   NULL);
  g_autofree gchar *expose_ro = g_build_filename (subdir, "expose-ro", NULL);
  g_autofree gchar *in_expose_ro = g_build_filename (subdir, "expose-ro",
                                                     "file", NULL);
  g_autofree gchar *hide = g_build_filename (subdir, "hide", NULL);
  g_autofree gchar *dont_hide = g_build_filename (subdir, "dont-hide", NULL);
  g_autofree gchar *hide_below_expose = g_build_filename (subdir,
                                                          "expose-ro",
                                                          "hide-me",
                                                          NULL);
  g_autofree gchar *enoent = g_build_filename (subdir, "ENOENT", NULL);
  g_autofree gchar *one = g_build_filename (subdir, "1", NULL);
  g_autofree gchar *rel_link = g_build_filename (subdir, "1", "rel-link", NULL);
  g_autofree gchar *abs_link = g_build_filename (subdir, "1", "abs-link", NULL);
  g_autofree gchar *in_abs_link = g_build_filename (subdir, "1", "abs-link",
                                                    "file", NULL);
  g_autofree gchar *dangling = g_build_filename (subdir, "1", "dangling", NULL);
  g_autofree gchar *in_dangling = g_build_filename (subdir, "1", "dangling",
                                                    "file", NULL);
  g_autofree gchar *abs_target = g_build_filename (subdir, "2", "abs-target", NULL);
  g_autofree gchar *target = g_build_filename (subdir, "2", "target", NULL);
  g_autofree gchar *create_dir = g_build_filename (subdir, "create-dir", NULL);
  g_autofree gchar *create_dir2 = g_build_filename (subdir, "create-dir2", NULL);
  gsize i;

  glnx_shutil_rm_rf_at (-1, subdir, NULL, &error);

  if (error != NULL)
    {
      g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND);
      g_clear_error (&error);
    }

  if (g_mkdir_with_parents (expose_rw, S_IRWXU) != 0)
    g_error ("mkdir: %s", g_strerror (errno));

  if (g_mkdir_with_parents (expose_ro, S_IRWXU) != 0)
    g_error ("mkdir: %s", g_strerror (errno));

  if (g_mkdir_with_parents (hide_below_expose, S_IRWXU) != 0)
    g_error ("mkdir: %s", g_strerror (errno));

  if (g_mkdir_with_parents (hide, S_IRWXU) != 0)
    g_error ("mkdir: %s", g_strerror (errno));

  if (g_mkdir_with_parents (dont_hide, S_IRWXU) != 0)
    g_error ("mkdir: %s", g_strerror (errno));

  if (g_mkdir_with_parents (dont_hide, S_IRWXU) != 0)
    g_error ("mkdir: %s", g_strerror (errno));

  if (g_mkdir_with_parents (abs_target, S_IRWXU) != 0)
    g_error ("mkdir: %s", g_strerror (errno));

  if (g_mkdir_with_parents (target, S_IRWXU) != 0)
    g_error ("mkdir: %s", g_strerror (errno));

  if (g_mkdir_with_parents (one, S_IRWXU) != 0)
    g_error ("mkdir: %s", g_strerror (errno));

  if (g_mkdir_with_parents (create_dir, S_IRWXU) != 0)
    g_error ("mkdir: %s", g_strerror (errno));

  if (symlink (abs_target, abs_link) != 0)
    g_error ("symlink: %s", g_strerror (errno));

  if (symlink ("nope", dangling) != 0)
    g_error ("symlink: %s", g_strerror (errno));

  if (symlink ("nope", dangling_link_in_expose_rw) != 0)
    g_error ("symlink: %s", g_strerror (errno));

  if (symlink ("../2/target", rel_link) != 0)
    g_error ("symlink: %s", g_strerror (errno));

  flatpak_exports_add_host_etc_expose (exports,
                                       FLATPAK_FILESYSTEM_MODE_READ_WRITE);
  flatpak_exports_add_host_os_expose (exports,
                                      FLATPAK_FILESYSTEM_MODE_READ_ONLY);
  flatpak_exports_add_path_expose (exports,
                                   FLATPAK_FILESYSTEM_MODE_READ_WRITE,
                                   expose_rw);
  flatpak_exports_add_path_expose (exports,
                                   FLATPAK_FILESYSTEM_MODE_READ_ONLY,
                                   expose_ro);
  flatpak_exports_add_path_tmpfs (exports, hide_below_expose);
  flatpak_exports_add_path_expose_or_hide (exports,
                                           FLATPAK_FILESYSTEM_MODE_NONE,
                                           hide);
  flatpak_exports_add_path_expose_or_hide (exports,
                                           FLATPAK_FILESYSTEM_MODE_READ_ONLY,
                                           dont_hide);
  flatpak_exports_add_path_expose_or_hide (exports,
                                           FLATPAK_FILESYSTEM_MODE_READ_ONLY,
                                           enoent);
  flatpak_exports_add_path_expose_or_hide (exports,
                                           FLATPAK_FILESYSTEM_MODE_READ_WRITE,
                                           rel_link);
  flatpak_exports_add_path_expose_or_hide (exports,
                                           FLATPAK_FILESYSTEM_MODE_READ_WRITE,
                                           abs_link);
  flatpak_exports_add_path_dir (exports, create_dir);
  flatpak_exports_add_path_dir (exports, create_dir2);

  g_assert_cmpuint (flatpak_exports_path_get_mode (exports, expose_rw), ==,
                    FLATPAK_FILESYSTEM_MODE_READ_WRITE);
  g_assert_cmpuint (flatpak_exports_path_get_mode (exports, expose_ro), ==,
                    FLATPAK_FILESYSTEM_MODE_READ_ONLY);
  g_assert_cmpuint (flatpak_exports_path_get_mode (exports, hide_below_expose), ==,
                    FLATPAK_FILESYSTEM_MODE_NONE);
  g_assert_cmpuint (flatpak_exports_path_get_mode (exports, hide), ==,
                    FLATPAK_FILESYSTEM_MODE_NONE);
  g_assert_cmpuint (flatpak_exports_path_get_mode (exports, dont_hide), ==,
                    FLATPAK_FILESYSTEM_MODE_READ_ONLY);
  /* It knows enoent didn't really exist */
  g_assert_cmpuint (flatpak_exports_path_get_mode (exports, enoent), ==,
                    FLATPAK_FILESYSTEM_MODE_NONE);
  g_assert_cmpuint (flatpak_exports_path_get_mode (exports, abs_link), ==,
                    FLATPAK_FILESYSTEM_MODE_READ_WRITE);
  g_assert_cmpuint (flatpak_exports_path_get_mode (exports, rel_link), ==,
                    FLATPAK_FILESYSTEM_MODE_READ_WRITE);

  /* Files the app would be allowed to create count as exposed */
  g_assert_cmpuint (flatpak_exports_path_get_mode (exports, in_expose_ro), ==,
                    FLATPAK_FILESYSTEM_MODE_NONE);
  g_assert_cmpuint (flatpak_exports_path_get_mode (exports, in_expose_rw), ==,
                    FLATPAK_FILESYSTEM_MODE_READ_WRITE);
  g_assert_cmpuint (flatpak_exports_path_get_mode (exports, in_abs_link), ==,
                    FLATPAK_FILESYSTEM_MODE_READ_WRITE);
  g_assert_cmpuint (flatpak_exports_path_get_mode (exports, in_dangling), ==,
                    FLATPAK_FILESYSTEM_MODE_NONE);

  flatpak_bwrap_add_arg (bwrap, "bwrap");
  flatpak_exports_append_bwrap_args (exports, bwrap);
  flatpak_bwrap_finish (bwrap);
  print_bwrap (bwrap);

  i = 0;
  g_assert_cmpuint (i, <, bwrap->argv->len);
  g_assert_cmpstr (bwrap->argv->pdata[i++], ==, "bwrap");

  i = assert_next_is_symlink (bwrap, i, abs_target, abs_link);
  i = assert_next_is_symlink (bwrap, i, "../2/target", rel_link);
  i = assert_next_is_bind (bwrap, i, "--bind", abs_target, abs_target);
  i = assert_next_is_bind (bwrap, i, "--bind", target, target);
  i = assert_next_is_dir (bwrap, i, create_dir);

  /* create_dir2 is not currently created with --dir inside the container
   * because it doesn't exist outside the container.
   * (Is this correct? For now, tolerate either way) */
  if (i + 2 < bwrap->argv->len &&
      g_strcmp0 (bwrap->argv->pdata[i], "--dir") == 0 &&
      g_strcmp0 (bwrap->argv->pdata[i + 1], create_dir2) == 0)
    i += 2;

  i = assert_next_is_bind (bwrap, i, "--ro-bind", dont_hide, dont_hide);
  i = assert_next_is_bind (bwrap, i, "--ro-bind", expose_ro, expose_ro);

  /* We don't create a FAKE_MODE_TMPFS in the container unless there is
   * a directory on the host to mount it on.
   * Hiding $subdir/expose-ro/hide-me has to use --tmpfs because
   * $subdir/expose-ro *is* exposed. */
  i = assert_next_is_tmpfs (bwrap, i, hide_below_expose);

  i = assert_next_is_bind (bwrap, i, "--bind", expose_rw, expose_rw);

  /* Hiding $subdir/hide just uses --dir, because $subdir is not
   * exposed. */
  i = assert_next_is_dir (bwrap, i, hide);

  while (i < bwrap->argv->len && bwrap->argv->pdata[i] != NULL)
    {
      /* An unknown number of --bind, --ro-bind and --symlink,
       * depending how your /usr and /etc are set up.
       * About the only thing we can say is that they are in threes. */
      g_assert_cmpuint (i++, <, bwrap->argv->len);
      g_assert_cmpuint (i++, <, bwrap->argv->len);
      g_assert_cmpuint (i++, <, bwrap->argv->len);
    }

  g_assert_cmpuint (i, ==, bwrap->argv->len - 1);
  g_assert_cmpstr (bwrap->argv->pdata[i++], ==, NULL);
  g_assert_cmpuint (i, ==, bwrap->argv->len);

  glnx_shutil_rm_rf_at (-1, subdir, NULL, &error);

  if (error != NULL)
    {
      g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND);
      g_clear_error (&error);
    }
}
test_full (void)
{
  g_autoptr(GError) error = NULL;
  g_autoptr(FlatpakBwrap) bwrap = flatpak_bwrap_new (NULL);
  g_autoptr(FlatpakExports) exports = flatpak_exports_new ();
  g_autofree gchar *subdir = g_build_filename (testdir, "test_full", NULL);
  g_autofree gchar *expose_rw = g_build_filename (subdir, "expose-rw", NULL);
  g_autofree gchar *in_expose_rw = g_build_filename (subdir, "expose-rw",
                                                     "file", NULL);
  g_autofree gchar *dangling_link_in_expose_rw = g_build_filename (subdir,
                                                                   "expose-rw",
                                                                   "dangling",
                                                                   NULL);
  g_autofree gchar *expose_ro = g_build_filename (subdir, "expose-ro", NULL);
  g_autofree gchar *in_expose_ro = g_build_filename (subdir, "expose-ro",
                                                     "file", NULL);
  g_autofree gchar *hide = g_build_filename (subdir, "hide", NULL);
  g_autofree gchar *dont_hide = g_build_filename (subdir, "dont-hide", NULL);
  g_autofree gchar *hide_below_expose = g_build_filename (subdir,
                                                          "expose-ro",
                                                          "hide-me",
                                                          NULL);
  g_autofree gchar *enoent = g_build_filename (subdir, "ENOENT", NULL);
  g_autofree gchar *one = g_build_filename (subdir, "1", NULL);
  g_autofree gchar *rel_link = g_build_filename (subdir, "1", "rel-link", NULL);
  g_autofree gchar *abs_link = g_build_filename (subdir, "1", "abs-link", NULL);
  g_autofree gchar *in_abs_link = g_build_filename (subdir, "1", "abs-link",
                                                    "file", NULL);
  g_autofree gchar *dangling = g_build_filename (subdir, "1", "dangling", NULL);
  g_autofree gchar *in_dangling = g_build_filename (subdir, "1", "dangling",
                                                    "file", NULL);
  g_autofree gchar *abs_target = g_build_filename (subdir, "2", "abs-target", NULL);
  g_autofree gchar *target = g_build_filename (subdir, "2", "target", NULL);
  g_autofree gchar *create_dir = g_build_filename (subdir, "create-dir", NULL);
  g_autofree gchar *create_dir2 = g_build_filename (subdir, "create-dir2", NULL);
  gsize i;

  glnx_shutil_rm_rf_at (-1, subdir, NULL, &error);

  if (error != NULL)
    {
      g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND);
      g_clear_error (&error);
    }

  if (g_mkdir_with_parents (expose_rw, S_IRWXU) != 0)
    g_error ("mkdir: %s", g_strerror (errno));

  if (g_mkdir_with_parents (expose_ro, S_IRWXU) != 0)
    g_error ("mkdir: %s", g_strerror (errno));

  if (g_mkdir_with_parents (hide_below_expose, S_IRWXU) != 0)
    g_error ("mkdir: %s", g_strerror (errno));

  if (g_mkdir_with_parents (hide, S_IRWXU) != 0)
    g_error ("mkdir: %s", g_strerror (errno));

  if (g_mkdir_with_parents (dont_hide, S_IRWXU) != 0)
    g_error ("mkdir: %s", g_strerror (errno));

  if (g_mkdir_with_parents (dont_hide, S_IRWXU) != 0)
    g_error ("mkdir: %s", g_strerror (errno));

  if (g_mkdir_with_parents (abs_target, S_IRWXU) != 0)
    g_error ("mkdir: %s", g_strerror (errno));

  if (g_mkdir_with_parents (target, S_IRWXU) != 0)
    g_error ("mkdir: %s", g_strerror (errno));

  if (g_mkdir_with_parents (one, S_IRWXU) != 0)
    g_error ("mkdir: %s", g_strerror (errno));

  if (g_mkdir_with_parents (create_dir, S_IRWXU) != 0)
    g_error ("mkdir: %s", g_strerror (errno));

  if (symlink (abs_target, abs_link) != 0)
    g_error ("symlink: %s", g_strerror (errno));

  if (symlink ("nope", dangling) != 0)
    g_error ("symlink: %s", g_strerror (errno));

  if (symlink ("nope", dangling_link_in_expose_rw) != 0)
    g_error ("symlink: %s", g_strerror (errno));

  if (symlink ("../2/target", rel_link) != 0)
    g_error ("symlink: %s", g_strerror (errno));

  flatpak_exports_add_host_etc_expose (exports,
                                       FLATPAK_FILESYSTEM_MODE_READ_WRITE);
  flatpak_exports_add_host_os_expose (exports,
                                      FLATPAK_FILESYSTEM_MODE_READ_ONLY);
  flatpak_exports_add_path_expose (exports,
                                   FLATPAK_FILESYSTEM_MODE_READ_WRITE,
                                   expose_rw);
  flatpak_exports_add_path_expose (exports,
                                   FLATPAK_FILESYSTEM_MODE_READ_ONLY,
                                   expose_ro);
  flatpak_exports_add_path_tmpfs (exports, hide_below_expose);
  flatpak_exports_add_path_expose_or_hide (exports,
                                           FLATPAK_FILESYSTEM_MODE_NONE,
                                           hide);
  flatpak_exports_add_path_expose_or_hide (exports,
                                           FLATPAK_FILESYSTEM_MODE_READ_ONLY,
                                           dont_hide);
  flatpak_exports_add_path_expose_or_hide (exports,
                                           FLATPAK_FILESYSTEM_MODE_READ_ONLY,
                                           enoent);
  flatpak_exports_add_path_expose_or_hide (exports,
                                           FLATPAK_FILESYSTEM_MODE_READ_WRITE,
                                           rel_link);
  flatpak_exports_add_path_expose_or_hide (exports,
                                           FLATPAK_FILESYSTEM_MODE_READ_WRITE,
                                           abs_link);
  flatpak_exports_add_path_dir (exports, create_dir);
  flatpak_exports_add_path_dir (exports, create_dir2);

  g_assert_cmpuint (flatpak_exports_path_get_mode (exports, expose_rw), ==,
                    FLATPAK_FILESYSTEM_MODE_READ_WRITE);
  g_assert_cmpuint (flatpak_exports_path_get_mode (exports, expose_ro), ==,
                    FLATPAK_FILESYSTEM_MODE_READ_ONLY);
  g_assert_cmpuint (flatpak_exports_path_get_mode (exports, hide_below_expose), ==,
                    FLATPAK_FILESYSTEM_MODE_NONE);
  g_assert_cmpuint (flatpak_exports_path_get_mode (exports, hide), ==,
                    FLATPAK_FILESYSTEM_MODE_NONE);
  g_assert_cmpuint (flatpak_exports_path_get_mode (exports, dont_hide), ==,
                    FLATPAK_FILESYSTEM_MODE_READ_ONLY);
   
  g_assert_cmpuint (flatpak_exports_path_get_mode (exports, enoent), ==,
                    FLATPAK_FILESYSTEM_MODE_NONE);
  g_assert_cmpuint (flatpak_exports_path_get_mode (exports, abs_link), ==,
                    FLATPAK_FILESYSTEM_MODE_READ_WRITE);
  g_assert_cmpuint (flatpak_exports_path_get_mode (exports, rel_link), ==,
                    FLATPAK_FILESYSTEM_MODE_READ_WRITE);

   
  g_assert_cmpuint (flatpak_exports_path_get_mode (exports, in_expose_ro), ==,
                    FLATPAK_FILESYSTEM_MODE_NONE);
  g_assert_cmpuint (flatpak_exports_path_get_mode (exports, in_expose_rw), ==,
                    FLATPAK_FILESYSTEM_MODE_READ_WRITE);
  g_assert_cmpuint (flatpak_exports_path_get_mode (exports, in_abs_link), ==,
                    FLATPAK_FILESYSTEM_MODE_READ_WRITE);
  g_assert_cmpuint (flatpak_exports_path_get_mode (exports, in_dangling), ==,
                    FLATPAK_FILESYSTEM_MODE_NONE);

  flatpak_bwrap_add_arg (bwrap, "bwrap");
  flatpak_exports_append_bwrap_args (exports, bwrap);
  flatpak_bwrap_finish (bwrap);
  print_bwrap (bwrap);

  i = 0;
  g_assert_cmpuint (i, <, bwrap->argv->len);
  g_assert_cmpstr (bwrap->argv->pdata[i++], ==, "bwrap");

  i = assert_next_is_symlink (bwrap, i, abs_target, abs_link);
  i = assert_next_is_symlink (bwrap, i, "../2/target", rel_link);
  i = assert_next_is_bind (bwrap, i, "--bind", abs_target, abs_target);
  i = assert_next_is_bind (bwrap, i, "--bind", target, target);
  i = assert_next_is_dir (bwrap, i, create_dir);

   
  if (i + 2 < bwrap->argv->len &&
      g_strcmp0 (bwrap->argv->pdata[i], "--dir") == 0 &&
      g_strcmp0 (bwrap->argv->pdata[i + 1], create_dir2) == 0)
    i += 2;

  i = assert_next_is_bind (bwrap, i, "--ro-bind", dont_hide, dont_hide);
  i = assert_next_is_bind (bwrap, i, "--ro-bind", expose_ro, expose_ro);

   
  i = assert_next_is_tmpfs (bwrap, i, hide_below_expose);

  i = assert_next_is_bind (bwrap, i, "--bind", expose_rw, expose_rw);

   
  i = assert_next_is_dir (bwrap, i, hide);

  while (i < bwrap->argv->len && bwrap->argv->pdata[i] != NULL)
    {
       
      g_assert_cmpuint (i++, <, bwrap->argv->len);
      g_assert_cmpuint (i++, <, bwrap->argv->len);
      g_assert_cmpuint (i++, <, bwrap->argv->len);
    }

  g_assert_cmpuint (i, ==, bwrap->argv->len - 1);
  g_assert_cmpstr (bwrap->argv->pdata[i++], ==, NULL);
  g_assert_cmpuint (i, ==, bwrap->argv->len);

  glnx_shutil_rm_rf_at (-1, subdir, NULL, &error);

  if (error != NULL)
    {
      g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND);
      g_clear_error (&error);
    }
}