1 //===-- flang/unittests/Runtime/AccessTest.cpp ----------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // TODO: ACCESS is not yet implemented on Windows
12 #include "CrashHandlerFixture.h"
13 #include "gtest/gtest.h"
14 #include "flang/Runtime/extensions.h"
15 #include "llvm/ADT/Twine.h"
19 #include <sys/types.h>
24 struct AccessTests
: public CrashHandlerFixture
{};
35 static bool userSkipsPermissionChecks() {
36 // The tests in this file assume normal permission checks apply to the user
37 // running the tests. This isn't true when the test is run by root.
38 return geteuid() == 0;
41 static std::string
addPIDSuffix(const char *name
) {
51 static bool exists(const std::string
&path
) {
52 return access(path
.c_str(), F_OK
) == 0;
55 // Implementation of std::filesystem::temp_directory_path adapted from libcxx
56 // See llvm-project/libcxx/src/filesystem/operations.cpp
57 // Using std::filesystem is inconvenient because the required flags are not
58 // consistent accross compilers and CMake doesn't have built in support to
59 // determine the correct flags.
60 static const char *temp_directory_path() {
62 const char *env_paths
[] = {"TMPDIR", "TMP", "TEMP", "TEMPDIR"};
63 const char *ret
= nullptr;
65 for (auto &ep
: env_paths
) {
66 if ((ret
= getenv(ep
))) {
72 #if defined(__ANDROID__)
73 ret
= "/data/local/tmp";
83 static std::string
createTemporaryFile(
84 const char *name
, const AccessType
&accessType
) {
86 (llvm::Twine
{temp_directory_path()} + "/" + addPIDSuffix(name
)).str();
88 // O_CREAT | O_EXCL enforces that this file is newly created by this call.
89 // This feels risky. If we don't have permission to create files in the
90 // temporary directory or if the files already exist, the test will fail.
91 // But we can't use std::tmpfile() because we need a path to the file and
92 // to control the filesystem permissions
94 if (accessType
.read
) {
97 if (accessType
.write
) {
100 if (accessType
.execute
) {
104 int file
= open(path
.c_str(), O_CREAT
| O_EXCL
, mode
);
114 static std::int64_t callAccess(
115 const std::string
&path
, const AccessType
&accessType
) {
116 const char *cpath
{path
.c_str()};
117 std::int64_t pathlen
= std::strlen(cpath
);
120 if (accessType
.read
) {
123 if (accessType
.write
) {
126 if (accessType
.execute
) {
129 if (accessType
.exists
) {
133 const char *cmode
= mode
.c_str();
134 std::int64_t modelen
= std::strlen(cmode
);
136 return FORTRAN_PROCEDURE_NAME(access
)(cpath
, pathlen
, cmode
, modelen
);
139 TEST(AccessTests
, TestExists
) {
140 AccessType accessType
;
141 accessType
.exists
= true;
143 std::string path
= createTemporaryFile(__func__
, accessType
);
144 ASSERT_FALSE(path
.empty());
146 std::int64_t res
= callAccess(path
, accessType
);
148 ASSERT_EQ(unlink(path
.c_str()), 0);
153 TEST(AccessTests
, TestNotExists
) {
154 std::string nonExistant
{addPIDSuffix(__func__
)};
155 ASSERT_FALSE(exists(nonExistant
));
157 AccessType accessType
;
158 accessType
.exists
= true;
159 std::int64_t res
= callAccess(nonExistant
, accessType
);
164 TEST(AccessTests
, TestRead
) {
165 AccessType accessType
;
166 accessType
.read
= true;
168 std::string path
= createTemporaryFile(__func__
, accessType
);
169 ASSERT_FALSE(path
.empty());
171 std::int64_t res
= callAccess(path
, accessType
);
173 ASSERT_EQ(unlink(path
.c_str()), 0);
175 if (userSkipsPermissionChecks()) {
182 TEST(AccessTests
, TestNotRead
) {
183 AccessType accessType
;
184 accessType
.read
= false;
186 std::string path
= createTemporaryFile(__func__
, accessType
);
187 ASSERT_FALSE(path
.empty());
189 accessType
.read
= true;
190 std::int64_t res
= callAccess(path
, accessType
);
192 ASSERT_EQ(unlink(path
.c_str()), 0);
194 if (userSkipsPermissionChecks()) {
201 TEST(AccessTests
, TestWrite
) {
202 AccessType accessType
;
203 accessType
.write
= true;
205 std::string path
= createTemporaryFile(__func__
, accessType
);
206 ASSERT_FALSE(path
.empty());
208 std::int64_t res
= callAccess(path
, accessType
);
210 ASSERT_EQ(unlink(path
.c_str()), 0);
212 if (userSkipsPermissionChecks()) {
219 TEST(AccessTests
, TestNotWrite
) {
220 AccessType accessType
;
221 accessType
.write
= false;
223 std::string path
= createTemporaryFile(__func__
, accessType
);
224 ASSERT_FALSE(path
.empty());
226 accessType
.write
= true;
227 std::int64_t res
= callAccess(path
, accessType
);
229 ASSERT_EQ(unlink(path
.c_str()), 0);
231 if (userSkipsPermissionChecks()) {
238 TEST(AccessTests
, TestReadWrite
) {
239 AccessType accessType
;
240 accessType
.read
= true;
241 accessType
.write
= true;
243 std::string path
= createTemporaryFile(__func__
, accessType
);
244 ASSERT_FALSE(path
.empty());
246 std::int64_t res
= callAccess(path
, accessType
);
248 ASSERT_EQ(unlink(path
.c_str()), 0);
250 if (userSkipsPermissionChecks()) {
257 TEST(AccessTests
, TestNotReadWrite0
) {
258 AccessType accessType
;
259 accessType
.read
= false;
260 accessType
.write
= false;
262 std::string path
= createTemporaryFile(__func__
, accessType
);
263 ASSERT_FALSE(path
.empty());
265 accessType
.read
= true;
266 accessType
.write
= true;
267 std::int64_t res
= callAccess(path
, accessType
);
269 ASSERT_EQ(unlink(path
.c_str()), 0);
271 if (userSkipsPermissionChecks()) {
278 TEST(AccessTests
, TestNotReadWrite1
) {
279 AccessType accessType
;
280 accessType
.read
= true;
281 accessType
.write
= false;
283 std::string path
= createTemporaryFile(__func__
, accessType
);
284 ASSERT_FALSE(path
.empty());
286 accessType
.read
= true;
287 accessType
.write
= true;
288 std::int64_t res
= callAccess(path
, accessType
);
290 ASSERT_EQ(unlink(path
.c_str()), 0);
292 if (userSkipsPermissionChecks()) {
299 TEST(AccessTests
, TestNotReadWrite2
) {
300 AccessType accessType
;
301 accessType
.read
= false;
302 accessType
.write
= true;
304 std::string path
= createTemporaryFile(__func__
, accessType
);
305 ASSERT_FALSE(path
.empty());
307 accessType
.read
= true;
308 accessType
.write
= true;
309 std::int64_t res
= callAccess(path
, accessType
);
311 ASSERT_EQ(unlink(path
.c_str()), 0);
313 if (userSkipsPermissionChecks()) {
320 TEST(AccessTests
, TestExecute
) {
321 AccessType accessType
;
322 accessType
.execute
= true;
324 std::string path
= createTemporaryFile(__func__
, accessType
);
325 ASSERT_FALSE(path
.empty());
327 std::int64_t res
= callAccess(path
, accessType
);
329 ASSERT_EQ(unlink(path
.c_str()), 0);
331 if (userSkipsPermissionChecks()) {
338 TEST(AccessTests
, TestNotExecute
) {
339 AccessType accessType
;
340 accessType
.execute
= false;
342 std::string path
= createTemporaryFile(__func__
, accessType
);
343 ASSERT_FALSE(path
.empty());
345 accessType
.execute
= true;
346 std::int64_t res
= callAccess(path
, accessType
);
348 ASSERT_EQ(unlink(path
.c_str()), 0);
350 if (userSkipsPermissionChecks()) {
357 TEST(AccessTests
, TestRWX
) {
358 AccessType accessType
;
359 accessType
.read
= true;
360 accessType
.write
= true;
361 accessType
.execute
= true;
363 std::string path
= createTemporaryFile(__func__
, accessType
);
364 ASSERT_FALSE(path
.empty());
366 std::int64_t res
= callAccess(path
, accessType
);
368 ASSERT_EQ(unlink(path
.c_str()), 0);
370 if (userSkipsPermissionChecks()) {
377 TEST(AccessTests
, TestNotRWX0
) {
378 AccessType accessType
;
379 accessType
.read
= false;
380 accessType
.write
= false;
381 accessType
.execute
= false;
383 std::string path
= createTemporaryFile(__func__
, accessType
);
384 ASSERT_FALSE(path
.empty());
386 accessType
.read
= true;
387 accessType
.write
= true;
388 accessType
.execute
= true;
389 std::int64_t res
= callAccess(path
, accessType
);
391 ASSERT_EQ(unlink(path
.c_str()), 0);
393 if (userSkipsPermissionChecks()) {
400 TEST(AccessTests
, TestNotRWX1
) {
401 AccessType accessType
;
402 accessType
.read
= true;
403 accessType
.write
= false;
404 accessType
.execute
= false;
406 std::string path
= createTemporaryFile(__func__
, accessType
);
407 ASSERT_FALSE(path
.empty());
409 accessType
.read
= true;
410 accessType
.write
= true;
411 accessType
.execute
= true;
412 std::int64_t res
= callAccess(path
, accessType
);
414 ASSERT_EQ(unlink(path
.c_str()), 0);
416 if (userSkipsPermissionChecks()) {
423 TEST(AccessTests
, TestNotRWX2
) {
424 AccessType accessType
;
425 accessType
.read
= true;
426 accessType
.write
= true;
427 accessType
.execute
= false;
429 std::string path
= createTemporaryFile(__func__
, accessType
);
430 ASSERT_FALSE(path
.empty());
432 accessType
.read
= true;
433 accessType
.write
= true;
434 accessType
.execute
= true;
435 std::int64_t res
= callAccess(path
, accessType
);
437 ASSERT_EQ(unlink(path
.c_str()), 0);
439 if (userSkipsPermissionChecks()) {
446 TEST(AccessTests
, TestNotRWX3
) {
447 AccessType accessType
;
448 accessType
.read
= true;
449 accessType
.write
= false;
450 accessType
.execute
= true;
452 std::string path
= createTemporaryFile(__func__
, accessType
);
453 ASSERT_FALSE(path
.empty());
455 accessType
.read
= true;
456 accessType
.write
= true;
457 accessType
.execute
= true;
458 std::int64_t res
= callAccess(path
, accessType
);
460 ASSERT_EQ(unlink(path
.c_str()), 0);
462 if (userSkipsPermissionChecks()) {
469 TEST(AccessTests
, TestNotRWX4
) {
470 AccessType accessType
;
471 accessType
.read
= false;
472 accessType
.write
= true;
473 accessType
.execute
= true;
475 std::string path
= createTemporaryFile(__func__
, accessType
);
476 ASSERT_FALSE(path
.empty());
478 accessType
.read
= true;
479 accessType
.write
= true;
480 accessType
.execute
= true;
481 std::int64_t res
= callAccess(path
, accessType
);
483 ASSERT_EQ(unlink(path
.c_str()), 0);
485 if (userSkipsPermissionChecks()) {