Add functionality to preserve nanosecond timestamps

file copy doesn't preserve nanosecond timestamps

Closes #369
This commit is contained in:
nitinosiris 2021-07-02 18:40:44 +05:30 committed by Philip Withnall
parent 7ad6b05458
commit b33ef610de
9 changed files with 252 additions and 25 deletions

View File

@ -314,12 +314,16 @@ G_FILE_ATTRIBUTE_MOUNTABLE_CAN_POLL
G_FILE_ATTRIBUTE_MOUNTABLE_IS_MEDIA_CHECK_AUTOMATIC G_FILE_ATTRIBUTE_MOUNTABLE_IS_MEDIA_CHECK_AUTOMATIC
G_FILE_ATTRIBUTE_TIME_MODIFIED G_FILE_ATTRIBUTE_TIME_MODIFIED
G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC
G_FILE_ATTRIBUTE_TIME_MODIFIED_NSEC
G_FILE_ATTRIBUTE_TIME_ACCESS G_FILE_ATTRIBUTE_TIME_ACCESS
G_FILE_ATTRIBUTE_TIME_ACCESS_USEC G_FILE_ATTRIBUTE_TIME_ACCESS_USEC
G_FILE_ATTRIBUTE_TIME_ACCESS_NSEC
G_FILE_ATTRIBUTE_TIME_CHANGED G_FILE_ATTRIBUTE_TIME_CHANGED
G_FILE_ATTRIBUTE_TIME_CHANGED_USEC G_FILE_ATTRIBUTE_TIME_CHANGED_USEC
G_FILE_ATTRIBUTE_TIME_CHANGED_NSEC
G_FILE_ATTRIBUTE_TIME_CREATED G_FILE_ATTRIBUTE_TIME_CREATED
G_FILE_ATTRIBUTE_TIME_CREATED_USEC G_FILE_ATTRIBUTE_TIME_CREATED_USEC
G_FILE_ATTRIBUTE_TIME_CREATED_NSEC
G_FILE_ATTRIBUTE_UNIX_DEVICE G_FILE_ATTRIBUTE_UNIX_DEVICE
G_FILE_ATTRIBUTE_UNIX_INODE G_FILE_ATTRIBUTE_UNIX_INODE
G_FILE_ATTRIBUTE_UNIX_MODE G_FILE_ATTRIBUTE_UNIX_MODE

View File

@ -75,6 +75,10 @@
#define G_FILE_ATTRIBUTE_ID_TIME_CHANGED_USEC (6291456 + 6) #define G_FILE_ATTRIBUTE_ID_TIME_CHANGED_USEC (6291456 + 6)
#define G_FILE_ATTRIBUTE_ID_TIME_CREATED (6291456 + 7) #define G_FILE_ATTRIBUTE_ID_TIME_CREATED (6291456 + 7)
#define G_FILE_ATTRIBUTE_ID_TIME_CREATED_USEC (6291456 + 8) #define G_FILE_ATTRIBUTE_ID_TIME_CREATED_USEC (6291456 + 8)
#define G_FILE_ATTRIBUTE_ID_TIME_MODIFIED_NSEC (6291456 + 9)
#define G_FILE_ATTRIBUTE_ID_TIME_ACCESS_NSEC (6291456 + 10)
#define G_FILE_ATTRIBUTE_ID_TIME_CREATED_NSEC (6291456 + 11)
#define G_FILE_ATTRIBUTE_ID_TIME_CHANGED_NSEC (6291456 + 12)
#define G_FILE_ATTRIBUTE_ID_UNIX_DEVICE (7340032 + 1) #define G_FILE_ATTRIBUTE_ID_UNIX_DEVICE (7340032 + 1)
#define G_FILE_ATTRIBUTE_ID_UNIX_INODE (7340032 + 2) #define G_FILE_ATTRIBUTE_ID_UNIX_INODE (7340032 + 2)
#define G_FILE_ATTRIBUTE_ID_UNIX_MODE (7340032 + 3) #define G_FILE_ATTRIBUTE_ID_UNIX_MODE (7340032 + 3)

View File

@ -241,6 +241,10 @@ ensure_attribute_hash (void)
REGISTER_ATTRIBUTE (TIME_CHANGED_USEC); REGISTER_ATTRIBUTE (TIME_CHANGED_USEC);
REGISTER_ATTRIBUTE (TIME_CREATED); REGISTER_ATTRIBUTE (TIME_CREATED);
REGISTER_ATTRIBUTE (TIME_CREATED_USEC); REGISTER_ATTRIBUTE (TIME_CREATED_USEC);
REGISTER_ATTRIBUTE (TIME_MODIFIED_NSEC);
REGISTER_ATTRIBUTE (TIME_ACCESS_NSEC);
REGISTER_ATTRIBUTE (TIME_CREATED_NSEC);
REGISTER_ATTRIBUTE (TIME_CHANGED_NSEC);
REGISTER_ATTRIBUTE (UNIX_DEVICE); REGISTER_ATTRIBUTE (UNIX_DEVICE);
REGISTER_ATTRIBUTE (UNIX_INODE); REGISTER_ATTRIBUTE (UNIX_INODE);
REGISTER_ATTRIBUTE (UNIX_MODE); REGISTER_ATTRIBUTE (UNIX_MODE);
@ -1820,6 +1824,9 @@ G_GNUC_END_IGNORE_DEPRECATIONS
* %G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC is provided, the resulting #GDateTime * %G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC is provided, the resulting #GDateTime
* will have microsecond precision. * will have microsecond precision.
* *
* If nanosecond precision is needed, %G_FILE_ATTRIBUTE_TIME_MODIFIED_NSEC must
* be queried separately using g_file_info_get_attribute_uint32().
*
* Returns: (transfer full) (nullable): modification time, or %NULL if unknown * Returns: (transfer full) (nullable): modification time, or %NULL if unknown
* Since: 2.62 * Since: 2.62
*/ */
@ -1865,6 +1872,9 @@ g_file_info_get_modification_date_time (GFileInfo *info)
* %G_FILE_ATTRIBUTE_TIME_ACCESS_USEC is provided, the resulting #GDateTime * %G_FILE_ATTRIBUTE_TIME_ACCESS_USEC is provided, the resulting #GDateTime
* will have microsecond precision. * will have microsecond precision.
* *
* If nanosecond precision is needed, %G_FILE_ATTRIBUTE_TIME_ACCESS_NSEC must
* be queried separately using g_file_info_get_attribute_uint32().
*
* Returns: (transfer full) (nullable): access time, or %NULL if unknown * Returns: (transfer full) (nullable): access time, or %NULL if unknown
* Since: 2.70 * Since: 2.70
*/ */
@ -1910,6 +1920,9 @@ g_file_info_get_access_date_time (GFileInfo *info)
* %G_FILE_ATTRIBUTE_TIME_CREATED_USEC is provided, the resulting #GDateTime * %G_FILE_ATTRIBUTE_TIME_CREATED_USEC is provided, the resulting #GDateTime
* will have microsecond precision. * will have microsecond precision.
* *
* If nanosecond precision is needed, %G_FILE_ATTRIBUTE_TIME_CREATED_NSEC must
* be queried separately using g_file_info_get_attribute_uint32().
*
* Returns: (transfer full) (nullable): creation time, or %NULL if unknown * Returns: (transfer full) (nullable): creation time, or %NULL if unknown
* Since: 2.70 * Since: 2.70
*/ */
@ -2283,6 +2296,8 @@ g_file_info_set_size (GFileInfo *info,
* %G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC attributes in the file info to the * %G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC attributes in the file info to the
* given time value. * given time value.
* *
* %G_FILE_ATTRIBUTE_TIME_MODIFIED_NSEC will be cleared.
*
* Deprecated: 2.62: Use g_file_info_set_modification_date_time() instead, as * Deprecated: 2.62: Use g_file_info_set_modification_date_time() instead, as
* #GTimeVal is deprecated due to the year 2038 problem. * #GTimeVal is deprecated due to the year 2038 problem.
**/ **/
@ -2291,7 +2306,7 @@ void
g_file_info_set_modification_time (GFileInfo *info, g_file_info_set_modification_time (GFileInfo *info,
GTimeVal *mtime) GTimeVal *mtime)
{ {
static guint32 attr_mtime = 0, attr_mtime_usec; static guint32 attr_mtime = 0, attr_mtime_usec = 0, attr_mtime_nsec = 0;
GFileAttributeValue *value; GFileAttributeValue *value;
g_return_if_fail (G_IS_FILE_INFO (info)); g_return_if_fail (G_IS_FILE_INFO (info));
@ -2301,6 +2316,7 @@ g_file_info_set_modification_time (GFileInfo *info,
{ {
attr_mtime = lookup_attribute (G_FILE_ATTRIBUTE_TIME_MODIFIED); attr_mtime = lookup_attribute (G_FILE_ATTRIBUTE_TIME_MODIFIED);
attr_mtime_usec = lookup_attribute (G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC); attr_mtime_usec = lookup_attribute (G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC);
attr_mtime_nsec = lookup_attribute (G_FILE_ATTRIBUTE_TIME_MODIFIED_NSEC);
} }
value = g_file_info_create_value (info, attr_mtime); value = g_file_info_create_value (info, attr_mtime);
@ -2309,6 +2325,9 @@ g_file_info_set_modification_time (GFileInfo *info,
value = g_file_info_create_value (info, attr_mtime_usec); value = g_file_info_create_value (info, attr_mtime_usec);
if (value) if (value)
_g_file_attribute_value_set_uint32 (value, mtime->tv_usec); _g_file_attribute_value_set_uint32 (value, mtime->tv_usec);
/* nsecs cant be known from a #GTimeVal, so remove them */
g_file_info_remove_value (info, attr_mtime_nsec);
} }
G_GNUC_END_IGNORE_DEPRECATIONS G_GNUC_END_IGNORE_DEPRECATIONS
@ -2321,13 +2340,15 @@ G_GNUC_END_IGNORE_DEPRECATIONS
* %G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC attributes in the file info to the * %G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC attributes in the file info to the
* given date/time value. * given date/time value.
* *
* %G_FILE_ATTRIBUTE_TIME_MODIFIED_NSEC will be cleared.
*
* Since: 2.62 * Since: 2.62
*/ */
void void
g_file_info_set_modification_date_time (GFileInfo *info, g_file_info_set_modification_date_time (GFileInfo *info,
GDateTime *mtime) GDateTime *mtime)
{ {
static guint32 attr_mtime = 0, attr_mtime_usec; static guint32 attr_mtime = 0, attr_mtime_usec = 0, attr_mtime_nsec = 0;
GFileAttributeValue *value; GFileAttributeValue *value;
g_return_if_fail (G_IS_FILE_INFO (info)); g_return_if_fail (G_IS_FILE_INFO (info));
@ -2337,6 +2358,7 @@ g_file_info_set_modification_date_time (GFileInfo *info,
{ {
attr_mtime = lookup_attribute (G_FILE_ATTRIBUTE_TIME_MODIFIED); attr_mtime = lookup_attribute (G_FILE_ATTRIBUTE_TIME_MODIFIED);
attr_mtime_usec = lookup_attribute (G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC); attr_mtime_usec = lookup_attribute (G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC);
attr_mtime_nsec = lookup_attribute (G_FILE_ATTRIBUTE_TIME_MODIFIED_NSEC);
} }
value = g_file_info_create_value (info, attr_mtime); value = g_file_info_create_value (info, attr_mtime);
@ -2345,6 +2367,9 @@ g_file_info_set_modification_date_time (GFileInfo *info,
value = g_file_info_create_value (info, attr_mtime_usec); value = g_file_info_create_value (info, attr_mtime_usec);
if (value) if (value)
_g_file_attribute_value_set_uint32 (value, g_date_time_get_microsecond (mtime)); _g_file_attribute_value_set_uint32 (value, g_date_time_get_microsecond (mtime));
/* nsecs cant be known from a #GDateTime, so remove them */
g_file_info_remove_value (info, attr_mtime_nsec);
} }
/** /**
@ -2356,13 +2381,15 @@ g_file_info_set_modification_date_time (GFileInfo *info,
* %G_FILE_ATTRIBUTE_TIME_ACCESS_USEC attributes in the file info to the * %G_FILE_ATTRIBUTE_TIME_ACCESS_USEC attributes in the file info to the
* given date/time value. * given date/time value.
* *
* %G_FILE_ATTRIBUTE_TIME_ACCESS_NSEC will be cleared.
*
* Since: 2.70 * Since: 2.70
*/ */
void void
g_file_info_set_access_date_time (GFileInfo *info, g_file_info_set_access_date_time (GFileInfo *info,
GDateTime *atime) GDateTime *atime)
{ {
static guint32 attr_atime = 0, attr_atime_usec; static guint32 attr_atime = 0, attr_atime_usec = 0, attr_atime_nsec = 0;
GFileAttributeValue *value; GFileAttributeValue *value;
g_return_if_fail (G_IS_FILE_INFO (info)); g_return_if_fail (G_IS_FILE_INFO (info));
@ -2372,6 +2399,7 @@ g_file_info_set_access_date_time (GFileInfo *info,
{ {
attr_atime = lookup_attribute (G_FILE_ATTRIBUTE_TIME_ACCESS); attr_atime = lookup_attribute (G_FILE_ATTRIBUTE_TIME_ACCESS);
attr_atime_usec = lookup_attribute (G_FILE_ATTRIBUTE_TIME_ACCESS_USEC); attr_atime_usec = lookup_attribute (G_FILE_ATTRIBUTE_TIME_ACCESS_USEC);
attr_atime_nsec = lookup_attribute (G_FILE_ATTRIBUTE_TIME_ACCESS_NSEC);
} }
value = g_file_info_create_value (info, attr_atime); value = g_file_info_create_value (info, attr_atime);
@ -2380,6 +2408,9 @@ g_file_info_set_access_date_time (GFileInfo *info,
value = g_file_info_create_value (info, attr_atime_usec); value = g_file_info_create_value (info, attr_atime_usec);
if (value) if (value)
_g_file_attribute_value_set_uint32 (value, g_date_time_get_microsecond (atime)); _g_file_attribute_value_set_uint32 (value, g_date_time_get_microsecond (atime));
/* nsecs cant be known from a #GDateTime, so remove them */
g_file_info_remove_value (info, attr_atime_nsec);
} }
/** /**
@ -2391,13 +2422,15 @@ g_file_info_set_access_date_time (GFileInfo *info,
* %G_FILE_ATTRIBUTE_TIME_CREATED_USEC attributes in the file info to the * %G_FILE_ATTRIBUTE_TIME_CREATED_USEC attributes in the file info to the
* given date/time value. * given date/time value.
* *
* %G_FILE_ATTRIBUTE_TIME_CREATED_NSEC will be cleared.
*
* Since: 2.70 * Since: 2.70
*/ */
void void
g_file_info_set_creation_date_time (GFileInfo *info, g_file_info_set_creation_date_time (GFileInfo *info,
GDateTime *creation_time) GDateTime *creation_time)
{ {
static guint32 attr_ctime = 0, attr_ctime_usec; static guint32 attr_ctime = 0, attr_ctime_usec = 0, attr_ctime_nsec = 0;
GFileAttributeValue *value; GFileAttributeValue *value;
g_return_if_fail (G_IS_FILE_INFO (info)); g_return_if_fail (G_IS_FILE_INFO (info));
@ -2407,6 +2440,7 @@ g_file_info_set_creation_date_time (GFileInfo *info,
{ {
attr_ctime = lookup_attribute (G_FILE_ATTRIBUTE_TIME_CREATED); attr_ctime = lookup_attribute (G_FILE_ATTRIBUTE_TIME_CREATED);
attr_ctime_usec = lookup_attribute (G_FILE_ATTRIBUTE_TIME_CREATED_USEC); attr_ctime_usec = lookup_attribute (G_FILE_ATTRIBUTE_TIME_CREATED_USEC);
attr_ctime_nsec = lookup_attribute (G_FILE_ATTRIBUTE_TIME_CREATED_NSEC);
} }
value = g_file_info_create_value (info, attr_ctime); value = g_file_info_create_value (info, attr_ctime);
@ -2415,6 +2449,9 @@ g_file_info_set_creation_date_time (GFileInfo *info,
value = g_file_info_create_value (info, attr_ctime_usec); value = g_file_info_create_value (info, attr_ctime_usec);
if (value) if (value)
_g_file_attribute_value_set_uint32 (value, g_date_time_get_microsecond (creation_time)); _g_file_attribute_value_set_uint32 (value, g_date_time_get_microsecond (creation_time));
/* nsecs cant be known from a #GDateTime, so remove them */
g_file_info_remove_value (info, attr_ctime_nsec);
} }
/** /**

View File

@ -562,6 +562,18 @@ typedef struct _GFileInfoClass GFileInfoClass;
**/ **/
#define G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC "time::modified-usec" /* uint32 */ #define G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC "time::modified-usec" /* uint32 */
/**
* G_FILE_ATTRIBUTE_TIME_MODIFIED_NSEC:
*
* A key in the "time" namespace for getting the nanoseconds of the time
* the file was last modified. This should be used in conjunction with
* #G_FILE_ATTRIBUTE_TIME_MODIFIED. Corresponding #GFileAttributeType is
* %G_FILE_ATTRIBUTE_TYPE_UINT32.
*
* Since: 2.74
**/
#define G_FILE_ATTRIBUTE_TIME_MODIFIED_NSEC "time::modified-nsec" /* uint32 */
/** /**
* G_FILE_ATTRIBUTE_TIME_ACCESS: * G_FILE_ATTRIBUTE_TIME_ACCESS:
* *
@ -586,6 +598,18 @@ typedef struct _GFileInfoClass GFileInfoClass;
**/ **/
#define G_FILE_ATTRIBUTE_TIME_ACCESS_USEC "time::access-usec" /* uint32 */ #define G_FILE_ATTRIBUTE_TIME_ACCESS_USEC "time::access-usec" /* uint32 */
/**
* G_FILE_ATTRIBUTE_TIME_ACCESS_NSEC:
*
* A key in the "time" namespace for getting the nanoseconds of the time
* the file was last accessed. This should be used in conjunction with
* #G_FILE_ATTRIBUTE_TIME_ACCESS. Corresponding #GFileAttributeType is
* %G_FILE_ATTRIBUTE_TYPE_UINT32.
*
* Since: 2.74
**/
#define G_FILE_ATTRIBUTE_TIME_ACCESS_NSEC "time::access-nsec" /* uint32 */
/** /**
* G_FILE_ATTRIBUTE_TIME_CHANGED: * G_FILE_ATTRIBUTE_TIME_CHANGED:
* *
@ -612,6 +636,18 @@ typedef struct _GFileInfoClass GFileInfoClass;
**/ **/
#define G_FILE_ATTRIBUTE_TIME_CHANGED_USEC "time::changed-usec" /* uint32 */ #define G_FILE_ATTRIBUTE_TIME_CHANGED_USEC "time::changed-usec" /* uint32 */
/**
* G_FILE_ATTRIBUTE_TIME_CHANGED_NSEC:
*
* A key in the "time" namespace for getting the nanoseconds of the time
* the file was last changed. This should be used in conjunction with
* #G_FILE_ATTRIBUTE_TIME_CHANGED. Corresponding #GFileAttributeType is
* %G_FILE_ATTRIBUTE_TYPE_UINT32.
*
* Since: 2.74
**/
#define G_FILE_ATTRIBUTE_TIME_CHANGED_NSEC "time::changed-nsec" /* uint32 */
/** /**
* G_FILE_ATTRIBUTE_TIME_CREATED: * G_FILE_ATTRIBUTE_TIME_CREATED:
* *
@ -638,6 +674,18 @@ typedef struct _GFileInfoClass GFileInfoClass;
**/ **/
#define G_FILE_ATTRIBUTE_TIME_CREATED_USEC "time::created-usec" /* uint32 */ #define G_FILE_ATTRIBUTE_TIME_CREATED_USEC "time::created-usec" /* uint32 */
/**
* G_FILE_ATTRIBUTE_TIME_CREATED_NSEC:
*
* A key in the "time" namespace for getting the nanoseconds of the time
* the file was created. This should be used in conjunction with
* #G_FILE_ATTRIBUTE_TIME_CREATED. Corresponding #GFileAttributeType is
* %G_FILE_ATTRIBUTE_TYPE_UINT32.
*
* Since: 2.74
**/
#define G_FILE_ATTRIBUTE_TIME_CREATED_NSEC "time::created-nsec" /* uint32 */
/* Unix specific attributes */ /* Unix specific attributes */
/** /**

View File

@ -168,7 +168,7 @@ g_local_file_class_init (GLocalFileClass *klass)
0); 0);
#endif #endif
#ifdef HAVE_UTIMES #if defined(HAVE_UTIMES) || defined(HAVE_UTIMENSAT)
g_file_attribute_info_list_add (list, g_file_attribute_info_list_add (list,
G_FILE_ATTRIBUTE_TIME_MODIFIED, G_FILE_ATTRIBUTE_TIME_MODIFIED,
G_FILE_ATTRIBUTE_TYPE_UINT64, G_FILE_ATTRIBUTE_TYPE_UINT64,
@ -190,6 +190,18 @@ g_local_file_class_init (GLocalFileClass *klass)
G_FILE_ATTRIBUTE_TIME_ACCESS_USEC, G_FILE_ATTRIBUTE_TIME_ACCESS_USEC,
G_FILE_ATTRIBUTE_TYPE_UINT32, G_FILE_ATTRIBUTE_TYPE_UINT32,
G_FILE_ATTRIBUTE_INFO_COPY_WHEN_MOVED); G_FILE_ATTRIBUTE_INFO_COPY_WHEN_MOVED);
#endif /* HAVE_UTIMES || HAVE_UTIMENSAT */
#ifdef HAVE_UTIMENSAT
g_file_attribute_info_list_add (list,
G_FILE_ATTRIBUTE_TIME_MODIFIED_NSEC,
G_FILE_ATTRIBUTE_TYPE_UINT32,
G_FILE_ATTRIBUTE_INFO_COPY_WITH_FILE |
G_FILE_ATTRIBUTE_INFO_COPY_WHEN_MOVED);
g_file_attribute_info_list_add (list,
G_FILE_ATTRIBUTE_TIME_ACCESS_NSEC,
G_FILE_ATTRIBUTE_TYPE_UINT32,
G_FILE_ATTRIBUTE_INFO_COPY_WHEN_MOVED);
#endif #endif
local_writable_attributes = list; local_writable_attributes = list;

View File

@ -123,25 +123,29 @@ static GHashTable *gid_cache = NULL;
char * char *
_g_local_file_info_create_etag (GLocalFileStat *statbuf) _g_local_file_info_create_etag (GLocalFileStat *statbuf)
{ {
glong sec, usec; glong sec, usec, nsec;
g_return_val_if_fail (_g_stat_has_field (statbuf, G_LOCAL_FILE_STAT_FIELD_MTIME), NULL); g_return_val_if_fail (_g_stat_has_field (statbuf, G_LOCAL_FILE_STAT_FIELD_MTIME), NULL);
#if defined (G_OS_WIN32) #if defined (G_OS_WIN32)
sec = statbuf->st_mtim.tv_sec; sec = statbuf->st_mtim.tv_sec;
usec = statbuf->st_mtim.tv_nsec / 1000; usec = statbuf->st_mtim.tv_nsec / 1000;
nsec = statbuf->st_mtim.tv_nsec;
#else #else
sec = _g_stat_mtime (statbuf); sec = _g_stat_mtime (statbuf);
#if defined (HAVE_STRUCT_STAT_ST_MTIMENSEC) #if defined (HAVE_STRUCT_STAT_ST_MTIMENSEC)
usec = statbuf->st_mtimensec / 1000; usec = statbuf->st_mtimensec / 1000;
nsec = statbuf->st_mtimensec;
#elif defined (HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC) #elif defined (HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC)
usec = _g_stat_mtim_nsec (statbuf) / 1000; usec = _g_stat_mtim_nsec (statbuf) / 1000;
nsec = _g_stat_mtim_nsec (statbuf);
#else #else
usec = 0; usec = 0;
nsec = 0;
#endif #endif
#endif #endif
return g_strdup_printf ("%lu:%lu", sec, usec); return g_strdup_printf ("%lu:%lu:%lu", sec, usec, nsec);
} }
static char * static char *
@ -1018,14 +1022,18 @@ set_info_from_stat (GFileInfo *info,
#if defined (G_OS_WIN32) #if defined (G_OS_WIN32)
_g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_MODIFIED, statbuf->st_mtim.tv_sec); _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_MODIFIED, statbuf->st_mtim.tv_sec);
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_MODIFIED_USEC, statbuf->st_mtim.tv_nsec / 1000); _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_MODIFIED_USEC, statbuf->st_mtim.tv_nsec / 1000);
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_MODIFIED_NSEC, statbuf->st_mtim.tv_nsec);
_g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_ACCESS, statbuf->st_atim.tv_sec); _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_ACCESS, statbuf->st_atim.tv_sec);
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_ACCESS_USEC, statbuf->st_atim.tv_nsec / 1000); _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_ACCESS_USEC, statbuf->st_atim.tv_nsec / 1000);
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_ACCESS_NSEC, statbuf->st_atim.tv_nsec);
#else #else
_g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_MODIFIED, _g_stat_mtime (statbuf)); _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_MODIFIED, _g_stat_mtime (statbuf));
#if defined (HAVE_STRUCT_STAT_ST_MTIMENSEC) #if defined (HAVE_STRUCT_STAT_ST_MTIMENSEC)
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_MODIFIED_USEC, statbuf->st_mtimensec / 1000); _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_MODIFIED_USEC, statbuf->st_mtimensec / 1000);
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_MODIFIED_NSEC, statbuf->st_mtimensec);
#elif defined (HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC) #elif defined (HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC)
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_MODIFIED_USEC, _g_stat_mtim_nsec (statbuf) / 1000); _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_MODIFIED_USEC, _g_stat_mtim_nsec (statbuf) / 1000);
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_MODIFIED_NSEC, _g_stat_mtim_nsec (statbuf));
#endif #endif
if (_g_stat_has_field (statbuf, G_LOCAL_FILE_STAT_FIELD_ATIME)) if (_g_stat_has_field (statbuf, G_LOCAL_FILE_STAT_FIELD_ATIME))
@ -1033,8 +1041,10 @@ set_info_from_stat (GFileInfo *info,
_g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_ACCESS, _g_stat_atime (statbuf)); _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_ACCESS, _g_stat_atime (statbuf));
#if defined (HAVE_STRUCT_STAT_ST_ATIMENSEC) #if defined (HAVE_STRUCT_STAT_ST_ATIMENSEC)
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_ACCESS_USEC, statbuf->st_atimensec / 1000); _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_ACCESS_USEC, statbuf->st_atimensec / 1000);
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_ACCESS_NSEC, statbuf->st_atimensec);
#elif defined (HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC) #elif defined (HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC)
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_ACCESS_USEC, _g_stat_atim_nsec (statbuf) / 1000); _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_ACCESS_USEC, _g_stat_atim_nsec (statbuf) / 1000);
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_ACCESS_NSEC, _g_stat_atim_nsec (statbuf));
#endif #endif
} }
#endif #endif
@ -1048,8 +1058,10 @@ set_info_from_stat (GFileInfo *info,
_g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CHANGED, _g_stat_ctime (statbuf)); _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CHANGED, _g_stat_ctime (statbuf));
#if defined (HAVE_STRUCT_STAT_ST_CTIMENSEC) #if defined (HAVE_STRUCT_STAT_ST_CTIMENSEC)
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CHANGED_USEC, statbuf->st_ctimensec / 1000); _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CHANGED_USEC, statbuf->st_ctimensec / 1000);
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CHANGED_NSEC, statbuf->st_ctimensec);
#elif defined (HAVE_STRUCT_STAT_ST_CTIM_TV_NSEC) #elif defined (HAVE_STRUCT_STAT_ST_CTIM_TV_NSEC)
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CHANGED_USEC, _g_stat_ctim_nsec (statbuf) / 1000); _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CHANGED_USEC, _g_stat_ctim_nsec (statbuf) / 1000);
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CHANGED_NSEC, _g_stat_ctim_nsec (statbuf));
#endif #endif
#endif #endif
@ -1058,13 +1070,16 @@ set_info_from_stat (GFileInfo *info,
{ {
_g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED, statbuf->stx_btime.tv_sec); _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED, statbuf->stx_btime.tv_sec);
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED_USEC, statbuf->stx_btime.tv_nsec / 1000); _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED_USEC, statbuf->stx_btime.tv_nsec / 1000);
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED_NSEC, statbuf->stx_btime.tv_nsec);
} }
#elif defined (HAVE_STRUCT_STAT_ST_BIRTHTIME) && defined (HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC) #elif defined (HAVE_STRUCT_STAT_ST_BIRTHTIME) && defined (HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC)
_g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED, statbuf->st_birthtime); _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED, statbuf->st_birthtime);
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED_USEC, statbuf->st_birthtimensec / 1000); _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED_USEC, statbuf->st_birthtimensec / 1000);
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED_NSEC, statbuf->st_birthtimensec);
#elif defined (HAVE_STRUCT_STAT_ST_BIRTHTIM) && defined (HAVE_STRUCT_STAT_ST_BIRTHTIM_TV_NSEC) #elif defined (HAVE_STRUCT_STAT_ST_BIRTHTIM) && defined (HAVE_STRUCT_STAT_ST_BIRTHTIM_TV_NSEC)
_g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED, statbuf->st_birthtim.tv_sec); _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED, statbuf->st_birthtim.tv_sec);
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED_USEC, statbuf->st_birthtim.tv_nsec / 1000); _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED_USEC, statbuf->st_birthtim.tv_nsec / 1000);
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED_NSEC, statbuf->st_birthtim.tv_nsec);
#elif defined (HAVE_STRUCT_STAT_ST_BIRTHTIME) #elif defined (HAVE_STRUCT_STAT_ST_BIRTHTIME)
_g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED, statbuf->st_birthtime); _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED, statbuf->st_birthtime);
#elif defined (HAVE_STRUCT_STAT_ST_BIRTHTIM) #elif defined (HAVE_STRUCT_STAT_ST_BIRTHTIM)
@ -1072,6 +1087,7 @@ set_info_from_stat (GFileInfo *info,
#elif defined (G_OS_WIN32) #elif defined (G_OS_WIN32)
_g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED, statbuf->st_ctim.tv_sec); _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED, statbuf->st_ctim.tv_sec);
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED_USEC, statbuf->st_ctim.tv_nsec / 1000); _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED_USEC, statbuf->st_ctim.tv_nsec / 1000);
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED_NSEC, statbuf->st_ctim.tv_nsec);
#endif #endif
if (_g_file_attribute_matcher_matches_id (attribute_matcher, if (_g_file_attribute_matcher_matches_id (attribute_matcher,
@ -2185,7 +2201,7 @@ get_uint32 (const GFileAttributeValue *value,
return TRUE; return TRUE;
} }
#if defined (HAVE_UTIMES) || defined (G_OS_WIN32) #if defined (HAVE_UTIMES) || defined (HAVE_UTIMENSAT) || defined (G_OS_WIN32)
static gboolean static gboolean
get_uint64 (const GFileAttributeValue *value, get_uint64 (const GFileAttributeValue *value,
guint64 *val_out, guint64 *val_out,
@ -2505,8 +2521,10 @@ static gboolean
set_mtime_atime (const char *filename, set_mtime_atime (const char *filename,
const GFileAttributeValue *mtime_value, const GFileAttributeValue *mtime_value,
const GFileAttributeValue *mtime_usec_value, const GFileAttributeValue *mtime_usec_value,
const GFileAttributeValue *mtime_nsec_value,
const GFileAttributeValue *atime_value, const GFileAttributeValue *atime_value,
const GFileAttributeValue *atime_usec_value, const GFileAttributeValue *atime_usec_value,
const GFileAttributeValue *atime_nsec_value,
GError **error) GError **error)
{ {
BOOL res; BOOL res;
@ -2528,6 +2546,7 @@ set_mtime_atime (const char *filename,
if (!get_uint64 (atime_value, &val, error)) if (!get_uint64 (atime_value, &val, error))
return FALSE; return FALSE;
val_usec = 0; val_usec = 0;
val_nsec = 0;
if (atime_usec_value && if (atime_usec_value &&
!get_uint32 (atime_usec_value, &val_usec, error)) !get_uint32 (atime_usec_value, &val_usec, error))
return FALSE; return FALSE;
@ -2537,8 +2556,19 @@ set_mtime_atime (const char *filename,
* _g_win32_unix_time_to_filetime() anyway. */ * _g_win32_unix_time_to_filetime() anyway. */
val_nsec = (val_usec > G_MAXINT32 / 1000) ? G_MAXINT32 : (val_usec * 1000); val_nsec = (val_usec > G_MAXINT32 / 1000) ? G_MAXINT32 : (val_usec * 1000);
if (!_g_win32_unix_time_to_filetime (val, val_nsec, &atime, error)) if (atime_nsec_value &&
return FALSE; !get_uint32 (atime_nsec_value, &val_nsec, error))
return FALSE;
if (val_nsec > 0)
{
if (!_g_win32_unix_time_to_filetime (val, val_nsec, &atime, error))
return FALSE;
}
else
{
if (!_g_win32_unix_time_to_filetime (val, val_usec, &atime, error))
return FALSE;
}
p_atime = &atime; p_atime = &atime;
} }
@ -2548,6 +2578,7 @@ set_mtime_atime (const char *filename,
if (!get_uint64 (mtime_value, &val, error)) if (!get_uint64 (mtime_value, &val, error))
return FALSE; return FALSE;
val_usec = 0; val_usec = 0;
val_nsec = 0;
if (mtime_usec_value && if (mtime_usec_value &&
!get_uint32 (mtime_usec_value, &val_usec, error)) !get_uint32 (mtime_usec_value, &val_usec, error))
return FALSE; return FALSE;
@ -2557,8 +2588,19 @@ set_mtime_atime (const char *filename,
* _g_win32_unix_time_to_filetime() anyway. */ * _g_win32_unix_time_to_filetime() anyway. */
val_nsec = (val_usec > G_MAXINT32 / 1000) ? G_MAXINT32 : (val_usec * 1000); val_nsec = (val_usec > G_MAXINT32 / 1000) ? G_MAXINT32 : (val_usec * 1000);
if (!_g_win32_unix_time_to_filetime (val, val_nsec, &mtime, error)) if (mtime_nsec_value &&
return FALSE; !get_uint32 (mtime_nsec_value, &val_nsec, error))
return FALSE;
if (val_nsec > 0)
{
if (!_g_win32_unix_time_to_filetime (val, val_nsec, &mtime, error))
return FALSE;
}
else
{
if (!_g_win32_unix_time_to_filetime (val, val_usec, &mtime, error))
return FALSE;
}
p_mtime = &mtime; p_mtime = &mtime;
} }
@ -2604,7 +2646,7 @@ set_mtime_atime (const char *filename,
return res; return res;
} }
#elif defined (HAVE_UTIMES) #elif defined (HAVE_UTIMES) || defined (HAVE_UTIMENSAT)
static int static int
lazy_stat (char *filename, lazy_stat (char *filename,
struct stat *statbuf, struct stat *statbuf,
@ -2628,23 +2670,31 @@ static gboolean
set_mtime_atime (char *filename, set_mtime_atime (char *filename,
const GFileAttributeValue *mtime_value, const GFileAttributeValue *mtime_value,
const GFileAttributeValue *mtime_usec_value, const GFileAttributeValue *mtime_usec_value,
const GFileAttributeValue *mtime_nsec_value,
const GFileAttributeValue *atime_value, const GFileAttributeValue *atime_value,
const GFileAttributeValue *atime_usec_value, const GFileAttributeValue *atime_usec_value,
const GFileAttributeValue *atime_nsec_value,
GError **error) GError **error)
{ {
int res; int res;
guint64 val = 0; guint64 val = 0;
guint32 val_usec = 0; guint32 val_usec = 0;
guint32 val_nsec = 0;
struct stat statbuf; struct stat statbuf;
gboolean got_stat = FALSE; gboolean got_stat = FALSE;
struct timeval times[2] = { {0, 0}, {0, 0} }; struct timeval times[2] = { {0, 0}, {0, 0} };
#ifdef HAVE_UTIMENSAT
struct timespec times_n[2] = { {0, 0}, {0, 0} };
#endif
/* ATIME */ /* ATIME */
if (atime_value) if (atime_value)
{ {
if (!get_uint64 (atime_value, &val, error)) if (!get_uint64 (atime_value, &val, error))
return FALSE; return FALSE;
times[0].tv_sec = val; times[0].tv_sec = val;
#if defined (HAVE_UTIMENSAT)
times_n[0].tv_sec = val;
#endif
} }
else else
{ {
@ -2653,8 +2703,14 @@ set_mtime_atime (char *filename,
times[0].tv_sec = statbuf.st_atime; times[0].tv_sec = statbuf.st_atime;
#if defined (HAVE_STRUCT_STAT_ST_ATIMENSEC) #if defined (HAVE_STRUCT_STAT_ST_ATIMENSEC)
times[0].tv_usec = statbuf.st_atimensec / 1000; times[0].tv_usec = statbuf.st_atimensec / 1000;
#if defined (HAVE_UTIMENSAT)
times_n[0].tv_nsec = statbuf.st_atimensec;
#endif /* HAVE_UTIMENSAT */
#elif defined (HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC) #elif defined (HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC)
times[0].tv_usec = statbuf.st_atim.tv_nsec / 1000; times[0].tv_usec = statbuf.st_atim.tv_nsec / 1000;
#if defined (HAVE_UTIMENSAT)
times_n[0].tv_nsec = statbuf.st_atim.tv_nsec;
#endif /* HAVE_UTIMENSAT */
#endif #endif
} }
} }
@ -2666,12 +2722,24 @@ set_mtime_atime (char *filename,
times[0].tv_usec = val_usec; times[0].tv_usec = val_usec;
} }
if (atime_nsec_value)
{
if (!get_uint32 (atime_nsec_value, &val_nsec, error))
return FALSE;
#if defined (HAVE_UTIMENSAT)
times_n[0].tv_nsec = val_nsec;
#endif
}
/* MTIME */ /* MTIME */
if (mtime_value) if (mtime_value)
{ {
if (!get_uint64 (mtime_value, &val, error)) if (!get_uint64 (mtime_value, &val, error))
return FALSE; return FALSE;
times[1].tv_sec = val; times[1].tv_sec = val;
#if defined (HAVE_UTIMENSAT)
times_n[1].tv_sec = val;
#endif
} }
else else
{ {
@ -2680,8 +2748,14 @@ set_mtime_atime (char *filename,
times[1].tv_sec = statbuf.st_mtime; times[1].tv_sec = statbuf.st_mtime;
#if defined (HAVE_STRUCT_STAT_ST_MTIMENSEC) #if defined (HAVE_STRUCT_STAT_ST_MTIMENSEC)
times[1].tv_usec = statbuf.st_mtimensec / 1000; times[1].tv_usec = statbuf.st_mtimensec / 1000;
#if defined (HAVE_UTIMENSAT)
times_n[1].tv_nsec = statbuf.st_mtimensec;
#endif /* HAVE_UTIMENSAT */
#elif defined (HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC) #elif defined (HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC)
times[1].tv_usec = statbuf.st_mtim.tv_nsec / 1000; times[1].tv_usec = statbuf.st_mtim.tv_nsec / 1000;
#if defined (HAVE_UTIMENSAT)
times_n[1].tv_nsec = statbuf.st_mtim.tv_nsec;
#endif /* HAVE_UTIMENSAT */
#endif #endif
} }
} }
@ -2692,6 +2766,14 @@ set_mtime_atime (char *filename,
return FALSE; return FALSE;
times[1].tv_usec = val_usec; times[1].tv_usec = val_usec;
} }
if (mtime_nsec_value)
{
if (!get_uint32 (mtime_nsec_value, &val_nsec, error))
return FALSE;
#if defined (HAVE_UTIMENSAT)
times_n[1].tv_nsec = val_nsec;
#endif
}
res = utimes (filename, times); res = utimes (filename, times);
if (res == -1) if (res == -1)
@ -2702,7 +2784,19 @@ set_mtime_atime (char *filename,
g_io_error_from_errno (errsv), g_io_error_from_errno (errsv),
_("Error setting modification or access time: %s"), _("Error setting modification or access time: %s"),
g_strerror (errsv)); g_strerror (errsv));
return FALSE; return FALSE;
}
res = utimensat (AT_FDCWD, filename, times_n, 0);
if (res == -1)
{
int errsv = errno;
g_set_error (error, G_IO_ERROR,
g_io_error_from_errno (errsv),
_("Error setting modification or access time: %s"),
g_strerror (errsv));
return FALSE;
} }
return TRUE; return TRUE;
} }
@ -2780,15 +2874,19 @@ _g_local_file_info_set_attribute (char *filename,
return set_symlink (filename, &value, error); return set_symlink (filename, &value, error);
#endif #endif
#if defined (HAVE_UTIMES) || defined (G_OS_WIN32) #if defined (HAVE_UTIMES) || defined (HAVE_UTIMENSAT) || defined (G_OS_WIN32)
else if (strcmp (attribute, G_FILE_ATTRIBUTE_TIME_MODIFIED) == 0) else if (strcmp (attribute, G_FILE_ATTRIBUTE_TIME_MODIFIED) == 0)
return set_mtime_atime (filename, &value, NULL, NULL, NULL, error); return set_mtime_atime (filename, &value, NULL, NULL, NULL, NULL, NULL, error);
else if (strcmp (attribute, G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC) == 0) else if (strcmp (attribute, G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC) == 0)
return set_mtime_atime (filename, NULL, &value, NULL, NULL, error); return set_mtime_atime (filename, NULL, &value, NULL, NULL, NULL, NULL, error);
else if (strcmp (attribute, G_FILE_ATTRIBUTE_TIME_MODIFIED_NSEC) == 0)
return set_mtime_atime (filename, NULL, NULL, &value, NULL, NULL, NULL, error);
else if (strcmp (attribute, G_FILE_ATTRIBUTE_TIME_ACCESS) == 0) else if (strcmp (attribute, G_FILE_ATTRIBUTE_TIME_ACCESS) == 0)
return set_mtime_atime (filename, NULL, NULL, &value, NULL, error); return set_mtime_atime (filename, NULL, NULL, NULL, &value, NULL, NULL, error);
else if (strcmp (attribute, G_FILE_ATTRIBUTE_TIME_ACCESS_USEC) == 0) else if (strcmp (attribute, G_FILE_ATTRIBUTE_TIME_ACCESS_USEC) == 0)
return set_mtime_atime (filename, NULL, NULL, NULL, &value, error); return set_mtime_atime (filename, NULL, NULL, NULL, NULL, &value, NULL, error);
else if (strcmp (attribute, G_FILE_ATTRIBUTE_TIME_ACCESS_NSEC) == 0)
return set_mtime_atime (filename, NULL, NULL, NULL, NULL, NULL, &value, error);
#endif #endif
#ifdef HAVE_XATTR #ifdef HAVE_XATTR
@ -2848,8 +2946,8 @@ _g_local_file_info_set_attributes (char *filename,
#ifdef G_OS_UNIX #ifdef G_OS_UNIX
GFileAttributeValue *uid, *gid; GFileAttributeValue *uid, *gid;
#endif #endif
#if defined (HAVE_UTIMES) || defined (G_OS_WIN32) #if defined (HAVE_UTIMES) || defined (HAVE_UTIMENSAT) || defined (G_OS_WIN32)
GFileAttributeValue *mtime, *mtime_usec, *atime, *atime_usec; GFileAttributeValue *mtime, *mtime_usec, *mtime_nsec, *atime, *atime_usec, *atime_nsec;
#endif #endif
#if defined (G_OS_UNIX) || defined (G_OS_WIN32) #if defined (G_OS_UNIX) || defined (G_OS_WIN32)
GFileAttributeStatus status; GFileAttributeStatus status;
@ -2922,19 +3020,21 @@ _g_local_file_info_set_attributes (char *filename,
} }
#if defined (HAVE_UTIMES) || defined (G_OS_WIN32) #if defined (HAVE_UTIMES) || defined (HAVE_UTIMENSAT) || defined (G_OS_WIN32)
/* Group all time settings into one call /* Group all time settings into one call
* Change times as the last thing to avoid it changing due to metadata changes * Change times as the last thing to avoid it changing due to metadata changes
*/ */
mtime = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_TIME_MODIFIED); mtime = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
mtime_usec = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC); mtime_usec = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC);
mtime_nsec = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_TIME_MODIFIED_NSEC);
atime = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_TIME_ACCESS); atime = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_TIME_ACCESS);
atime_usec = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_TIME_ACCESS_USEC); atime_usec = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_TIME_ACCESS_USEC);
atime_nsec = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_TIME_ACCESS_NSEC);
if (mtime || mtime_usec || atime || atime_usec) if (mtime || mtime_usec || mtime_nsec || atime || atime_usec || atime_nsec)
{ {
if (!set_mtime_atime (filename, mtime, mtime_usec, atime, atime_usec, error)) if (!set_mtime_atime (filename, mtime, mtime_usec, mtime_nsec, atime, atime_usec, atime_nsec, error))
{ {
status = G_FILE_ATTRIBUTE_STATUS_ERROR_SETTING; status = G_FILE_ATTRIBUTE_STATUS_ERROR_SETTING;
res = FALSE; res = FALSE;
@ -2948,10 +3048,14 @@ _g_local_file_info_set_attributes (char *filename,
mtime->status = status; mtime->status = status;
if (mtime_usec) if (mtime_usec)
mtime_usec->status = status; mtime_usec->status = status;
if (mtime_nsec)
mtime_nsec->status = status;
if (atime) if (atime)
atime->status = status; atime->status = status;
if (atime_usec) if (atime_usec)
atime_usec->status = status; atime_usec->status = status;
if (atime_nsec)
atime_nsec->status = status;
} }
#endif #endif

View File

@ -392,6 +392,9 @@ g_zlib_decompressor_convert (GConverter *converter,
g_file_info_set_attribute_uint32 (data->file_info, g_file_info_set_attribute_uint32 (data->file_info,
G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC, G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC,
0); 0);
g_file_info_set_attribute_uint32 (data->file_info,
G_FILE_ATTRIBUTE_TIME_MODIFIED_NSEC,
0);
if (data->filename[0] != '\0') if (data->filename[0] != '\0')
g_file_info_set_attribute_byte_string (data->file_info, g_file_info_set_attribute_byte_string (data->file_info,

View File

@ -2998,6 +2998,20 @@ test_build_attribute_list_for_copy (void)
g_assert_null (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_ACCESS ",")); g_assert_null (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_ACCESS ","));
g_assert_null (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_ACCESS_USEC ",")); g_assert_null (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_ACCESS_USEC ","));
} }
#endif
#ifdef HAVE_UTIMENSAT
g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_MODIFIED ","));
g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_MODIFIED_NSEC ","));
if (flags & G_FILE_COPY_ALL_METADATA)
{
g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_ACCESS ","));
g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_ACCESS_NSEC ","));
}
else
{
g_assert_null (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_ACCESS ","));
g_assert_null (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_ACCESS_NSEC ","));
}
#endif #endif
g_free (attrs_with_commas); g_free (attrs_with_commas);
} }

View File

@ -586,6 +586,7 @@ functions = [
'unsetenv', 'unsetenv',
'uselocale', 'uselocale',
'utimes', 'utimes',
'utimensat',
'valloc', 'valloc',
'vasprintf', 'vasprintf',
'vsnprintf', 'vsnprintf',