summary refs log tree commit diff
path: root/shared/nm-glib-aux/nm-io-utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'shared/nm-glib-aux/nm-io-utils.c')
-rw-r--r--shared/nm-glib-aux/nm-io-utils.c480
1 files changed, 0 insertions, 480 deletions
diff --git a/shared/nm-glib-aux/nm-io-utils.c b/shared/nm-glib-aux/nm-io-utils.c
deleted file mode 100644
index 429591ad..00000000
--- a/shared/nm-glib-aux/nm-io-utils.c
+++ /dev/null
@@ -1,480 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2018 Red Hat, Inc.
- */
-
-#include "nm-glib-aux/nm-default-glib-i18n-lib.h"
-
-#include "nm-io-utils.h"
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-#include "nm-str-buf.h"
-#include "nm-shared-utils.h"
-#include "nm-secret-utils.h"
-#include "nm-errno.h"
-
-/*****************************************************************************/
-
-_nm_printf(4, 5) static int _get_contents_error(GError **   error,
-                                                int         errsv,
-                                                int *       out_errsv,
-                                                const char *format,
-                                                ...)
-{
-    nm_assert(NM_ERRNO_NATIVE(errsv));
-
-    if (error) {
-        gs_free char *msg = NULL;
-        va_list       args;
-        char          bstrerr[NM_STRERROR_BUFSIZE];
-
-        va_start(args, format);
-        msg = g_strdup_vprintf(format, args);
-        va_end(args);
-        g_set_error(error,
-                    G_FILE_ERROR,
-                    g_file_error_from_errno(errsv),
-                    "%s: %s",
-                    msg,
-                    nm_strerror_native_r(errsv, bstrerr, sizeof(bstrerr)));
-    }
-
-    nm_assert(errsv > 0);
-    NM_SET_OUT(out_errsv, errsv);
-
-    return FALSE;
-}
-#define _get_contents_error_errno(error, out_errsv, ...)            \
-    ({                                                              \
-        int _errsv = (errno);                                       \
-                                                                    \
-        _get_contents_error(error, _errsv, out_errsv, __VA_ARGS__); \
-    })
-
-/**
- * nm_utils_fd_get_contents:
- * @fd: open file descriptor to read. The fd will not be closed,
- *   but don't rely on its state afterwards.
- * @close_fd: if %TRUE, @fd will be closed by the function.
- *  Passing %TRUE here might safe a syscall for dup().
- * @max_length: allocate at most @max_length bytes. If the
- *   file is larger, reading will fail. Set to zero to use
- *   a very large default.
- *   WARNING: @max_length is here to avoid a crash for huge/unlimited files.
- *   For example, stat(/sys/class/net/enp0s25/ifindex) gives a filesize of
- *   4K, although the actual real is small. @max_length is the memory
- *   allocated in the process of reading the file, thus it must be at least
- *   the size reported by fstat.
- *   If you set it to 1K, read will fail because fstat() claims the
- *   file is larger.
- * @flags: %NMUtilsFileGetContentsFlags for reading the file.
- * @contents: the output buffer with the file read. It is always
- *   NUL terminated. The buffer is at most @max_length long, including
- *  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.
- * @error:
- *
- *
- * A reimplementation of g_file_get_contents() with a few differences:
- *   - accepts an open fd, instead of a path name. This allows you to
- *     use openat().
- *   - limits the maximum filesize to max_length.
- *
- * Returns: TRUE on success.
- */
-gboolean
-nm_utils_fd_get_contents(int                         fd,
-                         gboolean                    close_fd,
-                         gsize                       max_length,
-                         NMUtilsFileGetContentsFlags flags,
-                         char **                     contents,
-                         gsize *                     length,
-                         int *                       out_errsv,
-                         GError **                   error)
-{
-    nm_auto_close int fd_keeper = close_fd ? fd : -1;
-    struct stat       stat_buf;
-    gs_free char *    str          = NULL;
-    const bool        do_bzero_mem = NM_FLAGS_HAS(flags, NM_UTILS_FILE_GET_CONTENTS_FLAG_SECRET);
-    int               errsv;
-
-    g_return_val_if_fail(fd >= 0, FALSE);
-    g_return_val_if_fail(contents && !*contents, FALSE);
-    g_return_val_if_fail(!error || !*error, FALSE);
-
-    NM_SET_OUT(length, 0);
-
-    if (fstat(fd, &stat_buf) < 0)
-        return _get_contents_error_errno(error, out_errsv, "failure during fstat");
-
-    if (!max_length) {
-        /* default to a very large size, but not extreme */
-        max_length = 2 * 1024 * 1024;
-    }
-
-    if (stat_buf.st_size > 0 && S_ISREG(stat_buf.st_mode)) {
-        const gsize n_stat = stat_buf.st_size;
-        ssize_t     n_read;
-
-        if (n_stat > max_length - 1)
-            return _get_contents_error(error,
-                                       EMSGSIZE,
-                                       out_errsv,
-                                       "file too large (%zu+1 bytes with maximum %zu bytes)",
-                                       n_stat,
-                                       max_length);
-
-        str = g_try_malloc(n_stat + 1);
-        if (!str)
-            return _get_contents_error(error,
-                                       ENOMEM,
-                                       out_errsv,
-                                       "failure to allocate buffer of %zu+1 bytes",
-                                       n_stat);
-
-        n_read = nm_utils_fd_read_loop(fd, str, n_stat, TRUE);
-        if (n_read < 0) {
-            if (do_bzero_mem)
-                nm_explicit_bzero(str, n_stat);
-            return _get_contents_error(error,
-                                       -n_read,
-                                       out_errsv,
-                                       "error reading %zu bytes from file descriptor",
-                                       n_stat);
-        }
-        str[n_read] = '\0';
-
-        if (n_read < n_stat) {
-            if (!(str = nm_secret_mem_try_realloc_take(str, do_bzero_mem, n_stat + 1, n_read + 1)))
-                return _get_contents_error(error,
-                                           ENOMEM,
-                                           out_errsv,
-                                           "failure to reallocate buffer with %zu bytes",
-                                           n_read + 1);
-        }
-        NM_SET_OUT(length, n_read);
-    } else {
-        nm_auto_fclose FILE *f = NULL;
-        char                 buf[4096];
-        gsize                n_have, n_alloc;
-        int                  fd2;
-
-        if (fd_keeper >= 0)
-            fd2 = nm_steal_fd(&fd_keeper);
-        else {
-            fd2 = fcntl(fd, F_DUPFD_CLOEXEC, 0);
-            if (fd2 < 0)
-                return _get_contents_error_errno(error, out_errsv, "error during dup");
-        }
-
-        if (!(f = fdopen(fd2, "r"))) {
-            errsv = errno;
-            nm_close(fd2);
-            return _get_contents_error(error, errsv, out_errsv, "failure during fdopen");
-        }
-
-        n_have  = 0;
-        n_alloc = 0;
-
-        while (!feof(f)) {
-            gsize n_read;
-
-            n_read = fread(buf, 1, sizeof(buf), f);
-            errsv  = errno;
-            if (ferror(f)) {
-                if (do_bzero_mem)
-                    nm_explicit_bzero(buf, sizeof(buf));
-                return _get_contents_error(error, errsv, out_errsv, "error during fread");
-            }
-
-            if (n_have > G_MAXSIZE - 1 - n_read || n_have + n_read + 1 > max_length) {
-                if (do_bzero_mem)
-                    nm_explicit_bzero(buf, sizeof(buf));
-                return _get_contents_error(
-                    error,
-                    EMSGSIZE,
-                    out_errsv,
-                    "file stream too large (%zu+1 bytes with maximum %zu bytes)",
-                    (n_have > G_MAXSIZE - 1 - n_read) ? G_MAXSIZE : n_have + n_read,
-                    max_length);
-            }
-
-            if (n_have + n_read + 1 >= n_alloc) {
-                gsize old_n_alloc = n_alloc;
-
-                if (n_alloc != 0) {
-                    nm_assert(str);
-                    if (n_alloc >= max_length / 2)
-                        n_alloc = max_length;
-                    else
-                        n_alloc *= 2;
-                } else {
-                    nm_assert(!str);
-                    n_alloc = NM_MIN(n_read + 1, sizeof(buf));
-                }
-
-                if (!(str = nm_secret_mem_try_realloc_take(str,
-                                                           do_bzero_mem,
-                                                           old_n_alloc,
-                                                           n_alloc))) {
-                    if (do_bzero_mem)
-                        nm_explicit_bzero(buf, sizeof(buf));
-                    return _get_contents_error(error,
-                                               ENOMEM,
-                                               out_errsv,
-                                               "failure to allocate buffer of %zu bytes",
-                                               n_alloc);
-                }
-            }
-
-            memcpy(str + n_have, buf, n_read);
-            n_have += n_read;
-        }
-
-        if (do_bzero_mem)
-            nm_explicit_bzero(buf, sizeof(buf));
-
-        if (n_alloc == 0)
-            str = g_new0(char, 1);
-        else {
-            str[n_have] = '\0';
-            if (n_have + 1 < n_alloc) {
-                if (!(str = nm_secret_mem_try_realloc_take(str, do_bzero_mem, n_alloc, n_have + 1)))
-                    return _get_contents_error(error,
-                                               ENOMEM,
-                                               out_errsv,
-                                               "failure to truncate buffer to %zu bytes",
-                                               n_have + 1);
-            }
-        }
-
-        NM_SET_OUT(length, n_have);
-    }
-
-    *contents = g_steal_pointer(&str);
-    NM_SET_OUT(out_errsv, 0);
-    return TRUE;
-}
-
-/**
- * nm_utils_file_get_contents:
- * @dirfd: optional file descriptor to use openat(). If negative, use plain open().
- * @filename: the filename to open. Possibly relative to @dirfd.
- * @max_length: allocate at most @max_length bytes.
- *   WARNING: see nm_utils_fd_get_contents() hint about @max_length.
- * @flags: %NMUtilsFileGetContentsFlags for reading the file.
- * @contents: the output buffer with the file read. It is always
- *   NUL terminated. The buffer is at most @max_length long, including
- *   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.
- * @error:
- *
- * A reimplementation of g_file_get_contents() with a few differences:
- *   - accepts an @dirfd to open @filename relative to that path via openat().
- *   - limits the maximum filesize to max_length.
- *   - uses O_CLOEXEC on internal file descriptor
- *   - optionally returns the native errno on failure.
- *
- * Returns: TRUE on success.
- */
-gboolean
-nm_utils_file_get_contents(int                         dirfd,
-                           const char *                filename,
-                           gsize                       max_length,
-                           NMUtilsFileGetContentsFlags flags,
-                           char **                     contents,
-                           gsize *                     length,
-                           int *                       out_errsv,
-                           GError **                   error)
-{
-    int fd;
-
-    g_return_val_if_fail(filename && filename[0], FALSE);
-    g_return_val_if_fail(contents && !*contents, FALSE);
-
-    NM_SET_OUT(length, 0);
-
-    if (dirfd >= 0) {
-        fd = openat(dirfd, filename, O_RDONLY | O_CLOEXEC);
-        if (fd < 0) {
-            return _get_contents_error_errno(error,
-                                             out_errsv,
-                                             "Failed to open file \"%s\" with openat",
-                                             filename);
-        }
-    } else {
-        fd = open(filename, O_RDONLY | O_CLOEXEC);
-        if (fd < 0) {
-            return _get_contents_error_errno(error,
-                                             out_errsv,
-                                             "Failed to open file \"%s\"",
-                                             filename);
-        }
-    }
-    return nm_utils_fd_get_contents(fd,
-                                    TRUE,
-                                    max_length,
-                                    flags,
-                                    contents,
-                                    length,
-                                    out_errsv,
-                                    error);
-}
-
-/*****************************************************************************/
-
-/*
- * Copied from GLib's g_file_set_contents() et al., but allows
- * specifying a mode for the new file.
- */
-gboolean
-nm_utils_file_set_contents(const char *filename,
-                           const char *contents,
-                           gssize      length,
-                           mode_t      mode,
-                           int *       out_errsv,
-                           GError **   error)
-{
-    gs_free char *tmp_name = NULL;
-    struct stat   statbuf;
-    int           errsv;
-    gssize        s;
-    int           fd;
-
-    g_return_val_if_fail(filename, FALSE);
-    g_return_val_if_fail(contents || !length, FALSE);
-    g_return_val_if_fail(!error || !*error, FALSE);
-    g_return_val_if_fail(length >= -1, FALSE);
-
-    if (length == -1)
-        length = strlen(contents);
-
-    tmp_name = g_strdup_printf("%s.XXXXXX", filename);
-    fd       = g_mkstemp_full(tmp_name, O_RDWR | O_CLOEXEC, mode);
-    if (fd < 0) {
-        return _get_contents_error_errno(error, out_errsv, "failed to create file %s", tmp_name);
-    }
-
-    while (length > 0) {
-        s = write(fd, contents, length);
-        if (s < 0) {
-            errsv = NM_ERRNO_NATIVE(errno);
-            if (errsv == EINTR)
-                continue;
-
-            nm_close(fd);
-            unlink(tmp_name);
-            return _get_contents_error(error,
-                                       errsv,
-                                       out_errsv,
-                                       "failed to write to file %s",
-                                       tmp_name);
-        }
-
-        g_assert(s <= length);
-
-        contents += s;
-        length -= s;
-    }
-
-    /* If the final destination exists and is > 0 bytes, we want to sync the
-     * newly written file to ensure the data is on disk when we rename over
-     * the destination. Otherwise, if we get a system crash we can lose both
-     * the new and the old file on some filesystems. (I.E. those that don't
-     * guarantee the data is written to the disk before the metadata.)
-     */
-    if (lstat(filename, &statbuf) == 0 && statbuf.st_size > 0) {
-        if (fsync(fd) != 0) {
-            errsv = NM_ERRNO_NATIVE(errno);
-            nm_close(fd);
-            unlink(tmp_name);
-            return _get_contents_error(error, errsv, out_errsv, "failed to fsync %s", tmp_name);
-        }
-    }
-
-    nm_close(fd);
-
-    if (rename(tmp_name, filename)) {
-        errsv = NM_ERRNO_NATIVE(errno);
-        unlink(tmp_name);
-        return _get_contents_error(error,
-                                   errsv,
-                                   out_errsv,
-                                   "failed rename %s to %s",
-                                   tmp_name,
-                                   filename);
-    }
-
-    return TRUE;
-}
-
-/**
- * nm_utils_file_stat:
- * @filename: the filename to stat.
- * @out_st: (allow-none) (out): 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
- * with
- *
- *    if (nm_utils_file_stat (filename, NULL) == -ENOENT) {
- *    }
- *
- * Returns: 0 on success a negative errno on failure. */
-int
-nm_utils_file_stat(const char *filename, struct stat *out_st)
-{
-    struct stat st;
-
-    if (stat(filename, out_st ?: &st) != 0)
-        return -NM_ERRNO_NATIVE(errno);
-    return 0;
-}
-
-/**
- * nm_utils_fd_read:
- * @fd: the fd to read from.
- * @out_string: (out): output string where read bytes will be stored.
- *
- * Returns: <0 on failure, which is -(errno).
- *          0 on EOF.
- *          >0 on success, which is the number of bytes read.  */
-gssize
-nm_utils_fd_read(int fd, NMStrBuf *out_string)
-{
-    gsize  buf_available;
-    gssize n_read;
-    int    errsv;
-
-    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.
-     *
-     * 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);
-
-    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);
-    if (n_read < 0) {
-        errsv = errno;
-        return -NM_ERRNO_NATIVE(errsv);
-    }
-
-    if (n_read > 0) {
-        nm_assert((gsize) n_read <= buf_available);
-        nm_str_buf_set_size(out_string, out_string->len + (gsize) n_read, TRUE, FALSE);
-    }
-
-    return n_read;
-}