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