1 /*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "base/unix_file/mapped_file.h"
18 #include "base/logging.h"
19 #include "base/unix_file/fd_file.h"
20 #include "base/unix_file/random_access_file_test.h"
21 #include "base/unix_file/random_access_file_utils.h"
22 #include "base/unix_file/string_file.h"
23 #include "gtest/gtest.h"
24
25 namespace unix_file {
26
27 class MappedFileTest : public RandomAccessFileTest {
28 protected:
MappedFileTest()29 MappedFileTest() : kContent("some content") {
30 }
31
SetUp()32 void SetUp() {
33 art::CommonTest::SetEnvironmentVariables(android_data_);
34
35 good_path_ = GetTmpPath("some-file.txt");
36 int fd = TEMP_FAILURE_RETRY(open(good_path_.c_str(), O_CREAT|O_RDWR, 0666));
37 FdFile dst(fd);
38
39 StringFile src;
40 src.Assign(kContent);
41
42 ASSERT_TRUE(CopyFile(src, &dst));
43 }
44
MakeTestFile()45 virtual RandomAccessFile* MakeTestFile() {
46 TEMP_FAILURE_RETRY(truncate(good_path_.c_str(), 0));
47 MappedFile* f = new MappedFile;
48 CHECK(f->Open(good_path_, MappedFile::kReadWriteMode));
49 return f;
50 }
51
52 const std::string kContent;
53 std::string good_path_;
54 };
55
TEST_F(MappedFileTest,OkayToNotUse)56 TEST_F(MappedFileTest, OkayToNotUse) {
57 MappedFile file;
58 EXPECT_EQ(-1, file.Fd());
59 EXPECT_FALSE(file.IsOpened());
60 EXPECT_FALSE(file.IsMapped());
61 }
62
TEST_F(MappedFileTest,OpenClose)63 TEST_F(MappedFileTest, OpenClose) {
64 MappedFile file;
65 ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode));
66 EXPECT_GE(file.Fd(), 0);
67 EXPECT_TRUE(file.IsOpened());
68 EXPECT_EQ(kContent.size(), file.size());
69 EXPECT_EQ(0, file.Close());
70 EXPECT_EQ(-1, file.Fd());
71 EXPECT_FALSE(file.IsOpened());
72 }
73
TEST_F(MappedFileTest,OpenFdClose)74 TEST_F(MappedFileTest, OpenFdClose) {
75 FILE* f = tmpfile();
76 ASSERT_TRUE(f != NULL);
77 MappedFile file(fileno(f));
78 EXPECT_GE(file.Fd(), 0);
79 EXPECT_TRUE(file.IsOpened());
80 EXPECT_EQ(0, file.Close());
81 }
82
TEST_F(MappedFileTest,CanUseAfterMapReadOnly)83 TEST_F(MappedFileTest, CanUseAfterMapReadOnly) {
84 MappedFile file;
85 ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode));
86 EXPECT_FALSE(file.IsMapped());
87 EXPECT_TRUE(file.MapReadOnly());
88 EXPECT_TRUE(file.IsMapped());
89 EXPECT_EQ(kContent.size(), file.size());
90 ASSERT_TRUE(file.data());
91 EXPECT_EQ(0, memcmp(kContent.c_str(), file.data(), file.size()));
92 EXPECT_EQ(0, file.Flush());
93 }
94
TEST_F(MappedFileTest,CanUseAfterMapReadWrite)95 TEST_F(MappedFileTest, CanUseAfterMapReadWrite) {
96 MappedFile file;
97 ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadWriteMode));
98 EXPECT_FALSE(file.IsMapped());
99 EXPECT_TRUE(file.MapReadWrite(1));
100 EXPECT_TRUE(file.IsMapped());
101 EXPECT_EQ(1, file.size());
102 ASSERT_TRUE(file.data());
103 EXPECT_EQ(kContent[0], *file.data());
104 EXPECT_EQ(0, file.Flush());
105 }
106
TEST_F(MappedFileTest,CanWriteNewData)107 TEST_F(MappedFileTest, CanWriteNewData) {
108 const std::string new_path(GetTmpPath("new-file.txt"));
109 ASSERT_EQ(-1, unlink(new_path.c_str()));
110 ASSERT_EQ(ENOENT, errno);
111
112 MappedFile file;
113 ASSERT_TRUE(file.Open(new_path, MappedFile::kReadWriteMode));
114 EXPECT_TRUE(file.MapReadWrite(kContent.size()));
115 EXPECT_TRUE(file.IsMapped());
116 EXPECT_EQ(kContent.size(), file.size());
117 ASSERT_TRUE(file.data());
118 memcpy(file.data(), kContent.c_str(), kContent.size());
119 EXPECT_EQ(0, file.Close());
120 EXPECT_FALSE(file.IsMapped());
121
122 FdFile new_file(TEMP_FAILURE_RETRY(open(new_path.c_str(), O_RDONLY)));
123 StringFile buffer;
124 ASSERT_TRUE(CopyFile(new_file, &buffer));
125 EXPECT_EQ(kContent, buffer.ToStringPiece());
126 EXPECT_EQ(0, unlink(new_path.c_str()));
127 }
128
TEST_F(MappedFileTest,FileMustExist)129 TEST_F(MappedFileTest, FileMustExist) {
130 const std::string bad_path(GetTmpPath("does-not-exist.txt"));
131 MappedFile file;
132 EXPECT_FALSE(file.Open(bad_path, MappedFile::kReadOnlyMode));
133 EXPECT_EQ(-1, file.Fd());
134 }
135
TEST_F(MappedFileTest,FileMustBeWritable)136 TEST_F(MappedFileTest, FileMustBeWritable) {
137 MappedFile file;
138 ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode));
139 EXPECT_FALSE(file.MapReadWrite(10));
140 }
141
TEST_F(MappedFileTest,RemappingAllowedUntilSuccess)142 TEST_F(MappedFileTest, RemappingAllowedUntilSuccess) {
143 MappedFile file;
144 ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode));
145 EXPECT_FALSE(file.MapReadWrite(10));
146 EXPECT_FALSE(file.MapReadWrite(10));
147 }
148
TEST_F(MappedFileTest,ResizeMappedFile)149 TEST_F(MappedFileTest, ResizeMappedFile) {
150 MappedFile file;
151 ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadWriteMode));
152 ASSERT_TRUE(file.MapReadWrite(10));
153 EXPECT_EQ(10, file.GetLength());
154 EXPECT_TRUE(file.Unmap());
155 EXPECT_TRUE(file.MapReadWrite(20));
156 EXPECT_EQ(20, file.GetLength());
157 EXPECT_EQ(0, file.Flush());
158 EXPECT_TRUE(file.Unmap());
159 EXPECT_EQ(0, file.Flush());
160 EXPECT_EQ(0, file.SetLength(5));
161 EXPECT_TRUE(file.MapReadOnly());
162 EXPECT_EQ(5, file.GetLength());
163 }
164
TEST_F(MappedFileTest,ReadNotMapped)165 TEST_F(MappedFileTest, ReadNotMapped) {
166 TestRead();
167 }
168
TEST_F(MappedFileTest,SetLengthNotMapped)169 TEST_F(MappedFileTest, SetLengthNotMapped) {
170 TestSetLength();
171 }
172
TEST_F(MappedFileTest,WriteNotMapped)173 TEST_F(MappedFileTest, WriteNotMapped) {
174 TestWrite();
175 }
176
TEST_F(MappedFileTest,ReadMappedReadOnly)177 TEST_F(MappedFileTest, ReadMappedReadOnly) {
178 MappedFile file;
179 ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode));
180 ASSERT_TRUE(file.MapReadOnly());
181 TestReadContent(kContent, &file);
182 }
183
TEST_F(MappedFileTest,ReadMappedReadWrite)184 TEST_F(MappedFileTest, ReadMappedReadWrite) {
185 MappedFile file;
186 ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadWriteMode));
187 ASSERT_TRUE(file.MapReadWrite(kContent.size()));
188 TestReadContent(kContent, &file);
189 }
190
TEST_F(MappedFileTest,WriteMappedReadWrite)191 TEST_F(MappedFileTest, WriteMappedReadWrite) {
192 TEMP_FAILURE_RETRY(unlink(good_path_.c_str()));
193 MappedFile file;
194 ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadWriteMode));
195 ASSERT_TRUE(file.MapReadWrite(kContent.size()));
196
197 // Can't write to a negative offset.
198 EXPECT_EQ(-EINVAL, file.Write(kContent.c_str(), 0, -123));
199
200 // A zero-length write is a no-op.
201 EXPECT_EQ(0, file.Write(kContent.c_str(), 0, 0));
202 // But the file size is as given when mapped.
203 EXPECT_EQ(kContent.size(), file.GetLength());
204
205 // Data written past the end are discarded.
206 EXPECT_EQ(kContent.size() - 1,
207 file.Write(kContent.c_str(), kContent.size(), 1));
208 EXPECT_EQ(0, memcmp(kContent.c_str(), file.data() + 1, kContent.size() - 1));
209
210 // Data can be overwritten.
211 EXPECT_EQ(kContent.size(), file.Write(kContent.c_str(), kContent.size(), 0));
212 EXPECT_EQ(0, memcmp(kContent.c_str(), file.data(), kContent.size()));
213 }
214
215 #if 0 // death tests don't work on android yet
216
217 class MappedFileDeathTest : public MappedFileTest {};
218
219 TEST_F(MappedFileDeathTest, MustMapBeforeUse) {
220 MappedFile file;
221 EXPECT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode));
222 EXPECT_DEATH(file.data(), "mapped_");
223 }
224
225 TEST_F(MappedFileDeathTest, RemappingNotAllowedReadOnly) {
226 MappedFile file;
227 ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode));
228 ASSERT_TRUE(file.MapReadOnly());
229 EXPECT_DEATH(file.MapReadOnly(), "mapped_");
230 }
231
232 TEST_F(MappedFileDeathTest, RemappingNotAllowedReadWrite) {
233 MappedFile file;
234 ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadWriteMode));
235 ASSERT_TRUE(file.MapReadWrite(10));
236 EXPECT_DEATH(file.MapReadWrite(10), "mapped_");
237 }
238
239 TEST_F(MappedFileDeathTest, SetLengthMappedReadWrite) {
240 MappedFile file;
241 ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadWriteMode));
242 ASSERT_TRUE(file.MapReadWrite(10));
243 EXPECT_EQ(10, file.GetLength());
244 EXPECT_DEATH(file.SetLength(0), ".*");
245 }
246
247 TEST_F(MappedFileDeathTest, SetLengthMappedReadOnly) {
248 MappedFile file;
249 ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode));
250 ASSERT_TRUE(file.MapReadOnly());
251 EXPECT_EQ(kContent.size(), file.GetLength());
252 EXPECT_DEATH(file.SetLength(0), ".*");
253 }
254
255 TEST_F(MappedFileDeathTest, WriteMappedReadOnly) {
256 MappedFile file;
257 ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode));
258 ASSERT_TRUE(file.MapReadOnly());
259 char buf[10];
260 EXPECT_DEATH(file.Write(buf, 0, 0), ".*");
261 }
262
263 #endif
264
265 } // namespace unix_file
266