[libglnx] fdio: New APIs to read/write on fds, fd-relative
- From: Colin Walters <walters src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libglnx] fdio: New APIs to read/write on fds, fd-relative
- Date: Fri, 20 Feb 2015 17:17:49 +0000 (UTC)
commit 1ebfefa565692ca033ba2d156c771d9e2c4017fc
Author: Colin Walters <walters verbum org>
Date: Fri Feb 20 11:28:47 2015 -0500
fdio: New APIs to read/write on fds, fd-relative
We don't have this really in GLib, unfortunately. We do want
GCancellable, but we also want to operate on raw fds where possible.
The "read a file and validate as UTF-8" is a common use case of mine,
and this combines that with openat().
Makefile-libglnx.am | 2 +
glnx-fdio.c | 225 +++++++++++++++++++++++++++++++++++++++++++++++++++
glnx-fdio.h | 50 +++++++++++
libglnx.h | 1 +
4 files changed, 278 insertions(+), 0 deletions(-)
---
diff --git a/Makefile-libglnx.am b/Makefile-libglnx.am
index 7463395..5b4411f 100644
--- a/Makefile-libglnx.am
+++ b/Makefile-libglnx.am
@@ -28,6 +28,8 @@ libglnx_la_SOURCES = \
$(libglnx_srcpath)/glnx-console.c \
$(libglnx_srcpath)/glnx-dirfd.h \
$(libglnx_srcpath)/glnx-dirfd.c \
+ $(libglnx_srcpath)/glnx-fdio.h \
+ $(libglnx_srcpath)/glnx-fdio.c \
$(libglnx_srcpath)/glnx-xattrs.h \
$(libglnx_srcpath)/glnx-xattrs.c \
$(libglnx_srcpath)/glnx-shutil.h \
diff --git a/glnx-fdio.c b/glnx-fdio.c
new file mode 100644
index 0000000..67653c2
--- /dev/null
+++ b/glnx-fdio.c
@@ -0,0 +1,225 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2014,2015 Colin Walters <walters verbum org>.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <stdio.h>
+
+#include <glnx-fdio.h>
+#include <glnx-errors.h>
+#include <glnx-local-alloc.h>
+
+static guint8*
+glnx_fd_readall_malloc (int fd,
+ gsize *out_len,
+ gboolean nul_terminate,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean success = FALSE;
+ const guint maxreadlen = 4096;
+ int res;
+ struct stat stbuf;
+ guint8* buf = NULL;
+ gsize buf_allocated;
+ gsize buf_size = 0;
+ gssize bytes_read;
+
+ do
+ res = fstat (fd, &stbuf);
+ while (G_UNLIKELY (res == -1 && errno == EINTR));
+ if (res == -1)
+ {
+ glnx_set_error_from_errno (error);
+ goto out;
+ }
+
+ if (S_ISREG (stbuf.st_mode) && stbuf.st_size > 0)
+ buf_allocated = stbuf.st_size;
+ else
+ buf_allocated = 16;
+
+ buf = g_malloc (buf_allocated);
+
+ while (TRUE)
+ {
+ gsize readlen = MIN (buf_allocated - buf_size, maxreadlen);
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ goto out;
+
+ do
+ bytes_read = read (fd, buf + buf_size, readlen);
+ while (G_UNLIKELY (bytes_read == -1 && errno == EINTR));
+ if (G_UNLIKELY (bytes_read == -1))
+ {
+ glnx_set_error_from_errno (error);
+ goto out;
+ }
+ if (bytes_read == 0)
+ break;
+
+ buf_size += bytes_read;
+ if (buf_allocated - buf_size < maxreadlen)
+ buf = g_realloc (buf, buf_allocated *= 2);
+ }
+
+ if (nul_terminate)
+ {
+ if (buf_allocated - buf_size == 0)
+ buf = g_realloc (buf, buf_allocated + 1);
+ buf[buf_size] = '\0';
+ }
+
+ success = TRUE;
+ out:
+ if (success)
+ {
+ *out_len = buf_size;
+ return buf;
+ }
+ g_free (buf);
+ return NULL;
+}
+
+/**
+ * glnx_fd_readall_bytes:
+ * @fd: A file descriptor
+ * @cancellable: Cancellable:
+ * @error: Error
+ *
+ * Read all data from file descriptor @fd into a #GBytes. It's
+ * recommended to only use this for small files.
+ *
+ * Returns: (transfer full): A newly allocated #GBytes
+ */
+GBytes *
+glnx_fd_readall_bytes (int fd,
+ GCancellable *cancellable,
+ GError **error)
+{
+ guint8 *buf;
+ gsize len;
+
+ buf = glnx_fd_readall_malloc (fd, &len, FALSE, cancellable, error);
+ if (!buf)
+ return NULL;
+
+ return g_bytes_new_take (buf, len);
+}
+
+/**
+ * glnx_fd_readall_utf8:
+ * @fd: A file descriptor
+ * @out_len: (out): Returned length
+ * @cancellable: Cancellable:
+ * @error: Error
+ *
+ * Read all data from file descriptor @fd, validating
+ * the result as UTF-8.
+ *
+ * Returns: (transfer full): A string validated as UTF-8, or %NULL on error.
+ */
+char *
+glnx_fd_readall_utf8 (int fd,
+ gsize *out_len,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean success = FALSE;
+ guint8 *buf;
+ gsize len;
+
+ buf = glnx_fd_readall_malloc (fd, &len, TRUE, cancellable, error);
+ if (!buf)
+ goto out;
+
+ if (!g_utf8_validate ((char*)buf, len, NULL))
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_DATA,
+ "Invalid UTF-8");
+ goto out;
+ }
+
+ success = TRUE;
+ out:
+ if (success)
+ {
+ if (out_len)
+ *out_len = len;
+ return (char*)buf;
+ }
+ g_free (buf);
+ return NULL;
+}
+
+/**
+ * glnx_file_get_contents_utf8_at:
+ * @dfd: Directory file descriptor
+ * @subpath: Path relative to @dfd
+ * @out_len: (out) (allow-none): Optional length
+ * @cancellable: Cancellable
+ * @error: Error
+ *
+ * Read the entire contents of the file referred
+ * to by @dfd and @subpath, validate the result as UTF-8.
+ * The length is optionally stored in @out_len.
+ *
+ * Returns: (transfer full): UTF-8 validated text, or %NULL on error
+ */
+char *
+glnx_file_get_contents_utf8_at (int dfd,
+ const char *subpath,
+ gsize *out_len,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean success = FALSE;
+ glnx_fd_close int fd = -1;
+ char *buf;
+ gsize len;
+
+ do
+ fd = openat (dfd, subpath, O_RDONLY | O_NOCTTY | O_CLOEXEC);
+ while (G_UNLIKELY (fd == -1 && errno == EINTR));
+ if (G_UNLIKELY (fd == -1))
+ {
+ glnx_set_error_from_errno (error);
+ goto out;
+ }
+
+ buf = glnx_fd_readall_utf8 (fd, &len, cancellable, error);
+ if (G_UNLIKELY(!buf))
+ goto out;
+
+ success = TRUE;
+ out:
+ if (success)
+ {
+ if (out_len)
+ *out_len = len;
+ return buf;
+ }
+ g_free (buf);
+ return NULL;
+}
diff --git a/glnx-fdio.h b/glnx-fdio.h
new file mode 100644
index 0000000..91e6aa6
--- /dev/null
+++ b/glnx-fdio.h
@@ -0,0 +1,50 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2014,2015 Colin Walters <walters verbum org>.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#pragma once
+
+#include <glnx-backport-autocleanups.h>
+#include <limits.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <attr/xattr.h>
+
+G_BEGIN_DECLS
+
+GBytes *
+glnx_fd_readall_bytes (int fd,
+ GCancellable *cancellable,
+ GError **error);
+
+char *
+glnx_fd_readall_utf8 (int fd,
+ gsize *out_len,
+ GCancellable *cancellable,
+ GError **error);
+
+char *
+glnx_file_get_contents_utf8_at (int dfd,
+ const char *subpath,
+ gsize *out_len,
+ GCancellable *cancellable,
+ GError **error);
+
+G_END_DECLS
diff --git a/libglnx.h b/libglnx.h
index 64c1ff1..3e81585 100644
--- a/libglnx.h
+++ b/libglnx.h
@@ -31,5 +31,6 @@ G_BEGIN_DECLS
#include <glnx-shutil.h>
#include <glnx-xattrs.h>
#include <glnx-console.h>
+#include <glnx-fdio.h>
G_END_DECLS
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]