[libc] Implemented utimes (Issue #133953) by hoarfrost32 · Pull Request #134167 · llvm/llvm-project (original) (raw)
@llvm/pr-subscribers-libc
Author: Aditya Tejpaul (hoarfrost32)
Changes
This pull request implements the utimes
command in libc.
- Add the implementation of
utimes
in/src/sys/time
. - Add tests for
utimes
in/test/src/sys/time
. - Add
utimes
to entrypoints.txt for at least x86_64 and whatever you're building on - Add
utimes
to include/sys/time.yaml
Full diff: https://github.com/llvm/llvm-project/pull/134167.diff
16 Files Affected:
- (added) __cmake_systeminformation/CMakeCache.txt (+86)
- (added) __cmake_systeminformation/CMakeFiles/3.31.5/CMakeSystem.cmake (+15)
- (added) __cmake_systeminformation/CMakeFiles/CMakeConfigureLog.yaml (+11)
- (added) __cmake_systeminformation/CMakeFiles/cmake.check_cache (+1)
- (added) __cmake_systeminformation/CMakeLists.txt (+91)
- (modified) libc/config/linux/x86_64/entrypoints.txt (+3)
- (modified) libc/include/sys/time.yaml (+6-1)
- (modified) libc/src/sys/CMakeLists.txt (+1)
- (added) libc/src/sys/time/CMakeLists.txt (+10)
- (added) libc/src/sys/time/linux/CMakeLists.txt (+15)
- (added) libc/src/sys/time/linux/utimes.cpp (+80)
- (added) libc/src/sys/time/utimes.h (+21)
- (modified) libc/test/src/sys/CMakeLists.txt (+1)
- (added) libc/test/src/sys/time/CMakeLists.txt (+21)
- (added) libc/test/src/sys/time/testdata/CMakeLists.txt (+3)
- (added) libc/test/src/sys/time/utimes_test.cpp (+81)
diff --git a/__cmake_systeminformation/CMakeCache.txt b/__cmake_systeminformation/CMakeCache.txt new file mode 100644 index 0000000000000..880b49ed4f29d --- /dev/null +++ b/__cmake_systeminformation/CMakeCache.txt @@ -0,0 +1,86 @@ +# This is the CMakeCache file. +# For build in directory: /home/hoarfrost/Projects/llvm/llvm-project/__cmake_systeminformation +# It was generated by CMake: /nix/store/ciiwq1ymzac9m5azhf4higkynmy3f8f7-cmake-3.31.5/bin/cmake +# You can edit this file to change values found and used by cmake. +# If you do not want to change any of the values, simply exit the editor. +# If you do want to change a value, simply edit, save, and exit the editor. +# The syntax for the file is as follows: +# KEY:TYPE=VALUE +# KEY is the name of a variable in the cache. +# TYPE is a hint to GUIs for the type of VALUE, DO NOT EDIT TYPE!. +# VALUE is the current value for the KEY. + +######################## +# EXTERNAL cache entries +######################## + +//Value Computed by CMake. +CMAKE_FIND_PACKAGE_REDIRECTS_DIR:STATIC=/home/hoarfrost/Projects/llvm/llvm-project/__cmake_systeminformation/CMakeFiles/pkgRedirects + +//Path to a program. +CMAKE_MAKE_PROGRAM:FILEPATH=CMAKE_MAKE_PROGRAM-NOTFOUND + +//Value Computed by CMake +CMAKE_PROJECT_DESCRIPTION:STATIC= + +//Value Computed by CMake +CMAKE_PROJECT_HOMEPAGE_URL:STATIC= + +//Value Computed by CMake +CMAKE_PROJECT_NAME:STATIC=DumpInformation + +//Value Computed by CMake +DumpInformation_BINARY_DIR:STATIC=/home/hoarfrost/Projects/llvm/llvm-project/__cmake_systeminformation + +//Value Computed by CMake +DumpInformation_IS_TOP_LEVEL:STATIC=ON + +//Value Computed by CMake +DumpInformation_SOURCE_DIR:STATIC=/home/hoarfrost/Projects/llvm/llvm-project/__cmake_systeminformation + +//No help, variable specified on the command line. +RESULT_FILE:UNINITIALIZED=/home/hoarfrost/Projects/llvm/llvm-project/__cmake_systeminformation/results.txt + + +######################## +# INTERNAL cache entries +######################## + +//This is the directory where this CMakeCache.txt was created +CMAKE_CACHEFILE_DIR:INTERNAL=/home/hoarfrost/Projects/llvm/llvm-project/__cmake_systeminformation +//Major version of cmake used to create the current loaded cache +CMAKE_CACHE_MAJOR_VERSION:INTERNAL=3 +//Minor version of cmake used to create the current loaded cache +CMAKE_CACHE_MINOR_VERSION:INTERNAL=31 +//Patch version of cmake used to create the current loaded cache +CMAKE_CACHE_PATCH_VERSION:INTERNAL=5 +//Path to CMake executable. +CMAKE_COMMAND:INTERNAL=/nix/store/ciiwq1ymzac9m5azhf4higkynmy3f8f7-cmake-3.31.5/bin/cmake +//Path to cpack program executable. +CMAKE_CPACK_COMMAND:INTERNAL=/nix/store/ciiwq1ymzac9m5azhf4higkynmy3f8f7-cmake-3.31.5/bin/cpack +//Path to ctest program executable. +CMAKE_CTEST_COMMAND:INTERNAL=/nix/store/ciiwq1ymzac9m5azhf4higkynmy3f8f7-cmake-3.31.5/bin/ctest +//Name of external makefile project generator. +CMAKE_EXTRA_GENERATOR:INTERNAL= +//Name of generator. +CMAKE_GENERATOR:INTERNAL=Unix Makefiles +//Generator instance identifier. +CMAKE_GENERATOR_INSTANCE:INTERNAL= +//Name of generator platform. +CMAKE_GENERATOR_PLATFORM:INTERNAL= +//Name of generator toolset. +CMAKE_GENERATOR_TOOLSET:INTERNAL= +//Source directory with the top level CMakeLists.txt file for this +// project +CMAKE_HOME_DIRECTORY:INTERNAL=/home/hoarfrost/Projects/llvm/llvm-project/__cmake_systeminformation +//ADVANCED property for variable: CMAKE_MAKE_PROGRAM +CMAKE_MAKE_PROGRAM-ADVANCED:INTERNAL=1 +//number of local generators +CMAKE_NUMBER_OF_MAKEFILES:INTERNAL=1 +//Platform information initialized +CMAKE_PLATFORM_INFO_INITIALIZED:INTERNAL=1 +//Path to CMake installation. +CMAKE_ROOT:INTERNAL=/nix/store/ciiwq1ymzac9m5azhf4higkynmy3f8f7-cmake-3.31.5/share/cmake-3.31 +//uname command +CMAKE_UNAME:INTERNAL=/usr/bin/uname + diff --git a/__cmake_systeminformation/CMakeFiles/3.31.5/CMakeSystem.cmake b/__cmake_systeminformation/CMakeFiles/3.31.5/CMakeSystem.cmake new file mode 100644 index 0000000000000..82aa456095f26 --- /dev/null +++ b/__cmake_systeminformation/CMakeFiles/3.31.5/CMakeSystem.cmake @@ -0,0 +1,15 @@ +set(CMAKE_HOST_SYSTEM "Linux-6.12.20") +set(CMAKE_HOST_SYSTEM_NAME "Linux") +set(CMAKE_HOST_SYSTEM_VERSION "6.12.20") +set(CMAKE_HOST_SYSTEM_PROCESSOR "x86_64") + + + +set(CMAKE_SYSTEM "Linux-6.12.20") +set(CMAKE_SYSTEM_NAME "Linux") +set(CMAKE_SYSTEM_VERSION "6.12.20") +set(CMAKE_SYSTEM_PROCESSOR "x86_64") + +set(CMAKE_CROSSCOMPILING "FALSE") + +set(CMAKE_SYSTEM_LOADED 1) diff --git a/__cmake_systeminformation/CMakeFiles/CMakeConfigureLog.yaml b/__cmake_systeminformation/CMakeFiles/CMakeConfigureLog.yaml new file mode 100644 index 0000000000000..b5439f4f72db7 --- /dev/null +++ b/__cmake_systeminformation/CMakeFiles/CMakeConfigureLog.yaml @@ -0,0 +1,11 @@ + +--- +events:
- kind: "message-v1"
- backtrace:
- "/nix/store/ciiwq1ymzac9m5azhf4higkynmy3f8f7-cmake-3.31.5/share/cmake-3.31/Modules/CMakeDetermineSystem.cmake:205 (message)"
- "CMakeLists.txt:6 (project)"
- message: |
The system is: Linux - 6.12.20 - x86_64
+... diff --git a/__cmake_systeminformation/CMakeFiles/cmake.check_cache b/__cmake_systeminformation/CMakeFiles/cmake.check_cache new file mode 100644 index 0000000000000..3dccd731726d7 --- /dev/null +++ b/__cmake_systeminformation/CMakeFiles/cmake.check_cache @@ -0,0 +1 @@ +# This file is generated by cmake for dependency checking of the CMakeCache.txt file diff --git a/__cmake_systeminformation/CMakeLists.txt b/__cmake_systeminformation/CMakeLists.txt new file mode 100644 index 0000000000000..97f385612c3b7 --- /dev/null +++ b/__cmake_systeminformation/CMakeLists.txt @@ -0,0 +1,91 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + + +cmake_minimum_required(VERSION ${CMAKE_VERSION}) +project(DumpInformation) + +# first get the standard information for the platform +include_directories("This does not exist") +get_directory_property(incl INCLUDE_DIRECTORIES) +set_directory_properties(PROPERTIES INCLUDE_DIRECTORIES "${DumpInformation_BINARY_DIR};${DumpInformation_SOURCE_DIR}") + +configure_file("${CMAKE_ROOT}/Modules/SystemInformation.in" "${RESULT_FILE}") + + +file(APPEND "${RESULT_FILE}"
- "\n=================================================================\n") +file(APPEND "${RESULT_FILE}"
- "=== VARIABLES\n") +file(APPEND "${RESULT_FILE}"
- "=================================================================\n") +get_cmake_property(res VARIABLES) +foreach(var ${res})
- file(APPEND "${RESULT_FILE}" "${var} "${${var}}"\n") +endforeach()
- +file(APPEND "${RESULT_FILE}"
- "\n=================================================================\n") +file(APPEND "${RESULT_FILE}"
- "=== COMMANDS\n") +file(APPEND "${RESULT_FILE}"
- "=================================================================\n") +get_cmake_property(res COMMANDS) +foreach(var ${res})
- file(APPEND "${RESULT_FILE}" "${var}\n") +endforeach()
- +file(APPEND "${RESULT_FILE}"
- "\n=================================================================\n") +file(APPEND "${RESULT_FILE}"
- "=== MACROS\n") +file(APPEND "${RESULT_FILE}"
- "=================================================================\n") +file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/AllMacros.txt "") +get_cmake_property(res MACROS) +foreach(var ${res})
- file(APPEND "${RESULT_FILE}" "${var}\n") +endforeach()
- +file(APPEND "${RESULT_FILE}"
- "\n=================================================================\n") +file(APPEND "${RESULT_FILE}"
- "=== OTHER\n") +file(APPEND "${RESULT_FILE}"
- "=================================================================\n") +get_directory_property(res INCLUDE_DIRECTORIES) +foreach(var ${res})
- file(APPEND "${RESULT_FILE}" "INCLUDE_DIRECTORY: ${var}\n") +endforeach()
- +get_directory_property(res LINK_DIRECTORIES) +foreach(var ${res})
- file(APPEND "${RESULT_FILE}" "LINK_DIRECTORIES: ${var}\n") +endforeach()
- +get_directory_property(res INCLUDE_REGULAR_EXPRESSION) +file(APPEND "${RESULT_FILE}" "INCLUDE_REGULAR_EXPRESSION: ${res}\n")
- +# include other files if they are present, such as when run from within the
+# binary tree +macro(DUMP_FILE THE_FILE)
if (EXISTS "${THE_FILE}")
file(APPEND "${RESULT_FILE}"
"\n=================================================================\n")
file(APPEND "${RESULT_FILE}"
"=== ${THE_FILE}\n")
file(APPEND "${RESULT_FILE}"
"=================================================================\n")
file(READ "${THE_FILE}" FILE_CONTENTS LIMIT 50000)
file(APPEND "${RESULT_FILE}" "${FILE_CONTENTS}")
endif () +endmacro()
+DUMP_FILE("../CMakeCache.txt") +DUMP_FILE("../CMakeFiles/CMakeSystem.cmake")
+foreach (EXTRA_FILE ${EXTRA_DUMP_FILES})
DUMP_FILE("${EXTRA_FILE}") +endforeach ()
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt index eccd222fa123e..1ac3a781d5279 100644 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -288,6 +288,9 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.sys.statvfs.fstatvfs libc.src.sys.statvfs.statvfs
sys/utimes.h entrypoints
libc.src.sys.time.utimes
# sys/utsname.h entrypoints libc.src.sys.utsname.uname
diff --git a/libc/include/sys/time.yaml b/libc/include/sys/time.yaml index ca497bbe92995..f2f0f5f949c77 100644 --- a/libc/include/sys/time.yaml +++ b/libc/include/sys/time.yaml @@ -5,5 +5,10 @@ macros: [] types:
- type_name: struct_timeval enums: [] -functions: [] objects: [] +functions:
- name: utimes
- return_type: int
- arguments:
- type: ptr<const char>
- type: ptr<const struct timeval>
\ No newline at end of file diff --git a/libc/src/sys/CMakeLists.txt b/libc/src/sys/CMakeLists.txt index bb177f11c6d62..9a73b80d35d2f 100644 --- a/libc/src/sys/CMakeLists.txt +++ b/libc/src/sys/CMakeLists.txt @@ -8,6 +8,7 @@ add_subdirectory(socket) add_subdirectory(sendfile) add_subdirectory(stat) add_subdirectory(statvfs) +add_subdirectory(time) add_subdirectory(utsname) add_subdirectory(wait) add_subdirectory(prctl) diff --git a/libc/src/sys/time/CMakeLists.txt b/libc/src/sys/time/CMakeLists.txt new file mode 100644 index 0000000000000..df8bf5b3630c3 --- /dev/null +++ b/libc/src/sys/time/CMakeLists.txt @@ -0,0 +1,10 @@ +if(EXISTS CMAKECURRENTSOURCEDIR/{CMAKE_CURRENT_SOURCE_DIR}/CMAKECURRENTSOURCEDIR/{LIBC_TARGET_OS})
- add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS}) +endif()
- +add_entrypoint_object(
- utimes
- ALIAS
- DEPENDS
- .${LIBC_TARGET_OS}.utimes
+) \ No newline at end of file diff --git a/libc/src/sys/time/linux/CMakeLists.txt b/libc/src/sys/time/linux/CMakeLists.txt new file mode 100644 index 0000000000000..26efce526e732 --- /dev/null +++ b/libc/src/sys/time/linux/CMakeLists.txt @@ -0,0 +1,15 @@ +add_entrypoint_object(
- utimes
- SRCS
- utimes.cpp
- HDRS
- ../utimes.h
- DEPENDS
- libc.hdr.types.struct_timeval
- libc.src.__support.OSUtil.osutil
- libc.include.sys_stat
- libc.include.sys_syscall
- libc.include.fcntl
- libc.src.__support.OSUtil.osutil
- libc.src.errno.errno
+) \ No newline at end of file diff --git a/libc/src/sys/time/linux/utimes.cpp b/libc/src/sys/time/linux/utimes.cpp new file mode 100644 index 0000000000000..12257f0f876fa --- /dev/null +++ b/libc/src/sys/time/linux/utimes.cpp @@ -0,0 +1,80 @@ +//===-- Linux implementation of utimes -------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===/ + +#include "src/sys/time/utimes.h" + +#include "hdr/types/struct_timeval.h" + +#include "src/__support/OSUtil/syscall.h" +#include "src/__support/common.h" + +#include "src/errno/libc_errno.h" + +#include +#include <sys/syscall.h> +#include <sys/stat.h> +#include <fcntl.h> + +namespace LIBC_NAMESPACE_DECL {
- LLVM_LIBC_FUNCTION(int, utimes, (const char *path, const struct timeval times[2])) {
- int ret;
- #ifdef SYS_utimensat
- //the utimensat syscall requires a timespec struct, not timeval.
- struct timespec ts[2];
- struct timespec *ts_ptr = nullptr; // default value if times is NULL
- // convert the microsec values in timeval struct times
- // to nanosecond values in timespec struct ts
- if (times != NULL) {
// ensure consistent values
if ((times[0].tv_usec < 0 || times[1].tv_usec < 0) ||
(times[0].tv_usec >= 1000000 || times[1].tv_usec >= 1000000)) {
libc_errno = EINVAL;
return -1;
}
// set seconds in ts
ts[0].tv_sec = times[0].tv_sec;
ts[1].tv_sec = times[1].tv_sec;
// convert u-seconds to nanoseconds
ts[0].tv_nsec = times[0].tv_usec * 1000;
ts[1].tv_nsec = times[1].tv_usec * 1000;
ts_ptr = ts;
- }
- // If times was NULL, ts_ptr remains NULL, which utimensat interprets
- // as setting times to the current time.
- // utimensat syscall.
- // flags=0 means don't follow symlinks (like utimes)
- ret = LIBC_NAMESPACE::syscall_impl(SYS_utimensat, AT_FDCWD, path,
ts_ptr, 0);
- #elif defined(SYS_utimes)
- // No need to define a timespec struct, use the syscall directly.
- ret = LIBC_NAMESPACE::syscall_impl(SYS_utimes, path, times);
- #else
- #error "utimensat and utimes syscalls not available."
- // To avoid compilation errors when neither is defined, return an error.
- libc_errno = ENOSYS; // Function not implemented
- return -1;
- #endif // SYS_utimensat
- if (ret < 0) {
libc_errno = -ret;
return -1;
- }
- return 0;
- } +} diff --git a/libc/src/sys/time/utimes.h b/libc/src/sys/time/utimes.h new file mode 100644 index 0000000000000..6dc33aae55621 --- /dev/null +++ b/libc/src/sys/time/utimes.h @@ -0,0 +1,21 @@ +//===-- Implementation header for utimes -----------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===//
- +#ifndef LLVM_LIBC_SRC_SYS_TIME_UTIMES_H
+#define LLVM_LIBC_SRC_SYS_TIME_UTIMES_H + +#include "hdr/types/struct_timeval.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +int utimes(const char *path, const struct timeval times[2]); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_SYS_TIME_UTIMES_H \ No newline at end of file diff --git a/libc/test/src/sys/CMakeLists.txt b/libc/test/src/sys/CMakeLists.txt index 9e9293aab628f..224cc7905ad31 100644 --- a/libc/test/src/sys/CMakeLists.txt +++ b/libc/test/src/sys/CMakeLists.txt @@ -12,3 +12,4 @@ add_subdirectory(prctl) add_subdirectory(auxv) add_subdirectory(epoll) add_subdirectory(uio) +add_subdirectory(time) diff --git a/libc/test/src/sys/time/CMakeLists.txt b/libc/test/src/sys/time/CMakeLists.txt new file mode 100644 index 0000000000000..fa76f2465b85b --- /dev/null +++ b/libc/test/src/sys/time/CMakeLists.txt @@ -0,0 +1,21 @@ +add_custom_target(libc_sys_time_unittests) + +add_subdirectory(testdata) + +add_libc_unittest(
- utimes_test
- SUITE
- libc_sys_time_unittests
- SRCS
- utimes_test.cpp
- DEPENDS
- libc.hdr.fcntl_macros
- libc.include.sys_stat
- libc.src.errno.errno
- libc.src.fcntl.open
- libc.src.sys.time.utimes
- libc.src.unistd.close
- libc.src.unistd.read
- libc.src.unistd.unlink
- libc.src.unistd.write
+)
diff --git a/libc/test/src/sys/time/testdata/CMakeLists.txt b/libc/test/src/sys/time/testdata/CMakeLists.txt
new file mode 100644
index 0000000000000..8703b80eab587
--- /dev/null
+++ b/libc/test/src/sys/time/testdata/CMakeLists.txt
@@ -0,0 +1,3 @@
+# This directory will be used to create test files.
+
+file(GENERATE OUTPUT utimes.test CONTENT "utimes test")
diff --git a/libc/test/src/sys/time/utimes_test.cpp b/libc/test/src/sys/time/utimes_test.cpp
new file mode 100644
index 0000000000000..e644d50607b7d
--- /dev/null
+++ b/libc/test/src/sys/time/utimes_test.cpp
@@ -0,0 +1,81 @@
+//===-- Unittests for utimes --------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// temp file related stuff
+#include "src/fcntl/open.h" // to open
+#include "src/unistd/close.h" // to close
+#include "src/sys/stat/stat.h" // for info
+#include "src/unistd/unlink.h" // to delete
+// testing error handling
+#include "test/UnitTest/Test.h"
+#include "src/errno/libc_errno.h"
+#include "test/UnitTest/ErrnoSetterMatcher.h"
+// dependencies for the tests themselves
+#include "hdr/types/struct_timeval.h"
+#include
+#include <fcntl.h>
+#include "hdr/fcntl_macros.h"
+// the utimes function
+#include "src/sys/time/utimes.h"
+constexpr const char* TEST_FILE = "testdata/utimes.test";
+
+// SUCCESS: Takes a file and successfully updates
+// its last access and modified times.
+TEST(LlvmLibcUtimesTest, ChangeTimesSpecific){
- using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
- // make a dummy timeval struct
- struct timeval times[2];
- times[0].tv_sec = 54321;
- times[0].tv_usec = 12345;
- times[1].tv_sec = 43210;
- times[1].tv_usec = 23456;
- // ensure utimes succeeds
- ASSERT_THAT(LIBC_NAMESPACE::utimes(TEST_FILE, times), Succeeds(0));
- // verify the times values against stat of the TEST_FILE
- struct stat statbuf;
- ASSERT_EQ(stat(TEST_FILE, &statbuf), 0);
- // seconds
- ASSERT_EQ(statbuf.st_atim.tv_sec, times[0].tv_sec);
- ASSERT_EQ(statbuf.st_mtim.tv_sec, times[1].tv_sec);
- //microseconds
- ASSERT_EQ(statbuf.st_atim.tv_nsec, times[0].tv_usec * 1000);
- ASSERT_EQ(statbuf.st_mtim.tv_nsec, times[1].tv_usec * 1000); +}
- +// FAILURE: Invalid values in the timeval struct +// to check that utimes rejects it. +TEST(LlvmLibcUtimesTest, InvalidMicroseconds){
- using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails;
- // make a dummy timeval struct
- // populated with bad usec values
- struct timeval times[2];
- times[0].tv_sec = 54321;
- times[0].tv_usec = 4567;
- times[1].tv_sec = 43210;
- times[1].tv_usec = 1000000; //invalid
- // ensure utimes fails
- ASSERT_THAT(LIBC_NAMESPACE::utimes(TEST_FILE, times), Fails(EINVAL));
- // check for failure on
- // the other possible bad values
- times[0].tv_sec = 54321;
- times[0].tv_usec = -4567; //invalid
- times[1].tv_sec = 43210;
- times[1].tv_usec = 1000;
- // ensure utimes fails once more
- ASSERT_THAT(LIBC_NAMESPACE::utimes(TEST_FILE, times), Fails(EINVAL));
+} \ No newline at end of file