Skip to content

Commit 79bd0ac

Browse files
committed
Add mm_futimens() and mm_utimens() API
Provides API to set access and modification timestamp of a file through either its path or a file descriptor. Change-Id: Ifa099932f53b6e3fb61eefa28a4b851c9d572115
1 parent 67a0d89 commit 79bd0ac

File tree

6 files changed

+354
-0
lines changed

6 files changed

+354
-0
lines changed

src/file-posix.c

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -666,6 +666,82 @@ int mm_stat(const char* path, struct mm_stat* buf, int flags)
666666
}
667667

668668

669+
/**
670+
* mm_futimens() - set file access and modification times of an opened file
671+
* @fd: file descriptor of an open file whose times must be changed
672+
* @ts: array of 2 timestamps (access and modification time). If NULL,
673+
* both time are set to current time.
674+
*
675+
* This set the access and modification times of a file associated with the
676+
* file description @fd to the values of the @ts argument. The file's relevant
677+
* timestamp is set to the greatest value supported by the file system that is
678+
* not greater than the specified time.
679+
*
680+
* The @ts argument is an array of two timespec structures. The first array
681+
* member @ts[0] represents the date and time of last access, and the second
682+
* member @ts[1] represents the date and time of last modification. The times
683+
* in the mmm_timespec structure are measured in seconds and nanoseconds since
684+
* the Epoch.
685+
*
686+
* If the tv_nsec field of a mm_timespec structure has the special value
687+
* UTIME_NOW, the file's relevant timestamp is set to the greatest value
688+
* supported by the file system that is not greater than the current time. If
689+
* the tv_nsec field has the special value UTIME_OMIT, the file's relevant
690+
* timestamp is not changed. In either case, the tv_sec field shall be ignored.
691+
*
692+
* If the @ts argument is a null pointer, both the access and modification
693+
* timestamps are set to the greatest value supported by the file system that
694+
* is not greater than the current time.
695+
*
696+
* Return: 0 in case of success, -1 otherwise with error state set.
697+
*/
698+
API_EXPORTED
699+
int mm_futimens(int fd, const struct mm_timespec ts[2])
700+
{
701+
if (futimens(fd, (const struct timespec*)ts))
702+
return mm_raise_from_errno("futimens(%i) failed", fd);
703+
704+
return 0;
705+
}
706+
707+
708+
/**
709+
* mm_utimens() - set file access and modification times
710+
* @path: path to file whose times must be changed
711+
* @ts: array of 2 timestamps (access and modification time). If NULL,
712+
* both time are set to current time.
713+
* @flags 0 or MM_NOFOLLOW
714+
*
715+
* This does the same as mm_futimes excepting that file is refered through its
716+
* file path while with mm_futimens() it must be refered though a file
717+
* descriptor.
718+
*
719+
* See documentation of mm_futimens() for the documentation of @ts argument.
720+
*
721+
* If @flags is 0, the time are set to the target if @path refers to a symlink.
722+
* Otherwise, if MM_NOFOLLOW is set in @flags, the times of the symlink itself
723+
* are set.
724+
*
725+
* Return: 0 in case of success, -1 otherwise with error state set.
726+
*/
727+
API_EXPORTED
728+
int mm_utimens(const char* path, const struct mm_timespec ts[2], int flags)
729+
{
730+
int uflags = 0;
731+
732+
if (flags & ~MM_NOFOLLOW)
733+
return mm_raise_error(EINVAL, "invalid flags (0x%08x)", flags);
734+
735+
if (flags & MM_NOFOLLOW)
736+
uflags |= AT_SYMLINK_NOFOLLOW;
737+
738+
if (utimensat(AT_FDCWD, path, (const struct timespec*)ts, uflags))
739+
return mm_raise_from_errno("utimensat(%s) failed", path);
740+
741+
return 0;
742+
}
743+
744+
669745
/**
670746
* mm_readlink() - read value of a symbolic link
671747
* @path: pathname of symbolic link

src/file-win32.c

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1620,6 +1620,84 @@ int mm_fstat(int fd, struct mm_stat* buf)
16201620
}
16211621

16221622

1623+
static
1624+
int hnd_utimens(HANDLE hnd, const struct mm_timespec ts[2])
1625+
{
1626+
FILETIME aft;
1627+
FILETIME mft;
1628+
FILETIME now;
1629+
1630+
if (!ts || ts[0].tv_nsec == UTIME_NOW || ts[1].tv_nsec == UTIME_NOW)
1631+
GetSystemTimePreciseAsFileTime(&now);
1632+
1633+
// Set access filetime
1634+
if (!ts || ts[0].tv_nsec == UTIME_NOW)
1635+
aft = now;
1636+
else if (ts[0].tv_nsec == UTIME_OMIT)
1637+
aft = (FILETIME) {0};
1638+
else
1639+
aft = timespec_to_filetime(ts[0]);
1640+
1641+
// Set modification filetime
1642+
if (!ts || ts[1].tv_nsec == UTIME_NOW)
1643+
mft = now;
1644+
else if (ts[1].tv_nsec == UTIME_OMIT)
1645+
mft = (FILETIME) {0};
1646+
else
1647+
mft = timespec_to_filetime(ts[1]);
1648+
1649+
return SetFileTime(hnd, NULL, &aft, &mft) ? 0 : -1;
1650+
}
1651+
1652+
1653+
/* doc in posix implementation */
1654+
API_EXPORTED
1655+
int mm_futimens(int fd, const struct mm_timespec ts[2])
1656+
{
1657+
HANDLE hnd, hnd_new;
1658+
int rv;
1659+
1660+
if (unwrap_handle_from_fd(&hnd, fd))
1661+
return -1;
1662+
1663+
hnd_new = ReOpenFile(hnd, FILE_WRITE_ATTRIBUTES, FILE_SHARE_ALL, 0);
1664+
if (hnd_new == INVALID_HANDLE_VALUE)
1665+
goto exit;
1666+
1667+
rv = hnd_utimens(hnd_new, ts);
1668+
CloseHandle(hnd_new);
1669+
1670+
exit:
1671+
if (rv)
1672+
mm_raise_from_w32err("Cannot change times of fd %i", fd);
1673+
return rv;
1674+
}
1675+
1676+
1677+
/* doc in posix implementation */
1678+
API_EXPORTED
1679+
int mm_utimens(const char* path, const struct mm_timespec ts[2], int flags)
1680+
{
1681+
HANDLE hnd;
1682+
int rv;
1683+
1684+
if (flags & ~MM_NOFOLLOW)
1685+
return mm_raise_error(EINVAL, "invalid flags (0x%08x)", flags);
1686+
1687+
hnd = open_handle(path, FILE_WRITE_ATTRIBUTES,
1688+
OPEN_EXISTING, NULL, flags);
1689+
if (hnd == INVALID_HANDLE_VALUE)
1690+
return mm_raise_from_w32err("Cannot open %s", path);
1691+
1692+
rv = hnd_utimens(hnd, ts);
1693+
if (rv)
1694+
mm_raise_from_w32err("Cannot change times of %s", path);
1695+
1696+
CloseHandle(hnd);
1697+
return rv;
1698+
}
1699+
1700+
16231701
/* doc in posix implementation */
16241702
API_EXPORTED
16251703
int mm_readlink(const char* path, char* buf, size_t bufsize)

src/libmmlib.map

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ MMLIB_1.0 {
6060
mm_fstat;
6161
mm_fsync;
6262
mm_ftruncate;
63+
mm_futimens;
6364
mm_get_basedir;
6465
mm_get_environ;
6566
mm_get_lasterror_desc;
@@ -122,6 +123,7 @@ MMLIB_1.0 {
122123
mm_unlink;
123124
mm_unmap;
124125
mm_unsetenv;
126+
mm_utimens;
125127
mm_wait_process;
126128
mm_write;
127129
mm_arg_complete_path;

src/mmsysio.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,9 @@ extern "C" {
188188
#define R_OK 0x04
189189
#endif
190190

191+
#define UTIME_NOW (-1L)
192+
#define UTIME_OMIT (-2L)
193+
191194
#endif /* _WIN32 */
192195

193196
/* file types returned when scanning a directory */
@@ -248,6 +251,9 @@ MMLIB_API mm_off_t mm_seek(int fd, mm_off_t offset, int whence);
248251
MMLIB_API int mm_ftruncate(int fd, mm_off_t length);
249252
MMLIB_API int mm_fstat(int fd, struct mm_stat* buf);
250253
MMLIB_API int mm_stat(const char* path, struct mm_stat* buf, int flags);
254+
MMLIB_API int mm_futimens(int fd, const struct mm_timespec ts[2]);
255+
MMLIB_API int mm_utimens(const char* path,
256+
const struct mm_timespec ts[2], int flags);
251257
MMLIB_API int mm_check_access(const char* path, int amode);
252258
MMLIB_API int mm_isatty(int fd);
253259

src/utils-win32.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,22 @@ time_t filetime_to_time(FILETIME ft)
294294
}
295295

296296

297+
static inline
298+
FILETIME timespec_to_filetime(struct mm_timespec ts)
299+
{
300+
ULARGE_INTEGER time_int;
301+
302+
time_int.QuadPart = ((LONGLONG)ts.tv_sec) * 10000000;
303+
time_int.QuadPart += (ts.tv_nsec / 100);
304+
time_int.QuadPart += FT_EPOCH;
305+
306+
return (FILETIME) {
307+
.dwLowDateTime = time_int.LowPart,
308+
.dwHighDateTime = time_int.HighPart,
309+
};
310+
}
311+
312+
297313
/**************************************************************************
298314
* *
299315
* thread related utils *

0 commit comments

Comments
 (0)