/src/pango/subprojects/glib/gio/gfileiostream.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* GIO - GLib Input, IO and Streaming Library |
2 | | * |
3 | | * Copyright (C) 2006-2007 Red Hat, Inc. |
4 | | * |
5 | | * SPDX-License-Identifier: LGPL-2.1-or-later |
6 | | * |
7 | | * This library 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 | | * This library 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 |
18 | | * Public License along with this library; if not, see <http://www.gnu.org/licenses/>. |
19 | | * |
20 | | * Author: Alexander Larsson <alexl@redhat.com> |
21 | | */ |
22 | | |
23 | | #include "config.h" |
24 | | |
25 | | #include <glib.h> |
26 | | #include <gfileiostream.h> |
27 | | #include <gseekable.h> |
28 | | #include "gasyncresult.h" |
29 | | #include "gtask.h" |
30 | | #include "gcancellable.h" |
31 | | #include "gioerror.h" |
32 | | #include "gfileoutputstream.h" |
33 | | #include "glibintl.h" |
34 | | |
35 | | |
36 | | /** |
37 | | * GFileIOStream: |
38 | | * |
39 | | * `GFileIOStream` provides I/O streams that both read and write to the same |
40 | | * file handle. |
41 | | * |
42 | | * `GFileIOStream` implements [iface@Gio.Seekable], which allows the I/O |
43 | | * stream to jump to arbitrary positions in the file and to truncate |
44 | | * the file, provided the filesystem of the file supports these |
45 | | * operations. |
46 | | * |
47 | | * To find the position of a file I/O stream, use [method@Gio.Seekable.tell]. |
48 | | * |
49 | | * To find out if a file I/O stream supports seeking, use |
50 | | * [method@Gio.Seekable.can_seek]. To position a file I/O stream, use |
51 | | * [method@Gio.Seekable.seek]. To find out if a file I/O stream supports |
52 | | * truncating, use [method@Gio.Seekable.can_truncate]. To truncate a file I/O |
53 | | * stream, use [method@Gio.Seekable.truncate]. |
54 | | * |
55 | | * The default implementation of all the `GFileIOStream` operations |
56 | | * and the implementation of [iface@Gio.Seekable] just call into the same |
57 | | * operations on the output stream. |
58 | | * |
59 | | * Since: 2.22 |
60 | | **/ |
61 | | |
62 | | static void g_file_io_stream_seekable_iface_init (GSeekableIface *iface); |
63 | | static goffset g_file_io_stream_seekable_tell (GSeekable *seekable); |
64 | | static gboolean g_file_io_stream_seekable_can_seek (GSeekable *seekable); |
65 | | static gboolean g_file_io_stream_seekable_seek (GSeekable *seekable, |
66 | | goffset offset, |
67 | | GSeekType type, |
68 | | GCancellable *cancellable, |
69 | | GError **error); |
70 | | static gboolean g_file_io_stream_seekable_can_truncate (GSeekable *seekable); |
71 | | static gboolean g_file_io_stream_seekable_truncate (GSeekable *seekable, |
72 | | goffset offset, |
73 | | GCancellable *cancellable, |
74 | | GError **error); |
75 | | static void g_file_io_stream_real_query_info_async (GFileIOStream *stream, |
76 | | const char *attributes, |
77 | | int io_priority, |
78 | | GCancellable *cancellable, |
79 | | GAsyncReadyCallback callback, |
80 | | gpointer user_data); |
81 | | static GFileInfo *g_file_io_stream_real_query_info_finish (GFileIOStream *stream, |
82 | | GAsyncResult *result, |
83 | | GError **error); |
84 | | |
85 | | struct _GFileIOStreamPrivate { |
86 | | GAsyncReadyCallback outstanding_callback; |
87 | | }; |
88 | | |
89 | | G_DEFINE_TYPE_WITH_CODE (GFileIOStream, g_file_io_stream, G_TYPE_IO_STREAM, |
90 | | G_ADD_PRIVATE (GFileIOStream) |
91 | | G_IMPLEMENT_INTERFACE (G_TYPE_SEEKABLE, |
92 | | g_file_io_stream_seekable_iface_init)) |
93 | | |
94 | | static void |
95 | | g_file_io_stream_seekable_iface_init (GSeekableIface *iface) |
96 | 0 | { |
97 | 0 | iface->tell = g_file_io_stream_seekable_tell; |
98 | 0 | iface->can_seek = g_file_io_stream_seekable_can_seek; |
99 | 0 | iface->seek = g_file_io_stream_seekable_seek; |
100 | 0 | iface->can_truncate = g_file_io_stream_seekable_can_truncate; |
101 | 0 | iface->truncate_fn = g_file_io_stream_seekable_truncate; |
102 | 0 | } |
103 | | |
104 | | static void |
105 | | g_file_io_stream_init (GFileIOStream *stream) |
106 | 0 | { |
107 | 0 | stream->priv = g_file_io_stream_get_instance_private (stream); |
108 | 0 | } |
109 | | |
110 | | /** |
111 | | * g_file_io_stream_query_info: |
112 | | * @stream: a #GFileIOStream. |
113 | | * @attributes: a file attribute query string. |
114 | | * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore. |
115 | | * @error: a #GError, %NULL to ignore. |
116 | | * |
117 | | * Queries a file io stream for the given @attributes. |
118 | | * This function blocks while querying the stream. For the asynchronous |
119 | | * version of this function, see g_file_io_stream_query_info_async(). |
120 | | * While the stream is blocked, the stream will set the pending flag |
121 | | * internally, and any other operations on the stream will fail with |
122 | | * %G_IO_ERROR_PENDING. |
123 | | * |
124 | | * Can fail if the stream was already closed (with @error being set to |
125 | | * %G_IO_ERROR_CLOSED), the stream has pending operations (with @error being |
126 | | * set to %G_IO_ERROR_PENDING), or if querying info is not supported for |
127 | | * the stream's interface (with @error being set to %G_IO_ERROR_NOT_SUPPORTED). I |
128 | | * all cases of failure, %NULL will be returned. |
129 | | * |
130 | | * If @cancellable is not %NULL, then the operation can be cancelled by |
131 | | * triggering the cancellable object from another thread. If the operation |
132 | | * was cancelled, the error %G_IO_ERROR_CANCELLED will be set, and %NULL will |
133 | | * be returned. |
134 | | * |
135 | | * Returns: (transfer full): a #GFileInfo for the @stream, or %NULL on error. |
136 | | * |
137 | | * Since: 2.22 |
138 | | **/ |
139 | | GFileInfo * |
140 | | g_file_io_stream_query_info (GFileIOStream *stream, |
141 | | const char *attributes, |
142 | | GCancellable *cancellable, |
143 | | GError **error) |
144 | 0 | { |
145 | 0 | GFileIOStreamClass *class; |
146 | 0 | GIOStream *io_stream; |
147 | 0 | GFileInfo *info; |
148 | |
|
149 | 0 | g_return_val_if_fail (G_IS_FILE_IO_STREAM (stream), NULL); |
150 | | |
151 | 0 | io_stream = G_IO_STREAM (stream); |
152 | |
|
153 | 0 | if (!g_io_stream_set_pending (io_stream, error)) |
154 | 0 | return NULL; |
155 | | |
156 | 0 | info = NULL; |
157 | |
|
158 | 0 | if (cancellable) |
159 | 0 | g_cancellable_push_current (cancellable); |
160 | |
|
161 | 0 | class = G_FILE_IO_STREAM_GET_CLASS (stream); |
162 | 0 | if (class->query_info) |
163 | 0 | info = class->query_info (stream, attributes, cancellable, error); |
164 | 0 | else |
165 | 0 | g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, |
166 | 0 | _("Stream doesn’t support query_info")); |
167 | |
|
168 | 0 | if (cancellable) |
169 | 0 | g_cancellable_pop_current (cancellable); |
170 | |
|
171 | 0 | g_io_stream_clear_pending (io_stream); |
172 | |
|
173 | 0 | return info; |
174 | 0 | } |
175 | | |
176 | | static void |
177 | | async_ready_callback_wrapper (GObject *source_object, |
178 | | GAsyncResult *res, |
179 | | gpointer user_data) |
180 | 0 | { |
181 | 0 | GFileIOStream *stream = G_FILE_IO_STREAM (source_object); |
182 | |
|
183 | 0 | g_io_stream_clear_pending (G_IO_STREAM (stream)); |
184 | 0 | if (stream->priv->outstanding_callback) |
185 | 0 | (*stream->priv->outstanding_callback) (source_object, res, user_data); |
186 | 0 | g_object_unref (stream); |
187 | 0 | } |
188 | | |
189 | | /** |
190 | | * g_file_io_stream_query_info_async: |
191 | | * @stream: a #GFileIOStream. |
192 | | * @attributes: a file attribute query string. |
193 | | * @io_priority: the [I/O priority](iface.AsyncResult.html#io-priority) of the |
194 | | * request |
195 | | * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore. |
196 | | * @callback: (scope async): a #GAsyncReadyCallback |
197 | | * to call when the request is satisfied |
198 | | * @user_data: the data to pass to callback function |
199 | | * |
200 | | * Asynchronously queries the @stream for a #GFileInfo. When completed, |
201 | | * @callback will be called with a #GAsyncResult which can be used to |
202 | | * finish the operation with g_file_io_stream_query_info_finish(). |
203 | | * |
204 | | * For the synchronous version of this function, see |
205 | | * g_file_io_stream_query_info(). |
206 | | * |
207 | | * Since: 2.22 |
208 | | **/ |
209 | | void |
210 | | g_file_io_stream_query_info_async (GFileIOStream *stream, |
211 | | const char *attributes, |
212 | | int io_priority, |
213 | | GCancellable *cancellable, |
214 | | GAsyncReadyCallback callback, |
215 | | gpointer user_data) |
216 | 0 | { |
217 | 0 | GFileIOStreamClass *klass; |
218 | 0 | GIOStream *io_stream; |
219 | 0 | GError *error = NULL; |
220 | |
|
221 | 0 | g_return_if_fail (G_IS_FILE_IO_STREAM (stream)); |
222 | | |
223 | 0 | io_stream = G_IO_STREAM (stream); |
224 | |
|
225 | 0 | if (!g_io_stream_set_pending (io_stream, &error)) |
226 | 0 | { |
227 | 0 | g_task_report_error (stream, callback, user_data, |
228 | 0 | g_file_io_stream_query_info_async, |
229 | 0 | error); |
230 | 0 | return; |
231 | 0 | } |
232 | | |
233 | 0 | klass = G_FILE_IO_STREAM_GET_CLASS (stream); |
234 | |
|
235 | 0 | stream->priv->outstanding_callback = callback; |
236 | 0 | g_object_ref (stream); |
237 | 0 | klass->query_info_async (stream, attributes, io_priority, cancellable, |
238 | 0 | async_ready_callback_wrapper, user_data); |
239 | 0 | } |
240 | | |
241 | | /** |
242 | | * g_file_io_stream_query_info_finish: |
243 | | * @stream: a #GFileIOStream. |
244 | | * @result: a #GAsyncResult. |
245 | | * @error: a #GError, %NULL to ignore. |
246 | | * |
247 | | * Finalizes the asynchronous query started |
248 | | * by g_file_io_stream_query_info_async(). |
249 | | * |
250 | | * Returns: (transfer full): A #GFileInfo for the finished query. |
251 | | * |
252 | | * Since: 2.22 |
253 | | **/ |
254 | | GFileInfo * |
255 | | g_file_io_stream_query_info_finish (GFileIOStream *stream, |
256 | | GAsyncResult *result, |
257 | | GError **error) |
258 | 0 | { |
259 | 0 | GFileIOStreamClass *class; |
260 | |
|
261 | 0 | g_return_val_if_fail (G_IS_FILE_IO_STREAM (stream), NULL); |
262 | 0 | g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL); |
263 | | |
264 | 0 | if (g_async_result_legacy_propagate_error (result, error)) |
265 | 0 | return NULL; |
266 | 0 | else if (g_async_result_is_tagged (result, g_file_io_stream_query_info_async)) |
267 | 0 | return g_task_propagate_pointer (G_TASK (result), error); |
268 | | |
269 | 0 | class = G_FILE_IO_STREAM_GET_CLASS (stream); |
270 | 0 | return class->query_info_finish (stream, result, error); |
271 | 0 | } |
272 | | |
273 | | /** |
274 | | * g_file_io_stream_get_etag: |
275 | | * @stream: a #GFileIOStream. |
276 | | * |
277 | | * Gets the entity tag for the file when it has been written. |
278 | | * This must be called after the stream has been written |
279 | | * and closed, as the etag can change while writing. |
280 | | * |
281 | | * Returns: (nullable) (transfer full): the entity tag for the stream. |
282 | | * |
283 | | * Since: 2.22 |
284 | | **/ |
285 | | char * |
286 | | g_file_io_stream_get_etag (GFileIOStream *stream) |
287 | 0 | { |
288 | 0 | GFileIOStreamClass *class; |
289 | 0 | GIOStream *io_stream; |
290 | 0 | char *etag; |
291 | |
|
292 | 0 | g_return_val_if_fail (G_IS_FILE_IO_STREAM (stream), NULL); |
293 | | |
294 | 0 | io_stream = G_IO_STREAM (stream); |
295 | |
|
296 | 0 | if (!g_io_stream_is_closed (io_stream)) |
297 | 0 | { |
298 | 0 | g_warning ("stream is not closed yet, can't get etag"); |
299 | 0 | return NULL; |
300 | 0 | } |
301 | | |
302 | 0 | etag = NULL; |
303 | |
|
304 | 0 | class = G_FILE_IO_STREAM_GET_CLASS (stream); |
305 | 0 | if (class->get_etag) |
306 | 0 | etag = class->get_etag (stream); |
307 | |
|
308 | 0 | return etag; |
309 | 0 | } |
310 | | |
311 | | static goffset |
312 | | g_file_io_stream_tell (GFileIOStream *stream) |
313 | 0 | { |
314 | 0 | GFileIOStreamClass *class; |
315 | 0 | goffset offset; |
316 | |
|
317 | 0 | g_return_val_if_fail (G_IS_FILE_IO_STREAM (stream), 0); |
318 | | |
319 | 0 | class = G_FILE_IO_STREAM_GET_CLASS (stream); |
320 | |
|
321 | 0 | offset = 0; |
322 | 0 | if (class->tell) |
323 | 0 | offset = class->tell (stream); |
324 | |
|
325 | 0 | return offset; |
326 | 0 | } |
327 | | |
328 | | static goffset |
329 | | g_file_io_stream_seekable_tell (GSeekable *seekable) |
330 | 0 | { |
331 | 0 | return g_file_io_stream_tell (G_FILE_IO_STREAM (seekable)); |
332 | 0 | } |
333 | | |
334 | | static gboolean |
335 | | g_file_io_stream_can_seek (GFileIOStream *stream) |
336 | 0 | { |
337 | 0 | GFileIOStreamClass *class; |
338 | 0 | gboolean can_seek; |
339 | |
|
340 | 0 | g_return_val_if_fail (G_IS_FILE_IO_STREAM (stream), FALSE); |
341 | | |
342 | 0 | class = G_FILE_IO_STREAM_GET_CLASS (stream); |
343 | |
|
344 | 0 | can_seek = FALSE; |
345 | 0 | if (class->seek) |
346 | 0 | { |
347 | 0 | can_seek = TRUE; |
348 | 0 | if (class->can_seek) |
349 | 0 | can_seek = class->can_seek (stream); |
350 | 0 | } |
351 | |
|
352 | 0 | return can_seek; |
353 | 0 | } |
354 | | |
355 | | static gboolean |
356 | | g_file_io_stream_seekable_can_seek (GSeekable *seekable) |
357 | 0 | { |
358 | 0 | return g_file_io_stream_can_seek (G_FILE_IO_STREAM (seekable)); |
359 | 0 | } |
360 | | |
361 | | static gboolean |
362 | | g_file_io_stream_seek (GFileIOStream *stream, |
363 | | goffset offset, |
364 | | GSeekType type, |
365 | | GCancellable *cancellable, |
366 | | GError **error) |
367 | 0 | { |
368 | 0 | GFileIOStreamClass *class; |
369 | 0 | GIOStream *io_stream; |
370 | 0 | gboolean res; |
371 | |
|
372 | 0 | g_return_val_if_fail (G_IS_FILE_IO_STREAM (stream), FALSE); |
373 | | |
374 | 0 | io_stream = G_IO_STREAM (stream); |
375 | 0 | class = G_FILE_IO_STREAM_GET_CLASS (stream); |
376 | |
|
377 | 0 | if (!class->seek) |
378 | 0 | { |
379 | 0 | g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, |
380 | 0 | _("Seek not supported on stream")); |
381 | 0 | return FALSE; |
382 | 0 | } |
383 | | |
384 | 0 | if (!g_io_stream_set_pending (io_stream, error)) |
385 | 0 | return FALSE; |
386 | | |
387 | 0 | if (cancellable) |
388 | 0 | g_cancellable_push_current (cancellable); |
389 | |
|
390 | 0 | res = class->seek (stream, offset, type, cancellable, error); |
391 | |
|
392 | 0 | if (cancellable) |
393 | 0 | g_cancellable_pop_current (cancellable); |
394 | |
|
395 | 0 | g_io_stream_clear_pending (io_stream); |
396 | |
|
397 | 0 | return res; |
398 | 0 | } |
399 | | |
400 | | static gboolean |
401 | | g_file_io_stream_seekable_seek (GSeekable *seekable, |
402 | | goffset offset, |
403 | | GSeekType type, |
404 | | GCancellable *cancellable, |
405 | | GError **error) |
406 | 0 | { |
407 | 0 | return g_file_io_stream_seek (G_FILE_IO_STREAM (seekable), |
408 | 0 | offset, type, cancellable, error); |
409 | 0 | } |
410 | | |
411 | | static gboolean |
412 | | g_file_io_stream_can_truncate (GFileIOStream *stream) |
413 | 0 | { |
414 | 0 | GFileIOStreamClass *class; |
415 | 0 | gboolean can_truncate; |
416 | |
|
417 | 0 | g_return_val_if_fail (G_IS_FILE_IO_STREAM (stream), FALSE); |
418 | | |
419 | 0 | class = G_FILE_IO_STREAM_GET_CLASS (stream); |
420 | |
|
421 | 0 | can_truncate = FALSE; |
422 | 0 | if (class->truncate_fn) |
423 | 0 | { |
424 | 0 | can_truncate = TRUE; |
425 | 0 | if (class->can_truncate) |
426 | 0 | can_truncate = class->can_truncate (stream); |
427 | 0 | } |
428 | |
|
429 | 0 | return can_truncate; |
430 | 0 | } |
431 | | |
432 | | static gboolean |
433 | | g_file_io_stream_seekable_can_truncate (GSeekable *seekable) |
434 | 0 | { |
435 | 0 | return g_file_io_stream_can_truncate (G_FILE_IO_STREAM (seekable)); |
436 | 0 | } |
437 | | |
438 | | static gboolean |
439 | | g_file_io_stream_truncate (GFileIOStream *stream, |
440 | | goffset size, |
441 | | GCancellable *cancellable, |
442 | | GError **error) |
443 | 0 | { |
444 | 0 | GFileIOStreamClass *class; |
445 | 0 | GIOStream *io_stream; |
446 | 0 | gboolean res; |
447 | |
|
448 | 0 | g_return_val_if_fail (G_IS_FILE_IO_STREAM (stream), FALSE); |
449 | | |
450 | 0 | io_stream = G_IO_STREAM (stream); |
451 | 0 | class = G_FILE_IO_STREAM_GET_CLASS (stream); |
452 | |
|
453 | 0 | if (!class->truncate_fn) |
454 | 0 | { |
455 | 0 | g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, |
456 | 0 | _("Truncate not supported on stream")); |
457 | 0 | return FALSE; |
458 | 0 | } |
459 | | |
460 | 0 | if (!g_io_stream_set_pending (io_stream, error)) |
461 | 0 | return FALSE; |
462 | | |
463 | 0 | if (cancellable) |
464 | 0 | g_cancellable_push_current (cancellable); |
465 | |
|
466 | 0 | res = class->truncate_fn (stream, size, cancellable, error); |
467 | |
|
468 | 0 | if (cancellable) |
469 | 0 | g_cancellable_pop_current (cancellable); |
470 | |
|
471 | 0 | g_io_stream_clear_pending (io_stream); |
472 | |
|
473 | 0 | return res; |
474 | 0 | } |
475 | | |
476 | | static gboolean |
477 | | g_file_io_stream_seekable_truncate (GSeekable *seekable, |
478 | | goffset size, |
479 | | GCancellable *cancellable, |
480 | | GError **error) |
481 | 0 | { |
482 | 0 | return g_file_io_stream_truncate (G_FILE_IO_STREAM (seekable), |
483 | 0 | size, cancellable, error); |
484 | 0 | } |
485 | | /***************************************************** |
486 | | * Default implementations based on output stream * |
487 | | *****************************************************/ |
488 | | |
489 | | static goffset |
490 | | g_file_io_stream_real_tell (GFileIOStream *stream) |
491 | 0 | { |
492 | 0 | GOutputStream *out; |
493 | 0 | GSeekable *seekable; |
494 | |
|
495 | 0 | out = g_io_stream_get_output_stream (G_IO_STREAM (stream)); |
496 | 0 | seekable = G_SEEKABLE (out); |
497 | |
|
498 | 0 | return g_seekable_tell (seekable); |
499 | 0 | } |
500 | | |
501 | | static gboolean |
502 | | g_file_io_stream_real_can_seek (GFileIOStream *stream) |
503 | 0 | { |
504 | 0 | GOutputStream *out; |
505 | 0 | GSeekable *seekable; |
506 | |
|
507 | 0 | out = g_io_stream_get_output_stream (G_IO_STREAM (stream)); |
508 | 0 | seekable = G_SEEKABLE (out); |
509 | |
|
510 | 0 | return g_seekable_can_seek (seekable); |
511 | 0 | } |
512 | | |
513 | | static gboolean |
514 | | g_file_io_stream_real_seek (GFileIOStream *stream, |
515 | | goffset offset, |
516 | | GSeekType type, |
517 | | GCancellable *cancellable, |
518 | | GError **error) |
519 | 0 | { |
520 | 0 | GOutputStream *out; |
521 | 0 | GSeekable *seekable; |
522 | |
|
523 | 0 | out = g_io_stream_get_output_stream (G_IO_STREAM (stream)); |
524 | 0 | seekable = G_SEEKABLE (out); |
525 | |
|
526 | 0 | return g_seekable_seek (seekable, offset, type, cancellable, error); |
527 | 0 | } |
528 | | |
529 | | static gboolean |
530 | | g_file_io_stream_real_can_truncate (GFileIOStream *stream) |
531 | 0 | { |
532 | 0 | GOutputStream *out; |
533 | 0 | GSeekable *seekable; |
534 | |
|
535 | 0 | out = g_io_stream_get_output_stream (G_IO_STREAM (stream)); |
536 | 0 | seekable = G_SEEKABLE (out); |
537 | |
|
538 | 0 | return g_seekable_can_truncate (seekable); |
539 | 0 | } |
540 | | |
541 | | static gboolean |
542 | | g_file_io_stream_real_truncate_fn (GFileIOStream *stream, |
543 | | goffset size, |
544 | | GCancellable *cancellable, |
545 | | GError **error) |
546 | 0 | { |
547 | 0 | GOutputStream *out; |
548 | 0 | GSeekable *seekable; |
549 | |
|
550 | 0 | out = g_io_stream_get_output_stream (G_IO_STREAM (stream)); |
551 | 0 | seekable = G_SEEKABLE (out); |
552 | |
|
553 | 0 | return g_seekable_truncate (seekable, size, cancellable, error); |
554 | 0 | } |
555 | | |
556 | | static char * |
557 | | g_file_io_stream_real_get_etag (GFileIOStream *stream) |
558 | 0 | { |
559 | 0 | GOutputStream *out; |
560 | 0 | GFileOutputStream *file_out; |
561 | |
|
562 | 0 | out = g_io_stream_get_output_stream (G_IO_STREAM (stream)); |
563 | 0 | file_out = G_FILE_OUTPUT_STREAM (out); |
564 | |
|
565 | 0 | return g_file_output_stream_get_etag (file_out); |
566 | 0 | } |
567 | | |
568 | | static GFileInfo * |
569 | | g_file_io_stream_real_query_info (GFileIOStream *stream, |
570 | | const char *attributes, |
571 | | GCancellable *cancellable, |
572 | | GError **error) |
573 | 0 | { |
574 | 0 | GOutputStream *out; |
575 | 0 | GFileOutputStream *file_out; |
576 | |
|
577 | 0 | out = g_io_stream_get_output_stream (G_IO_STREAM (stream)); |
578 | 0 | file_out = G_FILE_OUTPUT_STREAM (out); |
579 | |
|
580 | 0 | return g_file_output_stream_query_info (file_out, |
581 | 0 | attributes, cancellable, error); |
582 | 0 | } |
583 | | |
584 | | typedef struct { |
585 | | GObject *object; |
586 | | GAsyncReadyCallback callback; |
587 | | gpointer user_data; |
588 | | } AsyncOpWrapper; |
589 | | |
590 | | static AsyncOpWrapper * |
591 | | async_op_wrapper_new (gpointer object, |
592 | | GAsyncReadyCallback callback, |
593 | | gpointer user_data) |
594 | 0 | { |
595 | 0 | AsyncOpWrapper *data; |
596 | |
|
597 | 0 | data = g_new0 (AsyncOpWrapper, 1); |
598 | 0 | data->object = g_object_ref (object); |
599 | 0 | data->callback = callback; |
600 | 0 | data->user_data = user_data; |
601 | |
|
602 | 0 | return data; |
603 | 0 | } |
604 | | |
605 | | static void |
606 | | async_op_wrapper_callback (GObject *source_object, |
607 | | GAsyncResult *res, |
608 | | gpointer user_data) |
609 | 0 | { |
610 | 0 | AsyncOpWrapper *data = user_data; |
611 | 0 | data->callback (data->object, res, data->user_data); |
612 | 0 | g_object_unref (data->object); |
613 | 0 | g_free (data); |
614 | 0 | } |
615 | | |
616 | | static void |
617 | | g_file_io_stream_real_query_info_async (GFileIOStream *stream, |
618 | | const char *attributes, |
619 | | int io_priority, |
620 | | GCancellable *cancellable, |
621 | | GAsyncReadyCallback callback, |
622 | | gpointer user_data) |
623 | 0 | { |
624 | 0 | GOutputStream *out; |
625 | 0 | GFileOutputStream *file_out; |
626 | 0 | AsyncOpWrapper *data; |
627 | |
|
628 | 0 | out = g_io_stream_get_output_stream (G_IO_STREAM (stream)); |
629 | 0 | file_out = G_FILE_OUTPUT_STREAM (out); |
630 | |
|
631 | 0 | data = async_op_wrapper_new (stream, callback, user_data); |
632 | 0 | g_file_output_stream_query_info_async (file_out, |
633 | 0 | attributes, io_priority, |
634 | 0 | cancellable, async_op_wrapper_callback, data); |
635 | 0 | } |
636 | | |
637 | | static GFileInfo * |
638 | | g_file_io_stream_real_query_info_finish (GFileIOStream *stream, |
639 | | GAsyncResult *res, |
640 | | GError **error) |
641 | 0 | { |
642 | 0 | GOutputStream *out; |
643 | 0 | GFileOutputStream *file_out; |
644 | |
|
645 | 0 | out = g_io_stream_get_output_stream (G_IO_STREAM (stream)); |
646 | 0 | file_out = G_FILE_OUTPUT_STREAM (out); |
647 | |
|
648 | 0 | return g_file_output_stream_query_info_finish (file_out, res, error); |
649 | 0 | } |
650 | | |
651 | | static void |
652 | | g_file_io_stream_class_init (GFileIOStreamClass *klass) |
653 | 0 | { |
654 | 0 | klass->tell = g_file_io_stream_real_tell; |
655 | 0 | klass->can_seek = g_file_io_stream_real_can_seek; |
656 | 0 | klass->seek = g_file_io_stream_real_seek; |
657 | 0 | klass->can_truncate = g_file_io_stream_real_can_truncate; |
658 | 0 | klass->truncate_fn = g_file_io_stream_real_truncate_fn; |
659 | 0 | klass->query_info = g_file_io_stream_real_query_info; |
660 | 0 | klass->query_info_async = g_file_io_stream_real_query_info_async; |
661 | 0 | klass->query_info_finish = g_file_io_stream_real_query_info_finish; |
662 | 0 | klass->get_etag = g_file_io_stream_real_get_etag; |
663 | 0 | } |