<commit_before>/*
 * Copyright © 2017 Endless Mobile, Inc.
 *
 * SPDX-License-Identifier: LGPL-2.0+
 *
 * This library 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 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, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 *
 * Authors:
 *  - <NAME> <<EMAIL>>
 */

#include "config.h"

#include "ot-main.h"
#include "ot-builtins.h"
#include "ostree.h"
#include "otutil.h"

#include "ostree-remote-private.h"

static gboolean opt_disable_fsync = FALSE;
static char *opt_destination_repo = NULL;

static GOptionEntry options[] =
  {
    { "disable-fsync", 0, 0, G_OPTION_ARG_NONE, &opt_disable_fsync, "Do not invoke fsync()", NULL },
    { "destination-repo", 0, 0, G_OPTION_ARG_FILENAME, &opt_destination_repo, "Use custom repository directory within the mount", "DEST" },
    { NULL }
  };

gboolean
ostree_builtin_create_usb (int            argc,
                           char         **argv,
                           OstreeCommandInvocation *invocation,
                           GCancellable  *cancellable,
                           GError       **error)
{
  g_autoptr(GOptionContext) context = NULL;
  g_autoptr(OstreeAsyncProgress) progress = NULL;
  g_auto(GLnxConsoleRef) console = { 0, };

  context = g_option_context_new ("MOUNT-PATH COLLECTION-ID REF [COLLECTION-ID REF...]");

  /* Parse options. */
  g_autoptr(OstreeRepo) src_repo = NULL;

  if (!ostree_option_context_parse (context, options, &argc, &argv, invocation, &src_repo, cancellable, error))
    return FALSE;

  if (argc < 2)
    {
      ot_util_usage_error (context, "A MOUNT-PATH must be specified", error);
      return FALSE;
    }

  if (argc < 4)
    {
      ot_util_usage_error (context, "At least one COLLECTION-ID REF pair must be specified", error);
      return FALSE;
    }

  if (argc % 2 == 1)
    {
      ot_util_usage_error (context, "Only complete COLLECTION-ID REF pairs may be specified", error);
      return FALSE;
    }

  /* Open the USB stick, which must exist. Allow automounting and following symlinks. */
  const char *mount_root_path = argv[1];
  struct stat mount_root_stbuf;

  glnx_autofd int mount_root_dfd = -1;
  if (!glnx_opendirat (AT_FDCWD, mount_root_path, TRUE, &mount_root_dfd, error))
    return FALSE;
  if (!glnx_fstat (mount_root_dfd, &mount_root_stbuf, error))
    return FALSE;

  /* Read in the refs to add to the USB stick. */
  g_autoptr(GPtrArray) refs = g_ptr_array_new_full (argc, (GDestroyNotify) ostree_collection_ref_free);

  for (gsize i = 2; i < argc; i += 2)
    {
      if (!ostree_validate_collection_id (argv[i], error) ||
          !ostree_validate_rev (argv[i + 1], error))
        return FALSE;

      g_ptr_array_add (refs, ostree_collection_ref_new (argv[i], argv[i + 1]));
    }

  /* Open the destination repository on the USB stick or create it if it doesn’t exist.
   * Check it’s below @mount_root_path, and that it’s not the same as the source
   * repository.
   *
   * If the destination file system supports xattrs (for example, ext4), we use
   * a BARE_USER repository; if it doesn’t (for example, FAT), we use ARCHIVE.
   * In either case, we want a lossless repository. */
  const char *dest_repo_path = (opt_destination_repo != NULL) ? opt_destination_repo : ".ostree/repo";

  if (!glnx_shutil_mkdir_p_at (mount_root_dfd, dest_repo_path, 0755, cancellable, error))
    return FALSE;

  OstreeRepoMode mode = OSTREE_REPO_MODE_BARE_USER;

  if (TEMP_FAILURE_RETRY (fgetxattr (mount_root_dfd, "user.test", NULL, 0)) < 0 &&
      (errno == ENOTSUP || errno == EOPNOTSUPP))
    mode = OSTREE_REPO_MODE_ARCHIVE;

  g_debug ("%s: Creating repository in mode %u", G_STRFUNC, mode);

  g_autoptr(OstreeRepo) dest_repo = ostree_repo_create_at (mount_root_dfd, dest_repo_path,
                                                           mode, NULL, cancellable, error);

  if (dest_repo == NULL)
    return FALSE;

  struct stat dest_repo_stbuf;

  if (!glnx_fstat (ostree_repo_get_dfd (dest_repo), &dest_repo_stbuf, error))
    return FALSE;

  if (dest_repo_stbuf.st_dev != mount_root_stbuf.st_dev)
    {
      ot_util_usage_error (context, "--destination-repo must be a descendent of MOUNT-PATH", error);<commit_msg>create-usb: Always use archive mode<commit_after>/*
 * Copyright © 2017 Endless Mobile, Inc.
 *
 * SPDX-License-Identifier: LGPL-2.0+
 *
 * This library 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 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, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 *
 * Authors:
 *  - <NAME> <<EMAIL>>
 */

#include "config.h"

#include "ot-main.h"
#include "ot-builtins.h"
#include "ostree.h"
#include "otutil.h"

#include "ostree-remote-private.h"

static gboolean opt_disable_fsync = FALSE;
static char *opt_destination_repo = NULL;

static GOptionEntry options[] =
  {
    { "disable-fsync", 0, 0, G_OPTION_ARG_NONE, &opt_disable_fsync, "Do not invoke fsync()", NULL },
    { "destination-repo", 0, 0, G_OPTION_ARG_FILENAME, &opt_destination_repo, "Use custom repository directory within the mount", "DEST" },
    { NULL }
  };

gboolean
ostree_builtin_create_usb (int            argc,
                           char         **argv,
                           OstreeCommandInvocation *invocation,
                           GCancellable  *cancellable,
                           GError       **error)
{
  g_autoptr(GOptionContext) context = NULL;
  g_autoptr(OstreeAsyncProgress) progress = NULL;
  g_auto(GLnxConsoleRef) console = { 0, };

  context = g_option_context_new ("MOUNT-PATH COLLECTION-ID REF [COLLECTION-ID REF...]");

  /* Parse options. */
  g_autoptr(OstreeRepo) src_repo = NULL;

  if (!ostree_option_context_parse (context, options, &argc, &argv, invocation, &src_repo, cancellable, error))
    return FALSE;

  if (argc < 2)
    {
      ot_util_usage_error (context, "A MOUNT-PATH must be specified", error);
      return FALSE;
    }

  if (argc < 4)
    {
      ot_util_usage_error (context, "At least one COLLECTION-ID REF pair must be specified", error);
      return FALSE;
    }

  if (argc % 2 == 1)
    {
      ot_util_usage_error (context, "Only complete COLLECTION-ID REF pairs may be specified", error);
      return FALSE;
    }

  /* Open the USB stick, which must exist. Allow automounting and following symlinks. */
  const char *mount_root_path = argv[1];
  struct stat mount_root_stbuf;

  glnx_autofd int mount_root_dfd = -1;
  if (!glnx_opendirat (AT_FDCWD, mount_root_path, TRUE, &mount_root_dfd, error))
    return FALSE;
  if (!glnx_fstat (mount_root_dfd, &mount_root_stbuf, error))
    return FALSE;

  /* Read in the refs to add to the USB stick. */
  g_autoptr(GPtrArray) refs = g_ptr_array_new_full (argc, (GDestroyNotify) ostree_collection_ref_free);

  for (gsize i = 2; i < argc; i += 2)
    {
      if (!ostree_validate_collection_id (argv[i], error) ||
          !ostree_validate_rev (argv[i + 1], error))
        return FALSE;

      g_ptr_array_add (refs, ostree_collection_ref_new (argv[i], argv[i + 1]));
    }

  /* Open the destination repository on the USB stick or create it if it doesn’t exist.
   * Check it’s below @mount_root_path, and that it’s not the same as the source
   * repository. */
  const char *dest_repo_path = (opt_destination_repo != NULL) ? opt_destination_repo : ".ostree/repo";

  if (!glnx_shutil_mkdir_p_at (mount_root_dfd, dest_repo_path, 0755, cancellable, error))
    return FALSE;

  /* Always use the archive repo mode, which works on FAT file systems that
   * don't support xattrs, compresses files to save space, doesn't store
   * permission info directly in the file attributes, and is at least sometimes
   * more performant than bare-user */
  OstreeRepoMode mode = OSTREE_REPO_MODE_ARCHIVE;

  g_debug ("%s: Creating repository in mode %u", G_STRFUNC, mode);

  g_autoptr(OstreeRepo) dest_repo = ostree_repo_create_at (mount_root_dfd, dest_repo_path,
                                                           mode, NULL, cancellable, error);

  if (dest_repo == NULL)
    return FALSE;

  struct stat dest_repo_stbuf;

  if (!glnx_fstat (ostree_repo_get_dfd (dest_repo), &dest_repo_stbuf, error))
    return FALSE;

  if (dest_repo_stbuf.st_dev != mount_root_stbuf.st_dev)
    {
      ot_util_usage_error (context, "--destination-repo must be a descendent of MOUNT-PATH", error);
{'fraction_non_alphanumeric': 0.09831223628691983, 'fraction_numerical': 0.008755274261603375, 'mean_word_length': 3.2630395683453237, 'pattern_counts': {'":': 0, '<': 16, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5305863', 'n_tokens_mistral': 3147, 'n_tokens_neox': 3059, 'n_words': 970}