mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-11-10 03:16:17 +01:00
Implement GOutputStream::writev_fn() for GLocalFileOutputStream on UNIX
This commit is contained in:
parent
89da9eb6c0
commit
c39264d35b
@ -38,6 +38,7 @@
|
||||
#ifdef G_OS_UNIX
|
||||
#include <unistd.h>
|
||||
#include "gfiledescriptorbased.h"
|
||||
#include <sys/uio.h>
|
||||
#endif
|
||||
|
||||
#include "glib-private.h"
|
||||
@ -93,6 +94,14 @@ static gssize g_local_file_output_stream_write (GOutputStream *s
|
||||
gsize count,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
#ifdef G_OS_UNIX
|
||||
static gboolean g_local_file_output_stream_writev (GOutputStream *stream,
|
||||
const GOutputVector *vectors,
|
||||
gsize n_vectors,
|
||||
gsize *bytes_written,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
#endif
|
||||
static gboolean g_local_file_output_stream_close (GOutputStream *stream,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
@ -142,6 +151,9 @@ g_local_file_output_stream_class_init (GLocalFileOutputStreamClass *klass)
|
||||
gobject_class->finalize = g_local_file_output_stream_finalize;
|
||||
|
||||
stream_class->write_fn = g_local_file_output_stream_write;
|
||||
#ifdef G_OS_UNIX
|
||||
stream_class->writev_fn = g_local_file_output_stream_writev;
|
||||
#endif
|
||||
stream_class->close_fn = g_local_file_output_stream_close;
|
||||
file_stream_class->query_info = g_local_file_output_stream_query_info;
|
||||
file_stream_class->get_etag = g_local_file_output_stream_get_etag;
|
||||
@ -203,6 +215,89 @@ g_local_file_output_stream_write (GOutputStream *stream,
|
||||
return res;
|
||||
}
|
||||
|
||||
/* On Windows there is no equivalent API for files. The closest API to that is
|
||||
* WriteFileGather() but it is useless in general: it requires, among other
|
||||
* things, that each chunk is the size of a whole page and in memory aligned
|
||||
* to a page. We can't possibly guarantee that in GLib.
|
||||
*/
|
||||
#ifdef G_OS_UNIX
|
||||
/* Macro to check if struct iovec and GOutputVector have the same ABI */
|
||||
#define G_OUTPUT_VECTOR_IS_IOVEC (sizeof (struct iovec) == sizeof (GOutputVector) && \
|
||||
sizeof ((struct iovec *) 0)->iov_base == sizeof ((GOutputVector *) 0)->buffer && \
|
||||
G_STRUCT_OFFSET (struct iovec, iov_base) == G_STRUCT_OFFSET (GOutputVector, buffer) && \
|
||||
sizeof ((struct iovec *) 0)->iov_len == sizeof((GOutputVector *) 0)->size && \
|
||||
G_STRUCT_OFFSET (struct iovec, iov_len) == G_STRUCT_OFFSET (GOutputVector, size))
|
||||
|
||||
static gboolean
|
||||
g_local_file_output_stream_writev (GOutputStream *stream,
|
||||
const GOutputVector *vectors,
|
||||
gsize n_vectors,
|
||||
gsize *bytes_written,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
GLocalFileOutputStream *file;
|
||||
gssize res;
|
||||
struct iovec *iov;
|
||||
|
||||
if (bytes_written)
|
||||
*bytes_written = 0;
|
||||
|
||||
/* Clamp to G_MAXINT as writev() takes an integer for the number of vectors.
|
||||
* We handle this like a short write in this case
|
||||
*/
|
||||
if (n_vectors > G_MAXINT)
|
||||
n_vectors = G_MAXINT;
|
||||
|
||||
file = G_LOCAL_FILE_OUTPUT_STREAM (stream);
|
||||
|
||||
if (G_OUTPUT_VECTOR_IS_IOVEC)
|
||||
{
|
||||
/* ABI is compatible */
|
||||
iov = (struct iovec *) vectors;
|
||||
}
|
||||
else
|
||||
{
|
||||
gsize i;
|
||||
|
||||
/* ABI is incompatible */
|
||||
iov = g_newa (struct iovec, n_vectors);
|
||||
for (i = 0; i < n_vectors; i++)
|
||||
{
|
||||
iov[i].iov_base = (void *)vectors[i].buffer;
|
||||
iov[i].iov_len = vectors[i].size;
|
||||
}
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (g_cancellable_set_error_if_cancelled (cancellable, error))
|
||||
return FALSE;
|
||||
res = writev (file->priv->fd, iov, n_vectors);
|
||||
if (res == -1)
|
||||
{
|
||||
int errsv = errno;
|
||||
|
||||
if (errsv == EINTR)
|
||||
continue;
|
||||
|
||||
g_set_error (error, G_IO_ERROR,
|
||||
g_io_error_from_errno (errsv),
|
||||
_("Error writing to file: %s"),
|
||||
g_strerror (errsv));
|
||||
}
|
||||
else if (bytes_written)
|
||||
{
|
||||
*bytes_written = res;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return res != -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
_g_local_file_output_stream_set_do_close (GLocalFileOutputStream *out,
|
||||
gboolean do_close)
|
||||
|
Loading…
Reference in New Issue
Block a user