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/casts.h"
19 #include "base/logging.h"
20 #include "base/unix_file/fd_file.h"
21 #include "base/unix_file/random_access_file_test.h"
22 #include "base/unix_file/random_access_file_utils.h"
23 #include "base/unix_file/string_file.h"
24 #include "gtest/gtest.h"
25 
26 namespace unix_file {
27 
28 class MappedFileTest : public RandomAccessFileTest {
29  protected:
MappedFileTest()30   MappedFileTest() : kContent("some content") {
31   }
32 
SetUp()33   void SetUp() {
34     RandomAccessFileTest::SetUp();
35 
36     good_path_ = GetTmpPath("some-file.txt");
37     int fd = TEMP_FAILURE_RETRY(open(good_path_.c_str(), O_CREAT|O_RDWR, 0666));
38     FdFile dst(fd, false);
39 
40     StringFile src;
41     src.Assign(kContent);
42 
43     ASSERT_TRUE(CopyFile(src, &dst));
44     ASSERT_EQ(dst.FlushClose(), 0);
45   }
46 
TearDown()47   void TearDown() {
48     ASSERT_EQ(unlink(good_path_.c_str()), 0);
49 
50     RandomAccessFileTest::TearDown();
51   }
52 
MakeTestFile()53   virtual RandomAccessFile* MakeTestFile() {
54     TEMP_FAILURE_RETRY(truncate(good_path_.c_str(), 0));
55     MappedFile* f = new MappedFile;
56     CHECK(f->Open(good_path_, MappedFile::kReadWriteMode));
57     return f;
58   }
59 
CleanUp(RandomAccessFile * file)60   void CleanUp(RandomAccessFile* file) OVERRIDE {
61     if (file == nullptr) {
62       return;
63     }
64     MappedFile* f = ::art::down_cast<MappedFile*>(file);
65     UNUSED(f->Flush());
66     UNUSED(f->Close());
67   }
68 
69   const std::string kContent;
70   std::string good_path_;
71 };
72 
TEST_F(MappedFileTest,OkayToNotUse)73 TEST_F(MappedFileTest, OkayToNotUse) {
74   MappedFile file;
75   EXPECT_EQ(-1, file.Fd());
76   EXPECT_FALSE(file.IsOpened());
77   EXPECT_FALSE(file.IsMapped());
78 }
79 
TEST_F(MappedFileTest,OpenClose)80 TEST_F(MappedFileTest, OpenClose) {
81   MappedFile file;
82   ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode));
83   EXPECT_GE(file.Fd(), 0);
84   EXPECT_TRUE(file.IsOpened());
85   EXPECT_EQ(kContent.size(), static_cast<uint64_t>(file.size()));
86   EXPECT_EQ(0, file.Close());
87   EXPECT_EQ(-1, file.Fd());
88   EXPECT_FALSE(file.IsOpened());
89 }
90 
TEST_F(MappedFileTest,OpenFdClose)91 TEST_F(MappedFileTest, OpenFdClose) {
92   FILE* f = tmpfile();
93   ASSERT_TRUE(f != NULL);
94   MappedFile file(fileno(f), false);
95   EXPECT_GE(file.Fd(), 0);
96   EXPECT_TRUE(file.IsOpened());
97   EXPECT_EQ(0, file.Close());
98 }
99 
TEST_F(MappedFileTest,CanUseAfterMapReadOnly)100 TEST_F(MappedFileTest, CanUseAfterMapReadOnly) {
101   MappedFile file;
102   ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode));
103   EXPECT_FALSE(file.IsMapped());
104   EXPECT_TRUE(file.MapReadOnly());
105   EXPECT_TRUE(file.IsMapped());
106   EXPECT_EQ(kContent.size(), static_cast<uint64_t>(file.size()));
107   ASSERT_TRUE(file.data());
108   EXPECT_EQ(0, memcmp(kContent.c_str(), file.data(), file.size()));
109   EXPECT_EQ(0, file.Flush());
110 }
111 
TEST_F(MappedFileTest,CanUseAfterMapReadWrite)112 TEST_F(MappedFileTest, CanUseAfterMapReadWrite) {
113   MappedFile file;
114   ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadWriteMode));
115   EXPECT_FALSE(file.IsMapped());
116   EXPECT_TRUE(file.MapReadWrite(1));
117   EXPECT_TRUE(file.IsMapped());
118   EXPECT_EQ(1, file.size());
119   ASSERT_TRUE(file.data());
120   EXPECT_EQ(kContent[0], *file.data());
121   EXPECT_EQ(0, file.Flush());
122   file.Close();
123 }
124 
TEST_F(MappedFileTest,CanWriteNewData)125 TEST_F(MappedFileTest, CanWriteNewData) {
126   const std::string new_path(GetTmpPath("new-file.txt"));
127   ASSERT_EQ(-1, unlink(new_path.c_str()));
128   ASSERT_EQ(ENOENT, errno);
129 
130   MappedFile file;
131   ASSERT_TRUE(file.Open(new_path, MappedFile::kReadWriteMode));
132   EXPECT_TRUE(file.MapReadWrite(kContent.size()));
133   EXPECT_TRUE(file.IsMapped());
134   EXPECT_EQ(kContent.size(), static_cast<uint64_t>(file.size()));
135   ASSERT_TRUE(file.data());
136   memcpy(file.data(), kContent.c_str(), kContent.size());
137   EXPECT_EQ(0, file.Flush());
138   EXPECT_EQ(0, file.Close());
139   EXPECT_FALSE(file.IsMapped());
140 
141   FdFile new_file(TEMP_FAILURE_RETRY(open(new_path.c_str(), O_RDONLY)), false);
142   StringFile buffer;
143   ASSERT_TRUE(CopyFile(new_file, &buffer));
144   EXPECT_EQ(kContent, buffer.ToStringPiece());
145   EXPECT_EQ(0, unlink(new_path.c_str()));
146 }
147 
TEST_F(MappedFileTest,FileMustExist)148 TEST_F(MappedFileTest, FileMustExist) {
149   const std::string bad_path(GetTmpPath("does-not-exist.txt"));
150   MappedFile file;
151   EXPECT_FALSE(file.Open(bad_path, MappedFile::kReadOnlyMode));
152   EXPECT_EQ(-1, file.Fd());
153 }
154 
TEST_F(MappedFileTest,FileMustBeWritable)155 TEST_F(MappedFileTest, FileMustBeWritable) {
156   MappedFile file;
157   ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode));
158   EXPECT_FALSE(file.MapReadWrite(10));
159 }
160 
TEST_F(MappedFileTest,RemappingAllowedUntilSuccess)161 TEST_F(MappedFileTest, RemappingAllowedUntilSuccess) {
162   MappedFile file;
163   ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode));
164   EXPECT_FALSE(file.MapReadWrite(10));
165   EXPECT_FALSE(file.MapReadWrite(10));
166 }
167 
TEST_F(MappedFileTest,ResizeMappedFile)168 TEST_F(MappedFileTest, ResizeMappedFile) {
169   MappedFile file;
170   ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadWriteMode));
171   ASSERT_TRUE(file.MapReadWrite(10));
172   EXPECT_EQ(10, file.GetLength());
173   EXPECT_TRUE(file.Unmap());
174   EXPECT_TRUE(file.MapReadWrite(20));
175   EXPECT_EQ(20, file.GetLength());
176   EXPECT_EQ(0, file.Flush());
177   EXPECT_TRUE(file.Unmap());
178   EXPECT_EQ(0, file.Flush());
179   EXPECT_EQ(0, file.SetLength(5));
180   EXPECT_TRUE(file.MapReadOnly());
181   EXPECT_EQ(5, file.GetLength());
182 }
183 
TEST_F(MappedFileTest,ReadNotMapped)184 TEST_F(MappedFileTest, ReadNotMapped) {
185   TestRead();
186 }
187 
TEST_F(MappedFileTest,SetLengthNotMapped)188 TEST_F(MappedFileTest, SetLengthNotMapped) {
189   TestSetLength();
190 }
191 
TEST_F(MappedFileTest,WriteNotMapped)192 TEST_F(MappedFileTest, WriteNotMapped) {
193   TestWrite();
194 }
195 
TEST_F(MappedFileTest,ReadMappedReadOnly)196 TEST_F(MappedFileTest, ReadMappedReadOnly) {
197   MappedFile file;
198   ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode));
199   ASSERT_TRUE(file.MapReadOnly());
200   TestReadContent(kContent, &file);
201 }
202 
TEST_F(MappedFileTest,ReadMappedReadWrite)203 TEST_F(MappedFileTest, ReadMappedReadWrite) {
204   MappedFile file;
205   ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadWriteMode));
206   ASSERT_TRUE(file.MapReadWrite(kContent.size()));
207   TestReadContent(kContent, &file);
208   UNUSED(file.FlushClose());
209 }
210 
TEST_F(MappedFileTest,WriteMappedReadWrite)211 TEST_F(MappedFileTest, WriteMappedReadWrite) {
212   TEMP_FAILURE_RETRY(unlink(good_path_.c_str()));
213   MappedFile file;
214   ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadWriteMode));
215   ASSERT_TRUE(file.MapReadWrite(kContent.size()));
216 
217   // Can't write to a negative offset.
218   EXPECT_EQ(-EINVAL, file.Write(kContent.c_str(), 0, -123));
219 
220   // A zero-length write is a no-op.
221   EXPECT_EQ(0, file.Write(kContent.c_str(), 0, 0));
222   // But the file size is as given when mapped.
223   EXPECT_EQ(kContent.size(), static_cast<uint64_t>(file.GetLength()));
224 
225   // Data written past the end are discarded.
226   EXPECT_EQ(kContent.size() - 1,
227             static_cast<uint64_t>(file.Write(kContent.c_str(), kContent.size(), 1)));
228   EXPECT_EQ(0, memcmp(kContent.c_str(), file.data() + 1, kContent.size() - 1));
229 
230   // Data can be overwritten.
231   EXPECT_EQ(kContent.size(),
232             static_cast<uint64_t>(file.Write(kContent.c_str(), kContent.size(), 0)));
233   EXPECT_EQ(0, memcmp(kContent.c_str(), file.data(), kContent.size()));
234   UNUSED(file.FlushClose());
235 }
236 
237 #if 0  // death tests don't work on android yet
238 
239 class MappedFileDeathTest : public MappedFileTest {};
240 
241 TEST_F(MappedFileDeathTest, MustMapBeforeUse) {
242   MappedFile file;
243   EXPECT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode));
244   EXPECT_DEATH(file.data(), "mapped_");
245 }
246 
247 TEST_F(MappedFileDeathTest, RemappingNotAllowedReadOnly) {
248   MappedFile file;
249   ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode));
250   ASSERT_TRUE(file.MapReadOnly());
251   EXPECT_DEATH(file.MapReadOnly(), "mapped_");
252 }
253 
254 TEST_F(MappedFileDeathTest, RemappingNotAllowedReadWrite) {
255   MappedFile file;
256   ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadWriteMode));
257   ASSERT_TRUE(file.MapReadWrite(10));
258   EXPECT_DEATH(file.MapReadWrite(10), "mapped_");
259 }
260 
261 TEST_F(MappedFileDeathTest, SetLengthMappedReadWrite) {
262   MappedFile file;
263   ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadWriteMode));
264   ASSERT_TRUE(file.MapReadWrite(10));
265   EXPECT_EQ(10, file.GetLength());
266   EXPECT_DEATH(file.SetLength(0), ".*");
267 }
268 
269 TEST_F(MappedFileDeathTest, SetLengthMappedReadOnly) {
270   MappedFile file;
271   ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode));
272   ASSERT_TRUE(file.MapReadOnly());
273   EXPECT_EQ(kContent.size(), file.GetLength());
274   EXPECT_DEATH(file.SetLength(0), ".*");
275 }
276 
277 TEST_F(MappedFileDeathTest, WriteMappedReadOnly) {
278   MappedFile file;
279   ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode));
280   ASSERT_TRUE(file.MapReadOnly());
281   char buf[10];
282   EXPECT_DEATH(file.Write(buf, 0, 0), ".*");
283 }
284 
285 #endif
286 
287 }  // namespace unix_file
288