brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.5 KiB · d44f0ec Raw
494 lines · cpp
1//===-- unittests/Runtime/AccessTest.cpp ------------------------*- C++ -*-===//2//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-exception6//7//===----------------------------------------------------------------------===//8 9// TODO: ACCESS is not yet implemented on Windows10#ifndef _WIN3211 12#include "CrashHandlerFixture.h"13#include "gtest/gtest.h"14#include "flang/Runtime/extensions.h"15 16#include <cstring>17#include <fcntl.h>18#include <sys/stat.h>19#include <sys/types.h>20#include <unistd.h>21 22namespace {23 24struct AccessTests : public CrashHandlerFixture {};25 26struct AccessType {27  bool read{false};28  bool write{false};29  bool execute{false};30  bool exists{false};31};32 33} // namespace34 35static bool userSkipsPermissionChecks() {36  // The tests in this file assume normal permission checks apply to the user37  // running the tests. This isn't true when the test is run by root.38  return geteuid() == 0;39}40 41static std::string addPIDSuffix(const char *name) {42  std::stringstream ss;43  ss << name;44  ss << '.';45 46  ss << getpid();47 48  return ss.str();49}50 51static bool exists(const std::string &path) {52  return access(path.c_str(), F_OK) == 0;53}54 55// Implementation of std::filesystem::temp_directory_path adapted from libcxx56// See llvm-project/libcxx/src/filesystem/operations.cpp57// Using std::filesystem is inconvenient because the required flags are not58// consistent accross compilers and CMake doesn't have built in support to59// determine the correct flags.60static const char *temp_directory_path() {61  // TODO: Windows62  const char *env_paths[] = {"TMPDIR", "TMP", "TEMP", "TEMPDIR"};63  const char *ret = nullptr;64 65  for (auto &ep : env_paths) {66    if ((ret = getenv(ep))) {67      break;68    }69  }70 71  if (ret == nullptr) {72#if defined(__ANDROID__)73    ret = "/data/local/tmp";74#else75    ret = "/tmp";76#endif77  }78 79  assert(exists(ret));80  return ret;81}82 83static std::string createTemporaryFile(84    const char *name, const AccessType &accessType) {85  std::ostringstream pathS;86  pathS << temp_directory_path() << "/" << addPIDSuffix(name);87  std::string path = pathS.str();88 89  // O_CREAT | O_EXCL enforces that this file is newly created by this call.90  // This feels risky. If we don't have permission to create files in the91  // temporary directory or if the files already exist, the test will fail.92  // But we can't use std::tmpfile() because we need a path to the file and93  // to control the filesystem permissions94  mode_t mode{0};95  if (accessType.read) {96    mode |= S_IRUSR;97  }98  if (accessType.write) {99    mode |= S_IWUSR;100  }101  if (accessType.execute) {102    mode |= S_IXUSR;103  }104 105  int file = open(path.c_str(), O_CREAT | O_EXCL, mode);106  if (file == -1) {107    return {};108  }109 110  close(file);111 112  return path;113}114 115static std::int64_t callAccess(116    const std::string &path, const AccessType &accessType) {117  const char *cpath{path.c_str()};118  std::int64_t pathlen = std::strlen(cpath);119 120  std::string mode;121  if (accessType.read) {122    mode += 'r';123  }124  if (accessType.write) {125    mode += 'w';126  }127  if (accessType.execute) {128    mode += 'x';129  }130  if (accessType.exists) {131    mode += ' ';132  }133 134  const char *cmode = mode.c_str();135  std::int64_t modelen = std::strlen(cmode);136 137  return FORTRAN_PROCEDURE_NAME(access)(cpath, pathlen, cmode, modelen);138}139 140TEST(AccessTests, TestExists) {141  AccessType accessType;142  accessType.exists = true;143 144  std::string path = createTemporaryFile(__func__, accessType);145  ASSERT_FALSE(path.empty());146 147  std::int64_t res = callAccess(path, accessType);148 149  ASSERT_EQ(unlink(path.c_str()), 0);150 151  ASSERT_EQ(res, 0);152}153 154TEST(AccessTests, TestNotExists) {155  std::string nonExistant{addPIDSuffix(__func__)};156  ASSERT_FALSE(exists(nonExistant));157 158  AccessType accessType;159  accessType.exists = true;160  std::int64_t res = callAccess(nonExistant, accessType);161 162  ASSERT_NE(res, 0);163}164 165TEST(AccessTests, TestRead) {166  AccessType accessType;167  accessType.read = true;168 169  std::string path = createTemporaryFile(__func__, accessType);170  ASSERT_FALSE(path.empty());171 172  std::int64_t res = callAccess(path, accessType);173 174  ASSERT_EQ(unlink(path.c_str()), 0);175 176  if (userSkipsPermissionChecks()) {177    return;178  }179 180  ASSERT_EQ(res, 0);181}182 183TEST(AccessTests, TestNotRead) {184  AccessType accessType;185  accessType.read = false;186 187  std::string path = createTemporaryFile(__func__, accessType);188  ASSERT_FALSE(path.empty());189 190  accessType.read = true;191  std::int64_t res = callAccess(path, accessType);192 193  ASSERT_EQ(unlink(path.c_str()), 0);194 195  if (userSkipsPermissionChecks()) {196    return;197  }198 199  ASSERT_NE(res, 0);200}201 202TEST(AccessTests, TestWrite) {203  AccessType accessType;204  accessType.write = true;205 206  std::string path = createTemporaryFile(__func__, accessType);207  ASSERT_FALSE(path.empty());208 209  std::int64_t res = callAccess(path, accessType);210 211  ASSERT_EQ(unlink(path.c_str()), 0);212 213  if (userSkipsPermissionChecks()) {214    return;215  }216 217  ASSERT_EQ(res, 0);218}219 220TEST(AccessTests, TestNotWrite) {221  AccessType accessType;222  accessType.write = false;223 224  std::string path = createTemporaryFile(__func__, accessType);225  ASSERT_FALSE(path.empty());226 227  accessType.write = true;228  std::int64_t res = callAccess(path, accessType);229 230  ASSERT_EQ(unlink(path.c_str()), 0);231 232  if (userSkipsPermissionChecks()) {233    return;234  }235 236  ASSERT_NE(res, 0);237}238 239TEST(AccessTests, TestReadWrite) {240  AccessType accessType;241  accessType.read = true;242  accessType.write = true;243 244  std::string path = createTemporaryFile(__func__, accessType);245  ASSERT_FALSE(path.empty());246 247  std::int64_t res = callAccess(path, accessType);248 249  ASSERT_EQ(unlink(path.c_str()), 0);250 251  if (userSkipsPermissionChecks()) {252    return;253  }254 255  ASSERT_EQ(res, 0);256}257 258TEST(AccessTests, TestNotReadWrite0) {259  AccessType accessType;260  accessType.read = false;261  accessType.write = false;262 263  std::string path = createTemporaryFile(__func__, accessType);264  ASSERT_FALSE(path.empty());265 266  accessType.read = true;267  accessType.write = true;268  std::int64_t res = callAccess(path, accessType);269 270  ASSERT_EQ(unlink(path.c_str()), 0);271 272  if (userSkipsPermissionChecks()) {273    return;274  }275 276  ASSERT_NE(res, 0);277}278 279TEST(AccessTests, TestNotReadWrite1) {280  AccessType accessType;281  accessType.read = true;282  accessType.write = false;283 284  std::string path = createTemporaryFile(__func__, accessType);285  ASSERT_FALSE(path.empty());286 287  accessType.read = true;288  accessType.write = true;289  std::int64_t res = callAccess(path, accessType);290 291  ASSERT_EQ(unlink(path.c_str()), 0);292 293  if (userSkipsPermissionChecks()) {294    return;295  }296 297  ASSERT_NE(res, 0);298}299 300TEST(AccessTests, TestNotReadWrite2) {301  AccessType accessType;302  accessType.read = false;303  accessType.write = true;304 305  std::string path = createTemporaryFile(__func__, accessType);306  ASSERT_FALSE(path.empty());307 308  accessType.read = true;309  accessType.write = true;310  std::int64_t res = callAccess(path, accessType);311 312  ASSERT_EQ(unlink(path.c_str()), 0);313 314  if (userSkipsPermissionChecks()) {315    return;316  }317 318  ASSERT_NE(res, 0);319}320 321TEST(AccessTests, TestExecute) {322  AccessType accessType;323  accessType.execute = true;324 325  std::string path = createTemporaryFile(__func__, accessType);326  ASSERT_FALSE(path.empty());327 328  std::int64_t res = callAccess(path, accessType);329 330  ASSERT_EQ(unlink(path.c_str()), 0);331 332  if (userSkipsPermissionChecks()) {333    return;334  }335 336  ASSERT_EQ(res, 0);337}338 339TEST(AccessTests, TestNotExecute) {340  AccessType accessType;341  accessType.execute = false;342 343  std::string path = createTemporaryFile(__func__, accessType);344  ASSERT_FALSE(path.empty());345 346  accessType.execute = true;347  std::int64_t res = callAccess(path, accessType);348 349  ASSERT_EQ(unlink(path.c_str()), 0);350 351  if (userSkipsPermissionChecks()) {352    return;353  }354 355  ASSERT_NE(res, 0);356}357 358TEST(AccessTests, TestRWX) {359  AccessType accessType;360  accessType.read = true;361  accessType.write = true;362  accessType.execute = true;363 364  std::string path = createTemporaryFile(__func__, accessType);365  ASSERT_FALSE(path.empty());366 367  std::int64_t res = callAccess(path, accessType);368 369  ASSERT_EQ(unlink(path.c_str()), 0);370 371  if (userSkipsPermissionChecks()) {372    return;373  }374 375  ASSERT_EQ(res, 0);376}377 378TEST(AccessTests, TestNotRWX0) {379  AccessType accessType;380  accessType.read = false;381  accessType.write = false;382  accessType.execute = false;383 384  std::string path = createTemporaryFile(__func__, accessType);385  ASSERT_FALSE(path.empty());386 387  accessType.read = true;388  accessType.write = true;389  accessType.execute = true;390  std::int64_t res = callAccess(path, accessType);391 392  ASSERT_EQ(unlink(path.c_str()), 0);393 394  if (userSkipsPermissionChecks()) {395    return;396  }397 398  ASSERT_NE(res, 0);399}400 401TEST(AccessTests, TestNotRWX1) {402  AccessType accessType;403  accessType.read = true;404  accessType.write = false;405  accessType.execute = false;406 407  std::string path = createTemporaryFile(__func__, accessType);408  ASSERT_FALSE(path.empty());409 410  accessType.read = true;411  accessType.write = true;412  accessType.execute = true;413  std::int64_t res = callAccess(path, accessType);414 415  ASSERT_EQ(unlink(path.c_str()), 0);416 417  if (userSkipsPermissionChecks()) {418    return;419  }420 421  ASSERT_NE(res, 0);422}423 424TEST(AccessTests, TestNotRWX2) {425  AccessType accessType;426  accessType.read = true;427  accessType.write = true;428  accessType.execute = false;429 430  std::string path = createTemporaryFile(__func__, accessType);431  ASSERT_FALSE(path.empty());432 433  accessType.read = true;434  accessType.write = true;435  accessType.execute = true;436  std::int64_t res = callAccess(path, accessType);437 438  ASSERT_EQ(unlink(path.c_str()), 0);439 440  if (userSkipsPermissionChecks()) {441    return;442  }443 444  ASSERT_NE(res, 0);445}446 447TEST(AccessTests, TestNotRWX3) {448  AccessType accessType;449  accessType.read = true;450  accessType.write = false;451  accessType.execute = true;452 453  std::string path = createTemporaryFile(__func__, accessType);454  ASSERT_FALSE(path.empty());455 456  accessType.read = true;457  accessType.write = true;458  accessType.execute = true;459  std::int64_t res = callAccess(path, accessType);460 461  ASSERT_EQ(unlink(path.c_str()), 0);462 463  if (userSkipsPermissionChecks()) {464    return;465  }466 467  ASSERT_NE(res, 0);468}469 470TEST(AccessTests, TestNotRWX4) {471  AccessType accessType;472  accessType.read = false;473  accessType.write = true;474  accessType.execute = true;475 476  std::string path = createTemporaryFile(__func__, accessType);477  ASSERT_FALSE(path.empty());478 479  accessType.read = true;480  accessType.write = true;481  accessType.execute = true;482  std::int64_t res = callAccess(path, accessType);483 484  ASSERT_EQ(unlink(path.c_str()), 0);485 486  if (userSkipsPermissionChecks()) {487    return;488  }489 490  ASSERT_NE(res, 0);491}492 493#endif // !_WIN32494