summary refs log tree commit diff
path: root/src/libnm-glib-aux/nm-io-utils.c
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2023-08-09 21:55:35 +0200
committerMichael Biebl <biebl@debian.org>2023-08-09 21:55:35 +0200
commit05e4a733f2141995181a551854d5df929f084adf (patch)
tree83bb937740a6667525ba0df046748ecaa829c269 /src/libnm-glib-aux/nm-io-utils.c
parent14b0f3a9dc9ea90d60a3b057350fd4d637dc021a (diff)
New upstream version 1.44.0 upstream/1.44.0
Diffstat (limited to 'src/libnm-glib-aux/nm-io-utils.c')
-rw-r--r--src/libnm-glib-aux/nm-io-utils.c100
1 files changed, 92 insertions, 8 deletions
diff --git a/src/libnm-glib-aux/nm-io-utils.c b/src/libnm-glib-aux/nm-io-utils.c
index d1430595..ec016ed8 100644
--- a/src/libnm-glib-aux/nm-io-utils.c
+++ b/src/libnm-glib-aux/nm-io-utils.c
@@ -21,6 +21,86 @@
 
 /*****************************************************************************/
 
+int
+nm_io_fcntl_getfl(int fd)
+{
+    int f;
+
+    nm_assert(fd >= 0);
+
+    f = fcntl(fd, F_GETFL, 0);
+
+    /* The caller really must provide a valid FD. For a valid FD, there is not
+     * reason why this call could fail (or how we could handle the failure).
+     *
+     * Unlike plain fcntl(), nm_io_fcntl_getfl() cannot fail. */
+    nm_assert(f != -1);
+
+    /* We not only assert that the return value is "!= -1", but that it's not
+     * negative. Negative flags would be very odd, and not something we would
+     * expect for a successful call. */
+    nm_assert(f >= 0);
+
+    return f;
+}
+
+int
+nm_io_fcntl_setfl(int fd, int flags)
+{
+    int f;
+    int errsv;
+
+    nm_assert(fd >= 0);
+    nm_assert(flags >= 0);
+
+    f = fcntl(fd, F_SETFL, flags);
+    if (f != 0) {
+        errsv = errno;
+
+        nm_assert(errsv != EBADF);
+
+        return -NM_ERRNO_NATIVE(errsv);
+    }
+
+    return 0;
+}
+
+int
+nm_io_fcntl_setfl_update(int fd, int flags_mask, int flags_value)
+{
+    int flags_current;
+
+    nm_assert(fd >= 0);
+    nm_assert(flags_mask > 0);
+    nm_assert(flags_value >= 0);
+    nm_assert(((~flags_mask) & flags_value) == 0);
+
+    flags_current = nm_io_fcntl_getfl(fd);
+    return nm_io_fcntl_setfl(fd, (flags_current & ~flags_mask) | (flags_mask & flags_value));
+}
+
+void
+nm_io_fcntl_setfl_update_nonblock(int fd)
+{
+    int r;
+
+    nm_assert(fd >= 0);
+
+    r = nm_io_fcntl_setfl_update(fd, O_NONBLOCK, O_NONBLOCK);
+
+    /* nm_io_fcntl_setfl_update() already asserts that it cannot fail with
+     * EBADF.
+     *
+     * In nm_io_fcntl_setfl_update_nonblock() only sts O_NONBLOCK, where we
+     * don't expect any other error. Kernel should never reject setting this
+     * flags, and if it did, we have to find out how to handle that. Currently
+     * we don't handle it and assert against failure. */
+
+    nm_assert(r == 0);
+}
+
+/*****************************************************************************/
+
 _nm_printf(4, 5) static int _get_contents_error(GError    **error,
                                                 int         errsv,
                                                 int        *out_errsv,
@@ -79,7 +159,7 @@ _nm_printf(4, 5) static int _get_contents_error(GError    **error,
  *  the NUL byte. That is, it reads only files up to a length of
  *  @max_length - 1 bytes.
  * @length: optional output argument of the read file size.
- * @out_errsv: (allow-none) (out): on error, a positive errno. or zero.
+ * @out_errsv: (out) (optional): on error, a positive errno. or zero.
  * @error:
  *
  *
@@ -276,7 +356,7 @@ nm_utils_fd_get_contents(int                         fd,
  *   the NUL byte. That is, it reads only files up to a length of
  *   @max_length - 1 bytes.
  * @length: optional output argument of the read file size.
- * @out_errsv: (allow-none) (out): on error, a positive errno. or zero.
+ * @out_errsv: (out) (optional): on error, a positive errno. or zero.
  * @error:
  *
  * A reimplementation of g_file_get_contents() with a few differences:
@@ -444,7 +524,7 @@ nm_utils_file_set_contents(const char            *filename,
 /**
  * nm_utils_file_stat:
  * @filename: the filename to stat.
- * @out_st: (allow-none) (out): if given, this will be passed to stat().
+ * @out_st: (out) (nullable): if given, this will be passed to stat().
  *
  * Just wraps stat() and gives the errno number as function result instead
  * of setting the errno (though, errno is also set). It's only for convenience
@@ -482,13 +562,17 @@ nm_utils_fd_read(int fd, NMStrBuf *out_string)
     g_return_val_if_fail(fd >= 0, -1);
     g_return_val_if_fail(out_string, -1);
 
-    /* If the buffer size is 0, we allocate NM_UTILS_GET_NEXT_REALLOC_SIZE_1000 (1000 bytes)
-     * the first time. Afterwards, the buffer grows exponentially.
+    /* Reserve at least 488+1 bytes of buffer size. That is probably a suitable
+     * compromise between not wasting too much buffer space and not reading too much.
      *
-     * Note that with @buf_available, we always would read as much buffer as we actually
-     * have reserved. */
-    nm_str_buf_maybe_expand(out_string, NM_UTILS_GET_NEXT_REALLOC_SIZE_1000, FALSE);
+     * Note that when we start with an empty buffer, the first allocation of
+     * 488+1 bytes will actually allocate 1000 bytes. So if we were to receive
+     * one byte at a time, we don't need a reallocation for the first 1000-(488+1)
+     * bytes. Afterwards grows the buffer exponentially.
+     */
+    nm_str_buf_maybe_expand(out_string, NM_UTILS_GET_NEXT_REALLOC_SIZE_488 + 1, FALSE);
 
+    /* We always use all the available buffer size. */
     buf_available = out_string->allocated - out_string->len;
 
     n_read = read(fd, &((nm_str_buf_get_str_unsafe(out_string))[out_string->len]), buf_available);