New upstream version 2017.8
This commit is contained in:
commit
b6c0af922c
158 files changed
+12692
-2420
No files matched your search
@@ -22,7 +22,7 @@ EXTRA_DIST += \
|
||||
$(NULL)
|
||||
|
||||
libglnx_la_SOURCES = \
|
||||
$(libglnx_srcpath)/glnx-alloca.h \
|
||||
$(libglnx_srcpath)/glnx-macros.h \
|
||||
$(libglnx_srcpath)/glnx-backport-autocleanups.h \
|
||||
$(libglnx_srcpath)/glnx-backport-autoptr.h \
|
||||
$(libglnx_srcpath)/glnx-backports.h \
|
||||
@@ -52,7 +52,7 @@ libglnx_la_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags)
|
||||
libglnx_la_LDFLAGS = -avoid-version -Bsymbolic-functions -export-symbols-regex "^glnx_" -no-undefined -export-dynamic
|
||||
libglnx_la_LIBADD = $(libglnx_libs)
|
||||
|
||||
libglnx_tests = test-libglnx-xattrs test-libglnx-fdio test-libglnx-errors
|
||||
libglnx_tests = test-libglnx-xattrs test-libglnx-fdio test-libglnx-errors test-libglnx-macros
|
||||
TESTS += $(libglnx_tests)
|
||||
|
||||
check_PROGRAMS += $(libglnx_tests)
|
||||
@@ -67,3 +67,7 @@ test_libglnx_fdio_LDADD = $(libglnx_libs) libglnx.la
|
||||
test_libglnx_errors_SOURCES = $(libglnx_srcpath)/tests/test-libglnx-errors.c
|
||||
test_libglnx_errors_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags)
|
||||
test_libglnx_errors_LDADD = $(libglnx_libs) libglnx.la
|
||||
|
||||
test_libglnx_macros_SOURCES = $(libglnx_srcpath)/tests/test-libglnx-macros.c
|
||||
test_libglnx_macros_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags)
|
||||
test_libglnx_macros_LDADD = $(libglnx_libs) libglnx.la
|
||||
@@ -22,7 +22,7 @@ EXTRA_DIST += \
|
||||
$(NULL)
|
||||
|
||||
libglnx_la_SOURCES = \
|
||||
libglnx/glnx-alloca.h \
|
||||
libglnx/glnx-macros.h \
|
||||
libglnx/glnx-backport-autocleanups.h \
|
||||
libglnx/glnx-backport-autoptr.h \
|
||||
libglnx/glnx-backports.h \
|
||||
@@ -52,7 +52,7 @@ libglnx_la_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags)
|
||||
libglnx_la_LDFLAGS = -avoid-version -Bsymbolic-functions -export-symbols-regex "^glnx_" -no-undefined -export-dynamic
|
||||
libglnx_la_LIBADD = $(libglnx_libs)
|
||||
|
||||
libglnx_tests = test-libglnx-xattrs test-libglnx-fdio test-libglnx-errors
|
||||
libglnx_tests = test-libglnx-xattrs test-libglnx-fdio test-libglnx-errors test-libglnx-macros
|
||||
TESTS += $(libglnx_tests)
|
||||
|
||||
check_PROGRAMS += $(libglnx_tests)
|
||||
@@ -67,3 +67,7 @@ test_libglnx_fdio_LDADD = $(libglnx_libs) libglnx.la
|
||||
test_libglnx_errors_SOURCES = libglnx/tests/test-libglnx-errors.c
|
||||
test_libglnx_errors_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags)
|
||||
test_libglnx_errors_LDADD = $(libglnx_libs) libglnx.la
|
||||
|
||||
test_libglnx_macros_SOURCES = libglnx/tests/test-libglnx-macros.c
|
||||
test_libglnx_macros_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags)
|
||||
test_libglnx_macros_LDADD = $(libglnx_libs) libglnx.la
|
||||
@@ -1,47 +0,0 @@
|
||||
/* -*- 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 <stdlib.h>
|
||||
#include <glib.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/* Taken from https://github.com/systemd/systemd/src/basic/string-util.h
|
||||
* at revision v228-666-gcf6c8c4
|
||||
*/
|
||||
#define glnx_strjoina(a, ...) \
|
||||
({ \
|
||||
const char *_appendees_[] = { a, __VA_ARGS__ }; \
|
||||
char *_d_, *_p_; \
|
||||
int _len_ = 0; \
|
||||
unsigned _i_; \
|
||||
for (_i_ = 0; _i_ < G_N_ELEMENTS(_appendees_) && _appendees_[_i_]; _i_++) \
|
||||
_len_ += strlen(_appendees_[_i_]); \
|
||||
_p_ = _d_ = alloca(_len_ + 1); \
|
||||
for (_i_ = 0; _i_ < G_N_ELEMENTS(_appendees_) && _appendees_[_i_]; _i_++) \
|
||||
_p_ = stpcpy(_p_, _appendees_[_i_]); \
|
||||
*_p_ = 0; \
|
||||
_d_; \
|
||||
})
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
+13
-32
@@ -99,24 +99,19 @@ glnx_dirfd_iterator_init_at (int dfd,
|
||||
GLnxDirFdIterator *out_dfd_iter,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
glnx_fd_close int fd = -1;
|
||||
|
||||
if (!glnx_opendirat (dfd, path, follow, &fd, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
if (!glnx_dirfd_iterator_init_take_fd (fd, out_dfd_iter, error))
|
||||
goto out;
|
||||
fd = -1; /* Transfer ownership */
|
||||
if (!glnx_dirfd_iterator_init_take_fd (&fd, out_dfd_iter, error))
|
||||
return FALSE;
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* glnx_dirfd_iterator_init_take_fd:
|
||||
* @dfd: File descriptor - ownership is taken
|
||||
* @dfd: File descriptor - ownership is taken, and the value is set to -1
|
||||
* @dfd_iter: A directory iterator
|
||||
* @error: Error
|
||||
*
|
||||
@@ -124,28 +119,20 @@ glnx_dirfd_iterator_init_at (int dfd,
|
||||
* iteration.
|
||||
*/
|
||||
gboolean
|
||||
glnx_dirfd_iterator_init_take_fd (int dfd,
|
||||
glnx_dirfd_iterator_init_take_fd (int *dfd,
|
||||
GLnxDirFdIterator *dfd_iter,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
GLnxRealDirfdIterator *real_dfd_iter = (GLnxRealDirfdIterator*) dfd_iter;
|
||||
DIR *d = NULL;
|
||||
|
||||
d = fdopendir (dfd);
|
||||
DIR *d = fdopendir (*dfd);
|
||||
if (!d)
|
||||
{
|
||||
glnx_set_prefix_error_from_errno (error, "%s", "fdopendir");
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw_errno_prefix (error, "fdopendir");
|
||||
|
||||
real_dfd_iter->fd = dfd;
|
||||
real_dfd_iter->fd = glnx_steal_fd (dfd);
|
||||
real_dfd_iter->d = d;
|
||||
real_dfd_iter->initialized = TRUE;
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -165,31 +152,25 @@ glnx_dirfd_iterator_next_dent (GLnxDirFdIterator *dfd_iter,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
GLnxRealDirfdIterator *real_dfd_iter = (GLnxRealDirfdIterator*) dfd_iter;
|
||||
|
||||
g_return_val_if_fail (out_dent, FALSE);
|
||||
g_return_val_if_fail (dfd_iter->initialized, FALSE);
|
||||
|
||||
if (g_cancellable_set_error_if_cancelled (cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
do
|
||||
{
|
||||
errno = 0;
|
||||
*out_dent = readdir (real_dfd_iter->d);
|
||||
if (*out_dent == NULL && errno != 0)
|
||||
{
|
||||
glnx_set_prefix_error_from_errno (error, "%s", "fdopendir");
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw_errno_prefix (error, "readdir");
|
||||
} while (*out_dent &&
|
||||
(strcmp ((*out_dent)->d_name, ".") == 0 ||
|
||||
strcmp ((*out_dent)->d_name, "..") == 0));
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -55,7 +55,7 @@ typedef struct GLnxDirFdIterator GLnxDirFdIterator;
|
||||
gboolean glnx_dirfd_iterator_init_at (int dfd, const char *path,
|
||||
gboolean follow,
|
||||
GLnxDirFdIterator *dfd_iter, GError **error);
|
||||
gboolean glnx_dirfd_iterator_init_take_fd (int dfd, GLnxDirFdIterator *dfd_iter, GError **error);
|
||||
gboolean glnx_dirfd_iterator_init_take_fd (int *dfd, GLnxDirFdIterator *dfd_iter, GError **error);
|
||||
gboolean glnx_dirfd_iterator_next_dent (GLnxDirFdIterator *dfd_iter,
|
||||
struct dirent **out_dent,
|
||||
GCancellable *cancellable,
|
||||
|
||||
+98
-57
@@ -37,7 +37,6 @@
|
||||
|
||||
#include <glnx-fdio.h>
|
||||
#include <glnx-dirfd.h>
|
||||
#include <glnx-alloca.h>
|
||||
#include <glnx-errors.h>
|
||||
#include <glnx-xattrs.h>
|
||||
#include <glnx-backport-autoptr.h>
|
||||
@@ -65,7 +64,7 @@ glnx_renameat2_noreplace (int olddirfd, const char *oldpath,
|
||||
#ifndef ENABLE_WRPSEUDO_COMPAT
|
||||
if (renameat2 (olddirfd, oldpath, newdirfd, newpath, RENAME_NOREPLACE) < 0)
|
||||
{
|
||||
if (errno == EINVAL || errno == ENOSYS)
|
||||
if (G_IN_SET(errno, EINVAL, ENOSYS))
|
||||
{
|
||||
/* Fall through */
|
||||
}
|
||||
@@ -119,7 +118,7 @@ glnx_renameat2_exchange (int olddirfd, const char *oldpath,
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
if (errno == ENOSYS || errno == EINVAL)
|
||||
if (G_IN_SET(errno, ENOSYS, EINVAL))
|
||||
{
|
||||
/* Fall through */
|
||||
}
|
||||
@@ -146,17 +145,51 @@ glnx_renameat2_exchange (int olddirfd, const char *oldpath,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Deallocate a tmpfile, closing the fd and deleting the path, if any. This is
|
||||
* normally called by default by the autocleanup attribute, but you can also
|
||||
* invoke this directly.
|
||||
*/
|
||||
void
|
||||
glnx_tmpfile_clear (GLnxTmpfile *tmpf)
|
||||
{
|
||||
/* Support being passed NULL so we work nicely in a GPtrArray */
|
||||
if (!tmpf)
|
||||
return;
|
||||
if (!tmpf->initialized)
|
||||
return;
|
||||
if (tmpf->fd == -1)
|
||||
return;
|
||||
(void) close (tmpf->fd);
|
||||
/* If ->path is set, we're likely aborting due to an error. Clean it up */
|
||||
if (tmpf->path)
|
||||
{
|
||||
(void) unlinkat (tmpf->src_dfd, tmpf->path, 0);
|
||||
g_free (tmpf->path);
|
||||
}
|
||||
tmpf->initialized = FALSE;
|
||||
}
|
||||
|
||||
/* Allocate a temporary file, using Linux O_TMPFILE if available.
|
||||
* The result will be stored in @out_tmpf, which is caller allocated
|
||||
* so you can store it on the stack in common scenarios.
|
||||
*
|
||||
* Note that with O_TMPFILE, the file mode will be `000`; you likely
|
||||
* want to chmod it before calling glnx_link_tmpfile_at().
|
||||
*
|
||||
* The directory fd @dfd must live at least as long as the output @out_tmpf.
|
||||
*/
|
||||
gboolean
|
||||
glnx_open_tmpfile_linkable_at (int dfd,
|
||||
const char *subpath,
|
||||
int flags,
|
||||
int *out_fd,
|
||||
char **out_path,
|
||||
GLnxTmpfile *out_tmpf,
|
||||
GError **error)
|
||||
{
|
||||
glnx_fd_close int fd = -1;
|
||||
int count;
|
||||
|
||||
dfd = glnx_dirfd_canonicalize (dfd);
|
||||
|
||||
/* Don't allow O_EXCL, as that has a special meaning for O_TMPFILE */
|
||||
g_return_val_if_fail ((flags & O_EXCL) == 0, FALSE);
|
||||
|
||||
@@ -168,13 +201,14 @@ glnx_open_tmpfile_linkable_at (int dfd,
|
||||
* in full. */
|
||||
#if defined(O_TMPFILE) && !defined(DISABLE_OTMPFILE) && !defined(ENABLE_WRPSEUDO_COMPAT)
|
||||
fd = openat (dfd, subpath, O_TMPFILE|flags, 0600);
|
||||
if (fd == -1 && !(errno == ENOSYS || errno == EISDIR || errno == EOPNOTSUPP))
|
||||
if (fd == -1 && !(G_IN_SET(errno, ENOSYS, EISDIR, EOPNOTSUPP)))
|
||||
return glnx_throw_errno_prefix (error, "open(O_TMPFILE)");
|
||||
if (fd != -1)
|
||||
{
|
||||
*out_fd = fd;
|
||||
fd = -1;
|
||||
*out_path = NULL;
|
||||
out_tmpf->initialized = TRUE;
|
||||
out_tmpf->src_dfd = dfd; /* Copied; caller must keep open */
|
||||
out_tmpf->fd = glnx_steal_fd (&fd);
|
||||
out_tmpf->path = NULL;
|
||||
return TRUE;
|
||||
}
|
||||
/* Fallthrough */
|
||||
@@ -182,7 +216,7 @@ glnx_open_tmpfile_linkable_at (int dfd,
|
||||
|
||||
{ g_autofree char *tmp = g_strconcat (subpath, "/tmp.XXXXXX", NULL);
|
||||
const guint count_max = 100;
|
||||
|
||||
|
||||
for (count = 0; count < count_max; count++)
|
||||
{
|
||||
glnx_gen_temp_name (tmp);
|
||||
@@ -197,9 +231,10 @@ glnx_open_tmpfile_linkable_at (int dfd,
|
||||
}
|
||||
else
|
||||
{
|
||||
*out_fd = fd;
|
||||
fd = -1;
|
||||
*out_path = g_steal_pointer (&tmp);
|
||||
out_tmpf->initialized = TRUE;
|
||||
out_tmpf->src_dfd = dfd; /* Copied; caller must keep open */
|
||||
out_tmpf->fd = glnx_steal_fd (&fd);
|
||||
out_tmpf->path = g_steal_pointer (&tmp);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
@@ -209,11 +244,33 @@ glnx_open_tmpfile_linkable_at (int dfd,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* A variant of `glnx_open_tmpfile_linkable_at()` which doesn't support linking.
|
||||
* Useful for true temporary storage. The fd will be allocated in /var/tmp to
|
||||
* ensure maximum storage space.
|
||||
*/
|
||||
gboolean
|
||||
glnx_link_tmpfile_at (int dfd,
|
||||
glnx_open_anonymous_tmpfile (int flags,
|
||||
GLnxTmpfile *out_tmpf,
|
||||
GError **error)
|
||||
{
|
||||
if (!glnx_open_tmpfile_linkable_at (AT_FDCWD, "/var/tmp", flags, out_tmpf, error))
|
||||
return FALSE;
|
||||
if (out_tmpf->path)
|
||||
{
|
||||
(void) unlinkat (out_tmpf->src_dfd, out_tmpf->path, 0);
|
||||
g_clear_pointer (&out_tmpf->path, g_free);
|
||||
}
|
||||
out_tmpf->anonymous = TRUE;
|
||||
out_tmpf->src_dfd = -1;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Use this after calling glnx_open_tmpfile_linkable_at() to give
|
||||
* the file its final name (link into place).
|
||||
*/
|
||||
gboolean
|
||||
glnx_link_tmpfile_at (GLnxTmpfile *tmpf,
|
||||
GLnxLinkTmpfileReplaceMode mode,
|
||||
int fd,
|
||||
const char *tmpfile_path,
|
||||
int target_dfd,
|
||||
const char *target,
|
||||
GError **error)
|
||||
@@ -221,46 +278,42 @@ glnx_link_tmpfile_at (int dfd,
|
||||
const gboolean replace = (mode == GLNX_LINK_TMPFILE_REPLACE);
|
||||
const gboolean ignore_eexist = (mode == GLNX_LINK_TMPFILE_NOREPLACE_IGNORE_EXIST);
|
||||
|
||||
g_return_val_if_fail (fd >= 0, FALSE);
|
||||
g_return_val_if_fail (!tmpf->anonymous, FALSE);
|
||||
g_return_val_if_fail (tmpf->fd >= 0, FALSE);
|
||||
g_return_val_if_fail (tmpf->src_dfd == AT_FDCWD || tmpf->src_dfd >= 0, FALSE);
|
||||
|
||||
/* Unlike the original systemd code, this function also supports
|
||||
* replacing existing files.
|
||||
*/
|
||||
|
||||
/* We have `tmpfile_path` for old systems without O_TMPFILE. */
|
||||
if (tmpfile_path)
|
||||
if (tmpf->path)
|
||||
{
|
||||
if (replace)
|
||||
{
|
||||
/* We have a regular tempfile, we're overwriting - this is a
|
||||
* simple renameat().
|
||||
*/
|
||||
if (renameat (dfd, tmpfile_path, target_dfd, target) < 0)
|
||||
{
|
||||
int errsv = errno;
|
||||
(void) unlinkat (dfd, tmpfile_path, 0);
|
||||
errno = errsv;
|
||||
return glnx_throw_errno_prefix (error, "renameat");
|
||||
}
|
||||
if (renameat (tmpf->src_dfd, tmpf->path, target_dfd, target) < 0)
|
||||
return glnx_throw_errno_prefix (error, "renameat");
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We need to use renameat2(..., NOREPLACE) or emulate it */
|
||||
if (!rename_file_noreplace_at (dfd, tmpfile_path, target_dfd, target,
|
||||
if (!rename_file_noreplace_at (tmpf->src_dfd, tmpf->path, target_dfd, target,
|
||||
ignore_eexist,
|
||||
error))
|
||||
{
|
||||
(void) unlinkat (dfd, tmpfile_path, 0);
|
||||
return FALSE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
/* Now, clear the pointer so we don't try to unlink it */
|
||||
g_clear_pointer (&tmpf->path, g_free);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This case we have O_TMPFILE, so our reference to it is via /proc/self/fd */
|
||||
char proc_fd_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(fd) + 1];
|
||||
char proc_fd_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(tmpf->fd) + 1];
|
||||
|
||||
sprintf (proc_fd_path, "/proc/self/fd/%i", fd);
|
||||
sprintf (proc_fd_path, "/proc/self/fd/%i", tmpf->fd);
|
||||
|
||||
if (replace)
|
||||
{
|
||||
@@ -294,16 +347,15 @@ glnx_link_tmpfile_at (int dfd,
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_EXISTS,
|
||||
"Exhausted %u attempts to create temporary file", count);
|
||||
return FALSE;
|
||||
}
|
||||
if (renameat (target_dfd, tmpname_buf, target_dfd, target) < 0)
|
||||
if (!glnx_renameat (target_dfd, tmpname_buf, target_dfd, target, error))
|
||||
{
|
||||
/* This is currently the only case where we need to have
|
||||
* a cleanup unlinkat() still with O_TMPFILE.
|
||||
*/
|
||||
int errsv = errno;
|
||||
(void) unlinkat (target_dfd, tmpname_buf, 0);
|
||||
errno = errsv;
|
||||
return glnx_throw_errno_prefix (error, "renameat");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -895,7 +947,6 @@ glnx_file_replace_contents_with_perms_at (int dfd,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
int r;
|
||||
char *dnbuf = strdupa (subpath);
|
||||
const char *dn = dirname (dnbuf);
|
||||
|
||||
@@ -907,28 +958,18 @@ glnx_file_replace_contents_with_perms_at (int dfd,
|
||||
if (mode == (mode_t) -1)
|
||||
mode = 0644;
|
||||
|
||||
glnx_fd_close int fd = -1;
|
||||
g_autofree char *tmpfile_path = NULL;
|
||||
g_auto(GLnxTmpfile) tmpf = { 0, };
|
||||
if (!glnx_open_tmpfile_linkable_at (dfd, dn, O_WRONLY | O_CLOEXEC,
|
||||
&fd, &tmpfile_path,
|
||||
error))
|
||||
&tmpf, error))
|
||||
return FALSE;
|
||||
|
||||
if (len == -1)
|
||||
len = strlen ((char*)buf);
|
||||
|
||||
/* Note that posix_fallocate does *not* set errno but returns it. */
|
||||
if (len > 0)
|
||||
{
|
||||
r = posix_fallocate (fd, 0, len);
|
||||
if (r != 0)
|
||||
{
|
||||
errno = r;
|
||||
return glnx_throw_errno_prefix (error, "fallocate");
|
||||
}
|
||||
}
|
||||
if (!glnx_try_fallocate (tmpf.fd, 0, len, error))
|
||||
return FALSE;
|
||||
|
||||
if (glnx_loop_write (fd, buf, len) < 0)
|
||||
if (glnx_loop_write (tmpf.fd, buf, len) < 0)
|
||||
return glnx_throw_errno (error);
|
||||
|
||||
if (!(flags & GLNX_FILE_REPLACE_NODATASYNC))
|
||||
@@ -947,22 +988,22 @@ glnx_file_replace_contents_with_perms_at (int dfd,
|
||||
|
||||
if (do_sync)
|
||||
{
|
||||
if (fdatasync (fd) != 0)
|
||||
if (fdatasync (tmpf.fd) != 0)
|
||||
return glnx_throw_errno_prefix (error, "fdatasync");
|
||||
}
|
||||
}
|
||||
|
||||
if (uid != (uid_t) -1)
|
||||
{
|
||||
if (fchown (fd, uid, gid) != 0)
|
||||
if (fchown (tmpf.fd, uid, gid) != 0)
|
||||
return glnx_throw_errno (error);
|
||||
}
|
||||
|
||||
if (fchmod (fd, mode) != 0)
|
||||
if (fchmod (tmpf.fd, mode) != 0)
|
||||
return glnx_throw_errno (error);
|
||||
|
||||
if (!glnx_link_tmpfile_at (dfd, GLNX_LINK_TMPFILE_REPLACE,
|
||||
fd, tmpfile_path, dfd, subpath, error))
|
||||
if (!glnx_link_tmpfile_at (&tmpf, GLNX_LINK_TMPFILE_REPLACE,
|
||||
dfd, subpath, error))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
|
||||
+86
-6
@@ -27,6 +27,7 @@
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/xattr.h>
|
||||
/* From systemd/src/shared/util.h */
|
||||
/* When we include libgen.h because we need dirname() we immediately
|
||||
@@ -35,6 +36,7 @@
|
||||
#include <libgen.h>
|
||||
#undef basename
|
||||
|
||||
#include <glnx-macros.h>
|
||||
#include <glnx-errors.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
@@ -48,12 +50,26 @@ const char *glnx_basename (const char *path)
|
||||
return (basename) (path);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
gboolean initialized;
|
||||
gboolean anonymous;
|
||||
int src_dfd;
|
||||
int fd;
|
||||
char *path;
|
||||
} GLnxTmpfile;
|
||||
void glnx_tmpfile_clear (GLnxTmpfile *tmpf);
|
||||
G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(GLnxTmpfile, glnx_tmpfile_clear)
|
||||
|
||||
gboolean
|
||||
glnx_open_anonymous_tmpfile (int flags,
|
||||
GLnxTmpfile *out_tmpf,
|
||||
GError **error);
|
||||
|
||||
gboolean
|
||||
glnx_open_tmpfile_linkable_at (int dfd,
|
||||
const char *subpath,
|
||||
int flags,
|
||||
int *out_fd,
|
||||
char **out_path,
|
||||
GLnxTmpfile *out_tmpf,
|
||||
GError **error);
|
||||
|
||||
typedef enum {
|
||||
@@ -63,10 +79,8 @@ typedef enum {
|
||||
} GLnxLinkTmpfileReplaceMode;
|
||||
|
||||
gboolean
|
||||
glnx_link_tmpfile_at (int dfd,
|
||||
glnx_link_tmpfile_at (GLnxTmpfile *tmpf,
|
||||
GLnxLinkTmpfileReplaceMode flags,
|
||||
int fd,
|
||||
const char *tmpfile_path,
|
||||
int target_dfd,
|
||||
const char *target,
|
||||
GError **error);
|
||||
@@ -160,6 +174,38 @@ int glnx_renameat2_noreplace (int olddirfd, const char *oldpath,
|
||||
int glnx_renameat2_exchange (int olddirfd, const char *oldpath,
|
||||
int newdirfd, const char *newpath);
|
||||
|
||||
/**
|
||||
* glnx_try_fallocate:
|
||||
* @fd: File descriptor
|
||||
* @size: Size
|
||||
* @error: Error
|
||||
*
|
||||
* Wrapper for Linux fallocate(). Explicitly ignores a @size of zero.
|
||||
* Also, will silently do nothing if the underlying filesystem doesn't
|
||||
* support it. Use this instead of posix_fallocate(), since the glibc fallback
|
||||
* is bad: https://sourceware.org/bugzilla/show_bug.cgi?id=18515
|
||||
*/
|
||||
static inline gboolean
|
||||
glnx_try_fallocate (int fd,
|
||||
off_t offset,
|
||||
off_t size,
|
||||
GError **error)
|
||||
{
|
||||
/* This is just nicer than throwing an error */
|
||||
if (size == 0)
|
||||
return TRUE;
|
||||
|
||||
if (fallocate (fd, 0, offset, size) < 0)
|
||||
{
|
||||
if (G_IN_SET(errno, ENOSYS, EOPNOTSUPP))
|
||||
; /* Ignore */
|
||||
else
|
||||
return glnx_throw_errno_prefix (error, "fallocate");
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* glnx_fstat:
|
||||
* @fd: FD to stat
|
||||
@@ -205,8 +251,42 @@ glnx_fstatat (int dfd,
|
||||
GError **error)
|
||||
{
|
||||
if (TEMP_FAILURE_RETRY (fstatat (dfd, path, buf, flags)) != 0)
|
||||
return glnx_throw_errno (error);
|
||||
return glnx_throw_errno_prefix (error, "fstatat(%s)", path);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* glnx_renameat:
|
||||
*
|
||||
* Wrapper around renameat() which adds #GError support and ensures that it
|
||||
* retries on %EINTR.
|
||||
*/
|
||||
static inline gboolean
|
||||
glnx_renameat (int src_dfd,
|
||||
const gchar *src_path,
|
||||
int dest_dfd,
|
||||
const gchar *dest_path,
|
||||
GError **error)
|
||||
{
|
||||
if (TEMP_FAILURE_RETRY (renameat (src_dfd, src_path, dest_dfd, dest_path)) != 0)
|
||||
return glnx_throw_errno_prefix (error, "renameat(%s, %s)", src_path, dest_path);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* glnx_unlinkat:
|
||||
*
|
||||
* Wrapper around unlinkat() which adds #GError support and ensures that it
|
||||
* retries on %EINTR.
|
||||
*/
|
||||
static inline gboolean
|
||||
glnx_unlinkat (int dfd,
|
||||
const gchar *path,
|
||||
int flags,
|
||||
GError **error)
|
||||
{
|
||||
if (TEMP_FAILURE_RETRY (unlinkat (dfd, path, flags)) != 0)
|
||||
return glnx_throw_errno_prefix (error, "unlinkat(%s)", path);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* Copyright (C) 2017 Colin Walters <walters@verbum.org>
|
||||
* With original source from systemd:
|
||||
* Copyright 2010 Lennart Poettering
|
||||
*
|
||||
* 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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <gio/gio.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/* All of these are for C only. */
|
||||
#ifndef __GI_SCANNER__
|
||||
|
||||
/* Taken from https://github.com/systemd/systemd/src/basic/string-util.h
|
||||
* at revision v228-666-gcf6c8c4
|
||||
*/
|
||||
#define glnx_strjoina(a, ...) \
|
||||
({ \
|
||||
const char *_appendees_[] = { a, __VA_ARGS__ }; \
|
||||
char *_d_, *_p_; \
|
||||
int _len_ = 0; \
|
||||
unsigned _i_; \
|
||||
for (_i_ = 0; _i_ < G_N_ELEMENTS(_appendees_) && _appendees_[_i_]; _i_++) \
|
||||
_len_ += strlen(_appendees_[_i_]); \
|
||||
_p_ = _d_ = alloca(_len_ + 1); \
|
||||
for (_i_ = 0; _i_ < G_N_ELEMENTS(_appendees_) && _appendees_[_i_]; _i_++) \
|
||||
_p_ = stpcpy(_p_, _appendees_[_i_]); \
|
||||
*_p_ = 0; \
|
||||
_d_; \
|
||||
})
|
||||
|
||||
#ifndef G_IN_SET
|
||||
|
||||
/* Infrastructure for `G_IN_SET`; this code is copied from
|
||||
* systemd's macro.h - please treat that version as canonical
|
||||
* and submit patches first to systemd.
|
||||
*/
|
||||
#define _G_INSET_CASE_F(X) case X:
|
||||
#define _G_INSET_CASE_F_1(CASE, X) _G_INSET_CASE_F(X)
|
||||
#define _G_INSET_CASE_F_2(CASE, X, ...) CASE(X) _G_INSET_CASE_F_1(CASE, __VA_ARGS__)
|
||||
#define _G_INSET_CASE_F_3(CASE, X, ...) CASE(X) _G_INSET_CASE_F_2(CASE, __VA_ARGS__)
|
||||
#define _G_INSET_CASE_F_4(CASE, X, ...) CASE(X) _G_INSET_CASE_F_3(CASE, __VA_ARGS__)
|
||||
#define _G_INSET_CASE_F_5(CASE, X, ...) CASE(X) _G_INSET_CASE_F_4(CASE, __VA_ARGS__)
|
||||
#define _G_INSET_CASE_F_6(CASE, X, ...) CASE(X) _G_INSET_CASE_F_5(CASE, __VA_ARGS__)
|
||||
#define _G_INSET_CASE_F_7(CASE, X, ...) CASE(X) _G_INSET_CASE_F_6(CASE, __VA_ARGS__)
|
||||
#define _G_INSET_CASE_F_8(CASE, X, ...) CASE(X) _G_INSET_CASE_F_7(CASE, __VA_ARGS__)
|
||||
#define _G_INSET_CASE_F_9(CASE, X, ...) CASE(X) _G_INSET_CASE_F_8(CASE, __VA_ARGS__)
|
||||
#define _G_INSET_CASE_F_10(CASE, X, ...) CASE(X) _G_INSET_CASE_F_9(CASE, __VA_ARGS__)
|
||||
#define _G_INSET_CASE_F_11(CASE, X, ...) CASE(X) _G_INSET_CASE_F_10(CASE, __VA_ARGS__)
|
||||
#define _G_INSET_CASE_F_12(CASE, X, ...) CASE(X) _G_INSET_CASE_F_11(CASE, __VA_ARGS__)
|
||||
#define _G_INSET_CASE_F_13(CASE, X, ...) CASE(X) _G_INSET_CASE_F_12(CASE, __VA_ARGS__)
|
||||
#define _G_INSET_CASE_F_14(CASE, X, ...) CASE(X) _G_INSET_CASE_F_13(CASE, __VA_ARGS__)
|
||||
#define _G_INSET_CASE_F_15(CASE, X, ...) CASE(X) _G_INSET_CASE_F_14(CASE, __VA_ARGS__)
|
||||
#define _G_INSET_CASE_F_16(CASE, X, ...) CASE(X) _G_INSET_CASE_F_15(CASE, __VA_ARGS__)
|
||||
#define _G_INSET_CASE_F_17(CASE, X, ...) CASE(X) _G_INSET_CASE_F_16(CASE, __VA_ARGS__)
|
||||
#define _G_INSET_CASE_F_18(CASE, X, ...) CASE(X) _G_INSET_CASE_F_17(CASE, __VA_ARGS__)
|
||||
#define _G_INSET_CASE_F_19(CASE, X, ...) CASE(X) _G_INSET_CASE_F_18(CASE, __VA_ARGS__)
|
||||
#define _G_INSET_CASE_F_20(CASE, X, ...) CASE(X) _G_INSET_CASE_F_19(CASE, __VA_ARGS__)
|
||||
|
||||
#define _G_INSET_GET_CASE_F(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,NAME,...) NAME
|
||||
#define _G_INSET_FOR_EACH_MAKE_CASE(...) \
|
||||
_G_INSET_GET_CASE_F(__VA_ARGS__,_G_INSET_CASE_F_20,_G_INSET_CASE_F_19,_G_INSET_CASE_F_18,_G_INSET_CASE_F_17,_G_INSET_CASE_F_16,_G_INSET_CASE_F_15,_G_INSET_CASE_F_14,_G_INSET_CASE_F_13,_G_INSET_CASE_F_12,_G_INSET_CASE_F_11, \
|
||||
_G_INSET_CASE_F_10,_G_INSET_CASE_F_9,_G_INSET_CASE_F_8,_G_INSET_CASE_F_7,_G_INSET_CASE_F_6,_G_INSET_CASE_F_5,_G_INSET_CASE_F_4,_G_INSET_CASE_F_3,_G_INSET_CASE_F_2,_G_INSET_CASE_F_1) \
|
||||
(_G_INSET_CASE_F,__VA_ARGS__)
|
||||
|
||||
/* Note: claiming the name here even though it isn't upstream yet
|
||||
* https://bugzilla.gnome.org/show_bug.cgi?id=783751
|
||||
*/
|
||||
/**
|
||||
* G_IN_SET:
|
||||
* @x: Integer (or smaller) sized value
|
||||
* @...: Elements to compare
|
||||
*
|
||||
* It's quite common to test whether or not `char` values or Unix @errno (among) others
|
||||
* are members of a small set. Normally one has to choose to either use `if (x == val || x == otherval ...)`
|
||||
* or a `switch` statement. This macro is useful to reduce duplication in the first case,
|
||||
* where one can write simply `if (G_IN_SET (x, val, otherval))`, and avoid the verbosity
|
||||
* that the `switch` statement requires.
|
||||
*/
|
||||
#define G_IN_SET(x, ...) \
|
||||
({ \
|
||||
gboolean _g_inset_found = FALSE; \
|
||||
/* If the build breaks in the line below, you need to extend the case macros */ \
|
||||
static G_GNUC_UNUSED char _static_assert__macros_need_to_be_extended[20 - sizeof((int[]){__VA_ARGS__})/sizeof(int)]; \
|
||||
switch(x) { \
|
||||
_G_INSET_FOR_EACH_MAKE_CASE(__VA_ARGS__) \
|
||||
_g_inset_found = TRUE; \
|
||||
break; \
|
||||
default: \
|
||||
break; \
|
||||
} \
|
||||
_g_inset_found; \
|
||||
})
|
||||
|
||||
#endif /* ifndef G_IN_SET */
|
||||
|
||||
#define _GLNX_CONCAT(a, b) a##b
|
||||
#define _GLNX_CONCAT_INDIRECT(a, b) _GLNX_CONCAT(a, b)
|
||||
#define _GLNX_MAKE_ANONYMOUS(a) _GLNX_CONCAT_INDIRECT(a, __COUNTER__)
|
||||
|
||||
#define _GLNX_HASH_TABLE_FOREACH_IMPL_KV(guard, ht, it, kt, k, vt, v) \
|
||||
gboolean guard = TRUE; \
|
||||
G_STATIC_ASSERT (sizeof (kt) == sizeof (void*)); \
|
||||
G_STATIC_ASSERT (sizeof (vt) == sizeof (void*)); \
|
||||
for (GHashTableIter it; \
|
||||
guard && ({ g_hash_table_iter_init (&it, ht), TRUE; }); \
|
||||
guard = FALSE) \
|
||||
for (kt k; guard; guard = FALSE) \
|
||||
for (vt v; g_hash_table_iter_next (&it, (gpointer)&k, (gpointer)&v);)
|
||||
|
||||
|
||||
/* Cleaner method to iterate over a GHashTable. I.e. rather than
|
||||
*
|
||||
* gpointer k, v;
|
||||
* GHashTableIter it;
|
||||
* g_hash_table_iter_init (&it, table);
|
||||
* while (g_hash_table_iter_next (&it, &k, &v))
|
||||
* {
|
||||
* const char *str = k;
|
||||
* GPtrArray *arr = v;
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
* you can simply do
|
||||
*
|
||||
* GLNX_HASH_TABLE_FOREACH_IT (table, it, const char*, str, GPtrArray*, arr)
|
||||
* {
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
* All variables are scoped within the loop. You may use the `it` variable as
|
||||
* usual, e.g. to remove an element using g_hash_table_iter_remove(&it). There
|
||||
* are shorter variants for the more common cases where you do not need access
|
||||
* to the iterator or to keys/values:
|
||||
*
|
||||
* GLNX_HASH_TABLE_FOREACH (table, const char*, str) { ... }
|
||||
* GLNX_HASH_TABLE_FOREACH_V (table, MyData*, data) { ... }
|
||||
* GLNX_HASH_TABLE_FOREACH_KV (table, const char*, str, MyData*, data) { ... }
|
||||
*
|
||||
*/
|
||||
#define GLNX_HASH_TABLE_FOREACH_IT(ht, it, kt, k, vt, v) \
|
||||
_GLNX_HASH_TABLE_FOREACH_IMPL_KV( \
|
||||
_GLNX_MAKE_ANONYMOUS(_glnx_ht_iter_guard_), ht, it, kt, k, vt, v)
|
||||
|
||||
/* Variant of GLNX_HASH_TABLE_FOREACH without having to specify an iterator. An
|
||||
* anonymous iterator will be created. */
|
||||
#define GLNX_HASH_TABLE_FOREACH_KV(ht, kt, k, vt, v) \
|
||||
_GLNX_HASH_TABLE_FOREACH_IMPL_KV( \
|
||||
_GLNX_MAKE_ANONYMOUS(_glnx_ht_iter_guard_), ht, \
|
||||
_GLNX_MAKE_ANONYMOUS(_glnx_ht_iter_it_), kt, k, vt, v)
|
||||
|
||||
/* Variant of GLNX_HASH_TABLE_FOREACH_KV which omits unpacking keys. */
|
||||
#define GLNX_HASH_TABLE_FOREACH_V(ht, vt, v) \
|
||||
_GLNX_HASH_TABLE_FOREACH_IMPL_KV( \
|
||||
_GLNX_MAKE_ANONYMOUS(_glnx_ht_iter_guard_), ht, \
|
||||
_GLNX_MAKE_ANONYMOUS(_glnx_ht_iter_it_), \
|
||||
gpointer, _GLNX_MAKE_ANONYMOUS(_glnx_ht_iter_v_), \
|
||||
vt, v)
|
||||
|
||||
/* Variant of GLNX_HASH_TABLE_FOREACH_KV which omits unpacking vals. */
|
||||
#define GLNX_HASH_TABLE_FOREACH(ht, kt, k) \
|
||||
_GLNX_HASH_TABLE_FOREACH_IMPL_KV( \
|
||||
_GLNX_MAKE_ANONYMOUS(_glnx_ht_iter_guard_), ht, \
|
||||
_GLNX_MAKE_ANONYMOUS(_glnx_ht_iter_it_), kt, k, \
|
||||
gpointer, _GLNX_MAKE_ANONYMOUS(_glnx_ht_iter_v_))
|
||||
|
||||
#endif /* GI_SCANNER */
|
||||
|
||||
G_END_DECLS
|
||||
@@ -110,9 +110,8 @@ glnx_shutil_rm_rf_at (int dfd,
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!glnx_dirfd_iterator_init_take_fd (target_dfd, &dfd_iter, error))
|
||||
if (!glnx_dirfd_iterator_init_take_fd (&target_dfd, &dfd_iter, error))
|
||||
return FALSE;
|
||||
target_dfd = -1;
|
||||
|
||||
if (!glnx_shutil_rm_rf_children (&dfd_iter, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
+35
-99
@@ -23,6 +23,7 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <glnx-macros.h>
|
||||
#include <glnx-xattrs.h>
|
||||
#include <glnx-errors.h>
|
||||
#include <glnx-local-alloc.h>
|
||||
@@ -249,7 +250,7 @@ glnx_dfd_name_get_all_xattrs (int dfd,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
if (dfd == AT_FDCWD || dfd == -1)
|
||||
if (G_IN_SET(dfd, AT_FDCWD, -1))
|
||||
{
|
||||
return get_xattrs_impl (name, -1, out_xattrs, cancellable, error);
|
||||
}
|
||||
@@ -270,31 +271,22 @@ set_all_xattrs_for_path (const char *path,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
int i, n;
|
||||
|
||||
n = g_variant_n_children (xattrs);
|
||||
for (i = 0; i < n; i++)
|
||||
const guint n = g_variant_n_children (xattrs);
|
||||
for (guint i = 0; i < n; i++)
|
||||
{
|
||||
const guint8* name;
|
||||
g_autoptr(GVariant) value = NULL;
|
||||
const guint8* value_data;
|
||||
gsize value_len;
|
||||
|
||||
g_variant_get_child (xattrs, i, "(^&ay@ay)",
|
||||
&name, &value);
|
||||
value_data = g_variant_get_fixed_array (value, &value_len, 1);
|
||||
|
||||
|
||||
gsize value_len;
|
||||
const guint8* value_data = g_variant_get_fixed_array (value, &value_len, 1);
|
||||
|
||||
if (lsetxattr (path, (char*)name, (char*)value_data, value_len, 0) < 0)
|
||||
{
|
||||
glnx_set_prefix_error_from_errno (error, "%s", "lsetxattr");
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw_errno_prefix (error, "lsetxattr");
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -315,7 +307,7 @@ glnx_dfd_name_set_all_xattrs (int dfd,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
if (dfd == AT_FDCWD || dfd == -1)
|
||||
if (G_IN_SET(dfd, AT_FDCWD, -1))
|
||||
{
|
||||
return set_all_xattrs_for_path (name, xattrs, cancellable, error);
|
||||
}
|
||||
@@ -347,35 +339,22 @@ glnx_fd_set_all_xattrs (int fd,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
int i, n;
|
||||
|
||||
n = g_variant_n_children (xattrs);
|
||||
for (i = 0; i < n; i++)
|
||||
const guint n = g_variant_n_children (xattrs);
|
||||
for (guint i = 0; i < n; i++)
|
||||
{
|
||||
const guint8* name;
|
||||
const guint8* value_data;
|
||||
g_autoptr(GVariant) value = NULL;
|
||||
gsize value_len;
|
||||
int res;
|
||||
|
||||
g_variant_get_child (xattrs, i, "(^&ay@ay)",
|
||||
&name, &value);
|
||||
value_data = g_variant_get_fixed_array (value, &value_len, 1);
|
||||
|
||||
do
|
||||
res = fsetxattr (fd, (char*)name, (char*)value_data, value_len, 0);
|
||||
while (G_UNLIKELY (res == -1 && errno == EINTR));
|
||||
if (G_UNLIKELY (res == -1))
|
||||
{
|
||||
glnx_set_prefix_error_from_errno (error, "%s", "fsetxattr");
|
||||
goto out;
|
||||
}
|
||||
|
||||
gsize value_len;
|
||||
const guint8* value_data = g_variant_get_fixed_array (value, &value_len, 1);
|
||||
|
||||
if (TEMP_FAILURE_RETRY (fsetxattr (fd, (char*)name, (char*)value_data, value_len, 0)) < 0)
|
||||
return glnx_throw_errno_prefix (error, "fsetxattr");
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -395,35 +374,17 @@ glnx_lgetxattrat (int dfd,
|
||||
GError **error)
|
||||
{
|
||||
char pathbuf[PATH_MAX];
|
||||
GBytes *bytes = NULL;
|
||||
ssize_t bytes_read, real_size;
|
||||
guint8 *buf;
|
||||
|
||||
snprintf (pathbuf, sizeof (pathbuf), "/proc/self/fd/%d/%s", dfd, subpath);
|
||||
|
||||
do
|
||||
bytes_read = lgetxattr (pathbuf, attribute, NULL, 0);
|
||||
while (G_UNLIKELY (bytes_read < 0 && errno == EINTR));
|
||||
if (G_UNLIKELY (bytes_read < 0))
|
||||
{
|
||||
glnx_set_error_from_errno (error);
|
||||
goto out;
|
||||
}
|
||||
ssize_t bytes_read, real_size;
|
||||
if (TEMP_FAILURE_RETRY (bytes_read = lgetxattr (pathbuf, attribute, NULL, 0)) < 0)
|
||||
return glnx_null_throw_errno_prefix (error, "lgetxattr");
|
||||
|
||||
buf = g_malloc (bytes_read);
|
||||
do
|
||||
real_size = lgetxattr (pathbuf, attribute, buf, bytes_read);
|
||||
while (G_UNLIKELY (real_size < 0 && errno == EINTR));
|
||||
if (G_UNLIKELY (real_size < 0))
|
||||
{
|
||||
glnx_set_error_from_errno (error);
|
||||
g_free (buf);
|
||||
goto out;
|
||||
}
|
||||
g_autofree guint8 *buf = g_malloc (bytes_read);
|
||||
if (TEMP_FAILURE_RETRY (real_size = lgetxattr (pathbuf, attribute, buf, bytes_read)) < 0)
|
||||
return glnx_null_throw_errno_prefix (error, "lgetxattr");
|
||||
|
||||
bytes = g_bytes_new_take (buf, real_size);
|
||||
out:
|
||||
return bytes;
|
||||
return g_bytes_new_take (g_steal_pointer (&buf), real_size);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -439,33 +400,16 @@ glnx_fgetxattr_bytes (int fd,
|
||||
const char *attribute,
|
||||
GError **error)
|
||||
{
|
||||
GBytes *bytes = NULL;
|
||||
ssize_t bytes_read, real_size;
|
||||
guint8 *buf;
|
||||
|
||||
do
|
||||
bytes_read = fgetxattr (fd, attribute, NULL, 0);
|
||||
while (G_UNLIKELY (bytes_read < 0 && errno == EINTR));
|
||||
if (G_UNLIKELY (bytes_read < 0))
|
||||
{
|
||||
glnx_set_error_from_errno (error);
|
||||
goto out;
|
||||
}
|
||||
if (TEMP_FAILURE_RETRY (bytes_read = fgetxattr (fd, attribute, NULL, 0)) < 0)
|
||||
return glnx_null_throw_errno_prefix (error, "fgetxattr");
|
||||
|
||||
buf = g_malloc (bytes_read);
|
||||
do
|
||||
real_size = fgetxattr (fd, attribute, buf, bytes_read);
|
||||
while (G_UNLIKELY (real_size < 0 && errno == EINTR));
|
||||
if (G_UNLIKELY (real_size < 0))
|
||||
{
|
||||
glnx_set_error_from_errno (error);
|
||||
g_free (buf);
|
||||
goto out;
|
||||
}
|
||||
g_autofree guint8 *buf = g_malloc (bytes_read);
|
||||
if (TEMP_FAILURE_RETRY (real_size = fgetxattr (fd, attribute, buf, bytes_read)) < 0)
|
||||
return glnx_null_throw_errno_prefix (error, "fgetxattr");
|
||||
|
||||
bytes = g_bytes_new_take (buf, real_size);
|
||||
out:
|
||||
return bytes;
|
||||
return g_bytes_new_take (g_steal_pointer (&buf), real_size);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -490,18 +434,10 @@ glnx_lsetxattrat (int dfd,
|
||||
GError **error)
|
||||
{
|
||||
char pathbuf[PATH_MAX];
|
||||
int res;
|
||||
|
||||
snprintf (pathbuf, sizeof (pathbuf), "/proc/self/fd/%d/%s", dfd, subpath);
|
||||
|
||||
do
|
||||
res = lsetxattr (subpath, attribute, value, len, flags);
|
||||
while (G_UNLIKELY (res == -1 && errno == EINTR));
|
||||
if (G_UNLIKELY (res == -1))
|
||||
{
|
||||
glnx_set_error_from_errno (error);
|
||||
return FALSE;
|
||||
}
|
||||
if (TEMP_FAILURE_RETRY (lsetxattr (subpath, attribute, value, len, flags)) < 0)
|
||||
return glnx_throw_errno_prefix (error, "lsetxattr");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#include <glnx-alloca.h>
|
||||
#include <glnx-macros.h>
|
||||
#include <glnx-local-alloc.h>
|
||||
#include <glnx-backport-autocleanups.h>
|
||||
#include <glnx-backports.h>
|
||||
|
||||
@@ -80,11 +80,8 @@ test_renameat2_noreplace (void)
|
||||
glnx_set_error_from_errno (error);
|
||||
goto out;
|
||||
}
|
||||
if (fstatat (destfd, "bar", &stbuf, AT_SYMLINK_NOFOLLOW) < 0)
|
||||
{
|
||||
glnx_set_error_from_errno (error);
|
||||
goto out;
|
||||
}
|
||||
if (!glnx_fstatat (destfd, "bar", &stbuf, AT_SYMLINK_NOFOLLOW, error))
|
||||
goto out;
|
||||
|
||||
if (fstatat (srcfd, "foo", &stbuf, AT_SYMLINK_NOFOLLOW) == 0)
|
||||
g_assert_not_reached ();
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* Copyright (C) 2017 Red Hat, Inc.
|
||||
*
|
||||
* 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 "libglnx.h"
|
||||
#include <glib.h>
|
||||
#include <stdlib.h>
|
||||
#include <gio/gio.h>
|
||||
#include <string.h>
|
||||
|
||||
static void
|
||||
test_inset (void)
|
||||
{
|
||||
g_assert (G_IN_SET (7, 7));
|
||||
g_assert (G_IN_SET (7, 42, 7));
|
||||
g_assert (G_IN_SET (7, 7,42,3,9));
|
||||
g_assert (G_IN_SET (42, 7,42,3,9));
|
||||
g_assert (G_IN_SET (3, 7,42,3,9));
|
||||
g_assert (G_IN_SET (9, 7,42,3,9));
|
||||
g_assert (!G_IN_SET (8, 7,42,3,9));
|
||||
g_assert (!G_IN_SET (-1, 7,42,3,9));
|
||||
g_assert (G_IN_SET ('x', 'a', 'x', 'c'));
|
||||
g_assert (!G_IN_SET ('y', 'a', 'x', 'c'));
|
||||
}
|
||||
|
||||
static void
|
||||
test_hash_table_foreach (void)
|
||||
{
|
||||
/* use var names all different from the macro metavars to ensure proper
|
||||
* substitution */
|
||||
g_autoptr(GHashTable) table = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
const char *keys[] = {"key1", "key2"};
|
||||
const char *vals[] = {"val1", "val2"};
|
||||
g_hash_table_insert (table, (gpointer)keys[0], (gpointer)vals[0]);
|
||||
g_hash_table_insert (table, (gpointer)keys[1], (gpointer)vals[1]);
|
||||
|
||||
guint i = 0;
|
||||
GLNX_HASH_TABLE_FOREACH_IT (table, it, const char*, key, const char*, val)
|
||||
{
|
||||
g_assert_cmpstr (key, ==, keys[i]);
|
||||
g_assert_cmpstr (val, ==, vals[i]);
|
||||
i++;
|
||||
}
|
||||
g_assert_cmpuint (i, ==, 2);
|
||||
|
||||
i = 0;
|
||||
GLNX_HASH_TABLE_FOREACH_IT (table, it, const char*, key, const char*, val)
|
||||
{
|
||||
g_hash_table_iter_remove (&it);
|
||||
break;
|
||||
}
|
||||
g_assert_cmpuint (g_hash_table_size (table), ==, 1);
|
||||
|
||||
g_hash_table_insert (table, (gpointer)keys[1], (gpointer)vals[1]);
|
||||
g_assert_cmpuint (g_hash_table_size (table), ==, 1);
|
||||
|
||||
g_hash_table_insert (table, (gpointer)keys[0], (gpointer)vals[0]);
|
||||
g_assert_cmpuint (g_hash_table_size (table), ==, 2);
|
||||
|
||||
i = 0;
|
||||
GLNX_HASH_TABLE_FOREACH_KV (table, const char*, key, const char*, val)
|
||||
{
|
||||
g_assert_cmpstr (key, ==, keys[i]);
|
||||
g_assert_cmpstr (val, ==, vals[i]);
|
||||
i++;
|
||||
}
|
||||
g_assert_cmpuint (i, ==, 2);
|
||||
|
||||
i = 0;
|
||||
GLNX_HASH_TABLE_FOREACH (table, const char*, key)
|
||||
{
|
||||
g_assert_cmpstr (key, ==, keys[i]);
|
||||
i++;
|
||||
}
|
||||
g_assert_cmpuint (i, ==, 2);
|
||||
|
||||
i = 0;
|
||||
GLNX_HASH_TABLE_FOREACH_V (table, const char*, val)
|
||||
{
|
||||
g_assert_cmpstr (val, ==, vals[i]);
|
||||
i++;
|
||||
}
|
||||
g_assert_cmpuint (i, ==, 2);
|
||||
}
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
g_test_add_func ("/inset", test_inset);
|
||||
g_test_add_func ("/hash_table_foreach", test_hash_table_foreach);
|
||||
return g_test_run();
|
||||
}
|
||||
Reference in new issue
Block a user