1 // Copyright (c) 2012 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.
5 #include "base/file_util.h"
6 #include "base/platform_file.h"
7 #include "base/scoped_temp_dir.h"
9 #include "testing/gtest/include/gtest/gtest.h"
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 return base::ReadPlatformFile(file
, offset
, data
, size
);
19 // Writes the given number of bytes to a file.
20 // Returns the number of bytes written.
21 int WriteFully(base::PlatformFile file
, int64 offset
,
22 const char* data
, int size
) {
23 return base::WritePlatformFile(file
, offset
, data
, size
);
28 TEST(PlatformFile
, CreatePlatformFile
) {
29 ScopedTempDir temp_dir
;
30 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
31 FilePath file_path
= temp_dir
.path().AppendASCII("create_file_1");
33 // Open a file that doesn't exist.
34 base::PlatformFileError error_code
= base::PLATFORM_FILE_OK
;
35 base::PlatformFile file
= base::CreatePlatformFile(
36 file_path
, base::PLATFORM_FILE_OPEN
| base::PLATFORM_FILE_READ
,
38 EXPECT_EQ(base::kInvalidPlatformFileValue
, file
);
39 EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND
, error_code
);
41 // Open or create a file.
43 error_code
= base::PLATFORM_FILE_OK
;
44 file
= base::CreatePlatformFile(
45 file_path
, base::PLATFORM_FILE_OPEN_ALWAYS
| base::PLATFORM_FILE_READ
,
46 &created
, &error_code
);
47 EXPECT_NE(base::kInvalidPlatformFileValue
, file
);
49 EXPECT_EQ(base::PLATFORM_FILE_OK
, error_code
);
50 base::ClosePlatformFile(file
);
52 // Open an existing file.
54 file
= base::CreatePlatformFile(
55 file_path
, base::PLATFORM_FILE_OPEN
| base::PLATFORM_FILE_READ
,
56 &created
, &error_code
);
57 EXPECT_NE(base::kInvalidPlatformFileValue
, file
);
58 EXPECT_FALSE(created
);
59 EXPECT_EQ(base::PLATFORM_FILE_OK
, error_code
);
60 base::ClosePlatformFile(file
);
62 // Create a file that exists.
63 file
= base::CreatePlatformFile(
64 file_path
, base::PLATFORM_FILE_CREATE
| base::PLATFORM_FILE_READ
,
65 &created
, &error_code
);
66 EXPECT_EQ(base::kInvalidPlatformFileValue
, file
);
67 EXPECT_FALSE(created
);
68 EXPECT_EQ(base::PLATFORM_FILE_ERROR_EXISTS
, error_code
);
70 // Create or overwrite a file.
71 error_code
= base::PLATFORM_FILE_OK
;
72 file
= base::CreatePlatformFile(
73 file_path
, base::PLATFORM_FILE_CREATE_ALWAYS
| base::PLATFORM_FILE_READ
,
74 &created
, &error_code
);
75 EXPECT_NE(base::kInvalidPlatformFileValue
, file
);
77 EXPECT_EQ(base::PLATFORM_FILE_OK
, error_code
);
78 base::ClosePlatformFile(file
);
80 // Create a delete-on-close file.
82 file_path
= temp_dir
.path().AppendASCII("create_file_2");
83 file
= base::CreatePlatformFile(
85 base::PLATFORM_FILE_OPEN_ALWAYS
|
86 base::PLATFORM_FILE_DELETE_ON_CLOSE
|
87 base::PLATFORM_FILE_READ
,
88 &created
, &error_code
);
89 EXPECT_NE(base::kInvalidPlatformFileValue
, file
);
91 EXPECT_EQ(base::PLATFORM_FILE_OK
, error_code
);
93 EXPECT_TRUE(base::ClosePlatformFile(file
));
94 EXPECT_FALSE(file_util::PathExists(file_path
));
97 TEST(PlatformFile
, DeleteOpenFile
) {
98 ScopedTempDir temp_dir
;
99 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
100 FilePath file_path
= temp_dir
.path().AppendASCII("create_file_1");
103 bool created
= false;
104 base::PlatformFileError error_code
= base::PLATFORM_FILE_OK
;
105 base::PlatformFile file
= base::CreatePlatformFile(
107 base::PLATFORM_FILE_OPEN_ALWAYS
|
108 base::PLATFORM_FILE_READ
|
109 base::PLATFORM_FILE_SHARE_DELETE
,
110 &created
, &error_code
);
111 EXPECT_NE(base::kInvalidPlatformFileValue
, file
);
112 EXPECT_TRUE(created
);
113 EXPECT_EQ(base::PLATFORM_FILE_OK
, error_code
);
115 // Open an existing file and mark it as delete on close.
117 base::PlatformFile same_file
= base::CreatePlatformFile(
119 base::PLATFORM_FILE_OPEN
|
120 base::PLATFORM_FILE_DELETE_ON_CLOSE
|
121 base::PLATFORM_FILE_READ
,
122 &created
, &error_code
);
123 EXPECT_NE(base::kInvalidPlatformFileValue
, file
);
124 EXPECT_FALSE(created
);
125 EXPECT_EQ(base::PLATFORM_FILE_OK
, error_code
);
127 // Close both handles and check that the file is gone.
128 base::ClosePlatformFile(file
);
129 base::ClosePlatformFile(same_file
);
130 EXPECT_FALSE(file_util::PathExists(file_path
));
133 TEST(PlatformFile
, ReadWritePlatformFile
) {
134 ScopedTempDir temp_dir
;
135 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
136 FilePath file_path
= temp_dir
.path().AppendASCII("read_write_file");
137 base::PlatformFile file
= base::CreatePlatformFile(
139 base::PLATFORM_FILE_CREATE
|
140 base::PLATFORM_FILE_READ
|
141 base::PLATFORM_FILE_WRITE
,
143 EXPECT_NE(base::kInvalidPlatformFileValue
, file
);
145 char data_to_write
[] = "test";
146 const int kTestDataSize
= 4;
148 // Write 0 bytes to the file.
149 int bytes_written
= WriteFully(file
, 0, data_to_write
, 0);
150 EXPECT_EQ(0, bytes_written
);
152 // Write "test" to the file.
153 bytes_written
= WriteFully(file
, 0, data_to_write
, kTestDataSize
);
154 EXPECT_EQ(kTestDataSize
, bytes_written
);
157 char data_read_1
[32];
158 int bytes_read
= ReadFully(file
, kTestDataSize
, data_read_1
, kTestDataSize
);
159 EXPECT_EQ(0, bytes_read
);
161 // Read from somewhere in the middle of the file.
162 const int kPartialReadOffset
= 1;
163 bytes_read
= ReadFully(file
, kPartialReadOffset
, data_read_1
, kTestDataSize
);
164 EXPECT_EQ(kTestDataSize
- kPartialReadOffset
, bytes_read
);
165 for (int i
= 0; i
< bytes_read
; i
++)
166 EXPECT_EQ(data_to_write
[i
+ kPartialReadOffset
], data_read_1
[i
]);
169 bytes_read
= ReadFully(file
, 0, data_read_1
, 0);
170 EXPECT_EQ(0, bytes_read
);
172 // Read the entire file.
173 bytes_read
= ReadFully(file
, 0, data_read_1
, kTestDataSize
);
174 EXPECT_EQ(kTestDataSize
, bytes_read
);
175 for (int i
= 0; i
< bytes_read
; i
++)
176 EXPECT_EQ(data_to_write
[i
], data_read_1
[i
]);
178 // Read again, but using the trivial native wrapper.
179 bytes_read
= base::ReadPlatformFileNoBestEffort(file
, 0, data_read_1
,
181 EXPECT_LE(bytes_read
, kTestDataSize
);
182 for (int i
= 0; i
< bytes_read
; i
++)
183 EXPECT_EQ(data_to_write
[i
], data_read_1
[i
]);
185 // Write past the end of the file.
186 const int kOffsetBeyondEndOfFile
= 10;
187 const int kPartialWriteLength
= 2;
188 bytes_written
= WriteFully(file
, kOffsetBeyondEndOfFile
,
189 data_to_write
, kPartialWriteLength
);
190 EXPECT_EQ(kPartialWriteLength
, bytes_written
);
192 // Make sure the file was extended.
194 EXPECT_TRUE(file_util::GetFileSize(file_path
, &file_size
));
195 EXPECT_EQ(kOffsetBeyondEndOfFile
+ kPartialWriteLength
, file_size
);
197 // Make sure the file was zero-padded.
198 char data_read_2
[32];
199 bytes_read
= ReadFully(file
, 0, data_read_2
, static_cast<int>(file_size
));
200 EXPECT_EQ(file_size
, bytes_read
);
201 for (int i
= 0; i
< kTestDataSize
; i
++)
202 EXPECT_EQ(data_to_write
[i
], data_read_2
[i
]);
203 for (int i
= kTestDataSize
; i
< kOffsetBeyondEndOfFile
; i
++)
204 EXPECT_EQ(0, data_read_2
[i
]);
205 for (int i
= kOffsetBeyondEndOfFile
; i
< file_size
; i
++)
206 EXPECT_EQ(data_to_write
[i
- kOffsetBeyondEndOfFile
], data_read_2
[i
]);
208 // Close the file handle to allow the temp directory to be deleted.
209 base::ClosePlatformFile(file
);
212 TEST(PlatformFile
, TruncatePlatformFile
) {
213 ScopedTempDir temp_dir
;
214 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
215 FilePath file_path
= temp_dir
.path().AppendASCII("truncate_file");
216 base::PlatformFile file
= base::CreatePlatformFile(
218 base::PLATFORM_FILE_CREATE
|
219 base::PLATFORM_FILE_READ
|
220 base::PLATFORM_FILE_WRITE
,
222 EXPECT_NE(base::kInvalidPlatformFileValue
, file
);
224 // Write "test" to the file.
225 char data_to_write
[] = "test";
226 int kTestDataSize
= 4;
227 int bytes_written
= WriteFully(file
, 0, data_to_write
, kTestDataSize
);
228 EXPECT_EQ(kTestDataSize
, bytes_written
);
231 const int kExtendedFileLength
= 10;
233 EXPECT_TRUE(base::TruncatePlatformFile(file
, kExtendedFileLength
));
234 EXPECT_TRUE(file_util::GetFileSize(file_path
, &file_size
));
235 EXPECT_EQ(kExtendedFileLength
, file_size
);
237 // Make sure the file was zero-padded.
239 int bytes_read
= ReadFully(file
, 0, data_read
, static_cast<int>(file_size
));
240 EXPECT_EQ(file_size
, bytes_read
);
241 for (int i
= 0; i
< kTestDataSize
; i
++)
242 EXPECT_EQ(data_to_write
[i
], data_read
[i
]);
243 for (int i
= kTestDataSize
; i
< file_size
; i
++)
244 EXPECT_EQ(0, data_read
[i
]);
246 // Truncate the file.
247 const int kTruncatedFileLength
= 2;
248 EXPECT_TRUE(base::TruncatePlatformFile(file
, kTruncatedFileLength
));
249 EXPECT_TRUE(file_util::GetFileSize(file_path
, &file_size
));
250 EXPECT_EQ(kTruncatedFileLength
, file_size
);
252 // Make sure the file was truncated.
253 bytes_read
= ReadFully(file
, 0, data_read
, kTestDataSize
);
254 EXPECT_EQ(file_size
, bytes_read
);
255 for (int i
= 0; i
< file_size
; i
++)
256 EXPECT_EQ(data_to_write
[i
], data_read
[i
]);
258 // Close the file handle to allow the temp directory to be deleted.
259 base::ClosePlatformFile(file
);
262 // Flakily fails: http://crbug.com/86494
263 TEST(PlatformFile
, DISABLED_TouchGetInfoPlatformFile
) {
264 ScopedTempDir temp_dir
;
265 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
266 base::PlatformFile file
= base::CreatePlatformFile(
267 temp_dir
.path().AppendASCII("touch_get_info_file"),
268 base::PLATFORM_FILE_CREATE
|
269 base::PLATFORM_FILE_WRITE
|
270 base::PLATFORM_FILE_WRITE_ATTRIBUTES
,
272 EXPECT_NE(base::kInvalidPlatformFileValue
, file
);
274 // Get info for a newly created file.
275 base::PlatformFileInfo info
;
276 EXPECT_TRUE(base::GetPlatformFileInfo(file
, &info
));
278 // Add 2 seconds to account for possible rounding errors on
279 // filesystems that use a 1s or 2s timestamp granularity.
280 base::Time now
= base::Time::Now() + base::TimeDelta::FromSeconds(2);
281 EXPECT_EQ(0, info
.size
);
282 EXPECT_FALSE(info
.is_directory
);
283 EXPECT_FALSE(info
.is_symbolic_link
);
284 EXPECT_LE(info
.last_accessed
.ToInternalValue(), now
.ToInternalValue());
285 EXPECT_LE(info
.last_modified
.ToInternalValue(), now
.ToInternalValue());
286 EXPECT_LE(info
.creation_time
.ToInternalValue(), now
.ToInternalValue());
287 base::Time creation_time
= info
.creation_time
;
289 // Write "test" to the file.
290 char data
[] = "test";
291 const int kTestDataSize
= 4;
292 int bytes_written
= WriteFully(file
, 0, data
, kTestDataSize
);
293 EXPECT_EQ(kTestDataSize
, bytes_written
);
295 // Change the last_accessed and last_modified dates.
296 // It's best to add values that are multiples of 2 (in seconds)
297 // to the current last_accessed and last_modified times, because
298 // FATxx uses a 2s timestamp granularity.
299 base::Time new_last_accessed
=
300 info
.last_accessed
+ base::TimeDelta::FromSeconds(234);
301 base::Time new_last_modified
=
302 info
.last_modified
+ base::TimeDelta::FromMinutes(567);
304 EXPECT_TRUE(base::TouchPlatformFile(file
, new_last_accessed
,
307 // Make sure the file info was updated accordingly.
308 EXPECT_TRUE(base::GetPlatformFileInfo(file
, &info
));
309 EXPECT_EQ(info
.size
, kTestDataSize
);
310 EXPECT_FALSE(info
.is_directory
);
311 EXPECT_FALSE(info
.is_symbolic_link
);
313 // ext2/ext3 and HPS/HPS+ seem to have a timestamp granularity of 1s.
314 #if defined(OS_POSIX)
315 EXPECT_EQ(info
.last_accessed
.ToTimeVal().tv_sec
,
316 new_last_accessed
.ToTimeVal().tv_sec
);
317 EXPECT_EQ(info
.last_modified
.ToTimeVal().tv_sec
,
318 new_last_modified
.ToTimeVal().tv_sec
);
320 EXPECT_EQ(info
.last_accessed
.ToInternalValue(),
321 new_last_accessed
.ToInternalValue());
322 EXPECT_EQ(info
.last_modified
.ToInternalValue(),
323 new_last_modified
.ToInternalValue());
326 EXPECT_EQ(info
.creation_time
.ToInternalValue(),
327 creation_time
.ToInternalValue());
329 // Close the file handle to allow the temp directory to be deleted.
330 base::ClosePlatformFile(file
);