blob: d504e3c6989cf00f308843e90e8b80812c189d59 [file] [log] [blame]
Elliott Hughesd0be7c82013-08-08 17:13:33 -07001/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Elliott Hughesd0be7c82013-08-08 17:13:33 -070017#include <errno.h>
Elliott Hughesdb1ea342014-01-17 18:42:49 -080018#include <fcntl.h>
Elliott Hughesd0be7c82013-08-08 17:13:33 -070019#include <stdlib.h>
20#include <sys/stat.h>
21
Mark Salyzyn68a3bcc2018-11-13 07:35:21 -080022#include <android-base/file.h>
23#include <gtest/gtest.h>
Elliott Hughes594b1a42013-10-22 10:54:11 -070024
Elliott Hughes95646e62023-09-21 14:11:19 -070025#include "utils.h"
26
Elliott Hughes733cedd2020-02-21 23:21:28 -080027#if defined(__BIONIC__)
28#define HAVE_STATX
29#elif defined(__GLIBC_PREREQ)
30#if __GLIBC_PREREQ(2, 28)
31#define HAVE_STATX
32#endif
33#endif
34
Elliott Hughesd0be7c82013-08-08 17:13:33 -070035TEST(sys_stat, futimens) {
Elliott Hughes201fe932025-05-09 13:54:37 -070036 TemporaryFile tf;
Elliott Hughesd0be7c82013-08-08 17:13:33 -070037
38 timespec times[2];
39 times[0].tv_sec = 123;
40 times[0].tv_nsec = 0;
41 times[1].tv_sec = 456;
42 times[1].tv_nsec = 0;
Elliott Hughes201fe932025-05-09 13:54:37 -070043 ASSERT_EQ(0, futimens(tf.fd, times)) << strerror(errno);
Elliott Hughesd0be7c82013-08-08 17:13:33 -070044
45 struct stat sb;
Elliott Hughes201fe932025-05-09 13:54:37 -070046 ASSERT_EQ(0, fstat(tf.fd, &sb));
Elliott Hughesd0be7c82013-08-08 17:13:33 -070047 ASSERT_EQ(times[0].tv_sec, static_cast<long>(sb.st_atime));
48 ASSERT_EQ(times[1].tv_sec, static_cast<long>(sb.st_mtime));
Elliott Hughes201fe932025-05-09 13:54:37 -070049}
Elliott Hughesd0be7c82013-08-08 17:13:33 -070050
Elliott Hughes201fe932025-05-09 13:54:37 -070051TEST(sys_stat, futimens_null) {
52 TemporaryFile tf;
53 ASSERT_EQ(0, futimens(tf.fd, nullptr));
Elliott Hughesd0be7c82013-08-08 17:13:33 -070054}
55
56TEST(sys_stat, futimens_EBADF) {
57 timespec times[2];
58 times[0].tv_sec = 123;
59 times[0].tv_nsec = 0;
60 times[1].tv_sec = 456;
61 times[1].tv_nsec = 0;
62 ASSERT_EQ(-1, futimens(-1, times));
Elliott Hughes95646e62023-09-21 14:11:19 -070063 ASSERT_ERRNO(EBADF);
Elliott Hughesd0be7c82013-08-08 17:13:33 -070064}
Elliott Hughes594b1a42013-10-22 10:54:11 -070065
Elliott Hughes201fe932025-05-09 13:54:37 -070066TEST(sys_stat, utimensat) {
67 TemporaryFile tf;
68
69 timespec times[2];
70 times[0].tv_sec = 123;
71 times[0].tv_nsec = 0;
72 times[1].tv_sec = 456;
73 times[1].tv_nsec = 0;
74 ASSERT_EQ(0, utimensat(AT_FDCWD, tf.path, times, 0)) << strerror(errno);
75
76 struct stat sb;
77 ASSERT_EQ(0, fstat(tf.fd, &sb));
78 ASSERT_EQ(times[0].tv_sec, static_cast<long>(sb.st_atime));
79 ASSERT_EQ(times[1].tv_sec, static_cast<long>(sb.st_mtime));
80}
81
82TEST(sys_stat, utimensat_null) {
83 TemporaryFile tf;
84 ASSERT_EQ(0, utimensat(AT_FDCWD, tf.path, nullptr, 0));
85}
86
Elliott Hughesca8e84c2014-10-23 19:10:23 -070087TEST(sys_stat, mkfifo_failure) {
88 errno = 0;
89 ASSERT_EQ(-1, mkfifo("/", 0666));
Elliott Hughes95646e62023-09-21 14:11:19 -070090 ASSERT_ERRNO(EEXIST);
Elliott Hughesca8e84c2014-10-23 19:10:23 -070091}
92
93TEST(sys_stat, mkfifoat_failure) {
94 errno = 0;
95 ASSERT_EQ(-1, mkfifoat(-2, "x", 0666));
Elliott Hughes95646e62023-09-21 14:11:19 -070096 ASSERT_ERRNO(EBADF);
Elliott Hughesca8e84c2014-10-23 19:10:23 -070097}
98
Elliott Hughes594b1a42013-10-22 10:54:11 -070099TEST(sys_stat, mkfifo) {
Christopher Ferris528ad742014-09-24 16:01:18 -0700100 if (getuid() == 0) {
101 // Racy but probably sufficient way to get a suitable filename.
102 std::string path;
103 {
104 TemporaryFile tf;
Mark Salyzyn68a3bcc2018-11-13 07:35:21 -0800105 path = tf.path;
Christopher Ferris528ad742014-09-24 16:01:18 -0700106 }
Elliott Hughes594b1a42013-10-22 10:54:11 -0700107
Christopher Ferris528ad742014-09-24 16:01:18 -0700108 ASSERT_EQ(0, mkfifo(path.c_str(), 0666));
109 struct stat sb;
110 ASSERT_EQ(0, stat(path.c_str(), &sb));
111 ASSERT_TRUE(S_ISFIFO(sb.st_mode));
112 unlink(path.c_str());
113 } else {
Elliott Hughesca8e84c2014-10-23 19:10:23 -0700114 // SELinux policy forbids us from creating FIFOs. http://b/17646702.
Elliott Hughesbcaa4542019-03-08 15:20:23 -0800115 GTEST_SKIP() << "SELinux policy forbids non-root from creating FIFOs";
Christopher Ferris528ad742014-09-24 16:01:18 -0700116 }
Elliott Hughes594b1a42013-10-22 10:54:11 -0700117}
Elliott Hughesdb1ea342014-01-17 18:42:49 -0800118
119TEST(sys_stat, stat64_lstat64_fstat64) {
120 struct stat64 sb;
121 ASSERT_EQ(0, stat64("/proc/version", &sb));
122 ASSERT_EQ(0, lstat64("/proc/version", &sb));
123 int fd = open("/proc/version", O_RDONLY);
124 ASSERT_EQ(0, fstat64(fd, &sb));
125 close(fd);
126}
Nick Kralevich3cbc6c62015-01-31 19:57:46 -0800127
Elliott Hughes733cedd2020-02-21 23:21:28 -0800128TEST(sys_stat, statx) {
129#if defined(HAVE_STATX)
130 struct statx sx;
131 int rc = statx(AT_FDCWD, "/proc/version", AT_STATX_SYNC_AS_STAT, STATX_ALL, &sx);
Elliott Hughes4ae4be92023-09-22 17:15:25 -0700132 if (rc == -1 && errno == ENOSYS) GTEST_SKIP() << "no statx() in this kernel";
Elliott Hughes733cedd2020-02-21 23:21:28 -0800133 ASSERT_EQ(0, rc);
134 struct stat64 sb;
135 ASSERT_EQ(0, stat64("/proc/version", &sb));
136 EXPECT_EQ(sb.st_ino, sx.stx_ino);
137 EXPECT_EQ(sb.st_mode, sx.stx_mode);
138#else
139 GTEST_SKIP() << "statx not available";
140#endif
141}
142
Elliott Hughesdb6223f2021-03-08 14:10:46 -0800143TEST(sys_stat, fchmod_EBADF) {
144 ASSERT_EQ(-1, fchmod(-1, 0751));
Elliott Hughes95646e62023-09-21 14:11:19 -0700145 ASSERT_ERRNO(EBADF);
Elliott Hughesdb6223f2021-03-08 14:10:46 -0800146}
147
Nick Kralevich3cbc6c62015-01-31 19:57:46 -0800148TEST(sys_stat, fchmodat_EFAULT_file) {
149 ASSERT_EQ(-1, fchmodat(AT_FDCWD, (char *) 0x1, 0751, 0));
Elliott Hughes95646e62023-09-21 14:11:19 -0700150 ASSERT_ERRNO(EFAULT);
Nick Kralevich3cbc6c62015-01-31 19:57:46 -0800151}
152
153TEST(sys_stat, fchmodat_AT_SYMLINK_NOFOLLOW_EFAULT_file) {
154 ASSERT_EQ(-1, fchmodat(AT_FDCWD, (char *) 0x1, 0751, AT_SYMLINK_NOFOLLOW));
155#if defined(__BIONIC__)
Elliott Hughes95646e62023-09-21 14:11:19 -0700156 ASSERT_ERRNO(EFAULT);
Nick Kralevich3cbc6c62015-01-31 19:57:46 -0800157#else
158 // glibc 2.19 does not implement AT_SYMLINK_NOFOLLOW and always
159 // returns ENOTSUP
Elliott Hughes95646e62023-09-21 14:11:19 -0700160 ASSERT_ERRNO(ENOTSUP);
Nick Kralevich3cbc6c62015-01-31 19:57:46 -0800161#endif
162}
163
164TEST(sys_stat, fchmodat_bad_flags) {
165 ASSERT_EQ(-1, fchmodat(AT_FDCWD, "/blah", 0751, ~AT_SYMLINK_NOFOLLOW));
Elliott Hughes95646e62023-09-21 14:11:19 -0700166 ASSERT_ERRNO(EINVAL);
Nick Kralevich3cbc6c62015-01-31 19:57:46 -0800167}
168
169TEST(sys_stat, fchmodat_bad_flags_ALL) {
170 ASSERT_EQ(-1, fchmodat(AT_FDCWD, "/blah", 0751, ~0));
Elliott Hughes95646e62023-09-21 14:11:19 -0700171 ASSERT_ERRNO(EINVAL);
Nick Kralevich3cbc6c62015-01-31 19:57:46 -0800172}
173
Elliott Hughes219e6022024-08-27 19:12:08 +0000174TEST(sys_stat, fchmodat_nonexistent_file) {
Nick Kralevich3cbc6c62015-01-31 19:57:46 -0800175 ASSERT_EQ(-1, fchmodat(AT_FDCWD, "/blah", 0751, 0));
Elliott Hughes95646e62023-09-21 14:11:19 -0700176 ASSERT_ERRNO(ENOENT);
Nick Kralevich3cbc6c62015-01-31 19:57:46 -0800177}
178
Elliott Hughes219e6022024-08-27 19:12:08 +0000179TEST(sys_stat, fchmodat_AT_SYMLINK_NOFOLLOW_nonexistent_file) {
Nick Kralevich3cbc6c62015-01-31 19:57:46 -0800180 ASSERT_EQ(-1, fchmodat(AT_FDCWD, "/blah", 0751, AT_SYMLINK_NOFOLLOW));
181#if defined(__BIONIC__)
Elliott Hughes95646e62023-09-21 14:11:19 -0700182 ASSERT_ERRNO(ENOENT);
Nick Kralevich3cbc6c62015-01-31 19:57:46 -0800183#else
184 // glibc 2.19 does not implement AT_SYMLINK_NOFOLLOW and always
185 // returns ENOTSUP
Elliott Hughes95646e62023-09-21 14:11:19 -0700186 ASSERT_ERRNO(ENOTSUP);
Nick Kralevich3cbc6c62015-01-31 19:57:46 -0800187#endif
188}
189
Yabin Cuic6e58742015-03-09 13:55:18 -0700190static void AssertFileModeEquals(mode_t expected_mode, const char* filename) {
191 struct stat sb;
192 ASSERT_EQ(0, stat(filename, &sb));
193 mode_t mask = S_IRWXU | S_IRWXG | S_IRWXO;
194 ASSERT_EQ(expected_mode & mask, static_cast<mode_t>(sb.st_mode) & mask);
195}
196
Nick Kralevich3cbc6c62015-01-31 19:57:46 -0800197TEST(sys_stat, fchmodat_file) {
198 TemporaryFile tf;
Nick Kralevich3cbc6c62015-01-31 19:57:46 -0800199
Mark Salyzyn68a3bcc2018-11-13 07:35:21 -0800200 ASSERT_EQ(0, fchmodat(AT_FDCWD, tf.path, 0751, 0));
201 AssertFileModeEquals(0751, tf.path);
Nick Kralevich3cbc6c62015-01-31 19:57:46 -0800202}
203
204TEST(sys_stat, fchmodat_AT_SYMLINK_NOFOLLOW_file) {
205 TemporaryFile tf;
206 errno = 0;
Mark Salyzyn68a3bcc2018-11-13 07:35:21 -0800207 int result = fchmodat(AT_FDCWD, tf.path, 0751, AT_SYMLINK_NOFOLLOW);
Nick Kralevich3cbc6c62015-01-31 19:57:46 -0800208
209#if defined(__BIONIC__)
Nick Kralevich3cbc6c62015-01-31 19:57:46 -0800210 ASSERT_EQ(0, result);
Elliott Hughes95646e62023-09-21 14:11:19 -0700211 ASSERT_ERRNO(0);
Mark Salyzyn68a3bcc2018-11-13 07:35:21 -0800212 AssertFileModeEquals(0751, tf.path);
Nick Kralevich3cbc6c62015-01-31 19:57:46 -0800213#else
214 // glibc 2.19 does not implement AT_SYMLINK_NOFOLLOW and always
215 // returns ENOTSUP
216 ASSERT_EQ(-1, result);
Elliott Hughes95646e62023-09-21 14:11:19 -0700217 ASSERT_ERRNO(ENOTSUP);
Nick Kralevich3cbc6c62015-01-31 19:57:46 -0800218#endif
219}
220
221TEST(sys_stat, fchmodat_symlink) {
222 TemporaryFile tf;
223 char linkname[255];
Nick Kralevich3cbc6c62015-01-31 19:57:46 -0800224
Mark Salyzyn68a3bcc2018-11-13 07:35:21 -0800225 snprintf(linkname, sizeof(linkname), "%s.link", tf.path);
Nick Kralevich3cbc6c62015-01-31 19:57:46 -0800226
Mark Salyzyn68a3bcc2018-11-13 07:35:21 -0800227 ASSERT_EQ(0, symlink(tf.path, linkname));
Nick Kralevich3cbc6c62015-01-31 19:57:46 -0800228 ASSERT_EQ(0, fchmodat(AT_FDCWD, linkname, 0751, 0));
Mark Salyzyn68a3bcc2018-11-13 07:35:21 -0800229 AssertFileModeEquals(0751, tf.path);
Nick Kralevich3cbc6c62015-01-31 19:57:46 -0800230 unlink(linkname);
231}
232
233TEST(sys_stat, fchmodat_dangling_symlink) {
234 TemporaryFile tf;
235 char linkname[255];
236 char target[255];
237
Mark Salyzyn68a3bcc2018-11-13 07:35:21 -0800238 snprintf(linkname, sizeof(linkname), "%s.link", tf.path);
239 snprintf(target, sizeof(target), "%s.doesnotexist", tf.path);
Nick Kralevich3cbc6c62015-01-31 19:57:46 -0800240
241 ASSERT_EQ(0, symlink(target, linkname));
242 ASSERT_EQ(-1, fchmodat(AT_FDCWD, linkname, 0751, 0));
Elliott Hughes95646e62023-09-21 14:11:19 -0700243 ASSERT_ERRNO(ENOENT);
Nick Kralevich3cbc6c62015-01-31 19:57:46 -0800244 unlink(linkname);
245}
246
Yabin Cuic6e58742015-03-09 13:55:18 -0700247static void AssertSymlinkModeEquals(mode_t expected_mode, const char* linkname) {
248 struct stat sb;
249 ASSERT_EQ(0, fstatat(AT_FDCWD, linkname, &sb, AT_SYMLINK_NOFOLLOW));
250 mode_t mask = S_IRWXU | S_IRWXG | S_IRWXO;
251 ASSERT_EQ(expected_mode & mask, static_cast<mode_t>(sb.st_mode) & mask);
252}
253
Nick Kralevich3cbc6c62015-01-31 19:57:46 -0800254TEST(sys_stat, fchmodat_AT_SYMLINK_NOFOLLOW_with_symlink) {
255 TemporaryFile tf;
Yabin Cuic6e58742015-03-09 13:55:18 -0700256 struct stat tf_sb;
Mark Salyzyn68a3bcc2018-11-13 07:35:21 -0800257 ASSERT_EQ(0, stat(tf.path, &tf_sb));
Nick Kralevich3cbc6c62015-01-31 19:57:46 -0800258
Yabin Cuic6e58742015-03-09 13:55:18 -0700259 char linkname[255];
Mark Salyzyn68a3bcc2018-11-13 07:35:21 -0800260 snprintf(linkname, sizeof(linkname), "%s.link", tf.path);
Nick Kralevich3cbc6c62015-01-31 19:57:46 -0800261
Mark Salyzyn68a3bcc2018-11-13 07:35:21 -0800262 ASSERT_EQ(0, symlink(tf.path, linkname));
Yabin Cuic6e58742015-03-09 13:55:18 -0700263 int result = fchmodat(AT_FDCWD, linkname, 0751, AT_SYMLINK_NOFOLLOW);
264 // It depends on the kernel whether chmod operation on symlink is allowed.
265 if (result == 0) {
266 AssertSymlinkModeEquals(0751, linkname);
267 } else {
268 ASSERT_EQ(-1, result);
Elliott Hughes95646e62023-09-21 14:11:19 -0700269 ASSERT_ERRNO(ENOTSUP);
Yabin Cuic6e58742015-03-09 13:55:18 -0700270 }
271
272 // Target file mode shouldn't be modified.
Mark Salyzyn68a3bcc2018-11-13 07:35:21 -0800273 AssertFileModeEquals(tf_sb.st_mode, tf.path);
Nick Kralevich3cbc6c62015-01-31 19:57:46 -0800274 unlink(linkname);
275}
276
277TEST(sys_stat, fchmodat_AT_SYMLINK_NOFOLLOW_with_dangling_symlink) {
278 TemporaryFile tf;
Yabin Cuic6e58742015-03-09 13:55:18 -0700279
Nick Kralevich3cbc6c62015-01-31 19:57:46 -0800280 char linkname[255];
281 char target[255];
Mark Salyzyn68a3bcc2018-11-13 07:35:21 -0800282 snprintf(linkname, sizeof(linkname), "%s.link", tf.path);
283 snprintf(target, sizeof(target), "%s.doesnotexist", tf.path);
Nick Kralevich3cbc6c62015-01-31 19:57:46 -0800284
285 ASSERT_EQ(0, symlink(target, linkname));
Yabin Cuic6e58742015-03-09 13:55:18 -0700286 int result = fchmodat(AT_FDCWD, linkname, 0751, AT_SYMLINK_NOFOLLOW);
287 // It depends on the kernel whether chmod operation on symlink is allowed.
288 if (result == 0) {
289 AssertSymlinkModeEquals(0751, linkname);
290 } else {
291 ASSERT_EQ(-1, result);
Elliott Hughes95646e62023-09-21 14:11:19 -0700292 ASSERT_ERRNO(ENOTSUP);
Yabin Cuic6e58742015-03-09 13:55:18 -0700293 }
294
Nick Kralevich3cbc6c62015-01-31 19:57:46 -0800295 unlink(linkname);
296}
Nick Kralevich35778252015-02-24 13:40:43 -0800297
298TEST(sys_stat, faccessat_EINVAL) {
299 ASSERT_EQ(-1, faccessat(AT_FDCWD, "/dev/null", F_OK, ~AT_SYMLINK_NOFOLLOW));
Elliott Hughes95646e62023-09-21 14:11:19 -0700300 ASSERT_ERRNO(EINVAL);
Nick Kralevich35778252015-02-24 13:40:43 -0800301#if defined(__BIONIC__)
302 ASSERT_EQ(-1, faccessat(AT_FDCWD, "/dev/null", ~(R_OK | W_OK | X_OK), 0));
Elliott Hughes95646e62023-09-21 14:11:19 -0700303 ASSERT_ERRNO(EINVAL);
Nick Kralevich35778252015-02-24 13:40:43 -0800304#else
305 ASSERT_EQ(0, faccessat(AT_FDCWD, "/dev/null", ~(R_OK | W_OK | X_OK), AT_SYMLINK_NOFOLLOW));
306 ASSERT_EQ(-1, faccessat(AT_FDCWD, "/dev/null", ~(R_OK | W_OK | X_OK), 0));
Elliott Hughes95646e62023-09-21 14:11:19 -0700307 ASSERT_ERRNO(EINVAL);
Nick Kralevich35778252015-02-24 13:40:43 -0800308#endif
309}
310
311TEST(sys_stat, faccessat_AT_SYMLINK_NOFOLLOW_EINVAL) {
312#if defined(__BIONIC__)
313 // Android doesn't support AT_SYMLINK_NOFOLLOW
314 ASSERT_EQ(-1, faccessat(AT_FDCWD, "/dev/null", F_OK, AT_SYMLINK_NOFOLLOW));
Elliott Hughes95646e62023-09-21 14:11:19 -0700315 ASSERT_ERRNO(EINVAL);
Nick Kralevich35778252015-02-24 13:40:43 -0800316#else
317 ASSERT_EQ(0, faccessat(AT_FDCWD, "/dev/null", F_OK, AT_SYMLINK_NOFOLLOW));
318#endif
319}
320
321TEST(sys_stat, faccessat_dev_null) {
322 ASSERT_EQ(0, faccessat(AT_FDCWD, "/dev/null", F_OK, 0));
323 ASSERT_EQ(0, faccessat(AT_FDCWD, "/dev/null", R_OK, 0));
324 ASSERT_EQ(0, faccessat(AT_FDCWD, "/dev/null", W_OK, 0));
325 ASSERT_EQ(0, faccessat(AT_FDCWD, "/dev/null", R_OK|W_OK, 0));
326}
327
Elliott Hughes219e6022024-08-27 19:12:08 +0000328TEST(sys_stat, faccessat_nonexistent) {
Nick Kralevich35778252015-02-24 13:40:43 -0800329 ASSERT_EQ(-1, faccessat(AT_FDCWD, "/blah", F_OK, AT_SYMLINK_NOFOLLOW));
330#if defined(__BIONIC__)
331 // Android doesn't support AT_SYMLINK_NOFOLLOW
Elliott Hughes95646e62023-09-21 14:11:19 -0700332 ASSERT_ERRNO(EINVAL);
Nick Kralevich35778252015-02-24 13:40:43 -0800333#else
Elliott Hughes95646e62023-09-21 14:11:19 -0700334 ASSERT_ERRNO(ENOENT);
Nick Kralevich35778252015-02-24 13:40:43 -0800335#endif
336}
Elliott Hughes219e6022024-08-27 19:12:08 +0000337
338TEST(sys_stat, lchmod) {
339 TemporaryFile tf;
340 struct stat tf_sb;
341 ASSERT_EQ(0, stat(tf.path, &tf_sb));
342
343 char linkname[255];
344 snprintf(linkname, sizeof(linkname), "%s.link", tf.path);
345
346 ASSERT_EQ(0, symlink(tf.path, linkname));
347 int result = lchmod(linkname, 0751);
348 // Whether or not chmod is allowed on a symlink depends on the kernel.
349 if (result == 0) {
350 AssertSymlinkModeEquals(0751, linkname);
351 } else {
352 ASSERT_EQ(-1, result);
353 ASSERT_ERRNO(ENOTSUP);
354 }
355
356 // The target file mode shouldn't be modified.
357 AssertFileModeEquals(tf_sb.st_mode, tf.path);
358 unlink(linkname);
359}