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/files/scoped_temp_dir.h"
7 #include "base/platform_file.h"
9 #include "testing/gtest/include/gtest/gtest.h"
15 // Reads from a file the given number of bytes, or until EOF is reached.
16 // Returns the number of bytes read.
17 int ReadFully(base::PlatformFile file
, int64 offset
, char* data
, int size
) {
18 return base::ReadPlatformFile(file
, offset
, data
, size
);
21 // Writes the given number of bytes to a file.
22 // Returns the number of bytes written.
23 int WriteFully(base::PlatformFile file
, int64 offset
,
24 const char* data
, int size
) {
25 return base::WritePlatformFile(file
, offset
, data
, size
);
30 TEST(PlatformFile
, CreatePlatformFile
) {
31 base::ScopedTempDir temp_dir
;
32 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
33 FilePath file_path
= temp_dir
.path().AppendASCII("create_file_1");
35 // Open a file that doesn't exist.
36 base::PlatformFileError error_code
= base::PLATFORM_FILE_OK
;
37 base::PlatformFile file
= base::CreatePlatformFile(
38 file_path
, base::PLATFORM_FILE_OPEN
| base::PLATFORM_FILE_READ
,
40 EXPECT_EQ(base::kInvalidPlatformFileValue
, file
);
41 EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND
, error_code
);
43 // Open or create a file.
45 error_code
= base::PLATFORM_FILE_OK
;
46 file
= base::CreatePlatformFile(
47 file_path
, base::PLATFORM_FILE_OPEN_ALWAYS
| base::PLATFORM_FILE_READ
,
48 &created
, &error_code
);
49 EXPECT_NE(base::kInvalidPlatformFileValue
, file
);
51 EXPECT_EQ(base::PLATFORM_FILE_OK
, error_code
);
52 base::ClosePlatformFile(file
);
54 // Open an existing file.
56 file
= base::CreatePlatformFile(
57 file_path
, base::PLATFORM_FILE_OPEN
| base::PLATFORM_FILE_READ
,
58 &created
, &error_code
);
59 EXPECT_NE(base::kInvalidPlatformFileValue
, file
);
60 EXPECT_FALSE(created
);
61 EXPECT_EQ(base::PLATFORM_FILE_OK
, error_code
);
62 base::ClosePlatformFile(file
);
64 // Create a file that exists.
65 file
= base::CreatePlatformFile(
66 file_path
, base::PLATFORM_FILE_CREATE
| base::PLATFORM_FILE_READ
,
67 &created
, &error_code
);
68 EXPECT_EQ(base::kInvalidPlatformFileValue
, file
);
69 EXPECT_FALSE(created
);
70 EXPECT_EQ(base::PLATFORM_FILE_ERROR_EXISTS
, error_code
);
72 // Create or overwrite a file.
73 error_code
= base::PLATFORM_FILE_OK
;
74 file
= base::CreatePlatformFile(
75 file_path
, base::PLATFORM_FILE_CREATE_ALWAYS
| base::PLATFORM_FILE_READ
,
76 &created
, &error_code
);
77 EXPECT_NE(base::kInvalidPlatformFileValue
, file
);
79 EXPECT_EQ(base::PLATFORM_FILE_OK
, error_code
);
80 base::ClosePlatformFile(file
);
82 // Create a delete-on-close file.
84 file_path
= temp_dir
.path().AppendASCII("create_file_2");
85 file
= base::CreatePlatformFile(
87 base::PLATFORM_FILE_OPEN_ALWAYS
|
88 base::PLATFORM_FILE_DELETE_ON_CLOSE
|
89 base::PLATFORM_FILE_READ
,
90 &created
, &error_code
);
91 EXPECT_NE(base::kInvalidPlatformFileValue
, file
);
93 EXPECT_EQ(base::PLATFORM_FILE_OK
, error_code
);
95 EXPECT_TRUE(base::ClosePlatformFile(file
));
96 EXPECT_FALSE(file_util::PathExists(file_path
));
99 TEST(PlatformFile
, DeleteOpenFile
) {
100 base::ScopedTempDir temp_dir
;
101 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
102 FilePath file_path
= temp_dir
.path().AppendASCII("create_file_1");
105 bool created
= false;
106 base::PlatformFileError error_code
= base::PLATFORM_FILE_OK
;
107 base::PlatformFile file
= base::CreatePlatformFile(
109 base::PLATFORM_FILE_OPEN_ALWAYS
|
110 base::PLATFORM_FILE_READ
|
111 base::PLATFORM_FILE_SHARE_DELETE
,
112 &created
, &error_code
);
113 EXPECT_NE(base::kInvalidPlatformFileValue
, file
);
114 EXPECT_TRUE(created
);
115 EXPECT_EQ(base::PLATFORM_FILE_OK
, error_code
);
117 // Open an existing file and mark it as delete on close.
119 base::PlatformFile same_file
= base::CreatePlatformFile(
121 base::PLATFORM_FILE_OPEN
|
122 base::PLATFORM_FILE_DELETE_ON_CLOSE
|
123 base::PLATFORM_FILE_READ
,
124 &created
, &error_code
);
125 EXPECT_NE(base::kInvalidPlatformFileValue
, file
);
126 EXPECT_FALSE(created
);
127 EXPECT_EQ(base::PLATFORM_FILE_OK
, error_code
);
129 // Close both handles and check that the file is gone.
130 base::ClosePlatformFile(file
);
131 base::ClosePlatformFile(same_file
);
132 EXPECT_FALSE(file_util::PathExists(file_path
));
135 TEST(PlatformFile
, ReadWritePlatformFile
) {
136 base::ScopedTempDir temp_dir
;
137 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
138 FilePath file_path
= temp_dir
.path().AppendASCII("read_write_file");
139 base::PlatformFile file
= base::CreatePlatformFile(
141 base::PLATFORM_FILE_CREATE
|
142 base::PLATFORM_FILE_READ
|
143 base::PLATFORM_FILE_WRITE
,
145 EXPECT_NE(base::kInvalidPlatformFileValue
, file
);
147 char data_to_write
[] = "test";
148 const int kTestDataSize
= 4;
150 // Write 0 bytes to the file.
151 int bytes_written
= WriteFully(file
, 0, data_to_write
, 0);
152 EXPECT_EQ(0, bytes_written
);
154 // Write "test" to the file.
155 bytes_written
= WriteFully(file
, 0, data_to_write
, kTestDataSize
);
156 EXPECT_EQ(kTestDataSize
, bytes_written
);
159 char data_read_1
[32];
160 int bytes_read
= ReadFully(file
, kTestDataSize
, data_read_1
, kTestDataSize
);
161 EXPECT_EQ(0, bytes_read
);
163 // Read from somewhere in the middle of the file.
164 const int kPartialReadOffset
= 1;
165 bytes_read
= ReadFully(file
, kPartialReadOffset
, data_read_1
, kTestDataSize
);
166 EXPECT_EQ(kTestDataSize
- kPartialReadOffset
, bytes_read
);
167 for (int i
= 0; i
< bytes_read
; i
++)
168 EXPECT_EQ(data_to_write
[i
+ kPartialReadOffset
], data_read_1
[i
]);
171 bytes_read
= ReadFully(file
, 0, data_read_1
, 0);
172 EXPECT_EQ(0, bytes_read
);
174 // Read the entire file.
175 bytes_read
= ReadFully(file
, 0, data_read_1
, kTestDataSize
);
176 EXPECT_EQ(kTestDataSize
, bytes_read
);
177 for (int i
= 0; i
< bytes_read
; i
++)
178 EXPECT_EQ(data_to_write
[i
], data_read_1
[i
]);
180 // Read again, but using the trivial native wrapper.
181 bytes_read
= base::ReadPlatformFileNoBestEffort(file
, 0, data_read_1
,
183 EXPECT_LE(bytes_read
, kTestDataSize
);
184 for (int i
= 0; i
< bytes_read
; i
++)
185 EXPECT_EQ(data_to_write
[i
], data_read_1
[i
]);
187 // Write past the end of the file.
188 const int kOffsetBeyondEndOfFile
= 10;
189 const int kPartialWriteLength
= 2;
190 bytes_written
= WriteFully(file
, kOffsetBeyondEndOfFile
,
191 data_to_write
, kPartialWriteLength
);
192 EXPECT_EQ(kPartialWriteLength
, bytes_written
);
194 // Make sure the file was extended.
196 EXPECT_TRUE(file_util::GetFileSize(file_path
, &file_size
));
197 EXPECT_EQ(kOffsetBeyondEndOfFile
+ kPartialWriteLength
, file_size
);
199 // Make sure the file was zero-padded.
200 char data_read_2
[32];
201 bytes_read
= ReadFully(file
, 0, data_read_2
, static_cast<int>(file_size
));
202 EXPECT_EQ(file_size
, bytes_read
);
203 for (int i
= 0; i
< kTestDataSize
; i
++)
204 EXPECT_EQ(data_to_write
[i
], data_read_2
[i
]);
205 for (int i
= kTestDataSize
; i
< kOffsetBeyondEndOfFile
; i
++)
206 EXPECT_EQ(0, data_read_2
[i
]);
207 for (int i
= kOffsetBeyondEndOfFile
; i
< file_size
; i
++)
208 EXPECT_EQ(data_to_write
[i
- kOffsetBeyondEndOfFile
], data_read_2
[i
]);
210 // Close the file handle to allow the temp directory to be deleted.
211 base::ClosePlatformFile(file
);
214 TEST(PlatformFile
, TruncatePlatformFile
) {
215 base::ScopedTempDir temp_dir
;
216 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
217 FilePath file_path
= temp_dir
.path().AppendASCII("truncate_file");
218 base::PlatformFile file
= base::CreatePlatformFile(
220 base::PLATFORM_FILE_CREATE
|
221 base::PLATFORM_FILE_READ
|
222 base::PLATFORM_FILE_WRITE
,
224 EXPECT_NE(base::kInvalidPlatformFileValue
, file
);
226 // Write "test" to the file.
227 char data_to_write
[] = "test";
228 int kTestDataSize
= 4;
229 int bytes_written
= WriteFully(file
, 0, data_to_write
, kTestDataSize
);
230 EXPECT_EQ(kTestDataSize
, bytes_written
);
233 const int kExtendedFileLength
= 10;
235 EXPECT_TRUE(base::TruncatePlatformFile(file
, kExtendedFileLength
));
236 EXPECT_TRUE(file_util::GetFileSize(file_path
, &file_size
));
237 EXPECT_EQ(kExtendedFileLength
, file_size
);
239 // Make sure the file was zero-padded.
241 int bytes_read
= ReadFully(file
, 0, data_read
, static_cast<int>(file_size
));
242 EXPECT_EQ(file_size
, bytes_read
);
243 for (int i
= 0; i
< kTestDataSize
; i
++)
244 EXPECT_EQ(data_to_write
[i
], data_read
[i
]);
245 for (int i
= kTestDataSize
; i
< file_size
; i
++)
246 EXPECT_EQ(0, data_read
[i
]);
248 // Truncate the file.
249 const int kTruncatedFileLength
= 2;
250 EXPECT_TRUE(base::TruncatePlatformFile(file
, kTruncatedFileLength
));
251 EXPECT_TRUE(file_util::GetFileSize(file_path
, &file_size
));
252 EXPECT_EQ(kTruncatedFileLength
, file_size
);
254 // Make sure the file was truncated.
255 bytes_read
= ReadFully(file
, 0, data_read
, kTestDataSize
);
256 EXPECT_EQ(file_size
, bytes_read
);
257 for (int i
= 0; i
< file_size
; i
++)
258 EXPECT_EQ(data_to_write
[i
], data_read
[i
]);
260 // Close the file handle to allow the temp directory to be deleted.
261 base::ClosePlatformFile(file
);
264 // Flakily fails: http://crbug.com/86494
265 TEST(PlatformFile
, DISABLED_TouchGetInfoPlatformFile
) {
266 base::ScopedTempDir temp_dir
;
267 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
268 base::PlatformFile file
= base::CreatePlatformFile(
269 temp_dir
.path().AppendASCII("touch_get_info_file"),
270 base::PLATFORM_FILE_CREATE
|
271 base::PLATFORM_FILE_WRITE
|
272 base::PLATFORM_FILE_WRITE_ATTRIBUTES
,
274 EXPECT_NE(base::kInvalidPlatformFileValue
, file
);
276 // Get info for a newly created file.
277 base::PlatformFileInfo info
;
278 EXPECT_TRUE(base::GetPlatformFileInfo(file
, &info
));
280 // Add 2 seconds to account for possible rounding errors on
281 // filesystems that use a 1s or 2s timestamp granularity.
282 base::Time now
= base::Time::Now() + base::TimeDelta::FromSeconds(2);
283 EXPECT_EQ(0, info
.size
);
284 EXPECT_FALSE(info
.is_directory
);
285 EXPECT_FALSE(info
.is_symbolic_link
);
286 EXPECT_LE(info
.last_accessed
.ToInternalValue(), now
.ToInternalValue());
287 EXPECT_LE(info
.last_modified
.ToInternalValue(), now
.ToInternalValue());
288 EXPECT_LE(info
.creation_time
.ToInternalValue(), now
.ToInternalValue());
289 base::Time creation_time
= info
.creation_time
;
291 // Write "test" to the file.
292 char data
[] = "test";
293 const int kTestDataSize
= 4;
294 int bytes_written
= WriteFully(file
, 0, data
, kTestDataSize
);
295 EXPECT_EQ(kTestDataSize
, bytes_written
);
297 // Change the last_accessed and last_modified dates.
298 // It's best to add values that are multiples of 2 (in seconds)
299 // to the current last_accessed and last_modified times, because
300 // FATxx uses a 2s timestamp granularity.
301 base::Time new_last_accessed
=
302 info
.last_accessed
+ base::TimeDelta::FromSeconds(234);
303 base::Time new_last_modified
=
304 info
.last_modified
+ base::TimeDelta::FromMinutes(567);
306 EXPECT_TRUE(base::TouchPlatformFile(file
, new_last_accessed
,
309 // Make sure the file info was updated accordingly.
310 EXPECT_TRUE(base::GetPlatformFileInfo(file
, &info
));
311 EXPECT_EQ(info
.size
, kTestDataSize
);
312 EXPECT_FALSE(info
.is_directory
);
313 EXPECT_FALSE(info
.is_symbolic_link
);
315 // ext2/ext3 and HPS/HPS+ seem to have a timestamp granularity of 1s.
316 #if defined(OS_POSIX)
317 EXPECT_EQ(info
.last_accessed
.ToTimeVal().tv_sec
,
318 new_last_accessed
.ToTimeVal().tv_sec
);
319 EXPECT_EQ(info
.last_modified
.ToTimeVal().tv_sec
,
320 new_last_modified
.ToTimeVal().tv_sec
);
322 EXPECT_EQ(info
.last_accessed
.ToInternalValue(),
323 new_last_accessed
.ToInternalValue());
324 EXPECT_EQ(info
.last_modified
.ToInternalValue(),
325 new_last_modified
.ToInternalValue());
328 EXPECT_EQ(info
.creation_time
.ToInternalValue(),
329 creation_time
.ToInternalValue());
331 // Close the file handle to allow the temp directory to be deleted.
332 base::ClosePlatformFile(file
);