1// Copyright (c) 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <errno.h>
6#include <limits.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <sys/stat.h>
10
11#include "gtest/gtest.h"
12
13#include "nacl_io/kernel_intercept.h"
14#include "nacl_io/kernel_proxy.h"
15
16using namespace nacl_io;
17
18namespace {
19
20class SyscallsTest : public ::testing::Test {
21 public:
22  SyscallsTest() {}
23
24  void SetUp() {
25    ASSERT_EQ(0, ki_push_state_for_testing());
26    ASSERT_EQ(0, ki_init(&kp_));
27    // Unmount the passthrough FS and mount a memfs.
28    EXPECT_EQ(0, kp_.umount("/"));
29    EXPECT_EQ(0, kp_.mount("", "/", "memfs", 0, NULL));
30  }
31
32  void TearDown() { ki_uninit(); }
33
34 protected:
35  KernelProxy kp_;
36};
37
38}  // namespace
39
40#if defined(__native_client__) || defined(STANDALONE)
41
42// The Linux standalone test is unique in that it calls the real Linux
43// functions (realpath, mkdir, chdir, etc.), not the nacl_io functions. This is
44// done to show that the tests match the behavior for a real implementation.
45
46TEST_F(SyscallsTest, Realpath) {
47  char buffer[PATH_MAX];
48  int result;
49
50#if defined(__native_client__)
51  ASSERT_EQ(0, mkdir("/tmp", S_IREAD | S_IWRITE));
52#endif
53
54  result = mkdir("/tmp/bar", S_IREAD | S_IWRITE);
55#if defined(__native_client__)
56  ASSERT_EQ(0, result);
57#else
58  if (result == -1) {
59    ASSERT_EQ(EEXIST, errno);
60  } else {
61    ASSERT_EQ(0, result);
62  }
63#endif
64
65  int fd = open("/tmp/file", O_CREAT | O_RDWR, 0644);
66  ASSERT_GT(fd, -1);
67  ASSERT_EQ(0, close(fd));
68
69  // Test absolute paths.
70  EXPECT_STREQ("/", realpath("/", buffer));
71  EXPECT_STREQ("/", realpath("/tmp/..", buffer));
72  EXPECT_STREQ("/tmp", realpath("/tmp", buffer));
73  EXPECT_STREQ("/tmp", realpath("/tmp/", buffer));
74  EXPECT_STREQ("/tmp", realpath("/tmp/bar/..", buffer));
75  EXPECT_STREQ("/tmp", realpath("/tmp/bar/../bar/../../tmp", buffer));
76  EXPECT_STREQ("/tmp", realpath("/tmp/././", buffer));
77  EXPECT_STREQ("/tmp", realpath("///tmp", buffer));
78  EXPECT_STREQ("/tmp/bar", realpath("/tmp/bar", buffer));
79
80  EXPECT_EQ(NULL, realpath("/blah", buffer));
81  EXPECT_EQ(ENOENT, errno);
82
83  EXPECT_EQ(NULL, realpath("/blah/blah", buffer));
84  EXPECT_EQ(ENOENT, errno);
85
86  EXPECT_EQ(NULL, realpath("/tmp/baz/..", buffer));
87  EXPECT_EQ(ENOENT, errno);
88
89  EXPECT_EQ(NULL, realpath("/tmp/file/", buffer));
90  EXPECT_EQ(ENOTDIR, errno);
91
92  EXPECT_EQ(NULL, realpath(NULL, buffer));
93  EXPECT_EQ(EINVAL, errno);
94
95  // Test relative paths.
96  EXPECT_EQ(0, chdir("/tmp"));
97
98  EXPECT_STREQ("/", realpath("..", buffer));
99  EXPECT_STREQ("/tmp", realpath(".", buffer));
100  EXPECT_STREQ("/tmp", realpath("./", buffer));
101  EXPECT_STREQ("/tmp", realpath("bar/..", buffer));
102  EXPECT_STREQ("/tmp", realpath("bar/../../tmp", buffer));
103  EXPECT_STREQ("/tmp", realpath(".///", buffer));
104  EXPECT_STREQ("/tmp/bar", realpath("bar", buffer));
105
106  // Test when resolved_path is allocated.
107  char* allocated = realpath("/tmp", NULL);
108  EXPECT_STREQ("/tmp", allocated);
109  free(allocated);
110}
111
112#endif  // defined(__native_client__) || defined(STANDALONE)
113