diff --git a/src/build/libroot/fs.cpp b/src/build/libroot/fs.cpp index 149c8c054f..8b0c88c4a3 100644 --- a/src/build/libroot/fs.cpp +++ b/src/build/libroot/fs.cpp @@ -891,7 +891,6 @@ _kern_write_stat(int fd, const char *path, bool traverseLink, return errno; isSymlink = S_ISLNK(tmpStat.st_mode); - } else { Descriptor *descriptor = get_descriptor(fd); if (!descriptor) @@ -900,17 +899,14 @@ _kern_write_stat(int fd, const char *path, bool traverseLink, if (FileDescriptor *fileFD = dynamic_cast(descriptor)) { realFD = fileFD->fd; - } else if (dynamic_cast(descriptor)) { error = get_path(fd, NULL, realPath); if (error != B_OK) return error; - } else if (SymlinkDescriptor *linkFD = dynamic_cast(descriptor)) { realPath = linkFD->path; isSymlink = true; - } else return B_FILE_ERROR; } @@ -941,15 +937,27 @@ _kern_write_stat(int fd, const char *path, bool traverseLink, return errno; } - // The timestamps can only be set via utime(), but that requires a - // path we don't have. - if (statMask & (B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME - | B_STAT_CREATION_TIME | B_STAT_CHANGE_TIME)) { - return B_ERROR; + if (statMask & (B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME)) { + // Grab the previous mod and access times so we only overwrite + // the specified time and not both + struct stat oldStat; + 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 { if (statMask & B_STAT_MODE) { if (chmod(realPath.c_str(), st->st_mode) < 0)