libroot_build: Implement FD writing STAT_ACCESS_TIME and STAT_MODIFICATION_TIME.

We have used and had fallback futimens() implementations in libroot_build
(and in this file even) for over a decade, but nobody seems to have noticed
this bit of missing functionality which can be implemented with them.

In fact, this is rather important bit of functionality, as "copyattr"
relies on it to preserve the mtimes of copied files; and we use
recursive copyattr many places in Haiku builds. Thus, the lack of
an implementation here was the cause of all files in built Haiku images
having timestamps of whenever the build was done, and not whenever
the file was actually modified.

This should make development on Haiku nightlies much more pleasant,
as the system headers from the haiku_devel package should no longer
have always-current timestamps with every upgrade.
This commit is contained in:
Augustin Cavalier
2022-01-26 13:25:11 -05:00
parent e673363df1
commit eecf3977a5
+18 -10
View File
@@ -891,7 +891,6 @@ _kern_write_stat(int fd, const char *path, bool traverseLink,
return errno; return errno;
isSymlink = S_ISLNK(tmpStat.st_mode); isSymlink = S_ISLNK(tmpStat.st_mode);
} else { } else {
Descriptor *descriptor = get_descriptor(fd); Descriptor *descriptor = get_descriptor(fd);
if (!descriptor) if (!descriptor)
@@ -900,17 +899,14 @@ _kern_write_stat(int fd, const char *path, bool traverseLink,
if (FileDescriptor *fileFD if (FileDescriptor *fileFD
= dynamic_cast<FileDescriptor*>(descriptor)) { = dynamic_cast<FileDescriptor*>(descriptor)) {
realFD = fileFD->fd; realFD = fileFD->fd;
} else if (dynamic_cast<DirectoryDescriptor*>(descriptor)) { } else if (dynamic_cast<DirectoryDescriptor*>(descriptor)) {
error = get_path(fd, NULL, realPath); error = get_path(fd, NULL, realPath);
if (error != B_OK) if (error != B_OK)
return error; return error;
} else if (SymlinkDescriptor *linkFD } else if (SymlinkDescriptor *linkFD
= dynamic_cast<SymlinkDescriptor*>(descriptor)) { = dynamic_cast<SymlinkDescriptor*>(descriptor)) {
realPath = linkFD->path; realPath = linkFD->path;
isSymlink = true; isSymlink = true;
} else } else
return B_FILE_ERROR; return B_FILE_ERROR;
} }
@@ -941,15 +937,27 @@ _kern_write_stat(int fd, const char *path, bool traverseLink,
return errno; return errno;
} }
// The timestamps can only be set via utime(), but that requires a if (statMask & (B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME)) {
// path we don't have. // Grab the previous mod and access times so we only overwrite
if (statMask & (B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME // the specified time and not both
| B_STAT_CREATION_TIME | B_STAT_CHANGE_TIME)) { struct stat oldStat;
return B_ERROR; if (~statMask & (B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME)) {
if (fstat(realFD, &oldStat) < 0)
return errno;
}
struct timespec times[2];
times[0] = (statMask & B_STAT_ACCESS_TIME) ? st->st_atim : oldStat.st_atim;
times[1] = (statMask & B_STAT_MODIFICATION_TIME) ? st->st_mtim : oldStat.st_mtim;
if (futimens(realFD, times) < 0)
return errno;
} }
return 0; // not supported
if (statMask & (B_STAT_CREATION_TIME | B_STAT_CHANGE_TIME))
return B_ERROR;
return 0;
} else { } else {
if (statMask & B_STAT_MODE) { if (statMask & B_STAT_MODE) {
if (chmod(realPath.c_str(), st->st_mode) < 0) if (chmod(realPath.c_str(), st->st_mode) < 0)