summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Withnall <philip@tecnocode.co.uk>2021-03-29 16:47:58 +0000
committerPhilip Withnall <philip@tecnocode.co.uk>2021-03-29 16:47:58 +0000
commit622b31f69e72fdb05b813820e9cd8087e88a47bf (patch)
treeef52df4c42f9921c3de796277a0336731bff8bae
parente42aff259223af6213ccb91b1453d2363f782a22 (diff)
parent1bdfc1a36baa463942973db8b1ea7be572d6745d (diff)
downloadglib-622b31f69e72fdb05b813820e9cd8087e88a47bf.tar.gz
Merge branch 'fixing_2281' into 'master'
Update GFileInfo to use GDateTime as timestamps Closes #2281 See merge request GNOME/glib!2017
-rw-r--r--docs/reference/gio/gio-sections-common.txt4
-rw-r--r--gio/gfileinfo.c160
-rw-r--r--gio/gfileinfo.h10
-rw-r--r--gio/tests/g-file-info.c149
4 files changed, 323 insertions, 0 deletions
diff --git a/docs/reference/gio/gio-sections-common.txt b/docs/reference/gio/gio-sections-common.txt
index 945c26ade..e38971c12 100644
--- a/docs/reference/gio/gio-sections-common.txt
+++ b/docs/reference/gio/gio-sections-common.txt
@@ -397,6 +397,8 @@ g_file_info_get_content_type
g_file_info_get_size
g_file_info_get_modification_time
g_file_info_get_modification_date_time
+g_file_info_get_access_date_time
+g_file_info_get_creation_date_time
g_file_info_get_symlink_target
g_file_info_get_etag
g_file_info_get_sort_order
@@ -415,6 +417,8 @@ g_file_info_set_content_type
g_file_info_set_size
g_file_info_set_modification_time
g_file_info_set_modification_date_time
+g_file_info_set_access_date_time
+g_file_info_set_creation_date_time
g_file_info_set_symlink_target
g_file_info_set_sort_order
g_file_attribute_matcher_new
diff --git a/gio/gfileinfo.c b/gio/gfileinfo.c
index 2a97758b2..cec1b4e56 100644
--- a/gio/gfileinfo.c
+++ b/gio/gfileinfo.c
@@ -1835,6 +1835,96 @@ g_file_info_get_modification_date_time (GFileInfo *info)
}
/**
+ * g_file_info_get_access_date_time:
+ * @info: a #GFileInfo.
+ *
+ * Gets the access time of the current @info and returns it as a
+ * #GDateTime.
+ *
+ * This requires the %G_FILE_ATTRIBUTE_TIME_ACCESS attribute. If
+ * %G_FILE_ATTRIBUTE_TIME_ACCESS_USEC is provided, the resulting #GDateTime
+ * will have microsecond precision.
+ *
+ * Returns: (transfer full) (nullable): access time, or %NULL if unknown
+ * Since: 2.70
+ */
+GDateTime *
+g_file_info_get_access_date_time (GFileInfo *info)
+{
+ static guint32 attr_atime = 0, attr_atime_usec;
+ GFileAttributeValue *value, *value_usec;
+ GDateTime *dt = NULL, *dt2 = NULL;
+
+ g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
+
+ if (attr_atime == 0)
+ {
+ attr_atime = lookup_attribute (G_FILE_ATTRIBUTE_TIME_ACCESS);
+ attr_atime_usec = lookup_attribute (G_FILE_ATTRIBUTE_TIME_ACCESS_USEC);
+ }
+
+ value = g_file_info_find_value (info, attr_atime);
+ if (value == NULL)
+ return NULL;
+
+ dt = g_date_time_new_from_unix_utc (_g_file_attribute_value_get_uint64 (value));
+
+ value_usec = g_file_info_find_value (info, attr_atime_usec);
+ if (value_usec == NULL)
+ return g_steal_pointer (&dt);
+
+ dt2 = g_date_time_add (dt, _g_file_attribute_value_get_uint32 (value_usec));
+ g_date_time_unref (dt);
+
+ return g_steal_pointer (&dt2);
+}
+
+/**
+ * g_file_info_get_creation_date_time:
+ * @info: a #GFileInfo.
+ *
+ * Gets the creation time of the current @info and returns it as a
+ * #GDateTime.
+ *
+ * This requires the %G_FILE_ATTRIBUTE_TIME_CREATED attribute. If
+ * %G_FILE_ATTRIBUTE_TIME_CREATED_USEC is provided, the resulting #GDateTime
+ * will have microsecond precision.
+ *
+ * Returns: (transfer full) (nullable): creation time, or %NULL if unknown
+ * Since: 2.70
+ */
+GDateTime *
+g_file_info_get_creation_date_time (GFileInfo *info)
+{
+ static guint32 attr_ctime = 0, attr_ctime_usec;
+ GFileAttributeValue *value, *value_usec;
+ GDateTime *dt = NULL, *dt2 = NULL;
+
+ g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
+
+ if (attr_ctime == 0)
+ {
+ attr_ctime = lookup_attribute (G_FILE_ATTRIBUTE_TIME_CREATED);
+ attr_ctime_usec = lookup_attribute (G_FILE_ATTRIBUTE_TIME_CREATED_USEC);
+ }
+
+ value = g_file_info_find_value (info, attr_ctime);
+ if (value == NULL)
+ return NULL;
+
+ dt = g_date_time_new_from_unix_utc (_g_file_attribute_value_get_uint64 (value));
+
+ value_usec = g_file_info_find_value (info, attr_ctime_usec);
+ if (value_usec == NULL)
+ return g_steal_pointer (&dt);
+
+ dt2 = g_date_time_add (dt, _g_file_attribute_value_get_uint32 (value_usec));
+ g_date_time_unref (dt);
+
+ return g_steal_pointer (&dt2);
+}
+
+/**
* g_file_info_get_symlink_target:
* @info: a #GFileInfo.
*
@@ -2238,6 +2328,76 @@ g_file_info_set_modification_date_time (GFileInfo *info,
}
/**
+ * g_file_info_set_access_date_time:
+ * @info: a #GFileInfo.
+ * @atime: (not nullable): a #GDateTime.
+ *
+ * Sets the %G_FILE_ATTRIBUTE_TIME_ACCESS and
+ * %G_FILE_ATTRIBUTE_TIME_ACCESS_USEC attributes in the file info to the
+ * given date/time value.
+ *
+ * Since: 2.70
+ */
+void
+g_file_info_set_access_date_time (GFileInfo *info,
+ GDateTime *atime)
+{
+ static guint32 attr_atime = 0, attr_atime_usec;
+ GFileAttributeValue *value;
+
+ g_return_if_fail (G_IS_FILE_INFO (info));
+ g_return_if_fail (atime != NULL);
+
+ if (attr_atime == 0)
+ {
+ attr_atime = lookup_attribute (G_FILE_ATTRIBUTE_TIME_ACCESS);
+ attr_atime_usec = lookup_attribute (G_FILE_ATTRIBUTE_TIME_ACCESS_USEC);
+ }
+
+ value = g_file_info_create_value (info, attr_atime);
+ if (value)
+ _g_file_attribute_value_set_uint64 (value, g_date_time_to_unix (atime));
+ value = g_file_info_create_value (info, attr_atime_usec);
+ if (value)
+ _g_file_attribute_value_set_uint32 (value, g_date_time_get_microsecond (atime));
+}
+
+/**
+ * g_file_info_set_creation_date_time:
+ * @info: a #GFileInfo.
+ * @creation_time: (not nullable): a #GDateTime.
+ *
+ * Sets the %G_FILE_ATTRIBUTE_TIME_CREATED and
+ * %G_FILE_ATTRIBUTE_TIME_CREATED_USEC attributes in the file info to the
+ * given date/time value.
+ *
+ * Since: 2.70
+ */
+void
+g_file_info_set_creation_date_time (GFileInfo *info,
+ GDateTime *creation_time)
+{
+ static guint32 attr_ctime = 0, attr_ctime_usec;
+ GFileAttributeValue *value;
+
+ g_return_if_fail (G_IS_FILE_INFO (info));
+ g_return_if_fail (creation_time != NULL);
+
+ if (attr_ctime == 0)
+ {
+ attr_ctime = lookup_attribute (G_FILE_ATTRIBUTE_TIME_CREATED);
+ attr_ctime_usec = lookup_attribute (G_FILE_ATTRIBUTE_TIME_CREATED_USEC);
+ }
+
+ value = g_file_info_create_value (info, attr_ctime);
+ if (value)
+ _g_file_attribute_value_set_uint64 (value, g_date_time_to_unix (creation_time));
+ value = g_file_info_create_value (info, attr_ctime_usec);
+ if (value)
+ _g_file_attribute_value_set_uint32 (value, g_date_time_get_microsecond (creation_time));
+}
+
+/**
* g_file_info_set_symlink_target:
* @info: a #GFileInfo.
* @symlink_target: a static string containing a path to a symlink target.
diff --git a/gio/gfileinfo.h b/gio/gfileinfo.h
index da202e6a7..4f736e487 100644
--- a/gio/gfileinfo.h
+++ b/gio/gfileinfo.h
@@ -1057,6 +1057,10 @@ void g_file_info_get_modification_time (GFileInfo *info,
G_GNUC_END_IGNORE_DEPRECATIONS
GLIB_AVAILABLE_IN_2_62
GDateTime * g_file_info_get_modification_date_time (GFileInfo *info);
+GLIB_AVAILABLE_IN_2_70
+GDateTime * g_file_info_get_access_date_time (GFileInfo *info);
+GLIB_AVAILABLE_IN_2_70
+GDateTime * g_file_info_get_creation_date_time (GFileInfo *info);
GLIB_AVAILABLE_IN_ALL
const char * g_file_info_get_symlink_target (GFileInfo *info);
GLIB_AVAILABLE_IN_ALL
@@ -1109,6 +1113,12 @@ G_GNUC_END_IGNORE_DEPRECATIONS
GLIB_AVAILABLE_IN_2_62
void g_file_info_set_modification_date_time (GFileInfo *info,
GDateTime *mtime);
+GLIB_AVAILABLE_IN_2_70
+void g_file_info_set_access_date_time (GFileInfo *info,
+ GDateTime *atime);
+GLIB_AVAILABLE_IN_2_70
+void g_file_info_set_creation_date_time (GFileInfo *info,
+ GDateTime *creation_time);
GLIB_AVAILABLE_IN_ALL
void g_file_info_set_symlink_target (GFileInfo *info,
const char *symlink_target);
diff --git a/gio/tests/g-file-info.c b/gio/tests/g-file-info.c
index 1a02b5e0e..c11c50462 100644
--- a/gio/tests/g-file-info.c
+++ b/gio/tests/g-file-info.c
@@ -201,6 +201,153 @@ test_g_file_info_modification_time (void)
g_date_time_unref (dt_new_usecs);
}
+static void
+test_g_file_info_access_time (void)
+{
+ GFile *file = NULL;
+ GFileIOStream *io_stream = NULL;
+ GFileInfo *info = NULL;
+ GDateTime *dt = NULL, *dt_usecs = NULL, *dt_new = NULL, *dt_new_usecs = NULL,
+ *dt_before_epoch = NULL, *dt_before_epoch_returned = NULL;
+ GTimeSpan ts;
+ GError *error = NULL;
+
+ g_test_summary ("Test that getting the access time of a file works.");
+
+ file = g_file_new_tmp ("g-file-info-test-XXXXXX", &io_stream, &error);
+ g_assert_no_error (error);
+
+ info = g_file_query_info (file,
+ G_FILE_ATTRIBUTE_TIME_ACCESS,
+ G_FILE_QUERY_INFO_NONE,
+ NULL, &error);
+ g_assert_no_error (error);
+
+ /* Check the access time is retrievable. */
+ dt = g_file_info_get_access_date_time (info);
+ g_assert_nonnull (dt);
+
+ /* Try again with microsecond precision. */
+ g_clear_object (&info);
+ info = g_file_query_info (file,
+ G_FILE_ATTRIBUTE_TIME_ACCESS "," G_FILE_ATTRIBUTE_TIME_ACCESS_USEC,
+ G_FILE_QUERY_INFO_NONE,
+ NULL, &error);
+ g_assert_no_error (error);
+
+ dt_usecs = g_file_info_get_access_date_time (info);
+ g_assert_nonnull (dt_usecs);
+
+ ts = g_date_time_difference (dt_usecs, dt);
+ g_assert_cmpint (ts, >, 0);
+ g_assert_cmpint (ts, <, G_USEC_PER_SEC);
+
+ /* Try round-tripping the access time. */
+ dt_new = g_date_time_add (dt_usecs, G_USEC_PER_SEC + 50);
+ g_file_info_set_access_date_time (info, dt_new);
+
+ dt_new_usecs = g_file_info_get_access_date_time (info);
+ ts = g_date_time_difference (dt_new_usecs, dt_new);
+ g_assert_cmpint (ts, ==, 0);
+
+ // try with a negative timestamp
+ dt_before_epoch = g_date_time_new_from_unix_utc (-10000);
+ g_file_info_set_access_date_time (info, dt_before_epoch);
+ dt_before_epoch_returned = g_file_info_get_access_date_time (info);
+ ts = g_date_time_difference (dt_before_epoch, dt_before_epoch_returned);
+ g_assert_cmpint (ts, ==, 0);
+
+ /* Clean up. */
+ g_clear_object (&io_stream);
+ g_file_delete (file, NULL, NULL);
+ g_clear_object (&file);
+
+ g_clear_object (&info);
+ g_date_time_unref (dt);
+ g_date_time_unref (dt_usecs);
+ g_date_time_unref (dt_new);
+ g_date_time_unref (dt_new_usecs);
+ g_date_time_unref (dt_before_epoch);
+ g_date_time_unref (dt_before_epoch_returned);
+}
+
+static void
+test_g_file_info_creation_time (void)
+{
+ GFile *file = NULL;
+ GFileIOStream *io_stream = NULL;
+ GFileInfo *info = NULL;
+ GDateTime *dt = NULL, *dt_usecs = NULL, *dt_new = NULL, *dt_new_usecs = NULL,
+ *dt_before_epoch = NULL, *dt_before_epoch_returned = NULL;
+ GTimeSpan ts;
+ GError *error = NULL;
+
+ g_test_summary ("Test that getting the creation time of a file works.");
+
+ file = g_file_new_tmp ("g-file-info-test-XXXXXX", &io_stream, &error);
+ g_assert_no_error (error);
+
+ info = g_file_query_info (file,
+ G_FILE_ATTRIBUTE_TIME_CREATED,
+ G_FILE_QUERY_INFO_NONE,
+ NULL, &error);
+ g_assert_no_error (error);
+
+ /* Check the creation time is retrievable. */
+ dt = g_file_info_get_creation_date_time (info);
+ if (!dt)
+ {
+ g_test_skip ("Skipping testing creation time as it’s not supported by the kernel");
+ g_file_delete (file, NULL, NULL);
+ g_clear_object (&file);
+ g_clear_object (&info);
+ return;
+ }
+
+ /* Try again with microsecond precision. */
+ g_clear_object (&info);
+ info = g_file_query_info (file,
+ G_FILE_ATTRIBUTE_TIME_CREATED "," G_FILE_ATTRIBUTE_TIME_CREATED_USEC,
+ G_FILE_QUERY_INFO_NONE,
+ NULL, &error);
+ g_assert_no_error (error);
+
+ dt_usecs = g_file_info_get_creation_date_time (info);
+ g_assert_nonnull (dt_usecs);
+
+ ts = g_date_time_difference (dt_usecs, dt);
+ g_assert_cmpint (ts, >, 0);
+ g_assert_cmpint (ts, <, G_USEC_PER_SEC);
+
+ /* Try round-tripping the creation time. */
+ dt_new = g_date_time_add (dt_usecs, G_USEC_PER_SEC + 50);
+ g_file_info_set_creation_date_time (info, dt_new);
+
+ dt_new_usecs = g_file_info_get_creation_date_time (info);
+ ts = g_date_time_difference (dt_new_usecs, dt_new);
+ g_assert_cmpint (ts, ==, 0);
+
+ // try with a negative timestamp
+ dt_before_epoch = g_date_time_new_from_unix_utc (-10000);
+ g_file_info_set_creation_date_time (info, dt_before_epoch);
+ dt_before_epoch_returned = g_file_info_get_creation_date_time (info);
+ ts = g_date_time_difference (dt_before_epoch, dt_before_epoch_returned);
+ g_assert_cmpint (ts, ==, 0);
+
+ /* Clean up. */
+ g_clear_object (&io_stream);
+ g_file_delete (file, NULL, NULL);
+ g_clear_object (&file);
+
+ g_clear_object (&info);
+ g_date_time_unref (dt);
+ g_date_time_unref (dt_usecs);
+ g_date_time_unref (dt_new);
+ g_date_time_unref (dt_new_usecs);
+ g_date_time_unref (dt_before_epoch);
+ g_date_time_unref (dt_before_epoch_returned);
+}
+
#ifdef G_OS_WIN32
static void
test_internal_enhanced_stdio (void)
@@ -746,6 +893,8 @@ main (int argc,
g_test_add_func ("/g-file-info/test_g_file_info", test_g_file_info);
g_test_add_func ("/g-file-info/test_g_file_info/modification-time", test_g_file_info_modification_time);
+ g_test_add_func ("/g-file-info/test_g_file_info/access-time", test_g_file_info_access_time);
+ g_test_add_func ("/g-file-info/test_g_file_info/creation-time", test_g_file_info_creation_time);
#ifdef G_OS_WIN32
g_test_add_func ("/g-file-info/internal-enhanced-stdio", test_internal_enhanced_stdio);
#endif