diff options
author | Philip Withnall <philip@tecnocode.co.uk> | 2021-03-29 16:47:58 +0000 |
---|---|---|
committer | Philip Withnall <philip@tecnocode.co.uk> | 2021-03-29 16:47:58 +0000 |
commit | 622b31f69e72fdb05b813820e9cd8087e88a47bf (patch) | |
tree | ef52df4c42f9921c3de796277a0336731bff8bae | |
parent | e42aff259223af6213ccb91b1453d2363f782a22 (diff) | |
parent | 1bdfc1a36baa463942973db8b1ea7be572d6745d (diff) | |
download | glib-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.txt | 4 | ||||
-rw-r--r-- | gio/gfileinfo.c | 160 | ||||
-rw-r--r-- | gio/gfileinfo.h | 10 | ||||
-rw-r--r-- | gio/tests/g-file-info.c | 149 |
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 |