summaryrefslogtreecommitdiff
path: root/src/core/meta-anonymous-file.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/meta-anonymous-file.c')
-rw-r--r--src/core/meta-anonymous-file.c368
1 files changed, 0 insertions, 368 deletions
diff --git a/src/core/meta-anonymous-file.c b/src/core/meta-anonymous-file.c
deleted file mode 100644
index 95b63c9f0..000000000
--- a/src/core/meta-anonymous-file.c
+++ /dev/null
@@ -1,368 +0,0 @@
-/*
- * Copyright (C) 2020 Sebastian Wick
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program 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
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- *
- * Author: Sebastian Wick <sebastian@sebastianwick.net>
- */
-
-#include "config.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/mman.h>
-
-#include "core/meta-anonymous-file.h"
-
-struct _MetaAnonymousFile
-{
- int fd;
- size_t size;
-};
-
-#define READONLY_SEALS (F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE)
-
-static int
-create_tmpfile_cloexec (char *tmpname)
-{
- int fd;
-
-#if defined(HAVE_MKOSTEMP)
- fd = mkostemp (tmpname, O_CLOEXEC);
- if (fd >= 0)
- unlink (tmpname);
-#else
- fd = mkstemp (tmpname);
- if (fd >= 0)
- {
- long flags;
-
- unlink (tmpname);
-
- flags = fcntl (fd, F_GETFD);
- if (flags == -1 ||
- fcntl (fd, F_SETFD, flags | FD_CLOEXEC) == -1)
- {
- close (fd);
- return -1;
- }
- }
-#endif
-
- return fd;
-}
-
-/*
- * Create a new, unique, anonymous file of the given size, and
- * return the file descriptor for it. The file descriptor is set
- * CLOEXEC. The file is immediately suitable for mmap()'ing
- * the given size at offset zero.
- *
- * The file should not have a permanent backing store like a disk,
- * but may have if XDG_RUNTIME_DIR is not properly implemented in OS.
- *
- * The file name is deleted from the file system.
- *
- * The file is suitable for buffer sharing between processes by
- * transmitting the file descriptor over Unix sockets using the
- * SCM_RIGHTS methods.
- *
- * If the C library implements posix_fallocate(), it is used to
- * guarantee that disk space is available for the file at the
- * given size. If disk space is insufficient, errno is set to ENOSPC.
- * If posix_fallocate() is not supported, program may receive
- * SIGBUS on accessing mmap()'ed file contents instead.
- *
- * If the C library implements memfd_create(), it is used to create the
- * file purely in memory, without any backing file name on the file
- * system, and then sealing off the possibility of shrinking it. This
- * can then be checked before accessing mmap()'ed file contents, to make
- * sure SIGBUS can't happen. It also avoids requiring XDG_RUNTIME_DIR.
- */
-static int
-create_anonymous_file (off_t size)
-{
- int fd, ret;
-
-#if defined(HAVE_MEMFD_CREATE)
- fd = memfd_create ("mutter-shared", MFD_CLOEXEC | MFD_ALLOW_SEALING);
- if (fd >= 0)
- {
- /* We can add this seal before calling posix_fallocate(), as
- * the file is currently zero-sized anyway.
- *
- * There is also no need to check for the return value, we
- * couldn't do anything with it anyway.
- */
- fcntl (fd, F_ADD_SEALS, F_SEAL_SHRINK);
- }
- else
-#endif
- {
- static const char template[] = "/mutter-shared-XXXXXX";
- const char *path;
- char *name;
-
- path = getenv ("XDG_RUNTIME_DIR");
- if (!path)
- {
- errno = ENOENT;
- return -1;
- }
-
- name = g_malloc (strlen (path) + sizeof (template));
- if (!name)
- return -1;
-
- strcpy (name, path);
- strcat (name, template);
-
- fd = create_tmpfile_cloexec (name);
-
- g_free (name);
-
- if (fd < 0)
- return -1;
- }
-
-#if defined(HAVE_POSIX_FALLOCATE)
- do
- {
- ret = posix_fallocate (fd, 0, size);
- }
- while (ret == EINTR);
-
- if (ret != 0)
- {
- close (fd);
- errno = ret;
- return -1;
- }
-#else
- do
- {
- ret = ftruncate (fd, size);
- }
- while (ret < 0 && errno == EINTR);
-
- if (ret < 0)
- {
- close (fd);
- return -1;
- }
-#endif
-
- return fd;
-}
-
-/**
- * meta_anonymous_file_new: (skip)
- * @size: The size of @data
- * @data: The data of the file with the size @size
- *
- * Create a new anonymous read-only file of the given size and the given data
- * The intended use-case is for sending mid-sized data from the compositor
- * to clients.
- *
- * When done, free the data using meta_anonymous_file_free().
- *
- * If this function fails errno is set.
- *
- * Returns: The newly created #MetaAnonymousFile, or NULL on failure. Use
- * meta_anonymous_file_free() to free the resources when done.
- */
-MetaAnonymousFile *
-meta_anonymous_file_new (size_t size,
- const uint8_t *data)
-{
- MetaAnonymousFile *file;
- void *map;
-
- file = g_malloc0 (sizeof *file);
- if (!file)
- {
- errno = ENOMEM;
- return NULL;
- }
-
- file->size = size;
- file->fd = create_anonymous_file (size);
- if (file->fd == -1)
- goto err_free;
-
- map = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, file->fd, 0);
- if (map == MAP_FAILED)
- goto err_close;
-
- memcpy (map, data, size);
-
- munmap (map, size);
-
-#if defined(HAVE_MEMFD_CREATE)
- /* try to put seals on the file to make it read-only so that we can
- * return the fd later directly when MAPMODE_SHARED is not set.
- * meta_anonymous_file_open_fd can handle the fd even if it is not
- * sealed read-only and will instead create a new anonymous file on
- * each invocation.
- */
- fcntl (file->fd, F_ADD_SEALS, READONLY_SEALS);
-#endif
-
- return file;
-
-err_close:
- close (file->fd);
-err_free:
- g_free (file);
- return NULL;
-}
-
-
-/**
- * meta_anonymous_file_free: (skip)
- * @file: the #MetaAnonymousFile
- *
- * Free the resources used by an anonymous read-only file.
- */
-void
-meta_anonymous_file_free (MetaAnonymousFile *file)
-{
- close (file->fd);
- g_free (file);
-}
-
-/**
- * meta_anonymous_file_size: (skip)
- * @file: the #MetaAnonymousFile
- *
- * Get the size of an anonymous read-only file.
- *
- * Returns: The size of the anonymous read-only file.
- */
-size_t
-meta_anonymous_file_size (MetaAnonymousFile *file)
-{
- return file->size;
-}
-
-/**
- * meta_anonymous_file_open_fd: (skip)
- * @file: the #MetaAnonymousFile to get a file descriptor for
- * @mapmode: describes the ways in which the returned file descriptor can
- * be used with mmap
- *
- * Returns a file descriptor for the given file, ready to be sent to a client.
- * The returned file descriptor must not be shared between multiple clients.
- * If @mapmode is %META_ANONYMOUS_FILE_MAPMODE_PRIVATE the file descriptor is
- * only guaranteed to be mmapable with MAP_PRIVATE. If @mapmode is
- * %META_ANONYMOUS_FILE_MAPMODE_SHARED the file descriptor can be mmaped with
- * either MAP_PRIVATE or MAP_SHARED.
- *
- * In case %META_ANONYMOUS_FILE_MAPMODE_PRIVATE is used, it is important to
- * only read the returned fd using mmap() since using read() will move the
- * read cursor of the fd and thus may cause read() calls on other returned
- * fds to fail.
- *
- * When done using the fd, it is required to call meta_anonymous_file_close_fd()
- * instead of close().
- *
- * If this function fails errno is set.
- *
- * Returns: A file descriptor for the given file that can be sent to a client
- * or -1 on failure. Use meta_anonymous_file_close_fd() to release the fd
- * when done.
- */
-int
-meta_anonymous_file_open_fd (MetaAnonymousFile *file,
- MetaAnonymousFileMapmode mapmode)
-{
- void *src, *dst;
- int fd;
-
-#if defined(HAVE_MEMFD_CREATE)
- int seals;
-
- seals = fcntl (file->fd, F_GET_SEALS);
-
- /* file was sealed for read-only and we don't have to support MAP_SHARED
- * so we can simply pass the memfd fd
- */
- if (seals != -1 && mapmode == META_ANONYMOUS_FILE_MAPMODE_PRIVATE &&
- (seals & READONLY_SEALS) == READONLY_SEALS)
- return file->fd;
-#endif
-
- /* for all other cases we create a new anonymous file that can be mapped
- * with MAP_SHARED and copy the contents to it and return that instead
- */
- fd = create_anonymous_file (file->size);
- if (fd == -1)
- return fd;
-
- src = mmap (NULL, file->size, PROT_READ, MAP_PRIVATE, file->fd, 0);
- if (src == MAP_FAILED)
- {
- close (fd);
- return -1;
- }
-
- dst = mmap (NULL, file->size, PROT_WRITE, MAP_SHARED, fd, 0);
- if (dst == MAP_FAILED)
- {
- close (fd);
- munmap (src, file->size);
- return -1;
- }
-
- memcpy (dst, src, file->size);
- munmap (src, file->size);
- munmap (dst, file->size);
-
- return fd;
-}
-
-/**
- * meta_anonymous_file_close_fd: (skip)
- * @fd: A file descriptor obtained using meta_anonymous_file_open_fd()
- *
- * Release a file descriptor returned by meta_anonymous_file_open_fd().
- * This function must be called for every file descriptor created with
- * meta_anonymous_file_open_fd() to not leak any resources.
- *
- * If this function fails errno is set.
- */
-void
-meta_anonymous_file_close_fd (int fd)
-{
-#if defined(HAVE_MEMFD_CREATE)
- int seals;
-
- seals = fcntl (fd, F_GET_SEALS);
- if (seals == -1 && errno != EINVAL)
- {
- g_warning ("Reading seals of anonymous file %d failed", fd);
- return;
- }
-
- /* The only case in which we do NOT have to close the file is when the file
- * was sealed for read-only
- */
- if (seals != -1 && (seals & READONLY_SEALS) == READONLY_SEALS)
- return;
-#endif
-
- close (fd);
-}