New upstream version 2017.10
This commit is contained in:
commit
592e798794
140 files changed
+4813
-1216
No files matched your search
@@ -187,11 +187,12 @@ text_percent_internal (const char *text,
|
||||
const guint n_spaces = sizeof (spaces) - 1;
|
||||
const guint ncolumns = glnx_console_columns ();
|
||||
const guint bar_min = 10;
|
||||
const guint input_textlen = text ? strlen (text) : 0;
|
||||
|
||||
if (text && !*text)
|
||||
text = NULL;
|
||||
|
||||
const guint input_textlen = text ? strlen (text) : 0;
|
||||
|
||||
if (percentage == current_percent
|
||||
&& g_strcmp0 (text, current_text) == 0)
|
||||
return;
|
||||
@@ -221,7 +222,8 @@ text_percent_internal (const char *text,
|
||||
|
||||
if (percentage == -1)
|
||||
{
|
||||
fwrite (text, 1, input_textlen, stdout);
|
||||
if (text != NULL)
|
||||
fwrite (text, 1, input_textlen, stdout);
|
||||
|
||||
/* Overwrite remaining space, if any */
|
||||
if (ncolumns > input_textlen)
|
||||
@@ -273,7 +275,7 @@ void
|
||||
glnx_console_progress_text_percent (const char *text,
|
||||
guint percentage)
|
||||
{
|
||||
g_return_if_fail (percentage >= 0 && percentage <= 100);
|
||||
g_return_if_fail (percentage <= 100);
|
||||
|
||||
text_percent_internal (text, percentage);
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ typedef struct GLnxRealDirfdIterator GLnxRealDirfdIterator;
|
||||
/**
|
||||
* glnx_dirfd_iterator_init_at:
|
||||
* @dfd: File descriptor, may be AT_FDCWD or -1
|
||||
* @path: Path, may be relative to @df
|
||||
* @path: Path, may be relative to @dfd
|
||||
* @follow: If %TRUE and the last component of @path is a symlink, follow it
|
||||
* @out_dfd_iter: (out caller-allocates): A directory iterator, will be initialized
|
||||
* @error: Error
|
||||
|
||||
+104
-42
@@ -31,9 +31,6 @@
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/sendfile.h>
|
||||
#include <errno.h>
|
||||
/* See linux.git/fs/btrfs/ioctl.h */
|
||||
#define BTRFS_IOCTL_MAGIC 0x94
|
||||
#define BTRFS_IOC_CLONE _IOW(BTRFS_IOCTL_MAGIC, 9, int)
|
||||
|
||||
#include <glnx-fdio.h>
|
||||
#include <glnx-dirfd.h>
|
||||
@@ -43,6 +40,11 @@
|
||||
#include <glnx-local-alloc.h>
|
||||
#include <glnx-missing.h>
|
||||
|
||||
/* The standardized version of BTRFS_IOC_CLONE */
|
||||
#ifndef FICLONE
|
||||
#define FICLONE _IOW(0x94, 9, int)
|
||||
#endif
|
||||
|
||||
/* Returns the number of chars needed to format variables of the
|
||||
* specified type as a decimal string. Adds in extra space for a
|
||||
* negative '-' prefix (hence works correctly on signed
|
||||
@@ -654,13 +656,6 @@ copy_symlink_at (int src_dfd,
|
||||
* conveniently fit in with the rest of libglnx.
|
||||
*/
|
||||
|
||||
static int btrfs_reflink(int infd, int outfd) {
|
||||
g_return_val_if_fail(infd >= 0, -1);
|
||||
g_return_val_if_fail(outfd >= 0, -1);
|
||||
|
||||
return ioctl (outfd, BTRFS_IOC_CLONE, infd);
|
||||
}
|
||||
|
||||
/* Like write(), but loop until @nbytes are written, or an error
|
||||
* occurs.
|
||||
*
|
||||
@@ -703,8 +698,10 @@ glnx_loop_write(int fd, const void *buf, size_t nbytes)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read from @fdf until EOF, writing to @fdt. If @try_reflink is %TRUE,
|
||||
* attempt to use any "reflink" functionality; see e.g. https://lwn.net/Articles/331808/
|
||||
/* Read from @fdf until EOF, writing to @fdt. If max_bytes is -1, a full-file
|
||||
* clone will be attempted. Otherwise Linux copy_file_range(), sendfile()
|
||||
* syscall will be attempted. If none of those work, this function will do a
|
||||
* plain read()/write() loop.
|
||||
*
|
||||
* The file descriptor @fdf must refer to a regular file.
|
||||
*
|
||||
@@ -712,58 +709,123 @@ glnx_loop_write(int fd, const void *buf, size_t nbytes)
|
||||
* On error, this function returns `-1` and @errno will be set.
|
||||
*/
|
||||
int
|
||||
glnx_regfile_copy_bytes (int fdf, int fdt, off_t max_bytes, gboolean try_reflink)
|
||||
glnx_regfile_copy_bytes (int fdf, int fdt, off_t max_bytes)
|
||||
{
|
||||
bool try_sendfile = true;
|
||||
int r;
|
||||
/* Last updates from systemd as of commit 6bda23dd6aaba50cf8e3e6024248cf736cc443ca */
|
||||
static int have_cfr = -1; /* -1 means unknown */
|
||||
bool try_cfr = have_cfr != 0;
|
||||
static int have_sendfile = -1; /* -1 means unknown */
|
||||
bool try_sendfile = have_sendfile != 0;
|
||||
|
||||
g_return_val_if_fail (fdf >= 0, -1);
|
||||
g_return_val_if_fail (fdt >= 0, -1);
|
||||
g_return_val_if_fail (max_bytes >= -1, -1);
|
||||
|
||||
/* Try btrfs reflinks first. */
|
||||
if (try_reflink && max_bytes == (off_t) -1)
|
||||
/* If we've requested to copy the whole range, try a full-file clone first.
|
||||
*/
|
||||
if (max_bytes == (off_t) -1)
|
||||
{
|
||||
r = btrfs_reflink(fdf, fdt);
|
||||
if (r >= 0)
|
||||
if (ioctl (fdt, FICLONE, fdf) == 0)
|
||||
return 0;
|
||||
/* Fall through */
|
||||
struct stat stbuf;
|
||||
|
||||
/* Gather the size so we can provide the whole thing at once to
|
||||
* copy_file_range() or sendfile().
|
||||
*/
|
||||
if (fstat (fdf, &stbuf) < 0)
|
||||
return -1;
|
||||
max_bytes = stbuf.st_size;
|
||||
}
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
size_t m = COPY_BUFFER_SIZE;
|
||||
ssize_t n;
|
||||
|
||||
if (max_bytes != (off_t) -1)
|
||||
/* First, try copy_file_range(). Note this is an inlined version of
|
||||
* try_copy_file_range() from systemd upstream, which works better since
|
||||
* we use POSIX errno style.
|
||||
*/
|
||||
if (try_cfr)
|
||||
{
|
||||
if ((off_t) m > max_bytes)
|
||||
m = (size_t) max_bytes;
|
||||
}
|
||||
|
||||
/* First try sendfile(), unless we already tried */
|
||||
if (try_sendfile)
|
||||
{
|
||||
n = sendfile (fdt, fdf, NULL, m);
|
||||
n = copy_file_range (fdf, NULL, fdt, NULL, max_bytes, 0u);
|
||||
if (n < 0)
|
||||
{
|
||||
if (errno != EINVAL && errno != ENOSYS)
|
||||
if (errno == ENOSYS)
|
||||
{
|
||||
/* No cfr in kernel, mark as permanently unavailable
|
||||
* and fall through to sendfile().
|
||||
*/
|
||||
have_cfr = 0;
|
||||
try_cfr = false;
|
||||
}
|
||||
else if (errno == EXDEV)
|
||||
/* We won't try cfr again for this run, but let's be
|
||||
* conservative and not mark it as available/unavailable until
|
||||
* we know for sure.
|
||||
*/
|
||||
try_cfr = false;
|
||||
else
|
||||
return -1;
|
||||
|
||||
try_sendfile = false;
|
||||
/* use fallback below */
|
||||
}
|
||||
else if (n == 0) /* EOF */
|
||||
break;
|
||||
else if (n > 0)
|
||||
/* Succcess! */
|
||||
goto next;
|
||||
else
|
||||
{
|
||||
/* cfr worked, mark it as available */
|
||||
if (have_cfr == -1)
|
||||
have_cfr = 1;
|
||||
|
||||
if (n == 0) /* EOF */
|
||||
break;
|
||||
else
|
||||
/* Success! */
|
||||
goto next;
|
||||
}
|
||||
}
|
||||
|
||||
/* Next try sendfile(); this version is also changed from systemd upstream
|
||||
* to match the same logic we have for copy_file_range().
|
||||
*/
|
||||
if (try_sendfile)
|
||||
{
|
||||
n = sendfile (fdt, fdf, NULL, max_bytes);
|
||||
if (n < 0)
|
||||
{
|
||||
if (G_IN_SET (errno, EINVAL, ENOSYS))
|
||||
{
|
||||
/* No sendfile(), or it doesn't work on regular files.
|
||||
* Mark it as permanently unavailable, and fall through
|
||||
* to plain read()/write().
|
||||
*/
|
||||
have_sendfile = 0;
|
||||
try_sendfile = false;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* sendfile() worked, mark it as available */
|
||||
if (have_sendfile == -1)
|
||||
have_sendfile = 1;
|
||||
|
||||
if (n == 0) /* EOF */
|
||||
break;
|
||||
else if (n > 0)
|
||||
/* Succcess! */
|
||||
goto next;
|
||||
}
|
||||
}
|
||||
|
||||
/* As a fallback just copy bits by hand */
|
||||
{ char buf[m];
|
||||
{ size_t m = COPY_BUFFER_SIZE;
|
||||
if (max_bytes != (off_t) -1)
|
||||
{
|
||||
if ((off_t) m > max_bytes)
|
||||
m = (size_t) max_bytes;
|
||||
}
|
||||
char buf[m];
|
||||
|
||||
n = read (fdf, buf, m);
|
||||
n = TEMP_FAILURE_RETRY (read (fdf, buf, m));
|
||||
if (n < 0)
|
||||
return -1;
|
||||
if (n == 0) /* EOF */
|
||||
@@ -776,7 +838,7 @@ glnx_regfile_copy_bytes (int fdf, int fdt, off_t max_bytes, gboolean try_reflink
|
||||
next:
|
||||
if (max_bytes != (off_t) -1)
|
||||
{
|
||||
g_assert(max_bytes >= n);
|
||||
g_assert_cmpint (max_bytes, >=, n);
|
||||
max_bytes -= n;
|
||||
if (max_bytes == 0)
|
||||
break;
|
||||
@@ -867,7 +929,7 @@ glnx_file_copy_at (int src_dfd,
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = glnx_regfile_copy_bytes (src_fd, dest_fd, (off_t) -1, TRUE);
|
||||
r = glnx_regfile_copy_bytes (src_fd, dest_fd, (off_t) -1);
|
||||
if (r < 0)
|
||||
{
|
||||
glnx_set_error_from_errno (error);
|
||||
|
||||
+1
-1
@@ -170,7 +170,7 @@ int
|
||||
glnx_loop_write (int fd, const void *buf, size_t nbytes);
|
||||
|
||||
int
|
||||
glnx_regfile_copy_bytes (int fdf, int fdt, off_t max_bytes, gboolean try_reflink);
|
||||
glnx_regfile_copy_bytes (int fdf, int fdt, off_t max_bytes);
|
||||
|
||||
typedef enum {
|
||||
GLNX_FILE_COPY_OVERWRITE = (1 << 0),
|
||||
|
||||
+10
-160
@@ -25,30 +25,6 @@
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GLNX_DEFINE_CLEANUP_FUNCTION(Type, name, func) \
|
||||
static inline void name (void *v) \
|
||||
{ \
|
||||
func (*(Type*)v); \
|
||||
}
|
||||
|
||||
#define GLNX_DEFINE_CLEANUP_FUNCTION0(Type, name, func) \
|
||||
static inline void name (void *v) \
|
||||
{ \
|
||||
if (*(Type*)v) \
|
||||
func (*(Type*)v); \
|
||||
}
|
||||
|
||||
/**
|
||||
* glnx_free:
|
||||
*
|
||||
* Call g_free() on a variable location when it goes out of scope.
|
||||
*/
|
||||
#define glnx_free __attribute__ ((cleanup(glnx_local_free)))
|
||||
#ifdef GLNX_GSYSTEM_COMPAT
|
||||
#define gs_free __attribute__ ((cleanup(glnx_local_free)))
|
||||
#endif
|
||||
GLNX_DEFINE_CLEANUP_FUNCTION(void*, glnx_local_free, g_free)
|
||||
|
||||
/**
|
||||
* glnx_unref_object:
|
||||
*
|
||||
@@ -57,141 +33,14 @@ GLNX_DEFINE_CLEANUP_FUNCTION(void*, glnx_local_free, g_free)
|
||||
* %NULL.
|
||||
*/
|
||||
#define glnx_unref_object __attribute__ ((cleanup(glnx_local_obj_unref)))
|
||||
#ifdef GLNX_GSYSTEM_COMPAT
|
||||
#define gs_unref_object __attribute__ ((cleanup(glnx_local_obj_unref)))
|
||||
#endif
|
||||
GLNX_DEFINE_CLEANUP_FUNCTION0(GObject*, glnx_local_obj_unref, g_object_unref)
|
||||
|
||||
/**
|
||||
* glnx_unref_variant:
|
||||
*
|
||||
* Call g_variant_unref() on a variable location when it goes out of
|
||||
* scope. Note that unlike g_variant_unref(), the variable may be
|
||||
* %NULL.
|
||||
*/
|
||||
#define glnx_unref_variant __attribute__ ((cleanup(glnx_local_variant_unref)))
|
||||
#ifdef GLNX_GSYSTEM_COMPAT
|
||||
#define gs_unref_variant __attribute__ ((cleanup(glnx_local_variant_unref)))
|
||||
#endif
|
||||
GLNX_DEFINE_CLEANUP_FUNCTION0(GVariant*, glnx_local_variant_unref, g_variant_unref)
|
||||
|
||||
/**
|
||||
* glnx_free_variant_iter:
|
||||
*
|
||||
* Call g_variant_iter_free() on a variable location when it goes out of
|
||||
* scope.
|
||||
*/
|
||||
#define glnx_free_variant_iter __attribute__ ((cleanup(glnx_local_variant_iter_free)))
|
||||
GLNX_DEFINE_CLEANUP_FUNCTION0(GVariantIter*, glnx_local_variant_iter_free, g_variant_iter_free)
|
||||
|
||||
/**
|
||||
* glnx_free_variant_builder:
|
||||
*
|
||||
* Call g_variant_builder_unref() on a variable location when it goes out of
|
||||
* scope.
|
||||
*/
|
||||
#define glnx_unref_variant_builder __attribute__ ((cleanup(glnx_local_variant_builder_unref)))
|
||||
GLNX_DEFINE_CLEANUP_FUNCTION0(GVariantBuilder*, glnx_local_variant_builder_unref, g_variant_builder_unref)
|
||||
|
||||
/**
|
||||
* glnx_unref_array:
|
||||
*
|
||||
* Call g_array_unref() on a variable location when it goes out of
|
||||
* scope. Note that unlike g_array_unref(), the variable may be
|
||||
* %NULL.
|
||||
|
||||
*/
|
||||
#define glnx_unref_array __attribute__ ((cleanup(glnx_local_array_unref)))
|
||||
GLNX_DEFINE_CLEANUP_FUNCTION0(GArray*, glnx_local_array_unref, g_array_unref)
|
||||
|
||||
/**
|
||||
* glnx_unref_ptrarray:
|
||||
*
|
||||
* Call g_ptr_array_unref() on a variable location when it goes out of
|
||||
* scope. Note that unlike g_ptr_array_unref(), the variable may be
|
||||
* %NULL.
|
||||
|
||||
*/
|
||||
#define glnx_unref_ptrarray __attribute__ ((cleanup(glnx_local_ptrarray_unref)))
|
||||
#ifdef GLNX_GSYSTEM_COMPAT
|
||||
#define gs_unref_ptrarray __attribute__ ((cleanup(glnx_local_ptrarray_unref)))
|
||||
#endif
|
||||
GLNX_DEFINE_CLEANUP_FUNCTION0(GPtrArray*, glnx_local_ptrarray_unref, g_ptr_array_unref)
|
||||
|
||||
/**
|
||||
* glnx_unref_hashtable:
|
||||
*
|
||||
* Call g_hash_table_unref() on a variable location when it goes out
|
||||
* of scope. Note that unlike g_hash_table_unref(), the variable may
|
||||
* be %NULL.
|
||||
*/
|
||||
#define glnx_unref_hashtable __attribute__ ((cleanup(glnx_local_hashtable_unref)))
|
||||
#ifdef GLNX_GSYSTEM_COMPAT
|
||||
#define gs_unref_hashtable __attribute__ ((cleanup(glnx_local_hashtable_unref)))
|
||||
#endif
|
||||
GLNX_DEFINE_CLEANUP_FUNCTION0(GHashTable*, glnx_local_hashtable_unref, g_hash_table_unref)
|
||||
|
||||
/**
|
||||
* glnx_free_list:
|
||||
*
|
||||
* Call g_list_free() on a variable location when it goes out
|
||||
* of scope.
|
||||
*/
|
||||
#define glnx_free_list __attribute__ ((cleanup(glnx_local_free_list)))
|
||||
GLNX_DEFINE_CLEANUP_FUNCTION(GList*, glnx_local_free_list, g_list_free)
|
||||
|
||||
/**
|
||||
* glnx_free_slist:
|
||||
*
|
||||
* Call g_slist_free() on a variable location when it goes out
|
||||
* of scope.
|
||||
*/
|
||||
#define glnx_free_slist __attribute__ ((cleanup(glnx_local_free_slist)))
|
||||
GLNX_DEFINE_CLEANUP_FUNCTION(GSList*, glnx_local_free_slist, g_slist_free)
|
||||
|
||||
/**
|
||||
* glnx_free_checksum:
|
||||
*
|
||||
* Call g_checksum_free() on a variable location when it goes out
|
||||
* of scope. Note that unlike g_checksum_free(), the variable may
|
||||
* be %NULL.
|
||||
*/
|
||||
#define glnx_free_checksum __attribute__ ((cleanup(glnx_local_checksum_free)))
|
||||
GLNX_DEFINE_CLEANUP_FUNCTION0(GChecksum*, glnx_local_checksum_free, g_checksum_free)
|
||||
|
||||
/**
|
||||
* glnx_unref_bytes:
|
||||
*
|
||||
* Call g_bytes_unref() on a variable location when it goes out
|
||||
* of scope. Note that unlike g_bytes_unref(), the variable may
|
||||
* be %NULL.
|
||||
*/
|
||||
#define glnx_unref_bytes __attribute__ ((cleanup(glnx_local_bytes_unref)))
|
||||
GLNX_DEFINE_CLEANUP_FUNCTION0(GBytes*, glnx_local_bytes_unref, g_bytes_unref)
|
||||
|
||||
/**
|
||||
* glnx_strfreev:
|
||||
*
|
||||
* Call g_strfreev() on a variable location when it goes out of scope.
|
||||
*/
|
||||
#define glnx_strfreev __attribute__ ((cleanup(glnx_local_strfreev)))
|
||||
GLNX_DEFINE_CLEANUP_FUNCTION(char**, glnx_local_strfreev, g_strfreev)
|
||||
|
||||
/**
|
||||
* glnx_free_error:
|
||||
*
|
||||
* Call g_error_free() on a variable location when it goes out of scope.
|
||||
*/
|
||||
#define glnx_free_error __attribute__ ((cleanup(glnx_local_free_error)))
|
||||
GLNX_DEFINE_CLEANUP_FUNCTION0(GError*, glnx_local_free_error, g_error_free)
|
||||
|
||||
/**
|
||||
* glnx_unref_keyfile:
|
||||
*
|
||||
* Call g_key_file_unref() on a variable location when it goes out of scope.
|
||||
*/
|
||||
#define glnx_unref_keyfile __attribute__ ((cleanup(glnx_local_keyfile_unref)))
|
||||
GLNX_DEFINE_CLEANUP_FUNCTION0(GKeyFile*, glnx_local_keyfile_unref, g_key_file_unref)
|
||||
static inline void
|
||||
glnx_local_obj_unref (void *v)
|
||||
{
|
||||
GObject *o = *(GObject **)v;
|
||||
if (o)
|
||||
g_object_unref (o);
|
||||
}
|
||||
#define glnx_unref_object __attribute__ ((cleanup(glnx_local_obj_unref)))
|
||||
|
||||
static inline void
|
||||
glnx_cleanup_close_fdp (int *fdp)
|
||||
@@ -204,7 +53,8 @@ glnx_cleanup_close_fdp (int *fdp)
|
||||
if (fd >= 0)
|
||||
{
|
||||
errsv = errno;
|
||||
(void) close (fd);
|
||||
if (close (fd) < 0)
|
||||
g_assert (errno != EBADF);
|
||||
errno = errsv;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,3 +52,44 @@ static inline int renameat2(int oldfd, const char *oldname, int newfd, const cha
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Copied from systemd git:
|
||||
commit 6bda23dd6aaba50cf8e3e6024248cf736cc443ca
|
||||
Author: Yu Watanabe <watanabe.yu+github@gmail.com>
|
||||
AuthorDate: Thu Jul 27 20:22:54 2017 +0900
|
||||
Commit: Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
|
||||
CommitDate: Thu Jul 27 07:22:54 2017 -0400
|
||||
*/
|
||||
#if !HAVE_DECL_COPY_FILE_RANGE
|
||||
# ifndef __NR_copy_file_range
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_copy_file_range 326
|
||||
# elif defined(__i386__)
|
||||
# define __NR_copy_file_range 377
|
||||
# elif defined __s390__
|
||||
# define __NR_copy_file_range 375
|
||||
# elif defined __arm__
|
||||
# define __NR_copy_file_range 391
|
||||
# elif defined __aarch64__
|
||||
# define __NR_copy_file_range 285
|
||||
# elif defined __powerpc__
|
||||
# define __NR_copy_file_range 379
|
||||
# elif defined __arc__
|
||||
# define __NR_copy_file_range 285
|
||||
# else
|
||||
# warning "__NR_copy_file_range not defined for your architecture"
|
||||
# endif
|
||||
# endif
|
||||
|
||||
static inline ssize_t copy_file_range(int fd_in, loff_t *off_in,
|
||||
int fd_out, loff_t *off_out,
|
||||
size_t len,
|
||||
unsigned int flags) {
|
||||
# ifdef __NR_copy_file_range
|
||||
return syscall(__NR_copy_file_range, fd_in, off_in, fd_out, off_out, len, flags);
|
||||
# else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
@@ -145,8 +145,8 @@ get_xattrs_impl (const char *path,
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
ssize_t bytes_read, real_size;
|
||||
glnx_free char *xattr_names = NULL;
|
||||
glnx_free char *xattr_names_canonical = NULL;
|
||||
g_autofree char *xattr_names = NULL;
|
||||
g_autofree char *xattr_names_canonical = NULL;
|
||||
GVariantBuilder builder;
|
||||
gboolean builder_initialized = FALSE;
|
||||
g_autoptr(GVariant) ret_xattrs = NULL;
|
||||
|
||||
Reference in new issue
Block a user