Ejemplo n.º 1
0
static gboolean
maybe_prune_loose_object (OtPruneData        *data,
                          OstreeRepoPruneFlags    flags,
                          const char         *checksum,
                          OstreeObjectType    objtype,
                          GCancellable       *cancellable,
                          GError            **error)
{
  g_autoptr(GVariant) key = NULL;

  key = ostree_object_name_serialize (checksum, objtype);

  if (!g_hash_table_lookup_extended (data->reachable, key, NULL, NULL))
    {
      g_debug ("Pruning unneeded object %s.%s", checksum,
               ostree_object_type_to_string (objtype));
      if (!(flags & OSTREE_REPO_PRUNE_FLAGS_NO_PRUNE))
        {
          guint64 storage_size = 0;

          if (objtype == OSTREE_OBJECT_TYPE_COMMIT)
            {
              if (!prune_commitpartial_file (data->repo, checksum, cancellable, error))
                return FALSE;
            }

          if (!ostree_repo_query_object_storage_size (data->repo, objtype, checksum,
                                                      &storage_size, cancellable, error))
            return FALSE;

          if (!ostree_repo_delete_object (data->repo, objtype, checksum,
                                          cancellable, error))
            return FALSE;

          data->freed_bytes += storage_size;
        }
      if (OSTREE_OBJECT_TYPE_IS_META (objtype))
        data->n_unreachable_meta++;
      else
        data->n_unreachable_content++;
    }
  else
    {
      g_debug ("Keeping needed object %s.%s", checksum,
               ostree_object_type_to_string (objtype));
      if (OSTREE_OBJECT_TYPE_IS_META (objtype))
        data->n_reachable_meta++;
      else
        data->n_reachable_content++;
    }

  return TRUE;
}
Ejemplo n.º 2
0
gboolean
ostree_checksum_file_from_input (GFileInfo        *file_info,
                                 GVariant         *xattrs,
                                 GInputStream     *in,
                                 OstreeObjectType  objtype,
                                 guchar          **out_csum,
                                 GCancellable     *cancellable,
                                 GError          **error)
{
  gboolean ret = FALSE;
  ot_lfree guchar *ret_csum = NULL;
  GChecksum *checksum = NULL;

  checksum = g_checksum_new (G_CHECKSUM_SHA256);

  if (OSTREE_OBJECT_TYPE_IS_META (objtype))
    {
      if (!ot_gio_splice_update_checksum (NULL, in, checksum, cancellable, error))
        goto out;
    }
  else if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY)
    {
      ot_lvariant GVariant *dirmeta = ostree_create_directory_metadata (file_info, xattrs);
      g_checksum_update (checksum, g_variant_get_data (dirmeta),
                         g_variant_get_size (dirmeta));
      
    }
  else
    {
      ot_lvariant GVariant *file_header = NULL;

      file_header = ostree_file_header_new (file_info, xattrs);

      if (!ostree_write_file_header_update_checksum (NULL, file_header, checksum,
                                                     cancellable, error))
        goto out;

      if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR)
        {
          if (!ot_gio_splice_update_checksum (NULL, in, checksum, cancellable, error))
            goto out;
        }
    }

  ret_csum = ot_csum_from_gchecksum (checksum);

  ret = TRUE;
  ot_transfer_out_value (out_csum, &ret_csum);
 out:
  g_clear_pointer (&checksum, (GDestroyNotify)g_checksum_free);
  return ret;
}
Ejemplo n.º 3
0
static void
enqueue_one_object_request (OtPullData        *pull_data,
                            GVariant          *object_name,
                            gboolean           is_detached_meta)
{
  const char *checksum;
  OstreeObjectType objtype;
  SoupURI *obj_uri = NULL;
  gboolean is_meta;
  FetchObjectData *fetch_data;
  gs_free char *objpath = NULL;

  ostree_object_name_deserialize (object_name, &checksum, &objtype);

  if (is_detached_meta)
    {
      char buf[_OSTREE_LOOSE_PATH_MAX];
      _ostree_loose_path_with_suffix (buf, checksum, OSTREE_OBJECT_TYPE_COMMIT,
                                      pull_data->remote_mode, "meta");
      obj_uri = suburi_new (pull_data->base_uri, "objects", buf, NULL);
    }
  else
    {
      objpath = _ostree_get_relative_object_path (checksum, objtype, TRUE);
      obj_uri = suburi_new (pull_data->base_uri, objpath, NULL);
    }

  is_meta = OSTREE_OBJECT_TYPE_IS_META (objtype);
  if (is_meta)
    {
      pull_data->n_outstanding_metadata_fetches++;
      pull_data->n_requested_metadata++;
    }
  else
    {
      pull_data->n_outstanding_content_fetches++;
      pull_data->n_requested_content++;
    }
  fetch_data = g_new0 (FetchObjectData, 1);
  fetch_data->pull_data = pull_data;
  fetch_data->object = g_variant_ref (object_name);
  fetch_data->is_detached_meta = is_detached_meta;
  ostree_fetcher_request_uri_with_partial_async (pull_data->fetcher, obj_uri, pull_data->cancellable,
                                                 is_meta ? meta_fetch_on_complete : content_fetch_on_complete, fetch_data);
  soup_uri_free (obj_uri);
}
Ejemplo n.º 4
0
static void
on_metadata_writed (GObject           *object,
                    GAsyncResult      *result,
                    gpointer           user_data)
{
  FetchObjectData *fetch_data = user_data;
  OtPullData *pull_data = fetch_data->pull_data;
  GError *local_error = NULL;
  GError **error = &local_error;
  const char *expected_checksum;
  OstreeObjectType objtype;
  gs_free char *checksum = NULL;
  gs_free guchar *csum = NULL;

  if (!ostree_repo_write_metadata_finish ((OstreeRepo*)object, result, 
                                          &csum, error))
    goto out;

  checksum = ostree_checksum_from_bytes (csum);

  ostree_object_name_deserialize (fetch_data->object, &expected_checksum, &objtype);
  g_assert (OSTREE_OBJECT_TYPE_IS_META (objtype));

  g_debug ("write of %s complete", ostree_object_to_string (checksum, objtype));

  if (strcmp (checksum, expected_checksum) != 0)
    {
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                   "Corrupted metadata object; checksum expected='%s' actual='%s'",
                   expected_checksum, checksum);
      goto out;
    }

  pull_data->metadata_scan_idle = FALSE;
  ot_waitable_queue_push (pull_data->metadata_objects_to_scan,
                          pull_worker_message_new (PULL_MSG_SCAN,
                                                  g_variant_ref (fetch_data->object)));
 out:
  pull_data->n_outstanding_metadata_write_requests--;
  (void) gs_file_unlink (fetch_data->temp_path, NULL, NULL);
  g_object_unref (fetch_data->temp_path);
  g_variant_unref (fetch_data->object);
  g_free (fetch_data);

  check_outstanding_requests_handle_error (pull_data, local_error);
}
Ejemplo n.º 5
0
char *
ostree_get_relative_object_path (const char         *checksum,
                                 OstreeObjectType    type,
                                 gboolean            compressed)
{
  GString *path;

  g_assert (strlen (checksum) == 64);

  path = g_string_new ("objects/");

  g_string_append_len (path, checksum, 2);
  g_string_append_c (path, '/');
  g_string_append (path, checksum + 2);
  g_string_append_c (path, '.');
  g_string_append (path, ostree_object_type_to_string (type));
  if (!OSTREE_OBJECT_TYPE_IS_META (type) && compressed)
    g_string_append (path, "z");

  return g_string_free (path, FALSE);
}
static gboolean
dispatch_open_splice_and_close (OstreeRepo                 *repo,
                                StaticDeltaExecutionState  *state,
                                GCancellable               *cancellable,  
                                GError                    **error)
{
  gboolean ret = FALSE;

  if (!open_output_target (state, cancellable, error))
    goto out;

  if (OSTREE_OBJECT_TYPE_IS_META (state->output_objtype))
    {
      g_autoptr(GVariant) metadata = NULL;
      guint64 offset;
      guint64 length;

      if (!read_varuint64 (state, &length, error))
        goto out;
      if (!read_varuint64 (state, &offset, error))
        goto out;
      if (!validate_ofs (state, offset, length, error))
        goto out;

      if (state->stats_only)
        {
          ret = TRUE;
          goto out;
        }
      
      metadata = g_variant_new_from_data (ostree_metadata_variant_type (state->output_objtype),
                                          state->payload_data + offset, length, TRUE, NULL, NULL);

      {
        g_autofree guchar *actual_csum = NULL;

        if (!ostree_repo_write_metadata (state->repo, state->output_objtype,
                                         state->checksum,
                                         metadata, &actual_csum,
                                         cancellable,
                                         error))
          goto out;
      }
    }
  else
    {
      guint64 content_offset;
      guint64 objlen;
      g_autoptr(GInputStream) object_input = NULL;
      g_autoptr(GInputStream) memin = NULL;
      
      if (!do_content_open_generic (repo, state, cancellable, error))
        goto out;

      if (!read_varuint64 (state, &state->content_size, error))
        goto out;
      if (!read_varuint64 (state, &content_offset, error))
        goto out;
      if (!validate_ofs (state, content_offset, state->content_size, error))
        goto out;
      
      if (state->stats_only)
        {
          ret = TRUE;
          goto out;
        }

      /* Fast path for regular files to bare repositories */
      if (S_ISREG (state->mode) && 
          (repo->mode == OSTREE_REPO_MODE_BARE ||
           repo->mode == OSTREE_REPO_MODE_BARE_USER))
        {
          if (!_ostree_repo_open_content_bare (repo, state->checksum,
                                               state->content_size,
                                               &state->barecommitstate,
                                               &state->content_out,
                                               &state->have_obj,
                                               cancellable, error))
            goto out;

          if (!state->have_obj)
            {
              if (!handle_untrusted_content_checksum (repo, state, cancellable, error))
                goto out;

              if (!content_out_write (repo, state,
                                      state->payload_data + content_offset,
                                      state->content_size,
                                      cancellable, error))
                goto out;
            }
        }
      else
        {
          /* Slower path, for symlinks and unpacking deltas into archive-z2 */
          g_autoptr(GFileInfo) finfo = NULL;
      
          finfo = _ostree_header_gfile_info_new (state->mode, state->uid, state->gid);

          if (S_ISLNK (state->mode))
            {
              g_autofree char *nulterminated_target =
                g_strndup ((char*)state->payload_data + content_offset, state->content_size);
              g_file_info_set_symlink_target (finfo, nulterminated_target);
            }
          else
            {
              g_assert (S_ISREG (state->mode));
              g_file_info_set_size (finfo, state->content_size);
              memin = g_memory_input_stream_new_from_data (state->payload_data + content_offset, state->content_size, NULL);
            }

          if (!ostree_raw_file_to_content_stream (memin, finfo, state->xattrs,
                                                  &object_input, &objlen,
                                                  cancellable, error))
            goto out;

          {
            g_autofree guchar *actual_csum = NULL;
            if (!ostree_repo_write_content (state->repo,
                                            state->checksum,
                                            object_input,
                                            objlen,
                                            &actual_csum,
                                            cancellable,
                                            error))
              goto out;
          }
        }
    }

  if (!dispatch_close (repo, state, cancellable, error))
    goto out;

  ret = TRUE;
 out:
  if (state->stats_only)
    (void) dispatch_close (repo, state, cancellable, NULL);
  if (!ret)
    g_prefix_error (error, "opcode open-splice-and-close: ");
  return ret;
}
Ejemplo n.º 7
0
static gboolean
load_and_fsck_one_object (OstreeRepo            *repo,
                          const char            *checksum,
                          OstreeObjectType       objtype,
                          gboolean              *out_found_corruption,
                          GCancellable          *cancellable,
                          GError               **error)
{
  gboolean ret = FALSE;
  gboolean missing = FALSE;
  gs_unref_variant GVariant *metadata = NULL;
  gs_unref_object GInputStream *input = NULL;
  gs_unref_object GFileInfo *file_info = NULL;
  gs_unref_variant GVariant *xattrs = NULL;
  GError *temp_error = NULL;

  if (OSTREE_OBJECT_TYPE_IS_META (objtype))
    {
      if (!ostree_repo_load_variant (repo, objtype,
                                     checksum, &metadata, &temp_error))
        {
          if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
            {
              g_clear_error (&temp_error);
              g_printerr ("Object missing: %s.%s\n", checksum,
                          ostree_object_type_to_string (objtype));
              missing = TRUE;
            }
          else
            {
              g_prefix_error (error, "Loading metadata object %s: ", checksum);
              goto out;
            }
        }
      else
        {
          if (objtype == OSTREE_OBJECT_TYPE_COMMIT)
            {
              if (!ostree_validate_structureof_commit (metadata, error))
                {
                  g_prefix_error (error, "While validating commit metadata '%s': ", checksum);
                  goto out;
                }
            }
          else if (objtype == OSTREE_OBJECT_TYPE_DIR_TREE)
            {
              if (!ostree_validate_structureof_dirtree (metadata, error))
                {
                  g_prefix_error (error, "While validating directory tree '%s': ", checksum);
                  goto out;
                }
            }
          else if (objtype == OSTREE_OBJECT_TYPE_DIR_META)
            {
              if (!ostree_validate_structureof_dirmeta (metadata, error))
                {
                  g_prefix_error (error, "While validating directory metadata '%s': ", checksum);
                  goto out;
                }
            }
      
          input = g_memory_input_stream_new_from_data (g_variant_get_data (metadata),
                                                       g_variant_get_size (metadata),
                                                       NULL);

        }
    }
  else
    {
      guint32 mode;
      g_assert (objtype == OSTREE_OBJECT_TYPE_FILE);
      if (!ostree_repo_load_file (repo, checksum, &input, &file_info,
                                  &xattrs, cancellable, &temp_error))
        {
          if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
            {
              g_clear_error (&temp_error);
              g_printerr ("Object missing: %s.%s\n", checksum,
                          ostree_object_type_to_string (objtype));
              missing = TRUE;
            }
          else
            {
              g_prefix_error (error, "Loading file object %s: ", checksum);
              goto out;
            }
        }
      else
        {
          mode = g_file_info_get_attribute_uint32 (file_info, "unix::mode");
          if (!ostree_validate_structureof_file_mode (mode, error))
            {
              g_prefix_error (error, "While validating file '%s': ", checksum);
              goto out;
            }
        }
    }

  if (missing)
    {
      *out_found_corruption = TRUE;
    }
  else
    {
      gs_free guchar *computed_csum = NULL;
      gs_free char *tmp_checksum = NULL;

      if (!ostree_checksum_file_from_input (file_info, xattrs, input,
                                            objtype, &computed_csum,
                                            cancellable, error))
        goto out;
      
      tmp_checksum = ostree_checksum_from_bytes (computed_csum);
      if (strcmp (checksum, tmp_checksum) != 0)
        {
          gs_free char *msg = g_strdup_printf ("corrupted object %s.%s; actual checksum: %s",
                                               checksum, ostree_object_type_to_string (objtype),
                                               tmp_checksum);
          if (opt_delete)
            {
              g_printerr ("%s\n", msg);
              (void) ostree_repo_delete_object (repo, objtype, checksum, cancellable, NULL);
              *out_found_corruption = TRUE;
            }
          else
            {
              g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, msg);
              goto out;
            }
        }
    }

  ret = TRUE;
 out:
  return ret;
}
Ejemplo n.º 8
0
static gboolean
maybe_prune_loose_object (OtPruneData        *data,
                          OstreeRepoPruneFlags    flags,
                          const char         *checksum,
                          OstreeObjectType    objtype,
                          GCancellable       *cancellable,
                          GError            **error)
{
  gboolean reachable = FALSE;
  g_autoptr(GVariant) key = NULL;

  key = ostree_object_name_serialize (checksum, objtype);

  if (g_hash_table_lookup_extended (data->reachable, key, NULL, NULL))
    reachable = TRUE;
  else
    {
      guint64 storage_size = 0;

      g_debug ("Pruning unneeded object %s.%s", checksum,
               ostree_object_type_to_string (objtype));

      if (!ostree_repo_query_object_storage_size (data->repo, objtype, checksum,
                                                  &storage_size, cancellable, error))
        return FALSE;

      data->freed_bytes += storage_size;

      if (!(flags & OSTREE_REPO_PRUNE_FLAGS_NO_PRUNE))
        {
          if (objtype == OSTREE_OBJECT_TYPE_PAYLOAD_LINK)
            {
              ssize_t size;
              char loose_path_buf[_OSTREE_LOOSE_PATH_MAX];
              char target_checksum[OSTREE_SHA256_STRING_LEN+1];
              char target_buf[_OSTREE_LOOSE_PATH_MAX + _OSTREE_PAYLOAD_LINK_PREFIX_LEN];

              _ostree_loose_path (loose_path_buf, checksum, OSTREE_OBJECT_TYPE_PAYLOAD_LINK, data->repo->mode);
              size = readlinkat (data->repo->objects_dir_fd, loose_path_buf, target_buf, sizeof (target_buf));
              if (size < 0)
                return glnx_throw_errno_prefix (error, "readlinkat");

              if (size < OSTREE_SHA256_STRING_LEN + _OSTREE_PAYLOAD_LINK_PREFIX_LEN)
                return glnx_throw (error, "invalid data size for %s", loose_path_buf);

              sprintf (target_checksum, "%.2s%.62s", target_buf + _OSTREE_PAYLOAD_LINK_PREFIX_LEN, target_buf + _OSTREE_PAYLOAD_LINK_PREFIX_LEN + 3);

              g_autoptr(GVariant) target_key = ostree_object_name_serialize (target_checksum, OSTREE_OBJECT_TYPE_FILE);

              if (g_hash_table_lookup_extended (data->reachable, target_key, NULL, NULL))
                {
                  guint64 target_storage_size = 0;
                  if (!ostree_repo_query_object_storage_size (data->repo, OSTREE_OBJECT_TYPE_FILE, target_checksum,
                                                              &target_storage_size, cancellable, error))
                    return FALSE;

                  reachable = target_storage_size >= data->repo->payload_link_threshold;
                  if (reachable)
                    goto exit;
                }
            }
          else if (objtype == OSTREE_OBJECT_TYPE_COMMIT)
            {
              if (!ostree_repo_mark_commit_partial (data->repo, checksum, FALSE, error))
                return FALSE;
            }

          if (!ostree_repo_delete_object (data->repo, objtype, checksum,
                                          cancellable, error))
            return FALSE;

        }

      if (OSTREE_OBJECT_TYPE_IS_META (objtype))
        data->n_unreachable_meta++;
      else
        data->n_unreachable_content++;
    }

 exit:
  if (reachable)
    {
      g_debug ("Keeping needed object %s.%s", checksum,
               ostree_object_type_to_string (objtype));
      if (OSTREE_OBJECT_TYPE_IS_META (objtype))
        data->n_reachable_meta++;
      else
        data->n_reachable_content++;
    }

  return TRUE;
}