chromium/native_client_sdk/src/tests/nacl_io_test/syscalls_test.cc

// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>

#include "gtest/gtest.h"

#include "nacl_io/kernel_intercept.h"
#include "nacl_io/kernel_proxy.h"

using namespace nacl_io;

namespace {

class SyscallsTest : public ::testing::Test {
 public:
  SyscallsTest() {}

  void SetUp() {
    ASSERT_EQ(0, ki_push_state_for_testing());
    ASSERT_EQ(0, ki_init(&kp_));
    // Unmount the passthrough FS and mount a memfs.
    EXPECT_EQ(0, kp_.umount("/"));
    EXPECT_EQ(0, kp_.mount("", "/", "memfs", 0, NULL));
  }

  void TearDown() { ki_uninit(); }

 protected:
  KernelProxy kp_;
};

}  // namespace

#if defined(__native_client__) || defined(STANDALONE)

// The Linux standalone test is unique in that it calls the real Linux
// functions (realpath, mkdir, chdir, etc.), not the nacl_io functions. This is
// done to show that the tests match the behavior for a real implementation.

TEST_F(SyscallsTest, Realpath) {
  char buffer[PATH_MAX];
  int result;

#if defined(__native_client__)
  ASSERT_EQ(0, mkdir("/tmp", S_IRUSR | S_IWUSR));
#endif

  result = mkdir("/tmp/bar", S_IRUSR | S_IWUSR);
#if defined(__native_client__)
  ASSERT_EQ(0, result);
#else
  if (result == -1) {
    ASSERT_EQ(EEXIST, errno);
  } else {
    ASSERT_EQ(0, result);
  }
#endif

  int fd = open("/tmp/file", O_CREAT | O_RDWR, 0644);
  ASSERT_GT(fd, -1);
  ASSERT_EQ(0, close(fd));

  // Test absolute paths.
  EXPECT_STREQ("/", realpath("/", buffer));
  EXPECT_STREQ("/", realpath("/tmp/..", buffer));
  EXPECT_STREQ("/tmp", realpath("/tmp", buffer));
  EXPECT_STREQ("/tmp", realpath("/tmp/", buffer));
  EXPECT_STREQ("/tmp", realpath("/tmp/bar/..", buffer));
  EXPECT_STREQ("/tmp", realpath("/tmp/bar/../bar/../../tmp", buffer));
  EXPECT_STREQ("/tmp", realpath("/tmp/././", buffer));
  EXPECT_STREQ("/tmp", realpath("///tmp", buffer));
  EXPECT_STREQ("/tmp/bar", realpath("/tmp/bar", buffer));

  EXPECT_EQ(NULL, realpath("/blah", buffer));
  EXPECT_EQ(ENOENT, errno);

  EXPECT_EQ(NULL, realpath("/blah/blah", buffer));
  EXPECT_EQ(ENOENT, errno);

  EXPECT_EQ(NULL, realpath("/tmp/baz/..", buffer));
  EXPECT_EQ(ENOENT, errno);

  EXPECT_EQ(NULL, realpath("/tmp/file/", buffer));
  EXPECT_EQ(ENOTDIR, errno);

  EXPECT_EQ(NULL, realpath(NULL, buffer));
  EXPECT_EQ(EINVAL, errno);

  // Test relative paths.
  EXPECT_EQ(0, chdir("/tmp"));

  EXPECT_STREQ("/", realpath("..", buffer));
  EXPECT_STREQ("/tmp", realpath(".", buffer));
  EXPECT_STREQ("/tmp", realpath("./", buffer));
  EXPECT_STREQ("/tmp", realpath("bar/..", buffer));
  EXPECT_STREQ("/tmp", realpath("bar/../../tmp", buffer));
  EXPECT_STREQ("/tmp", realpath(".///", buffer));
  EXPECT_STREQ("/tmp/bar", realpath("bar", buffer));

  // Test when resolved_path is allocated.
  char* allocated = realpath("/tmp", NULL);
  EXPECT_STREQ("/tmp", allocated);
  free(allocated);
}

#endif  // defined(__native_client__) || defined(STANDALONE)