]> git.ipfire.org Git - thirdparty/gcc.git/blame - libstdc++-v3/testsuite/27_io/filesystem/operations/last_write_time.cc
Update copyright years.
[thirdparty/gcc.git] / libstdc++-v3 / testsuite / 27_io / filesystem / operations / last_write_time.cc
CommitLineData
99dee823 1// Copyright (C) 2016-2021 Free Software Foundation, Inc.
641cb5a6
JW
2//
3// This file is part of the GNU ISO C++ Library. This library is free
4// software; you can redistribute it and/or modify it under the
5// terms of the GNU General Public License as published by the
6// Free Software Foundation; either version 3, or (at your option)
7// any later version.
8
9// This library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License along
15// with this library; see the file COPYING3. If not see
16// <http://www.gnu.org/licenses/>.
17
de4db54f 18// { dg-options "-std=gnu++17" }
641cb5a6
JW
19// { dg-do run { target c++17 } }
20// { dg-require-filesystem-ts "" }
21
22// 15.25 Permissions [fs.op.last_write_time]
23
24#include <filesystem>
174f1d26 25#include <limits>
641cb5a6
JW
26#include <testsuite_fs.h>
27#include <testsuite_hooks.h>
28
29#ifdef _GLIBCXX_HAVE_FCNTL_H
30# include <fcntl.h>
31#endif
32#if _GLIBCXX_HAVE_UTIME_H
33# include <utime.h>
34#endif
a51a546c 35#include <stdio.h>
641cb5a6
JW
36
37using time_type = std::filesystem::file_time_type;
38
a51a546c
JW
39namespace chrono = std::chrono;
40
641cb5a6
JW
41void
42test01()
43{
44 // read times
45
46 auto p = __gnu_test::nonexistent_path();
47 std::error_code ec;
48 time_type mtime = last_write_time(p, ec);
49 VERIFY( ec );
50 VERIFY( ec == std::make_error_code(std::errc::no_such_file_or_directory) );
51#if __cpp_exceptions
52 bool caught = false;
53 try {
54 mtime = last_write_time(p);
55 } catch (std::system_error const& e) {
56 caught = true;
57 ec = e.code();
58 }
59 VERIFY( caught );
60 VERIFY( ec );
61 VERIFY( ec == std::make_error_code(std::errc::no_such_file_or_directory) );
62#endif
63
64 __gnu_test::scoped_file file(p);
65 VERIFY( exists(p) );
66 mtime = last_write_time(p, ec);
67 VERIFY( !ec );
68 VERIFY( mtime <= time_type::clock::now() );
69 VERIFY( mtime == last_write_time(p) );
70
71 auto end_of_time = time_type::duration::max();
72 auto last_second
a51a546c 73 = chrono::duration_cast<chrono::seconds>(end_of_time).count();
641cb5a6 74 if (last_second > std::numeric_limits<std::time_t>::max())
a51a546c
JW
75 {
76 puts("Range of time_t is smaller than range of chrono::file_clock, "
77 "can't test for overflow on this target.");
78 return;
79 }
641cb5a6 80
a51a546c 81 // Set mtime to a date past the maximum possible file_time_type:
641cb5a6
JW
82#if _GLIBCXX_USE_UTIMENSAT
83 struct ::timespec ts[2];
84 ts[0].tv_sec = 0;
85 ts[0].tv_nsec = UTIME_NOW;
86 ts[1].tv_sec = std::numeric_limits<std::time_t>::max() - 1;
87 ts[1].tv_nsec = 0;
88 VERIFY( !::utimensat(AT_FDCWD, p.c_str(), ts, 0) );
89#elif _GLIBCXX_HAVE_UTIME_H
90 ::utimbuf times;
91 times.modtime = std::numeric_limits<std::time_t>::max() - 1;
92 times.actime = std::numeric_limits<std::time_t>::max() - 1;
9534a5e6 93 VERIFY( !::utime(p.string().c_str(), &times) );
641cb5a6 94#else
a51a546c 95 puts("No utimensat or utime, giving up.");
641cb5a6
JW
96 return;
97#endif
98
a51a546c 99 // Try to read back the impossibly-large mtime:
641cb5a6 100 mtime = last_write_time(p, ec);
a51a546c
JW
101 // Some filesystems (e.g. XFS) silently truncate distant times to
102 // the time_t epochalypse, Jan 19 2038, so we won't get an error when
103 // reading it back:
104 if (ec)
105 {
106 VERIFY( ec == std::make_error_code(std::errc::value_too_large) );
107 VERIFY( mtime == time_type::min() );
108 }
109 else
110 puts("No overflow error, filesystem may not support 64-bit time_t.");
641cb5a6
JW
111
112#if __cpp_exceptions
a51a546c 113 // Once more, with exceptions:
641cb5a6 114 try {
a51a546c
JW
115 auto mtime2 = last_write_time(p);
116 // If it didn't throw, expect to have read back the same value:
117 VERIFY( mtime2 == mtime );
118 } catch (std::filesystem::filesystem_error const& e) {
119 // If it did throw, expect the error_code to be the same:
120 VERIFY( e.code() == ec );
121 VERIFY( e.path1() == p );
641cb5a6 122 }
641cb5a6
JW
123#endif
124}
125
126bool approx_equal(time_type file_time, time_type expected)
127{
128 auto delta = expected - file_time;
129 if (delta < delta.zero())
130 delta = -delta;
a51a546c 131 return delta < chrono::seconds(1);
641cb5a6
JW
132}
133
134void
135test02()
136{
137 // write times
138
139 const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
140 __gnu_test::scoped_file f;
141 std::error_code ec;
142 time_type time;
143
641cb5a6 144 ec = bad_ec;
a51a546c 145 time = last_write_time(f.path);
641cb5a6
JW
146 last_write_time(f.path, time, ec);
147 VERIFY( !ec );
148 VERIFY( approx_equal(last_write_time(f.path), time) );
149
150 ec = bad_ec;
a51a546c 151 time -= chrono::milliseconds(1000 * 60 * 10 + 15);
641cb5a6
JW
152 last_write_time(f.path, time, ec);
153 VERIFY( !ec );
154 VERIFY( approx_equal(last_write_time(f.path), time) );
155
156 ec = bad_ec;
a51a546c 157 time += chrono::milliseconds(1000 * 60 * 20 + 15);
641cb5a6
JW
158 last_write_time(f.path, time, ec);
159 VERIFY( !ec );
160 VERIFY( approx_equal(last_write_time(f.path), time) );
161
174f1d26
JW
162 if (std::numeric_limits<std::time_t>::max()
163 < std::numeric_limits<std::int64_t>::max())
164 return; // file clock's epoch is out of range for 32-bit time_t
165
a51a546c
JW
166 using sys_time_32b
167 = chrono::time_point<chrono::system_clock, chrono::duration<std::int32_t>>;
168 auto duration_until_2038 = sys_time_32b::max() - sys_time_32b::clock::now();
169 auto file_time_2038 = time_type::clock::now() + duration_until_2038;
170
171 ec = bad_ec;
172 time = file_time_2038 - chrono::seconds(1);
173 // Assume all filesystems can store times that fit in 32-bit time_t
174 // (i.e. up to Jan 19 2038)
175 last_write_time(f.path, time, ec);
176 VERIFY( !ec );
177 VERIFY( approx_equal(last_write_time(f.path), time) );
178
179 // Check whether the filesystem supports times larger than 32-bit time_t:
180 time += chrono::seconds(60);
181 last_write_time(f.path, time, ec);
182 if (ec || !approx_equal(last_write_time(f.path), time))
183 {
184 puts("Filesystem seems to truncate times past Jan 19 2038, giving up.");
185 return; // Tests below will fail on this filesystem
186 }
187
641cb5a6 188 ec = bad_ec;
174f1d26 189 // The file clock's epoch:
641cb5a6
JW
190 time = time_type();
191 last_write_time(f.path, time, ec);
192 VERIFY( !ec );
193 VERIFY( approx_equal(last_write_time(f.path), time) );
194
195 ec = bad_ec;
174f1d26 196 // A time after the epoch
a51a546c 197 time += chrono::milliseconds(1000 * 60 * 10 + 15);
174f1d26
JW
198 last_write_time(f.path, time, ec);
199 VERIFY( !ec );
200 VERIFY( approx_equal(last_write_time(f.path), time) );
201
202 ec = bad_ec;
203 // A time before than the epoch
a51a546c 204 time -= chrono::milliseconds(1000 * 60 * 20 + 15);
641cb5a6
JW
205 last_write_time(f.path, time, ec);
206 VERIFY( !ec );
207 VERIFY( approx_equal(last_write_time(f.path), time) );
208}
209
210int
211main()
212{
213 test01();
214 test02();
215}