Skip to content
Commits on Source (20)
Overview of changes in GLib 2.68.3
==================================
* Bugs fixed:
- #2311 testfilemonitor test leaks ip_watched_file_t struct
- #2417 GFile: `g_file_replace_contents()` reports `G_IO_ERROR_WRONG_ETAG` when saving from a symlink
- !2133 Backport !2128 “inotify: Fix a memory leak” to glib-2-68
- !2137 Backport !2136 “tlscertificate: Avoid possible invalid read” to glib-2-68
- !2141 Backport !2138 “glocalfileoutputstream: Fix ETag check when replacing through a symlink” to glib-2-68
Overview of changes in GLib 2.68.2
==================================
* Fix building third-party projects against GLib on CentOS 7 (work by
Ignacio Casal Quinteiro) (#2387)
* Bugs fixed:
- #2387 json-glib does not build with glib 2.68.1
- !2060 gmacros: check that __cplusplus or _MSC_VER is defined
- !2068 gmacros: missing check if __STDC_VERSION__ is defined
- !2079 Backport !2078 “gthreadedresolver: don't ignore flags in lookup_by_name_with_flags” to glib-2-68
* Translation updates:
- Nepali
- Serbian
Overview of changes in GLib 2.68.1
==================================
......
......@@ -975,7 +975,36 @@ handle_overwrite_open (const char *filename,
if (etag != NULL)
{
current_etag = _g_local_file_info_create_etag (&original_stat);
GLocalFileStat etag_stat;
GLocalFileStat *etag_stat_pointer;
/* The ETag is calculated on the details of the target file, for symlinks,
* so we might need to stat() again. */
if (is_symlink)
{
res = g_local_file_stat (filename,
G_LOCAL_FILE_STAT_FIELD_MTIME,
G_LOCAL_FILE_STAT_FIELD_ALL, &etag_stat);
errsv = errno;
if (res != 0)
{
char *display_name = g_filename_display_name (filename);
g_set_error (error, G_IO_ERROR,
g_io_error_from_errno (errsv),
_("Error when getting information for file “%s”: %s"),
display_name, g_strerror (errsv));
g_free (display_name);
goto error;
}
etag_stat_pointer = &etag_stat;
}
else
etag_stat_pointer = &original_stat;
/* Compare the ETags */
current_etag = _g_local_file_info_create_etag (etag_stat_pointer);
if (strcmp (etag, current_etag) != 0)
{
g_set_error_literal (error,
......
......@@ -226,7 +226,7 @@ lookup_by_name_with_flags (GResolver *resolver,
GList *addresses;
LookupData *data;
data = lookup_data_new (hostname, AF_UNSPEC);
data = lookup_data_new (hostname, flags_to_family (flags));
task = g_task_new (resolver, cancellable, NULL, NULL);
g_task_set_source_tag (task, lookup_by_name_with_flags);
g_task_set_name (task, "[gio] resolver lookup");
......
......@@ -286,6 +286,7 @@ parse_private_key (const gchar *data,
GError **error)
{
const gchar *header_start = NULL, *header_end, *footer_start = NULL, *footer_end;
const gchar *data_end = data + data_len;
header_end = g_strstr_len (data, data_len, PEM_PRIVKEY_HEADER_END);
if (header_end)
......@@ -322,7 +323,7 @@ parse_private_key (const gchar *data,
footer_end += strlen (PEM_PRIVKEY_FOOTER_END);
while (*footer_end == '\r' || *footer_end == '\n')
while ((footer_end < data_end) && (*footer_end == '\r' || *footer_end == '\n'))
footer_end++;
return g_strndup (header_start, footer_end - header_start);
......@@ -356,7 +357,7 @@ parse_next_pem_certificate (const gchar **data,
return NULL;
}
end += strlen (PEM_CERTIFICATE_FOOTER);
while (*end == '\r' || *end == '\n')
while ((end < data_end) && (*end == '\r' || *end == '\n'))
end++;
*data = end;
......@@ -388,7 +389,7 @@ parse_and_create_certificate_list (const gchar *data,
/* If we read one certificate successfully, let's see if we can read
* some more. If not, we will simply return a list with the first one.
*/
while (p && *p)
while (p < end && p && *p)
{
gchar *cert_pem;
GError *error = NULL;
......
......@@ -208,6 +208,7 @@ ip_watched_file_free (ip_watched_file_t *file)
g_assert (file->subs == NULL);
g_free (file->filename);
g_free (file->path);
g_free (file);
}
static void
......
......@@ -932,6 +932,125 @@ test_replace_symlink (void)
#endif
}
static void
test_replace_symlink_using_etag (void)
{
#ifdef G_OS_UNIX
gchar *tmpdir_path = NULL;
GFile *tmpdir = NULL, *source_file = NULL, *target_file = NULL;
GFileOutputStream *stream = NULL;
const gchar *old_contents = "this is a test message which should be written to target and then overwritten";
gchar *old_etag = NULL;
const gchar *new_contents = "this is an updated message";
gsize n_written;
gchar *contents = NULL;
gsize length = 0;
GFileInfo *info = NULL;
GError *local_error = NULL;
g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/2417");
g_test_summary ("Test that ETag checks work when replacing a file through a symlink");
/* Create a fresh, empty working directory. */
tmpdir_path = g_dir_make_tmp ("g_file_replace_symlink_using_etag_XXXXXX", &local_error);
g_assert_no_error (local_error);
tmpdir = g_file_new_for_path (tmpdir_path);
g_test_message ("Using temporary directory %s", tmpdir_path);
g_free (tmpdir_path);
/* Create symlink `source` which points to `target`. */
source_file = g_file_get_child (tmpdir, "source");
target_file = g_file_get_child (tmpdir, "target");
g_file_make_symbolic_link (source_file, "target", NULL, &local_error);
g_assert_no_error (local_error);
/* Sleep for at least 1s to ensure the mtimes of `source` and `target` differ,
* as that’s what _g_local_file_info_create_etag() uses to create the ETag,
* and one failure mode we’re testing for is that the ETags of `source` and
* `target` are conflated. */
sleep (1);
/* Create `target` with some arbitrary content. */
stream = g_file_create (target_file, G_FILE_CREATE_NONE, NULL, &local_error);
g_assert_no_error (local_error);
g_output_stream_write_all (G_OUTPUT_STREAM (stream), old_contents, strlen (old_contents),
&n_written, NULL, &local_error);
g_assert_no_error (local_error);
g_assert_cmpint (n_written, ==, strlen (old_contents));
g_output_stream_close (G_OUTPUT_STREAM (stream), NULL, &local_error);
g_assert_no_error (local_error);
old_etag = g_file_output_stream_get_etag (stream);
g_assert_nonnull (old_etag);
g_assert_cmpstr (old_etag, !=, "");
g_clear_object (&stream);
/* Sleep again to ensure the ETag changes again. */
sleep (1);
/* Write out a new copy of the `target`, checking its ETag first. This should
* replace `target` by following the symlink. */
stream = g_file_replace (source_file, old_etag, FALSE /* no backup */,
G_FILE_CREATE_NONE, NULL, &local_error);
g_assert_no_error (local_error);
g_output_stream_write_all (G_OUTPUT_STREAM (stream), new_contents, strlen (new_contents),
&n_written, NULL, &local_error);
g_assert_no_error (local_error);
g_assert_cmpint (n_written, ==, strlen (new_contents));
g_output_stream_close (G_OUTPUT_STREAM (stream), NULL, &local_error);
g_assert_no_error (local_error);
g_clear_object (&stream);
/* At this point, there should be a regular file, `target`, containing
* @new_contents; and a symlink `source` which points to `target`. */
g_assert_cmpint (g_file_query_file_type (source_file, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL), ==, G_FILE_TYPE_SYMBOLIC_LINK);
g_assert_cmpint (g_file_query_file_type (target_file, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL), ==, G_FILE_TYPE_REGULAR);
/* Check the content of `target`. */
g_file_load_contents (target_file,
NULL,
&contents,
&length,
NULL,
&local_error);
g_assert_no_error (local_error);
g_assert_cmpstr (contents, ==, new_contents);
g_assert_cmpuint (length, ==, strlen (new_contents));
g_free (contents);
/* And check its ETag value has changed. */
info = g_file_query_info (target_file, G_FILE_ATTRIBUTE_ETAG_VALUE,
G_FILE_QUERY_INFO_NONE, NULL, &local_error);
g_assert_no_error (local_error);
g_assert_cmpstr (g_file_info_get_etag (info), !=, old_etag);
g_clear_object (&info);
g_free (old_etag);
/* Tidy up. */
g_file_delete (target_file, NULL, &local_error);
g_assert_no_error (local_error);
g_file_delete (source_file, NULL, &local_error);
g_assert_no_error (local_error);
g_file_delete (tmpdir, NULL, &local_error);
g_assert_no_error (local_error);
g_clear_object (&target_file);
g_clear_object (&source_file);
g_clear_object (&tmpdir);
#else /* if !G_OS_UNIX */
g_test_skip ("Symlink replacement tests can only be run on Unix")
#endif
}
/* FIXME: These tests have only been checked on Linux. Most of them are probably
* applicable on Windows, too, but that has not been tested yet.
* See https://gitlab.gnome.org/GNOME/glib/-/issues/2325 */
......@@ -2906,6 +3025,7 @@ main (int argc, char *argv[])
g_test_add_func ("/file/replace-load", test_replace_load);
g_test_add_func ("/file/replace-cancel", test_replace_cancel);
g_test_add_func ("/file/replace-symlink", test_replace_symlink);
g_test_add_func ("/file/replace-symlink/using-etag", test_replace_symlink_using_etag);
g_test_add_data_func ("/file/replace/write-only", GUINT_TO_POINTER (FALSE), test_replace);
g_test_add_data_func ("/file/replace/read-write", GUINT_TO_POINTER (TRUE), test_replace);
g_test_add_func ("/file/async-delete", test_async_delete);
......
......@@ -4,8 +4,6 @@
#include <stdlib.h>
#include <gio/gio.h>
#include "glib/glib-private.h"
/* These tests were written for the inotify implementation.
* Other implementations may require slight adjustments in
* the tests, e.g. the length of timeouts
......@@ -956,11 +954,6 @@ static void
test_file_hard_links (Fixture *fixture,
gconstpointer user_data)
{
#ifdef _GLIB_ADDRESS_SANITIZER
g_test_incomplete ("FIXME: Leaks an inotify data structure, see glib#2311");
(void) file_hard_links_output;
(void) file_hard_links_step;
#else
GError *error = NULL;
TestData data;
......@@ -1011,7 +1004,6 @@ test_file_hard_links (Fixture *fixture,
g_object_unref (data.monitor);
g_object_unref (data.file);
g_object_unref (data.output_stream);
#endif
}
int
......
......@@ -200,6 +200,38 @@ pem_parser_handles_chain (const Reference *ref)
g_object_unref (original_cert);
}
static void
pem_parser_no_sentinel (void)
{
GTlsCertificate *cert;
gchar *pem;
gsize pem_len = 0;
gchar *pem_copy;
GError *error = NULL;
/* Check certificate from not-nul-terminated PEM */
g_file_get_contents (g_test_get_filename (G_TEST_DIST, "cert-tests", "cert1.pem", NULL), &pem, &pem_len, &error);
g_assert_no_error (error);
g_assert_nonnull (pem);
g_assert_cmpuint (pem_len, >=, 10);
pem_copy = g_new (char, pem_len);
/* Do not copy the terminating nul: */
memmove (pem_copy, pem, pem_len);
g_free (pem);
/* Check whether the parser respects the @length parameter.
* pem_copy is allocated exactly pem_len bytes, so accessing memory
* outside its bounds will be detected by, for example, valgrind or
* asan. */
cert = g_tls_certificate_new_from_pem (pem_copy, pem_len, &error);
g_assert_no_error (error);
g_assert_nonnull (cert);
g_free (pem_copy);
g_object_unref (cert);
}
static void
from_file (const Reference *ref)
{
......@@ -500,6 +532,8 @@ main (int argc,
from_pkcs11_uri);
g_test_add_func ("/tls-certificate/pkcs11-uri-unsupported",
from_unsupported_pkcs11_uri);
g_test_add_func ("/tls-certificate/pem-parser-no-sentinel",
pem_parser_no_sentinel);
rtv = g_test_run();
......
......@@ -960,14 +960,14 @@
/* For compatibility with G_NORETURN_FUNCPTR on clang, use
__attribute__((__noreturn__)), not _Noreturn. */
# define G_NORETURN __attribute__ ((__noreturn__))
#elif 1200 <= _MSC_VER
#elif defined (_MSC_VER) && (1200 <= _MSC_VER)
/* Use MSVC specific syntax. */
# define G_NORETURN __declspec (noreturn)
/* Use ISO C++11 syntax when the compiler supports it. */
#elif (__cplusplus >= 201103 && !(__GNUC__ == 4 && __GNUC_MINOR__ == 7)) || (_MSC_VER >= 1900)
#elif (defined (__cplusplus) && __cplusplus >= 201103 && !(__GNUC__ == 4 && __GNUC_MINOR__ == 7)) || defined (_MSC_VER) && (_MSC_VER >= 1900)
# define G_NORETURN [[noreturn]]
/* Use ISO C11 syntax when the compiler supports it. */
#elif __STDC_VERSION__ >= 201112 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)
#elif (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)
# define G_NORETURN _Noreturn
#else
# define G_NORETURN /* empty */
......
project('glib', 'c', 'cpp',
version : '2.68.1',
version : '2.68.3',
# NOTE: We keep this pinned at 0.49 because that's what Debian 10 ships
meson_version : '>= 0.49.2',
default_options : [
......
This diff is collapsed.
This diff is collapsed.