(root)/
glib-2.79.0/
gio/
gfileiostream.c
       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  {
      97    iface->tell = g_file_io_stream_seekable_tell;
      98    iface->can_seek = g_file_io_stream_seekable_can_seek;
      99    iface->seek = g_file_io_stream_seekable_seek;
     100    iface->can_truncate = g_file_io_stream_seekable_can_truncate;
     101    iface->truncate_fn = g_file_io_stream_seekable_truncate;
     102  }
     103  
     104  static void
     105  g_file_io_stream_init (GFileIOStream *stream)
     106  {
     107    stream->priv = g_file_io_stream_get_instance_private (stream);
     108  }
     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  {
     145    GFileIOStreamClass *class;
     146    GIOStream *io_stream;
     147    GFileInfo *info;
     148  
     149    g_return_val_if_fail (G_IS_FILE_IO_STREAM (stream), NULL);
     150  
     151    io_stream = G_IO_STREAM (stream);
     152  
     153    if (!g_io_stream_set_pending (io_stream, error))
     154      return NULL;
     155  
     156    info = NULL;
     157  
     158    if (cancellable)
     159      g_cancellable_push_current (cancellable);
     160  
     161    class = G_FILE_IO_STREAM_GET_CLASS (stream);
     162    if (class->query_info)
     163      info = class->query_info (stream, attributes, cancellable, error);
     164    else
     165      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
     166                           _("Stream doesn’t support query_info"));
     167  
     168    if (cancellable)
     169      g_cancellable_pop_current (cancellable);
     170  
     171    g_io_stream_clear_pending (io_stream);
     172  
     173    return info;
     174  }
     175  
     176  static void
     177  async_ready_callback_wrapper (GObject *source_object,
     178  			      GAsyncResult *res,
     179  			      gpointer      user_data)
     180  {
     181    GFileIOStream *stream = G_FILE_IO_STREAM (source_object);
     182  
     183    g_io_stream_clear_pending (G_IO_STREAM (stream));
     184    if (stream->priv->outstanding_callback)
     185      (*stream->priv->outstanding_callback) (source_object, res, user_data);
     186    g_object_unref (stream);
     187  }
     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  {
     217    GFileIOStreamClass *klass;
     218    GIOStream *io_stream;
     219    GError *error = NULL;
     220  
     221    g_return_if_fail (G_IS_FILE_IO_STREAM (stream));
     222  
     223    io_stream = G_IO_STREAM (stream);
     224  
     225    if (!g_io_stream_set_pending (io_stream, &error))
     226      {
     227        g_task_report_error (stream, callback, user_data,
     228                             g_file_io_stream_query_info_async,
     229                             error);
     230        return;
     231      }
     232  
     233    klass = G_FILE_IO_STREAM_GET_CLASS (stream);
     234  
     235    stream->priv->outstanding_callback = callback;
     236    g_object_ref (stream);
     237    klass->query_info_async (stream, attributes, io_priority, cancellable,
     238                             async_ready_callback_wrapper, user_data);
     239  }
     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  {
     259    GFileIOStreamClass *class;
     260  
     261    g_return_val_if_fail (G_IS_FILE_IO_STREAM (stream), NULL);
     262    g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
     263  
     264    if (g_async_result_legacy_propagate_error (result, error))
     265      return NULL;
     266    else if (g_async_result_is_tagged (result, g_file_io_stream_query_info_async))
     267      return g_task_propagate_pointer (G_TASK (result), error);
     268  
     269    class = G_FILE_IO_STREAM_GET_CLASS (stream);
     270    return class->query_info_finish (stream, result, error);
     271  }
     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  {
     288    GFileIOStreamClass *class;
     289    GIOStream *io_stream;
     290    char *etag;
     291  
     292    g_return_val_if_fail (G_IS_FILE_IO_STREAM (stream), NULL);
     293  
     294    io_stream = G_IO_STREAM (stream);
     295  
     296    if (!g_io_stream_is_closed (io_stream))
     297      {
     298        g_warning ("stream is not closed yet, can't get etag");
     299        return NULL;
     300      }
     301  
     302    etag = NULL;
     303  
     304    class = G_FILE_IO_STREAM_GET_CLASS (stream);
     305    if (class->get_etag)
     306      etag = class->get_etag (stream);
     307  
     308    return etag;
     309  }
     310  
     311  static goffset
     312  g_file_io_stream_tell (GFileIOStream  *stream)
     313  {
     314    GFileIOStreamClass *class;
     315    goffset offset;
     316  
     317    g_return_val_if_fail (G_IS_FILE_IO_STREAM (stream), 0);
     318  
     319    class = G_FILE_IO_STREAM_GET_CLASS (stream);
     320  
     321    offset = 0;
     322    if (class->tell)
     323      offset = class->tell (stream);
     324  
     325    return offset;
     326  }
     327  
     328  static goffset
     329  g_file_io_stream_seekable_tell (GSeekable *seekable)
     330  {
     331    return g_file_io_stream_tell (G_FILE_IO_STREAM (seekable));
     332  }
     333  
     334  static gboolean
     335  g_file_io_stream_can_seek (GFileIOStream  *stream)
     336  {
     337    GFileIOStreamClass *class;
     338    gboolean can_seek;
     339  
     340    g_return_val_if_fail (G_IS_FILE_IO_STREAM (stream), FALSE);
     341  
     342    class = G_FILE_IO_STREAM_GET_CLASS (stream);
     343  
     344    can_seek = FALSE;
     345    if (class->seek)
     346      {
     347        can_seek = TRUE;
     348        if (class->can_seek)
     349  	can_seek = class->can_seek (stream);
     350      }
     351  
     352    return can_seek;
     353  }
     354  
     355  static gboolean
     356  g_file_io_stream_seekable_can_seek (GSeekable *seekable)
     357  {
     358    return g_file_io_stream_can_seek (G_FILE_IO_STREAM (seekable));
     359  }
     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  {
     368    GFileIOStreamClass *class;
     369    GIOStream *io_stream;
     370    gboolean res;
     371  
     372    g_return_val_if_fail (G_IS_FILE_IO_STREAM (stream), FALSE);
     373  
     374    io_stream = G_IO_STREAM (stream);
     375    class = G_FILE_IO_STREAM_GET_CLASS (stream);
     376  
     377    if (!class->seek)
     378      {
     379        g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
     380                             _("Seek not supported on stream"));
     381        return FALSE;
     382      }
     383  
     384    if (!g_io_stream_set_pending (io_stream, error))
     385      return FALSE;
     386  
     387    if (cancellable)
     388      g_cancellable_push_current (cancellable);
     389  
     390    res = class->seek (stream, offset, type, cancellable, error);
     391  
     392    if (cancellable)
     393      g_cancellable_pop_current (cancellable);
     394  
     395    g_io_stream_clear_pending (io_stream);
     396  
     397    return res;
     398  }
     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  {
     407    return g_file_io_stream_seek (G_FILE_IO_STREAM (seekable),
     408  				offset, type, cancellable, error);
     409  }
     410  
     411  static gboolean
     412  g_file_io_stream_can_truncate (GFileIOStream  *stream)
     413  {
     414    GFileIOStreamClass *class;
     415    gboolean can_truncate;
     416  
     417    g_return_val_if_fail (G_IS_FILE_IO_STREAM (stream), FALSE);
     418  
     419    class = G_FILE_IO_STREAM_GET_CLASS (stream);
     420  
     421    can_truncate = FALSE;
     422    if (class->truncate_fn)
     423      {
     424        can_truncate = TRUE;
     425        if (class->can_truncate)
     426  	can_truncate = class->can_truncate (stream);
     427      }
     428  
     429    return can_truncate;
     430  }
     431  
     432  static gboolean
     433  g_file_io_stream_seekable_can_truncate (GSeekable  *seekable)
     434  {
     435    return g_file_io_stream_can_truncate (G_FILE_IO_STREAM (seekable));
     436  }
     437  
     438  static gboolean
     439  g_file_io_stream_truncate (GFileIOStream  *stream,
     440  			   goffset             size,
     441  			   GCancellable       *cancellable,
     442  			   GError            **error)
     443  {
     444    GFileIOStreamClass *class;
     445    GIOStream *io_stream;
     446    gboolean res;
     447  
     448    g_return_val_if_fail (G_IS_FILE_IO_STREAM (stream), FALSE);
     449  
     450    io_stream = G_IO_STREAM (stream);
     451    class = G_FILE_IO_STREAM_GET_CLASS (stream);
     452  
     453    if (!class->truncate_fn)
     454      {
     455        g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
     456                             _("Truncate not supported on stream"));
     457        return FALSE;
     458      }
     459  
     460    if (!g_io_stream_set_pending (io_stream, error))
     461      return FALSE;
     462  
     463    if (cancellable)
     464      g_cancellable_push_current (cancellable);
     465  
     466    res = class->truncate_fn (stream, size, cancellable, error);
     467  
     468    if (cancellable)
     469      g_cancellable_pop_current (cancellable);
     470  
     471    g_io_stream_clear_pending (io_stream);
     472  
     473    return res;
     474  }
     475  
     476  static gboolean
     477  g_file_io_stream_seekable_truncate (GSeekable     *seekable,
     478  				    goffset        size,
     479  				    GCancellable  *cancellable,
     480  				    GError       **error)
     481  {
     482    return g_file_io_stream_truncate (G_FILE_IO_STREAM (seekable),
     483  					size, cancellable, error);
     484  }
     485  /*****************************************************
     486   *   Default implementations based on output stream  *
     487   *****************************************************/
     488  
     489  static goffset
     490  g_file_io_stream_real_tell (GFileIOStream    *stream)
     491  {
     492    GOutputStream *out;
     493    GSeekable *seekable;
     494  
     495    out = g_io_stream_get_output_stream (G_IO_STREAM (stream));
     496    seekable = G_SEEKABLE (out);
     497  
     498    return g_seekable_tell (seekable);
     499  }
     500  
     501  static gboolean
     502  g_file_io_stream_real_can_seek (GFileIOStream    *stream)
     503  {
     504    GOutputStream *out;
     505    GSeekable *seekable;
     506  
     507    out = g_io_stream_get_output_stream (G_IO_STREAM (stream));
     508    seekable = G_SEEKABLE (out);
     509  
     510    return g_seekable_can_seek (seekable);
     511  }
     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  {
     520    GOutputStream *out;
     521    GSeekable *seekable;
     522  
     523    out = g_io_stream_get_output_stream (G_IO_STREAM (stream));
     524    seekable = G_SEEKABLE (out);
     525  
     526    return g_seekable_seek (seekable, offset, type, cancellable, error);
     527  }
     528  
     529  static  gboolean
     530  g_file_io_stream_real_can_truncate (GFileIOStream    *stream)
     531  {
     532    GOutputStream *out;
     533    GSeekable *seekable;
     534  
     535    out = g_io_stream_get_output_stream (G_IO_STREAM (stream));
     536    seekable = G_SEEKABLE (out);
     537  
     538    return g_seekable_can_truncate (seekable);
     539  }
     540  
     541  static gboolean
     542  g_file_io_stream_real_truncate_fn (GFileIOStream    *stream,
     543  				   goffset               size,
     544  				   GCancellable         *cancellable,
     545  				   GError              **error)
     546  {
     547    GOutputStream *out;
     548    GSeekable *seekable;
     549  
     550    out = g_io_stream_get_output_stream (G_IO_STREAM (stream));
     551    seekable = G_SEEKABLE (out);
     552  
     553    return g_seekable_truncate (seekable, size, cancellable, error);
     554  }
     555  
     556  static char *
     557  g_file_io_stream_real_get_etag (GFileIOStream    *stream)
     558  {
     559    GOutputStream *out;
     560    GFileOutputStream *file_out;
     561  
     562    out = g_io_stream_get_output_stream (G_IO_STREAM (stream));
     563    file_out = G_FILE_OUTPUT_STREAM (out);
     564  
     565    return g_file_output_stream_get_etag (file_out);
     566  }
     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  {
     574    GOutputStream *out;
     575    GFileOutputStream *file_out;
     576  
     577    out = g_io_stream_get_output_stream (G_IO_STREAM (stream));
     578    file_out = G_FILE_OUTPUT_STREAM (out);
     579  
     580    return g_file_output_stream_query_info (file_out,
     581  					  attributes, cancellable, error);
     582  }
     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  {
     595    AsyncOpWrapper *data;
     596  
     597    data = g_new0 (AsyncOpWrapper, 1);
     598    data->object = g_object_ref (object);
     599    data->callback = callback;
     600    data->user_data = user_data;
     601  
     602    return data;
     603  }
     604  
     605  static void
     606  async_op_wrapper_callback (GObject *source_object,
     607  			   GAsyncResult *res,
     608  			   gpointer user_data)
     609  {
     610    AsyncOpWrapper *data  = user_data;
     611    data->callback (data->object, res, data->user_data);
     612    g_object_unref (data->object);
     613    g_free (data);
     614  }
     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  {
     624    GOutputStream *out;
     625    GFileOutputStream *file_out;
     626    AsyncOpWrapper *data;
     627  
     628    out = g_io_stream_get_output_stream (G_IO_STREAM (stream));
     629    file_out = G_FILE_OUTPUT_STREAM (out);
     630  
     631    data = async_op_wrapper_new (stream, callback, user_data);
     632    g_file_output_stream_query_info_async (file_out,
     633  					 attributes, io_priority,
     634  					 cancellable, async_op_wrapper_callback, data);
     635  }
     636  
     637  static GFileInfo *
     638  g_file_io_stream_real_query_info_finish (GFileIOStream     *stream,
     639  					 GAsyncResult      *res,
     640  					 GError           **error)
     641  {
     642    GOutputStream *out;
     643    GFileOutputStream *file_out;
     644  
     645    out = g_io_stream_get_output_stream (G_IO_STREAM (stream));
     646    file_out = G_FILE_OUTPUT_STREAM (out);
     647  
     648    return g_file_output_stream_query_info_finish (file_out, res, error);
     649  }
     650  
     651  static void
     652  g_file_io_stream_class_init (GFileIOStreamClass *klass)
     653  {
     654    klass->tell = g_file_io_stream_real_tell;
     655    klass->can_seek = g_file_io_stream_real_can_seek;
     656    klass->seek = g_file_io_stream_real_seek;
     657    klass->can_truncate = g_file_io_stream_real_can_truncate;
     658    klass->truncate_fn = g_file_io_stream_real_truncate_fn;
     659    klass->query_info = g_file_io_stream_real_query_info;
     660    klass->query_info_async = g_file_io_stream_real_query_info_async;
     661    klass->query_info_finish = g_file_io_stream_real_query_info_finish;
     662    klass->get_etag = g_file_io_stream_real_get_etag;
     663  }