summaryrefslogtreecommitdiff
path: root/src/libostree/ostree-content-writer.c
blob: bbca28791d78dde1f7f3b3e14ce2eb368190b9a8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/*
 * 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, see <https://www.gnu.org/licenses/>.
 */

#include "config.h"

#include "ostree-autocleanups.h"
#include "ostree-content-writer.h"
#include "ostree-repo-private.h"

struct _OstreeContentWriter
{
  GOutputStream parent_instance;

  OstreeRepo *repo;
  OstreeRepoBareContent output;
};

G_DEFINE_TYPE (OstreeContentWriter, ostree_content_writer, G_TYPE_OUTPUT_STREAM)

static void ostree_content_writer_finalize (GObject *object);
static gssize ostree_content_writer_write (GOutputStream *stream, const void *buffer, gsize count,
                                           GCancellable *cancellable, GError **error);
static gboolean ostree_content_writer_close (GOutputStream *stream, GCancellable *cancellable,
                                             GError **error);

static void
ostree_content_writer_class_init (OstreeContentWriterClass *klass)
{
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
  GOutputStreamClass *stream_class = G_OUTPUT_STREAM_CLASS (klass);

  gobject_class->finalize = ostree_content_writer_finalize;

  stream_class->write_fn = ostree_content_writer_write;
  stream_class->close_fn = ostree_content_writer_close;
}

static void
ostree_content_writer_finalize (GObject *object)
{
  OstreeContentWriter *stream;

  stream = (OstreeContentWriter *)(object);

  g_clear_object (&stream->repo);
  _ostree_repo_bare_content_cleanup (&stream->output);

  G_OBJECT_CLASS (ostree_content_writer_parent_class)->finalize (object);
}

static void
ostree_content_writer_init (OstreeContentWriter *self)
{
  self->output.initialized = FALSE;
}

OstreeContentWriter *
_ostree_content_writer_new (OstreeRepo *repo, const char *checksum, guint uid, guint gid,
                            guint mode, guint64 content_len, GVariant *xattrs, GError **error)
{
  g_autoptr (OstreeContentWriter) stream = g_object_new (OSTREE_TYPE_CONTENT_WRITER, NULL);
  stream->repo = g_object_ref (repo);
  if (!_ostree_repo_bare_content_open (stream->repo, checksum, content_len, uid, gid, mode, xattrs,
                                       &stream->output, NULL, error))
    return NULL;
  return g_steal_pointer (&stream);
}

static gssize
ostree_content_writer_write (GOutputStream *stream, const void *buffer, gsize count,
                             GCancellable *cancellable, GError **error)
{
  OstreeContentWriter *self = (OstreeContentWriter *)stream;

  if (g_cancellable_set_error_if_cancelled (cancellable, error))
    return -1;

  if (!_ostree_repo_bare_content_write (self->repo, &self->output, buffer, count, cancellable,
                                        error))
    return -1;
  return count;
}

static gboolean
ostree_content_writer_close (GOutputStream *stream, GCancellable *cancellable, GError **error)
{
  /* We don't expect people to invoke close() - they need to call finish()
   * to get the checksum.  We'll clean up in finalize anyways if need be.
   */
  return TRUE;
}

/**
 * ostree_content_writer_finish:
 * @self: Writer
 * @cancellable: Cancellable
 * @error: Error
 *
 * Complete the object write and return the checksum.
 * Returns: (transfer full): Checksum, or %NULL on error
 */
char *
ostree_content_writer_finish (OstreeContentWriter *self, GCancellable *cancellable, GError **error)
{
  char actual_checksum[OSTREE_SHA256_STRING_LEN + 1];
  if (!_ostree_repo_bare_content_commit (self->repo, &self->output, actual_checksum,
                                         sizeof (actual_checksum), cancellable, error))
    return NULL;

  return g_strdup (actual_checksum);
}