Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2011 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 "base/file_util.h"
      6 #include "base/memory/scoped_temp_dir.h"
      7 #include "base/platform_file.h"
      8 #include "base/time.h"
      9 #include "testing/gtest/include/gtest/gtest.h"
     10 
     11 namespace {
     12 
     13 // Reads from a file the given number of bytes, or until EOF is reached.
     14 // Returns the number of bytes read.
     15 int ReadFully(base::PlatformFile file, int64 offset, char* data, int size) {
     16   int total_bytes_read = 0;
     17   int bytes_read;
     18   while (total_bytes_read < size) {
     19     bytes_read = base::ReadPlatformFile(
     20         file, offset + total_bytes_read, &data[total_bytes_read],
     21         size - total_bytes_read);
     22 
     23     // If we reached EOF, bytes_read will be 0.
     24     if (bytes_read == 0)
     25       return total_bytes_read;
     26 
     27     if ((bytes_read < 0) || (bytes_read > size - total_bytes_read))
     28       return -1;
     29 
     30     total_bytes_read += bytes_read;
     31   }
     32 
     33   return total_bytes_read;
     34 }
     35 
     36 // Writes the given number of bytes to a file.
     37 // Returns the number of bytes written.
     38 int WriteFully(base::PlatformFile file, int64 offset,
     39                const char* data, int size) {
     40   int total_bytes_written = 0;
     41   int bytes_written;
     42   while (total_bytes_written < size) {
     43     bytes_written = base::WritePlatformFile(
     44         file, offset + total_bytes_written, &data[total_bytes_written],
     45         size - total_bytes_written);
     46 
     47     if ((bytes_written == 0) && (size == 0))
     48       return 0;
     49 
     50     if ((bytes_written <= 0) || (bytes_written > size - total_bytes_written))
     51       return -1;
     52 
     53     total_bytes_written += bytes_written;
     54   }
     55 
     56   return total_bytes_written;
     57 }
     58 
     59 } // namespace
     60 
     61 TEST(PlatformFile, CreatePlatformFile) {
     62   ScopedTempDir temp_dir;
     63   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
     64   FilePath file_path = temp_dir.path().AppendASCII("create_file_1");
     65 
     66   // Open a file that doesn't exist.
     67   base::PlatformFileError error_code = base::PLATFORM_FILE_OK;
     68   base::PlatformFile file = base::CreatePlatformFile(
     69       file_path, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ,
     70       NULL, &error_code);
     71   EXPECT_EQ(base::kInvalidPlatformFileValue, file);
     72   EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, error_code);
     73 
     74   // Open or create a file.
     75   bool created = false;
     76   error_code = base::PLATFORM_FILE_OK;
     77   file = base::CreatePlatformFile(
     78       file_path, base::PLATFORM_FILE_OPEN_ALWAYS | base::PLATFORM_FILE_READ,
     79       &created, &error_code);
     80   EXPECT_NE(base::kInvalidPlatformFileValue, file);
     81   EXPECT_TRUE(created);
     82   EXPECT_EQ(base::PLATFORM_FILE_OK, error_code);
     83   base::ClosePlatformFile(file);
     84 
     85   // Open an existing file.
     86   created = false;
     87   file = base::CreatePlatformFile(
     88       file_path, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ,
     89       &created, &error_code);
     90   EXPECT_NE(base::kInvalidPlatformFileValue, file);
     91   EXPECT_FALSE(created);
     92   EXPECT_EQ(base::PLATFORM_FILE_OK, error_code);
     93   base::ClosePlatformFile(file);
     94 
     95   // Create a file that exists.
     96   file = base::CreatePlatformFile(
     97       file_path, base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_READ,
     98       &created, &error_code);
     99   EXPECT_EQ(base::kInvalidPlatformFileValue, file);
    100   EXPECT_FALSE(created);
    101   EXPECT_EQ(base::PLATFORM_FILE_ERROR_EXISTS, error_code);
    102 
    103   // Create or overwrite a file.
    104   error_code = base::PLATFORM_FILE_OK;
    105   file = base::CreatePlatformFile(
    106       file_path, base::PLATFORM_FILE_CREATE_ALWAYS | base::PLATFORM_FILE_READ,
    107       &created, &error_code);
    108   EXPECT_NE(base::kInvalidPlatformFileValue, file);
    109   EXPECT_TRUE(created);
    110   EXPECT_EQ(base::PLATFORM_FILE_OK, error_code);
    111   base::ClosePlatformFile(file);
    112 
    113   // Create a delete-on-close file.
    114   created = false;
    115   file_path = temp_dir.path().AppendASCII("create_file_2");
    116   file = base::CreatePlatformFile(
    117       file_path,
    118       base::PLATFORM_FILE_OPEN_ALWAYS |
    119       base::PLATFORM_FILE_DELETE_ON_CLOSE |
    120       base::PLATFORM_FILE_READ,
    121       &created, &error_code);
    122   EXPECT_NE(base::kInvalidPlatformFileValue, file);
    123   EXPECT_TRUE(created);
    124   EXPECT_EQ(base::PLATFORM_FILE_OK, error_code);
    125 
    126   EXPECT_TRUE(base::ClosePlatformFile(file));
    127   EXPECT_FALSE(file_util::PathExists(file_path));
    128 }
    129 
    130 TEST(PlatformFile, ReadWritePlatformFile) {
    131   ScopedTempDir temp_dir;
    132   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
    133   FilePath file_path = temp_dir.path().AppendASCII("read_write_file");
    134   base::PlatformFile file = base::CreatePlatformFile(
    135       file_path,
    136       base::PLATFORM_FILE_CREATE |
    137       base::PLATFORM_FILE_READ |
    138       base::PLATFORM_FILE_WRITE,
    139       NULL, NULL);
    140   EXPECT_NE(base::kInvalidPlatformFileValue, file);
    141 
    142   char data_to_write[] = "test";
    143   const int kTestDataSize = 4;
    144 
    145   // Write 0 bytes to the file.
    146   int bytes_written = WriteFully(file, 0, data_to_write, 0);
    147   EXPECT_EQ(0, bytes_written);
    148 
    149   // Write "test" to the file.
    150   bytes_written = WriteFully(file, 0, data_to_write, kTestDataSize);
    151   EXPECT_EQ(kTestDataSize, bytes_written);
    152 
    153   // Read from EOF.
    154   char data_read_1[32];
    155   int bytes_read = ReadFully(file, kTestDataSize, data_read_1, kTestDataSize);
    156   EXPECT_EQ(0, bytes_read);
    157 
    158   // Read from somewhere in the middle of the file.
    159   const int kPartialReadOffset = 1;
    160   bytes_read = ReadFully(file, kPartialReadOffset, data_read_1, kTestDataSize);
    161   EXPECT_EQ(kTestDataSize - kPartialReadOffset, bytes_read);
    162   for (int i = 0; i < bytes_read; i++)
    163     EXPECT_EQ(data_to_write[i + kPartialReadOffset], data_read_1[i]);
    164 
    165   // Read 0 bytes.
    166   bytes_read = ReadFully(file, 0, data_read_1, 0);
    167   EXPECT_EQ(0, bytes_read);
    168 
    169   // Read the entire file.
    170   bytes_read = ReadFully(file, 0, data_read_1, kTestDataSize);
    171   EXPECT_EQ(kTestDataSize, bytes_read);
    172   for (int i = 0; i < bytes_read; i++)
    173     EXPECT_EQ(data_to_write[i], data_read_1[i]);
    174 
    175   // Write past the end of the file.
    176   const int kOffsetBeyondEndOfFile = 10;
    177   const int kPartialWriteLength = 2;
    178   bytes_written = WriteFully(file, kOffsetBeyondEndOfFile,
    179                              data_to_write, kPartialWriteLength);
    180   EXPECT_EQ(kPartialWriteLength, bytes_written);
    181 
    182   // Make sure the file was extended.
    183   int64 file_size = 0;
    184   EXPECT_TRUE(file_util::GetFileSize(file_path, &file_size));
    185   EXPECT_EQ(kOffsetBeyondEndOfFile + kPartialWriteLength, file_size);
    186 
    187   // Make sure the file was zero-padded.
    188   char data_read_2[32];
    189   bytes_read = ReadFully(file, 0, data_read_2, static_cast<int>(file_size));
    190   EXPECT_EQ(file_size, bytes_read);
    191   for (int i = 0; i < kTestDataSize; i++)
    192     EXPECT_EQ(data_to_write[i], data_read_2[i]);
    193   for (int i = kTestDataSize; i < kOffsetBeyondEndOfFile; i++)
    194     EXPECT_EQ(0, data_read_2[i]);
    195   for (int i = kOffsetBeyondEndOfFile; i < file_size; i++)
    196     EXPECT_EQ(data_to_write[i - kOffsetBeyondEndOfFile], data_read_2[i]);
    197 
    198   // Close the file handle to allow the temp directory to be deleted.
    199   base::ClosePlatformFile(file);
    200 }
    201 
    202 TEST(PlatformFile, TruncatePlatformFile) {
    203   ScopedTempDir temp_dir;
    204   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
    205   FilePath file_path = temp_dir.path().AppendASCII("truncate_file");
    206   base::PlatformFile file = base::CreatePlatformFile(
    207       file_path,
    208       base::PLATFORM_FILE_CREATE |
    209       base::PLATFORM_FILE_READ |
    210       base::PLATFORM_FILE_WRITE,
    211       NULL, NULL);
    212   EXPECT_NE(base::kInvalidPlatformFileValue, file);
    213 
    214   // Write "test" to the file.
    215   char data_to_write[] = "test";
    216   int kTestDataSize = 4;
    217   int bytes_written = WriteFully(file, 0, data_to_write, kTestDataSize);
    218   EXPECT_EQ(kTestDataSize, bytes_written);
    219 
    220   // Extend the file.
    221   const int kExtendedFileLength = 10;
    222   int64 file_size = 0;
    223   EXPECT_TRUE(base::TruncatePlatformFile(file, kExtendedFileLength));
    224   EXPECT_TRUE(file_util::GetFileSize(file_path, &file_size));
    225   EXPECT_EQ(kExtendedFileLength, file_size);
    226 
    227   // Make sure the file was zero-padded.
    228   char data_read[32];
    229   int bytes_read = ReadFully(file, 0, data_read, static_cast<int>(file_size));
    230   EXPECT_EQ(file_size, bytes_read);
    231   for (int i = 0; i < kTestDataSize; i++)
    232     EXPECT_EQ(data_to_write[i], data_read[i]);
    233   for (int i = kTestDataSize; i < file_size; i++)
    234     EXPECT_EQ(0, data_read[i]);
    235 
    236   // Truncate the file.
    237   const int kTruncatedFileLength = 2;
    238   EXPECT_TRUE(base::TruncatePlatformFile(file, kTruncatedFileLength));
    239   EXPECT_TRUE(file_util::GetFileSize(file_path, &file_size));
    240   EXPECT_EQ(kTruncatedFileLength, file_size);
    241 
    242   // Make sure the file was truncated.
    243   bytes_read = ReadFully(file, 0, data_read, kTestDataSize);
    244   EXPECT_EQ(file_size, bytes_read);
    245   for (int i = 0; i < file_size; i++)
    246     EXPECT_EQ(data_to_write[i], data_read[i]);
    247 
    248   // Close the file handle to allow the temp directory to be deleted.
    249   base::ClosePlatformFile(file);
    250 }
    251 
    252 TEST(PlatformFile, TouchGetInfoPlatformFile) {
    253   ScopedTempDir temp_dir;
    254   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
    255   base::PlatformFile file = base::CreatePlatformFile(
    256       temp_dir.path().AppendASCII("touch_get_info_file"),
    257       base::PLATFORM_FILE_CREATE |
    258       base::PLATFORM_FILE_WRITE |
    259       base::PLATFORM_FILE_WRITE_ATTRIBUTES,
    260       NULL, NULL);
    261   EXPECT_NE(base::kInvalidPlatformFileValue, file);
    262 
    263   // Get info for a newly created file.
    264   base::PlatformFileInfo info;
    265   EXPECT_TRUE(base::GetPlatformFileInfo(file, &info));
    266 
    267   // Add 2 seconds to account for possible rounding errors on
    268   // filesystems that use a 1s or 2s timestamp granularity.
    269   base::Time now = base::Time::Now() + base::TimeDelta::FromSeconds(2);
    270   EXPECT_EQ(0, info.size);
    271   EXPECT_FALSE(info.is_directory);
    272   EXPECT_FALSE(info.is_symbolic_link);
    273   EXPECT_LE(info.last_accessed.ToInternalValue(), now.ToInternalValue());
    274   EXPECT_LE(info.last_modified.ToInternalValue(), now.ToInternalValue());
    275   EXPECT_LE(info.creation_time.ToInternalValue(), now.ToInternalValue());
    276   base::Time creation_time = info.creation_time;
    277 
    278   // Write "test" to the file.
    279   char data[] = "test";
    280   const int kTestDataSize = 4;
    281   int bytes_written = WriteFully(file, 0, data, kTestDataSize);
    282   EXPECT_EQ(kTestDataSize, bytes_written);
    283 
    284   // Change the last_accessed and last_modified dates.
    285   // It's best to add values that are multiples of 2 (in seconds)
    286   // to the current last_accessed and last_modified times, because
    287   // FATxx uses a 2s timestamp granularity.
    288   base::Time new_last_accessed =
    289       info.last_accessed + base::TimeDelta::FromSeconds(234);
    290   base::Time new_last_modified =
    291       info.last_modified + base::TimeDelta::FromMinutes(567);
    292 
    293   EXPECT_TRUE(base::TouchPlatformFile(file, new_last_accessed,
    294                                       new_last_modified));
    295 
    296   // Make sure the file info was updated accordingly.
    297   EXPECT_TRUE(base::GetPlatformFileInfo(file, &info));
    298   EXPECT_EQ(info.size, kTestDataSize);
    299   EXPECT_FALSE(info.is_directory);
    300   EXPECT_FALSE(info.is_symbolic_link);
    301 
    302   // ext2/ext3 and HPS/HPS+ seem to have a timestamp granularity of 1s.
    303 #if defined(OS_POSIX)
    304   EXPECT_EQ(info.last_accessed.ToTimeVal().tv_sec,
    305             new_last_accessed.ToTimeVal().tv_sec);
    306   EXPECT_EQ(info.last_modified.ToTimeVal().tv_sec,
    307             new_last_modified.ToTimeVal().tv_sec);
    308 #else
    309   EXPECT_EQ(info.last_accessed.ToInternalValue(),
    310             new_last_accessed.ToInternalValue());
    311   EXPECT_EQ(info.last_modified.ToInternalValue(),
    312             new_last_modified.ToInternalValue());
    313 #endif
    314 
    315   EXPECT_EQ(info.creation_time.ToInternalValue(),
    316             creation_time.ToInternalValue());
    317 
    318   // Close the file handle to allow the temp directory to be deleted.
    319   base::ClosePlatformFile(file);
    320 }
    321