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.
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 int total_bytes_read
= 0;
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
);
23 // If we reached EOF, bytes_read will be 0.
25 return total_bytes_read
;
27 if ((bytes_read
< 0) || (bytes_read
> size
- total_bytes_read
))
30 total_bytes_read
+= bytes_read
;
33 return total_bytes_read
;
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;
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
);
47 if ((bytes_written
== 0) && (size
== 0))
50 if ((bytes_written
<= 0) || (bytes_written
> size
- total_bytes_written
))
53 total_bytes_written
+= bytes_written
;
56 return total_bytes_written
;
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");
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
,
71 EXPECT_EQ(base::kInvalidPlatformFileValue
, file
);
72 EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND
, error_code
);
74 // Open or create a file.
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
);
82 EXPECT_EQ(base::PLATFORM_FILE_OK
, error_code
);
83 base::ClosePlatformFile(file
);
85 // Open an existing file.
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
);
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
);
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
);
113 // Create a delete-on-close file.
115 file_path
= temp_dir
.path().AppendASCII("create_file_2");
116 file
= base::CreatePlatformFile(
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
);
126 EXPECT_TRUE(base::ClosePlatformFile(file
));
127 EXPECT_FALSE(file_util::PathExists(file_path
));
130 TEST(PlatformFile
, DeleteOpenFile
) {
131 ScopedTempDir temp_dir
;
132 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
133 FilePath file_path
= temp_dir
.path().AppendASCII("create_file_1");
136 bool created
= false;
137 base::PlatformFileError error_code
= base::PLATFORM_FILE_OK
;
138 base::PlatformFile file
= base::CreatePlatformFile(
140 base::PLATFORM_FILE_OPEN_ALWAYS
|
141 base::PLATFORM_FILE_READ
|
142 base::PLATFORM_FILE_SHARE_DELETE
,
143 &created
, &error_code
);
144 EXPECT_NE(base::kInvalidPlatformFileValue
, file
);
145 EXPECT_TRUE(created
);
146 EXPECT_EQ(base::PLATFORM_FILE_OK
, error_code
);
148 // Open an existing file and mark it as delete on close.
150 base::PlatformFile same_file
= base::CreatePlatformFile(
152 base::PLATFORM_FILE_OPEN
|
153 base::PLATFORM_FILE_DELETE_ON_CLOSE
|
154 base::PLATFORM_FILE_READ
,
155 &created
, &error_code
);
156 EXPECT_NE(base::kInvalidPlatformFileValue
, file
);
157 EXPECT_FALSE(created
);
158 EXPECT_EQ(base::PLATFORM_FILE_OK
, error_code
);
160 // Close both handles and check that the file is gone.
161 base::ClosePlatformFile(file
);
162 base::ClosePlatformFile(same_file
);
163 EXPECT_FALSE(file_util::PathExists(file_path
));
166 TEST(PlatformFile
, ReadWritePlatformFile
) {
167 ScopedTempDir temp_dir
;
168 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
169 FilePath file_path
= temp_dir
.path().AppendASCII("read_write_file");
170 base::PlatformFile file
= base::CreatePlatformFile(
172 base::PLATFORM_FILE_CREATE
|
173 base::PLATFORM_FILE_READ
|
174 base::PLATFORM_FILE_WRITE
,
176 EXPECT_NE(base::kInvalidPlatformFileValue
, file
);
178 char data_to_write
[] = "test";
179 const int kTestDataSize
= 4;
181 // Write 0 bytes to the file.
182 int bytes_written
= WriteFully(file
, 0, data_to_write
, 0);
183 EXPECT_EQ(0, bytes_written
);
185 // Write "test" to the file.
186 bytes_written
= WriteFully(file
, 0, data_to_write
, kTestDataSize
);
187 EXPECT_EQ(kTestDataSize
, bytes_written
);
190 char data_read_1
[32];
191 int bytes_read
= ReadFully(file
, kTestDataSize
, data_read_1
, kTestDataSize
);
192 EXPECT_EQ(0, bytes_read
);
194 // Read from somewhere in the middle of the file.
195 const int kPartialReadOffset
= 1;
196 bytes_read
= ReadFully(file
, kPartialReadOffset
, data_read_1
, kTestDataSize
);
197 EXPECT_EQ(kTestDataSize
- kPartialReadOffset
, bytes_read
);
198 for (int i
= 0; i
< bytes_read
; i
++)
199 EXPECT_EQ(data_to_write
[i
+ kPartialReadOffset
], data_read_1
[i
]);
202 bytes_read
= ReadFully(file
, 0, data_read_1
, 0);
203 EXPECT_EQ(0, bytes_read
);
205 // Read the entire file.
206 bytes_read
= ReadFully(file
, 0, data_read_1
, kTestDataSize
);
207 EXPECT_EQ(kTestDataSize
, bytes_read
);
208 for (int i
= 0; i
< bytes_read
; i
++)
209 EXPECT_EQ(data_to_write
[i
], data_read_1
[i
]);
211 // Write past the end of the file.
212 const int kOffsetBeyondEndOfFile
= 10;
213 const int kPartialWriteLength
= 2;
214 bytes_written
= WriteFully(file
, kOffsetBeyondEndOfFile
,
215 data_to_write
, kPartialWriteLength
);
216 EXPECT_EQ(kPartialWriteLength
, bytes_written
);
218 // Make sure the file was extended.
220 EXPECT_TRUE(file_util::GetFileSize(file_path
, &file_size
));
221 EXPECT_EQ(kOffsetBeyondEndOfFile
+ kPartialWriteLength
, file_size
);
223 // Make sure the file was zero-padded.
224 char data_read_2
[32];
225 bytes_read
= ReadFully(file
, 0, data_read_2
, static_cast<int>(file_size
));
226 EXPECT_EQ(file_size
, bytes_read
);
227 for (int i
= 0; i
< kTestDataSize
; i
++)
228 EXPECT_EQ(data_to_write
[i
], data_read_2
[i
]);
229 for (int i
= kTestDataSize
; i
< kOffsetBeyondEndOfFile
; i
++)
230 EXPECT_EQ(0, data_read_2
[i
]);
231 for (int i
= kOffsetBeyondEndOfFile
; i
< file_size
; i
++)
232 EXPECT_EQ(data_to_write
[i
- kOffsetBeyondEndOfFile
], data_read_2
[i
]);
234 // Close the file handle to allow the temp directory to be deleted.
235 base::ClosePlatformFile(file
);
238 TEST(PlatformFile
, TruncatePlatformFile
) {
239 ScopedTempDir temp_dir
;
240 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
241 FilePath file_path
= temp_dir
.path().AppendASCII("truncate_file");
242 base::PlatformFile file
= base::CreatePlatformFile(
244 base::PLATFORM_FILE_CREATE
|
245 base::PLATFORM_FILE_READ
|
246 base::PLATFORM_FILE_WRITE
,
248 EXPECT_NE(base::kInvalidPlatformFileValue
, file
);
250 // Write "test" to the file.
251 char data_to_write
[] = "test";
252 int kTestDataSize
= 4;
253 int bytes_written
= WriteFully(file
, 0, data_to_write
, kTestDataSize
);
254 EXPECT_EQ(kTestDataSize
, bytes_written
);
257 const int kExtendedFileLength
= 10;
259 EXPECT_TRUE(base::TruncatePlatformFile(file
, kExtendedFileLength
));
260 EXPECT_TRUE(file_util::GetFileSize(file_path
, &file_size
));
261 EXPECT_EQ(kExtendedFileLength
, file_size
);
263 // Make sure the file was zero-padded.
265 int bytes_read
= ReadFully(file
, 0, data_read
, static_cast<int>(file_size
));
266 EXPECT_EQ(file_size
, bytes_read
);
267 for (int i
= 0; i
< kTestDataSize
; i
++)
268 EXPECT_EQ(data_to_write
[i
], data_read
[i
]);
269 for (int i
= kTestDataSize
; i
< file_size
; i
++)
270 EXPECT_EQ(0, data_read
[i
]);
272 // Truncate the file.
273 const int kTruncatedFileLength
= 2;
274 EXPECT_TRUE(base::TruncatePlatformFile(file
, kTruncatedFileLength
));
275 EXPECT_TRUE(file_util::GetFileSize(file_path
, &file_size
));
276 EXPECT_EQ(kTruncatedFileLength
, file_size
);
278 // Make sure the file was truncated.
279 bytes_read
= ReadFully(file
, 0, data_read
, kTestDataSize
);
280 EXPECT_EQ(file_size
, bytes_read
);
281 for (int i
= 0; i
< file_size
; i
++)
282 EXPECT_EQ(data_to_write
[i
], data_read
[i
]);
284 // Close the file handle to allow the temp directory to be deleted.
285 base::ClosePlatformFile(file
);
288 #if defined(OS_MACOSX)
289 // Flakily fails: http://crbug.com/86494
290 #define MAYBE_TouchGetInfoPlatformFile FLAKY_TouchGetInfoPlatformFile
292 #define MAYBE_TouchGetInfoPlatformFile TouchGetInfoPlatformFile
294 TEST(PlatformFile
, MAYBE_TouchGetInfoPlatformFile
) {
295 ScopedTempDir temp_dir
;
296 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
297 base::PlatformFile file
= base::CreatePlatformFile(
298 temp_dir
.path().AppendASCII("touch_get_info_file"),
299 base::PLATFORM_FILE_CREATE
|
300 base::PLATFORM_FILE_WRITE
|
301 base::PLATFORM_FILE_WRITE_ATTRIBUTES
,
303 EXPECT_NE(base::kInvalidPlatformFileValue
, file
);
305 // Get info for a newly created file.
306 base::PlatformFileInfo info
;
307 EXPECT_TRUE(base::GetPlatformFileInfo(file
, &info
));
309 // Add 2 seconds to account for possible rounding errors on
310 // filesystems that use a 1s or 2s timestamp granularity.
311 base::Time now
= base::Time::Now() + base::TimeDelta::FromSeconds(2);
312 EXPECT_EQ(0, info
.size
);
313 EXPECT_FALSE(info
.is_directory
);
314 EXPECT_FALSE(info
.is_symbolic_link
);
315 EXPECT_LE(info
.last_accessed
.ToInternalValue(), now
.ToInternalValue());
316 EXPECT_LE(info
.last_modified
.ToInternalValue(), now
.ToInternalValue());
317 EXPECT_LE(info
.creation_time
.ToInternalValue(), now
.ToInternalValue());
318 base::Time creation_time
= info
.creation_time
;
320 // Write "test" to the file.
321 char data
[] = "test";
322 const int kTestDataSize
= 4;
323 int bytes_written
= WriteFully(file
, 0, data
, kTestDataSize
);
324 EXPECT_EQ(kTestDataSize
, bytes_written
);
326 // Change the last_accessed and last_modified dates.
327 // It's best to add values that are multiples of 2 (in seconds)
328 // to the current last_accessed and last_modified times, because
329 // FATxx uses a 2s timestamp granularity.
330 base::Time new_last_accessed
=
331 info
.last_accessed
+ base::TimeDelta::FromSeconds(234);
332 base::Time new_last_modified
=
333 info
.last_modified
+ base::TimeDelta::FromMinutes(567);
335 EXPECT_TRUE(base::TouchPlatformFile(file
, new_last_accessed
,
338 // Make sure the file info was updated accordingly.
339 EXPECT_TRUE(base::GetPlatformFileInfo(file
, &info
));
340 EXPECT_EQ(info
.size
, kTestDataSize
);
341 EXPECT_FALSE(info
.is_directory
);
342 EXPECT_FALSE(info
.is_symbolic_link
);
344 // ext2/ext3 and HPS/HPS+ seem to have a timestamp granularity of 1s.
345 #if defined(OS_POSIX)
346 EXPECT_EQ(info
.last_accessed
.ToTimeVal().tv_sec
,
347 new_last_accessed
.ToTimeVal().tv_sec
);
348 EXPECT_EQ(info
.last_modified
.ToTimeVal().tv_sec
,
349 new_last_modified
.ToTimeVal().tv_sec
);
351 EXPECT_EQ(info
.last_accessed
.ToInternalValue(),
352 new_last_accessed
.ToInternalValue());
353 EXPECT_EQ(info
.last_modified
.ToInternalValue(),
354 new_last_modified
.ToInternalValue());
357 EXPECT_EQ(info
.creation_time
.ToInternalValue(),
358 creation_time
.ToInternalValue());
360 // Close the file handle to allow the temp directory to be deleted.
361 base::ClosePlatformFile(file
);