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 std::string
addPIDSuffix(const char *name
) {
45 static bool exists(const std::string
&path
) {
46 return access(path
.c_str(), F_OK
) == 0;
49 // Implementation of std::filesystem::temp_directory_path adapted from libcxx
50 // See llvm-project/libcxx/src/filesystem/operations.cpp
51 // Using std::filesystem is inconvenient because the required flags are not
52 // consistent accross compilers and CMake doesn't have built in support to
53 // determine the correct flags.
54 static const char *temp_directory_path() {
56 const char *env_paths
[] = {"TMPDIR", "TMP", "TEMP", "TEMPDIR"};
57 const char *ret
= nullptr;
59 for (auto &ep
: env_paths
) {
60 if ((ret
= getenv(ep
))) {
66 #if defined(__ANDROID__)
67 ret
= "/data/local/tmp";
77 static std::string
createTemporaryFile(
78 const char *name
, const AccessType
&accessType
) {
80 (llvm::Twine
{temp_directory_path()} + "/" + addPIDSuffix(name
)).str();
82 // O_CREAT | O_EXCL enforces that this file is newly created by this call.
83 // This feels risky. If we don't have permission to create files in the
84 // temporary directory or if the files already exist, the test will fail.
85 // But we can't use std::tmpfile() because we need a path to the file and
86 // to control the filesystem permissions
88 if (accessType
.read
) {
91 if (accessType
.write
) {
94 if (accessType
.execute
) {
98 int file
= open(path
.c_str(), O_CREAT
| O_EXCL
, mode
);
108 static std::int64_t callAccess(
109 const std::string
&path
, const AccessType
&accessType
) {
110 const char *cpath
{path
.c_str()};
111 std::int64_t pathlen
= std::strlen(cpath
);
114 if (accessType
.read
) {
117 if (accessType
.write
) {
120 if (accessType
.execute
) {
123 if (accessType
.exists
) {
127 const char *cmode
= mode
.c_str();
128 std::int64_t modelen
= std::strlen(cmode
);
130 return FORTRAN_PROCEDURE_NAME(access
)(cpath
, pathlen
, cmode
, modelen
);
133 TEST(AccessTests
, TestExists
) {
134 AccessType accessType
;
135 accessType
.exists
= true;
137 std::string path
= createTemporaryFile(__func__
, accessType
);
138 ASSERT_FALSE(path
.empty());
140 std::int64_t res
= callAccess(path
, accessType
);
142 ASSERT_EQ(unlink(path
.c_str()), 0);
147 TEST(AccessTests
, TestNotExists
) {
148 std::string nonExistant
{addPIDSuffix(__func__
)};
149 ASSERT_FALSE(exists(nonExistant
));
151 AccessType accessType
;
152 accessType
.exists
= true;
153 std::int64_t res
= callAccess(nonExistant
, accessType
);
158 TEST(AccessTests
, TestRead
) {
159 AccessType accessType
;
160 accessType
.read
= true;
162 std::string path
= createTemporaryFile(__func__
, accessType
);
163 ASSERT_FALSE(path
.empty());
165 std::int64_t res
= callAccess(path
, accessType
);
167 ASSERT_EQ(unlink(path
.c_str()), 0);
172 TEST(AccessTests
, TestNotRead
) {
173 AccessType accessType
;
174 accessType
.read
= false;
176 std::string path
= createTemporaryFile(__func__
, accessType
);
177 ASSERT_FALSE(path
.empty());
179 accessType
.read
= true;
180 std::int64_t res
= callAccess(path
, accessType
);
182 ASSERT_EQ(unlink(path
.c_str()), 0);
187 TEST(AccessTests
, TestWrite
) {
188 AccessType accessType
;
189 accessType
.write
= true;
191 std::string path
= createTemporaryFile(__func__
, accessType
);
192 ASSERT_FALSE(path
.empty());
194 std::int64_t res
= callAccess(path
, accessType
);
196 ASSERT_EQ(unlink(path
.c_str()), 0);
201 TEST(AccessTests
, TestNotWrite
) {
202 AccessType accessType
;
203 accessType
.write
= false;
205 std::string path
= createTemporaryFile(__func__
, accessType
);
206 ASSERT_FALSE(path
.empty());
208 accessType
.write
= true;
209 std::int64_t res
= callAccess(path
, accessType
);
211 ASSERT_EQ(unlink(path
.c_str()), 0);
216 TEST(AccessTests
, TestReadWrite
) {
217 AccessType accessType
;
218 accessType
.read
= true;
219 accessType
.write
= true;
221 std::string path
= createTemporaryFile(__func__
, accessType
);
222 ASSERT_FALSE(path
.empty());
224 std::int64_t res
= callAccess(path
, accessType
);
226 ASSERT_EQ(unlink(path
.c_str()), 0);
231 TEST(AccessTests
, TestNotReadWrite0
) {
232 AccessType accessType
;
233 accessType
.read
= false;
234 accessType
.write
= false;
236 std::string path
= createTemporaryFile(__func__
, accessType
);
237 ASSERT_FALSE(path
.empty());
239 accessType
.read
= true;
240 accessType
.write
= true;
241 std::int64_t res
= callAccess(path
, accessType
);
243 ASSERT_EQ(unlink(path
.c_str()), 0);
248 TEST(AccessTests
, TestNotReadWrite1
) {
249 AccessType accessType
;
250 accessType
.read
= true;
251 accessType
.write
= false;
253 std::string path
= createTemporaryFile(__func__
, accessType
);
254 ASSERT_FALSE(path
.empty());
256 accessType
.read
= true;
257 accessType
.write
= true;
258 std::int64_t res
= callAccess(path
, accessType
);
260 ASSERT_EQ(unlink(path
.c_str()), 0);
265 TEST(AccessTests
, TestNotReadWrite2
) {
266 AccessType accessType
;
267 accessType
.read
= false;
268 accessType
.write
= true;
270 std::string path
= createTemporaryFile(__func__
, accessType
);
271 ASSERT_FALSE(path
.empty());
273 accessType
.read
= true;
274 accessType
.write
= true;
275 std::int64_t res
= callAccess(path
, accessType
);
277 ASSERT_EQ(unlink(path
.c_str()), 0);
282 TEST(AccessTests
, TestExecute
) {
283 AccessType accessType
;
284 accessType
.execute
= true;
286 std::string path
= createTemporaryFile(__func__
, accessType
);
287 ASSERT_FALSE(path
.empty());
289 std::int64_t res
= callAccess(path
, accessType
);
291 ASSERT_EQ(unlink(path
.c_str()), 0);
296 TEST(AccessTests
, TestNotExecute
) {
297 AccessType accessType
;
298 accessType
.execute
= false;
300 std::string path
= createTemporaryFile(__func__
, accessType
);
301 ASSERT_FALSE(path
.empty());
303 accessType
.execute
= true;
304 std::int64_t res
= callAccess(path
, accessType
);
306 ASSERT_EQ(unlink(path
.c_str()), 0);
311 TEST(AccessTests
, TestRWX
) {
312 AccessType accessType
;
313 accessType
.read
= true;
314 accessType
.write
= true;
315 accessType
.execute
= true;
317 std::string path
= createTemporaryFile(__func__
, accessType
);
318 ASSERT_FALSE(path
.empty());
320 std::int64_t res
= callAccess(path
, accessType
);
322 ASSERT_EQ(unlink(path
.c_str()), 0);
327 TEST(AccessTests
, TestNotRWX0
) {
328 AccessType accessType
;
329 accessType
.read
= false;
330 accessType
.write
= false;
331 accessType
.execute
= false;
333 std::string path
= createTemporaryFile(__func__
, accessType
);
334 ASSERT_FALSE(path
.empty());
336 accessType
.read
= true;
337 accessType
.write
= true;
338 accessType
.execute
= true;
339 std::int64_t res
= callAccess(path
, accessType
);
341 ASSERT_EQ(unlink(path
.c_str()), 0);
346 TEST(AccessTests
, TestNotRWX1
) {
347 AccessType accessType
;
348 accessType
.read
= true;
349 accessType
.write
= false;
350 accessType
.execute
= false;
352 std::string path
= createTemporaryFile(__func__
, accessType
);
353 ASSERT_FALSE(path
.empty());
355 accessType
.read
= true;
356 accessType
.write
= true;
357 accessType
.execute
= true;
358 std::int64_t res
= callAccess(path
, accessType
);
360 ASSERT_EQ(unlink(path
.c_str()), 0);
365 TEST(AccessTests
, TestNotRWX2
) {
366 AccessType accessType
;
367 accessType
.read
= true;
368 accessType
.write
= true;
369 accessType
.execute
= false;
371 std::string path
= createTemporaryFile(__func__
, accessType
);
372 ASSERT_FALSE(path
.empty());
374 accessType
.read
= true;
375 accessType
.write
= true;
376 accessType
.execute
= true;
377 std::int64_t res
= callAccess(path
, accessType
);
379 ASSERT_EQ(unlink(path
.c_str()), 0);
384 TEST(AccessTests
, TestNotRWX3
) {
385 AccessType accessType
;
386 accessType
.read
= true;
387 accessType
.write
= false;
388 accessType
.execute
= true;
390 std::string path
= createTemporaryFile(__func__
, accessType
);
391 ASSERT_FALSE(path
.empty());
393 accessType
.read
= true;
394 accessType
.write
= true;
395 accessType
.execute
= true;
396 std::int64_t res
= callAccess(path
, accessType
);
398 ASSERT_EQ(unlink(path
.c_str()), 0);
403 TEST(AccessTests
, TestNotRWX4
) {
404 AccessType accessType
;
405 accessType
.read
= false;
406 accessType
.write
= true;
407 accessType
.execute
= true;
409 std::string path
= createTemporaryFile(__func__
, accessType
);
410 ASSERT_FALSE(path
.empty());
412 accessType
.read
= true;
413 accessType
.write
= true;
414 accessType
.execute
= true;
415 std::int64_t res
= callAccess(path
, accessType
);
417 ASSERT_EQ(unlink(path
.c_str()), 0);