1 /*
2 * ggit-blob-output-stream.c
3 * This file is part of libgit2-glib
4 *
5 * Copyright (C) 2013 - Jesse van den Kieboom
6 *
7 * libgit2-glib is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * libgit2-glib is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with libgit2-glib. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "ggit-blob-output-stream.h"
22 #include "ggit-repository.h"
23 #include "ggit-oid.h"
24 #include "ggit-error.h"
25
26 #include <git2.h>
27 #include <string.h>
28
29 /**
30 * GgitBlobOutputStream:
31 *
32 * Represents a blob stream object.
33 */
34
35 typedef struct _GgitBlobOutputStreamPrivate
36 {
37 GgitRepository *repository;
38
39 git_writestream *stream;
40 gboolean something_written;
41
42 gint ret;
43 GgitOId *oid;
44 } GgitBlobOutputStreamPrivate;
45
46 G_DEFINE_TYPE_WITH_PRIVATE (GgitBlobOutputStream, ggit_blob_output_stream, G_TYPE_OUTPUT_STREAM)
47
48 enum
49 {
50 PROP_0,
51 PROP_REPOSITORY
52 };
53
54 static gboolean
ggit_blob_output_stream_close(GOutputStream * object,GCancellable * cancellable,GError ** error)55 ggit_blob_output_stream_close (GOutputStream *object,
56 GCancellable *cancellable,
57 GError **error)
58 {
59 GgitBlobOutputStream *stream = GGIT_BLOB_OUTPUT_STREAM (object);
60 GgitBlobOutputStreamPrivate *priv;
61
62 priv = ggit_blob_output_stream_get_instance_private (stream);
63
64 if (g_cancellable_set_error_if_cancelled (cancellable, error))
65 {
66 return FALSE;
67 }
68
69 if (priv->ret != GIT_OK)
70 {
71 return TRUE;
72 }
73
74 if (priv->something_written)
75 {
76 git_oid oid;
77
78 if (git_blob_create_fromstream_commit (&oid, priv->stream) == GIT_OK)
79 {
80 priv->oid = _ggit_oid_wrap (&oid);
81 }
82 else
83 {
84 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
85 "Could not create object id");
86 return FALSE;
87 }
88 }
89 else
90 {
91 if (priv->stream->close (priv->stream) != GIT_OK)
92 {
93 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
94 "Could not close write stream");
95 return FALSE;
96 }
97 }
98
99 return TRUE;
100 }
101
102 static gboolean
ggit_blob_output_stream_flush(GOutputStream * stream,GCancellable * cancellable,GError ** error)103 ggit_blob_output_stream_flush (GOutputStream *stream,
104 GCancellable *cancellable,
105 GError **error)
106 {
107 if (g_cancellable_set_error_if_cancelled (cancellable, error))
108 {
109 return FALSE;
110 }
111
112 return TRUE;
113 }
114
115 static gssize
ggit_blob_output_stream_write(GOutputStream * object,const void * buffer,gsize count,GCancellable * cancellable,GError ** error)116 ggit_blob_output_stream_write (GOutputStream *object,
117 const void *buffer,
118 gsize count,
119 GCancellable *cancellable,
120 GError **error)
121 {
122 GgitBlobOutputStream *stream = GGIT_BLOB_OUTPUT_STREAM (object);
123 GgitBlobOutputStreamPrivate *priv;
124
125 priv = ggit_blob_output_stream_get_instance_private (stream);
126
127 if (g_cancellable_set_error_if_cancelled (cancellable, error))
128 {
129 return -1;
130 }
131
132 if (priv->ret != GIT_OK)
133 {
134 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
135 "Could not create write stream");
136 return -1;
137 }
138
139 if (count == 0)
140 {
141 return 0;
142 }
143
144 if (count > 0)
145 {
146 gint ret = 0;
147
148 ret = priv->stream->write (priv->stream, buffer, count);
149
150 if (ret == GIT_OK)
151 {
152 priv->something_written = TRUE;
153 return count;
154 }
155 }
156
157 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
158 "Could not write the blob");
159
160 return -1;
161 }
162
163 static void
ggit_blob_output_stream_finalize(GObject * object)164 ggit_blob_output_stream_finalize (GObject *object)
165 {
166 GgitBlobOutputStream *stream;
167 GgitBlobOutputStreamPrivate *priv;
168
169 stream = GGIT_BLOB_OUTPUT_STREAM (object);
170 priv = ggit_blob_output_stream_get_instance_private (stream);
171
172
173 if (priv->oid)
174 {
175 ggit_oid_free (priv->oid);
176 }
177 else
178 {
179 /* NOTE: if we have an oid the stream is already freed */
180 priv->stream->free (priv->stream);
181 }
182
183 g_clear_object (&priv->repository);
184
185 G_OBJECT_CLASS (ggit_blob_output_stream_parent_class)->finalize (object);
186 }
187
188 static void
ggit_blob_output_stream_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)189 ggit_blob_output_stream_set_property (GObject *object,
190 guint prop_id,
191 const GValue *value,
192 GParamSpec *pspec)
193 {
194 GgitBlobOutputStream *stream = GGIT_BLOB_OUTPUT_STREAM (object);
195 GgitBlobOutputStreamPrivate *priv;
196
197 priv = ggit_blob_output_stream_get_instance_private (stream);
198
199 switch (prop_id)
200 {
201 case PROP_REPOSITORY:
202 g_clear_object (&priv->repository);
203 priv->repository = g_value_dup_object (value);
204 break;
205 default:
206 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
207 break;
208 }
209 }
210
211 static void
ggit_blob_output_stream_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)212 ggit_blob_output_stream_get_property (GObject *object,
213 guint prop_id,
214 GValue *value,
215 GParamSpec *pspec)
216 {
217 switch (prop_id)
218 {
219 default:
220 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
221 break;
222 }
223 }
224
225 static void
ggit_blob_output_stream_constructed(GObject * object)226 ggit_blob_output_stream_constructed (GObject *object)
227 {
228 GgitBlobOutputStream *stream;
229 GgitBlobOutputStreamPrivate *priv;
230
231 stream = GGIT_BLOB_OUTPUT_STREAM (object);
232 priv = ggit_blob_output_stream_get_instance_private (stream);
233
234 priv->ret = git_blob_create_fromstream (&priv->stream,
235 _ggit_native_get (priv->repository),
236 NULL);
237
238 G_OBJECT_CLASS (ggit_blob_output_stream_parent_class)->constructed (object);
239 }
240
241 static void
ggit_blob_output_stream_class_init(GgitBlobOutputStreamClass * klass)242 ggit_blob_output_stream_class_init (GgitBlobOutputStreamClass *klass)
243 {
244 GObjectClass *object_class = G_OBJECT_CLASS (klass);
245 GOutputStreamClass *stream_class = G_OUTPUT_STREAM_CLASS (klass);
246
247 object_class->finalize = ggit_blob_output_stream_finalize;
248 object_class->get_property = ggit_blob_output_stream_get_property;
249 object_class->set_property = ggit_blob_output_stream_set_property;
250 object_class->constructed = ggit_blob_output_stream_constructed;
251
252 stream_class->write_fn = ggit_blob_output_stream_write;
253 stream_class->close_fn = ggit_blob_output_stream_close;
254 stream_class->flush = ggit_blob_output_stream_flush;
255
256 g_object_class_install_property (object_class,
257 PROP_REPOSITORY,
258 g_param_spec_object ("repository",
259 "Repository",
260 "Repository",
261 GGIT_TYPE_REPOSITORY,
262 G_PARAM_WRITABLE |
263 G_PARAM_CONSTRUCT_ONLY |
264 G_PARAM_STATIC_STRINGS));
265 }
266
267 static void
ggit_blob_output_stream_init(GgitBlobOutputStream * stream)268 ggit_blob_output_stream_init (GgitBlobOutputStream *stream)
269 {
270 }
271
272 GgitBlobOutputStream *
_ggit_blob_output_stream_new(GgitRepository * repository)273 _ggit_blob_output_stream_new (GgitRepository *repository)
274 {
275 return g_object_new (GGIT_TYPE_BLOB_OUTPUT_STREAM,
276 "repository", repository,
277 NULL);
278 }
279
280 /**
281 * ggit_blob_output_stream_get_id:
282 * @stream: a #GgitBlobOutputStream.
283 * @error: a #GError for error reporting, or %NULL.
284 *
285 * Get the id of the written blob. The blob id is only available after the
286 * stream has been properly closed. If an error occurred while writing the blob,
287 * the %NULL is returned and @error is set accordingly.
288 *
289 * Returns: (transfer full) (nullable): a #GgitOId or %NULL.
290 *
291 **/
292 GgitOId *
ggit_blob_output_stream_get_id(GgitBlobOutputStream * stream,GError ** error)293 ggit_blob_output_stream_get_id (GgitBlobOutputStream *stream,
294 GError **error)
295 {
296 GgitBlobOutputStreamPrivate *priv;
297
298 g_return_val_if_fail (GGIT_IS_BLOB_OUTPUT_STREAM (stream), NULL);
299
300 priv = ggit_blob_output_stream_get_instance_private (stream);
301
302 if (priv->ret != GIT_OK)
303 {
304 _ggit_error_set (error, priv->ret);
305 return NULL;
306 }
307
308 return ggit_oid_copy (priv->oid);
309 }
310
311 /* ex:set ts=8 noet: */
312