diff --git a/src/libotutil/ot-gpg-utils.c b/src/libotutil/ot-gpg-utils.c index d603b09b..aa5b4819 100644 --- a/src/libotutil/ot-gpg-utils.c +++ b/src/libotutil/ot-gpg-utils.c @@ -138,3 +138,274 @@ out: return ret; } + +/**** The functions below are based on seahorse-gpgme-data.c ****/ + +static void +set_errno_from_gio_error (GError *error) +{ + /* This is the reverse of g_io_error_from_errno() */ + + g_return_if_fail (error != NULL); + + switch (error->code) + { + case G_IO_ERROR_FAILED: + errno = EIO; + break; + case G_IO_ERROR_NOT_FOUND: + errno = ENOENT; + break; + case G_IO_ERROR_EXISTS: + errno = EEXIST; + break; + case G_IO_ERROR_IS_DIRECTORY: + errno = EISDIR; + break; + case G_IO_ERROR_NOT_DIRECTORY: + errno = ENOTDIR; + break; + case G_IO_ERROR_NOT_EMPTY: + errno = ENOTEMPTY; + break; + case G_IO_ERROR_NOT_REGULAR_FILE: + case G_IO_ERROR_NOT_SYMBOLIC_LINK: + case G_IO_ERROR_NOT_MOUNTABLE_FILE: + errno = EBADF; + break; + case G_IO_ERROR_FILENAME_TOO_LONG: + errno = ENAMETOOLONG; + break; + case G_IO_ERROR_INVALID_FILENAME: + errno = EINVAL; + break; + case G_IO_ERROR_TOO_MANY_LINKS: + errno = EMLINK; + break; + case G_IO_ERROR_NO_SPACE: + errno = ENOSPC; + break; + case G_IO_ERROR_INVALID_ARGUMENT: + errno = EINVAL; + break; + case G_IO_ERROR_PERMISSION_DENIED: + errno = EPERM; + break; + case G_IO_ERROR_NOT_SUPPORTED: + errno = ENOTSUP; + break; + case G_IO_ERROR_NOT_MOUNTED: + errno = ENOENT; + break; + case G_IO_ERROR_ALREADY_MOUNTED: + errno = EALREADY; + break; + case G_IO_ERROR_CLOSED: + errno = EBADF; + break; + case G_IO_ERROR_CANCELLED: + errno = EINTR; + break; + case G_IO_ERROR_PENDING: + errno = EALREADY; + break; + case G_IO_ERROR_READ_ONLY: + errno = EACCES; + break; + case G_IO_ERROR_CANT_CREATE_BACKUP: + errno = EIO; + break; + case G_IO_ERROR_WRONG_ETAG: + errno = EACCES; + break; + case G_IO_ERROR_TIMED_OUT: + errno = EIO; + break; + case G_IO_ERROR_WOULD_RECURSE: + errno = ELOOP; + break; + case G_IO_ERROR_BUSY: + errno = EBUSY; + break; + case G_IO_ERROR_WOULD_BLOCK: + errno = EWOULDBLOCK; + break; + case G_IO_ERROR_HOST_NOT_FOUND: + errno = EHOSTDOWN; + break; + case G_IO_ERROR_WOULD_MERGE: + errno = EIO; + break; + case G_IO_ERROR_FAILED_HANDLED: + errno = 0; + break; + default: + errno = EIO; + break; + } +} + +static ssize_t +data_read_cb (void *handle, void *buffer, size_t size) +{ + GInputStream *input_stream = handle; + gsize bytes_read; + GError *local_error = NULL; + + g_return_val_if_fail (G_IS_INPUT_STREAM (input_stream), -1); + + g_input_stream_read_all (input_stream, buffer, size, + &bytes_read, NULL, &local_error); + + if (local_error != NULL) + { + set_errno_from_gio_error (local_error); + g_clear_error (&local_error); + bytes_read = -1; + } + + return bytes_read; +} + +static ssize_t +data_write_cb (void *handle, const void *buffer, size_t size) +{ + GOutputStream *output_stream = handle; + gsize bytes_written; + GError *local_error = NULL; + + g_return_val_if_fail (G_IS_OUTPUT_STREAM (output_stream), -1); + + if (g_output_stream_write_all (output_stream, buffer, size, + &bytes_written, NULL, &local_error)) + { + g_output_stream_flush (output_stream, NULL, &local_error); + } + + if (local_error != NULL) + { + set_errno_from_gio_error (local_error); + g_clear_error (&local_error); + bytes_written = -1; + } + + return bytes_written; +} + +static off_t +data_seek_cb (void *handle, off_t offset, int whence) +{ + GObject *stream = handle; + GSeekable *seekable; + GSeekType seek_type = 0; + off_t position = -1; + GError *local_error = NULL; + + g_return_val_if_fail (G_IS_INPUT_STREAM (stream) || + G_IS_OUTPUT_STREAM (stream), -1); + + if (!G_IS_SEEKABLE (stream)) { + errno = EOPNOTSUPP; + goto out; + } + + switch (whence) + { + case SEEK_SET: + seek_type = G_SEEK_SET; + break; + case SEEK_CUR: + seek_type = G_SEEK_CUR; + break; + case SEEK_END: + seek_type = G_SEEK_END; + break; + default: + g_assert_not_reached (); + } + + seekable = G_SEEKABLE (stream); + + if (!g_seekable_seek (seekable, offset, seek_type, NULL, &local_error)) + { + set_errno_from_gio_error (local_error); + g_clear_error (&local_error); + goto out; + } + + position = g_seekable_tell (seekable); + +out: + return position; +} + +static void +data_release_cb (void *handle) +{ + GObject *stream = handle; + + g_return_if_fail (G_IS_INPUT_STREAM (stream) || + G_IS_OUTPUT_STREAM (stream)); + + g_object_unref (stream); +} + +static struct gpgme_data_cbs data_input_cbs = { + data_read_cb, + NULL, + data_seek_cb, + data_release_cb +}; + +static struct gpgme_data_cbs data_output_cbs = { + NULL, + data_write_cb, + data_seek_cb, + data_release_cb +}; + +gpgme_data_t +ot_gpgme_data_input (GInputStream *input_stream) +{ + gpgme_data_t data = NULL; + gpgme_error_t gpg_error; + + g_return_val_if_fail (G_IS_INPUT_STREAM (input_stream), NULL); + + gpg_error = gpgme_data_new_from_cbs (&data, &data_input_cbs, input_stream); + + /* The only possible error is ENOMEM, which we abort on. */ + if (gpg_error != GPG_ERR_NO_ERROR) + { + g_assert (gpgme_err_code (gpg_error) == GPG_ERR_ENOMEM); + ot_gpgme_error_to_gio_error (gpg_error, NULL); + g_assert_not_reached (); + } + + g_object_ref (input_stream); + + return data; +} + +gpgme_data_t +ot_gpgme_data_output (GOutputStream *output_stream) +{ + gpgme_data_t data = NULL; + gpgme_error_t gpg_error; + + g_return_val_if_fail (G_IS_OUTPUT_STREAM (output_stream), NULL); + + gpg_error = gpgme_data_new_from_cbs (&data, &data_output_cbs, output_stream); + + /* The only possible error is ENOMEM, which we abort on. */ + if (gpg_error != GPG_ERR_NO_ERROR) + { + g_assert (gpgme_err_code (gpg_error) == GPG_ERR_ENOMEM); + ot_gpgme_error_to_gio_error (gpg_error, NULL); + g_assert_not_reached (); + } + + g_object_ref (output_stream); + + return data; +} diff --git a/src/libotutil/ot-gpg-utils.h b/src/libotutil/ot-gpg-utils.h index 0a67070e..edb249f4 100644 --- a/src/libotutil/ot-gpg-utils.h +++ b/src/libotutil/ot-gpg-utils.h @@ -34,4 +34,7 @@ gboolean ot_gpgme_ctx_tmp_home_dir (gpgme_ctx_t gpgme_ctx, GCancellable *cancellable, GError **error); +gpgme_data_t ot_gpgme_data_input (GInputStream *input_stream); +gpgme_data_t ot_gpgme_data_output (GOutputStream *output_stream); + G_END_DECLS