1 /*
2 * Copyright (C) 2021 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 <android-base/file.h>
18 #include <android-base/logging.h>
19 #include <android-base/stringprintf.h>
20 #include <gtest/gtest.h>
21 #include <log/log.h>
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include "restorable_file.h"
26 #include "unique_file.h"
27 #include "utils.h"
28
29 #undef LOG_TAG
30 #define LOG_TAG "installd_file_test"
31
32 namespace {
33
34 constexpr char kFileTestDir[] = "/data/local/tmp/installd_file_test_data";
35 constexpr char kTmpFileSuffix[] = ".tmp";
36 constexpr char kBackupFileSuffix[] = ".backup";
37
UnlinkWithAssert(const std::string & path)38 void UnlinkWithAssert(const std::string& path) {
39 ASSERT_EQ(0, unlink(path.c_str()));
40 }
41
42 } // namespace
43
44 namespace android {
45 namespace installd {
46
47 // Add these as macros as functions make it hard to tell where the failure has happened.
48 #define ASSERT_FILE_NOT_EXISTING(path) \
49 { \
50 struct stat st; \
51 ASSERT_NE(0, ::stat(path.c_str(), &st)); \
52 }
53 #define ASSERT_FILE_EXISTING(path) \
54 { \
55 struct stat st; \
56 ASSERT_EQ(0, ::stat(path.c_str(), &st)); \
57 }
58 #define ASSERT_FILE_CONTENT(path, expectedContent) ASSERT_EQ(expectedContent, ReadTestFile(path))
59 #define ASSERT_FILE_OPEN(path, fd) \
60 { \
61 fd = open(path.c_str(), O_RDWR); \
62 ASSERT_TRUE(fd >= 0); \
63 }
64 #define ASSERT_WRITE_TO_FD(fd, content) \
65 ASSERT_TRUE(android::base::WriteStringToFd(content, android::base::borrowed_fd(fd)))
66
67 class FileTest : public testing::Test {
68 protected:
SetUp()69 virtual void SetUp() {
70 setenv("ANDROID_LOG_TAGS", "*:v", 1);
71 android::base::InitLogging(nullptr);
72
73 ASSERT_EQ(0, create_dir_if_needed(kFileTestDir, 0777));
74 }
75
TearDown()76 virtual void TearDown() {
77 system(android::base::StringPrintf("rm -rf %s", kFileTestDir).c_str());
78 }
79
GetTestFilePath(const std::string & fileName)80 std::string GetTestFilePath(const std::string& fileName) {
81 return android::base::StringPrintf("%s/%s", kFileTestDir, fileName.c_str());
82 }
83
CreateTestFileWithContents(const std::string & path,const std::string & content)84 void CreateTestFileWithContents(const std::string& path, const std::string& content) {
85 ALOGI("CreateTestFileWithContents:%s", path.c_str());
86 ASSERT_TRUE(android::base::WriteStringToFile(content, path));
87 }
88
GetTestName()89 std::string GetTestName() {
90 std::string name(testing::UnitTest::GetInstance()->current_test_info()->name());
91 return name;
92 }
93
ReadTestFile(const std::string & path)94 std::string ReadTestFile(const std::string& path) {
95 std::string content;
96 bool r = android::base::ReadFileToString(path, &content);
97 if (!r) {
98 PLOG(ERROR) << "Cannot read file:" << path;
99 }
100 return content;
101 }
102 };
103
TEST_F(FileTest,TestUniqueFileMoveConstruction)104 TEST_F(FileTest, TestUniqueFileMoveConstruction) {
105 const int fd = 101;
106 std::string testFile = GetTestFilePath(GetTestName());
107 UniqueFile uf1(fd, testFile);
108 uf1.DisableAutoClose();
109
110 UniqueFile uf2(std::move(uf1));
111
112 ASSERT_EQ(fd, uf2.fd());
113 ASSERT_EQ(testFile, uf2.path());
114 }
115
TEST_F(FileTest,TestUniqueFileAssignment)116 TEST_F(FileTest, TestUniqueFileAssignment) {
117 const int fd1 = 101;
118 const int fd2 = 102;
119 std::string testFile1 = GetTestFilePath(GetTestName());
120 std::string testFile2 = GetTestFilePath(GetTestName() + "2");
121
122 UniqueFile uf1(fd1, testFile1);
123 uf1.DisableAutoClose();
124
125 UniqueFile uf2(fd2, testFile2);
126 uf2.DisableAutoClose();
127
128 ASSERT_EQ(fd2, uf2.fd());
129 ASSERT_EQ(testFile2, uf2.path());
130
131 uf2 = std::move(uf1);
132
133 ASSERT_EQ(fd1, uf2.fd());
134 ASSERT_EQ(testFile1, uf2.path());
135 }
136
TEST_F(FileTest,TestUniqueFileCleanup)137 TEST_F(FileTest, TestUniqueFileCleanup) {
138 std::string testFile = GetTestFilePath(GetTestName());
139 CreateTestFileWithContents(testFile, "OriginalContent");
140
141 int fd;
142 ASSERT_FILE_OPEN(testFile, fd);
143
144 { UniqueFile uf = UniqueFile(fd, testFile, UnlinkWithAssert); }
145
146 ASSERT_FILE_NOT_EXISTING(testFile);
147 }
148
TEST_F(FileTest,TestUniqueFileNoCleanup)149 TEST_F(FileTest, TestUniqueFileNoCleanup) {
150 std::string testFile = GetTestFilePath(GetTestName());
151 CreateTestFileWithContents(testFile, "OriginalContent");
152
153 int fd;
154 ASSERT_FILE_OPEN(testFile, fd);
155
156 {
157 UniqueFile uf = UniqueFile(fd, testFile, UnlinkWithAssert);
158 uf.DisableCleanup();
159 }
160
161 ASSERT_FILE_CONTENT(testFile, "OriginalContent");
162 }
163
TEST_F(FileTest,TestUniqueFileFd)164 TEST_F(FileTest, TestUniqueFileFd) {
165 std::string testFile = GetTestFilePath(GetTestName());
166 CreateTestFileWithContents(testFile, "OriginalContent");
167
168 int fd;
169 ASSERT_FILE_OPEN(testFile, fd);
170
171 UniqueFile uf(fd, testFile, UnlinkWithAssert);
172
173 ASSERT_EQ(fd, uf.fd());
174
175 uf.reset();
176
177 ASSERT_EQ(-1, uf.fd());
178 }
179
TEST_F(FileTest,TestRestorableFileMoveConstruction)180 TEST_F(FileTest, TestRestorableFileMoveConstruction) {
181 std::string testFile = GetTestFilePath(GetTestName());
182
183 RestorableFile rf1 = RestorableFile::CreateWritableFile(testFile, 0600);
184 int fd = rf1.fd();
185
186 RestorableFile rf2(std::move(rf1));
187
188 ASSERT_EQ(fd, rf2.fd());
189 ASSERT_EQ(testFile, rf2.path());
190 }
191
TEST_F(FileTest,TestRestorableFileAssignment)192 TEST_F(FileTest, TestRestorableFileAssignment) {
193 std::string testFile1 = GetTestFilePath(GetTestName());
194 std::string testFile2 = GetTestFilePath(GetTestName() + "2");
195
196 RestorableFile rf1 = RestorableFile::CreateWritableFile(testFile1, 0600);
197 int fd1 = rf1.fd();
198
199 RestorableFile rf2 = RestorableFile::CreateWritableFile(testFile2, 0600);
200 int fd2 = rf2.fd();
201
202 ASSERT_EQ(fd2, rf2.fd());
203 ASSERT_EQ(testFile2, rf2.path());
204
205 rf2 = std::move(rf1);
206
207 ASSERT_EQ(fd1, rf2.fd());
208 ASSERT_EQ(testFile1, rf2.path());
209 }
210
TEST_F(FileTest,TestRestorableFileVerifyUniqueFileWithReset)211 TEST_F(FileTest, TestRestorableFileVerifyUniqueFileWithReset) {
212 std::string testFile = GetTestFilePath(GetTestName());
213 std::string tmpFile = testFile + kTmpFileSuffix;
214
215 {
216 RestorableFile rf = RestorableFile::CreateWritableFile(testFile, 0600);
217
218 ASSERT_FILE_EXISTING(tmpFile);
219
220 const UniqueFile& uf = rf.GetUniqueFile();
221
222 ASSERT_EQ(rf.fd(), uf.fd());
223 ASSERT_EQ(rf.path(), uf.path());
224
225 rf.reset();
226
227 ASSERT_EQ(rf.fd(), uf.fd());
228 ASSERT_EQ(rf.path(), uf.path());
229 ASSERT_EQ(-1, rf.fd());
230 ASSERT_TRUE(rf.path().empty());
231 }
232 }
233
TEST_F(FileTest,TestRestorableFileVerifyUniqueFileWithCommit)234 TEST_F(FileTest, TestRestorableFileVerifyUniqueFileWithCommit) {
235 std::string testFile = GetTestFilePath(GetTestName());
236 std::string tmpFile = testFile + kTmpFileSuffix;
237 std::string backupFile = testFile + kBackupFileSuffix;
238
239 {
240 RestorableFile rf = RestorableFile::CreateWritableFile(testFile, 0600);
241
242 ASSERT_FILE_EXISTING(tmpFile);
243
244 const UniqueFile& uf = rf.GetUniqueFile();
245
246 ASSERT_EQ(rf.fd(), uf.fd());
247 ASSERT_EQ(rf.path(), uf.path());
248
249 ASSERT_TRUE(rf.CreateBackupFile());
250
251 ASSERT_FILE_NOT_EXISTING(backupFile);
252
253 rf.CommitWorkFile();
254
255 ASSERT_EQ(rf.fd(), uf.fd());
256 ASSERT_EQ(rf.path(), uf.path());
257 ASSERT_EQ(-1, rf.fd());
258 ASSERT_EQ(testFile, rf.path());
259 }
260 }
261
TEST_F(FileTest,TestRestorableFileNewFileNotCommitted)262 TEST_F(FileTest, TestRestorableFileNewFileNotCommitted) {
263 std::string testFile = GetTestFilePath(GetTestName());
264 std::string tmpFile = testFile + kTmpFileSuffix;
265
266 {
267 RestorableFile rf = RestorableFile::CreateWritableFile(testFile, 0600);
268
269 ASSERT_FILE_EXISTING(tmpFile);
270 ASSERT_FILE_NOT_EXISTING(testFile);
271
272 ASSERT_WRITE_TO_FD(rf.fd(), "NewContent");
273
274 ASSERT_FILE_CONTENT(tmpFile, "NewContent");
275 }
276
277 ASSERT_FILE_NOT_EXISTING(tmpFile);
278 ASSERT_FILE_NOT_EXISTING(testFile);
279 }
280
TEST_F(FileTest,TestRestorableFileNotCommittedWithOriginal)281 TEST_F(FileTest, TestRestorableFileNotCommittedWithOriginal) {
282 std::string testFile = GetTestFilePath(GetTestName());
283 std::string tmpFile = testFile + kTmpFileSuffix;
284 CreateTestFileWithContents(testFile, "OriginalContent");
285
286 {
287 RestorableFile rf = RestorableFile::CreateWritableFile(testFile, 0600);
288 ASSERT_WRITE_TO_FD(rf.fd(), "NewContent");
289
290 ASSERT_FILE_CONTENT(tmpFile, "NewContent");
291 ASSERT_FILE_EXISTING(testFile);
292 }
293
294 ASSERT_FILE_NOT_EXISTING(tmpFile);
295 ASSERT_FILE_CONTENT(testFile, "OriginalContent");
296 }
297
TEST_F(FileTest,TestRestorableFileNotCommittedWithOriginalAndOldTmp)298 TEST_F(FileTest, TestRestorableFileNotCommittedWithOriginalAndOldTmp) {
299 std::string testFile = GetTestFilePath(GetTestName());
300 std::string tmpFile = testFile + kTmpFileSuffix;
301 CreateTestFileWithContents(testFile, "OriginalContent");
302 CreateTestFileWithContents(testFile + kTmpFileSuffix, "OldTmp");
303
304 {
305 RestorableFile rf = RestorableFile::CreateWritableFile(testFile, 0600);
306 ASSERT_WRITE_TO_FD(rf.fd(), "NewContent");
307
308 ASSERT_FILE_CONTENT(tmpFile, "NewContent");
309 ASSERT_FILE_EXISTING(testFile);
310 }
311
312 ASSERT_FILE_NOT_EXISTING(tmpFile);
313 ASSERT_FILE_CONTENT(testFile, "OriginalContent");
314 }
315
TEST_F(FileTest,TestRestorableFileNewFileCommitted)316 TEST_F(FileTest, TestRestorableFileNewFileCommitted) {
317 std::string testFile = GetTestFilePath(GetTestName());
318 std::string tmpFile = testFile + kTmpFileSuffix;
319 std::string backupFile = testFile + kBackupFileSuffix;
320
321 {
322 RestorableFile rf = RestorableFile::CreateWritableFile(testFile, 0600);
323
324 ASSERT_FILE_EXISTING(tmpFile);
325 ASSERT_FILE_NOT_EXISTING(testFile);
326
327 ASSERT_WRITE_TO_FD(rf.fd(), "NewContent");
328 ASSERT_FILE_CONTENT(tmpFile, "NewContent");
329
330 ASSERT_TRUE(rf.CreateBackupFile());
331
332 ASSERT_FILE_NOT_EXISTING(backupFile);
333
334 ASSERT_TRUE(rf.CommitWorkFile());
335 rf.RemoveBackupFile();
336
337 ASSERT_FILE_CONTENT(testFile, "NewContent");
338 }
339
340 ASSERT_FILE_NOT_EXISTING(tmpFile);
341 ASSERT_FILE_NOT_EXISTING(backupFile);
342 ASSERT_FILE_CONTENT(testFile, "NewContent");
343 }
344
TEST_F(FileTest,TestRestorableFileCommittedWithOriginal)345 TEST_F(FileTest, TestRestorableFileCommittedWithOriginal) {
346 std::string testFile = GetTestFilePath(GetTestName());
347 std::string tmpFile = testFile + kTmpFileSuffix;
348 std::string backupFile = testFile + kBackupFileSuffix;
349 CreateTestFileWithContents(testFile, "OriginalContent");
350
351 {
352 RestorableFile rf = RestorableFile::CreateWritableFile(testFile, 0600);
353 ASSERT_WRITE_TO_FD(rf.fd(), "NewContent");
354 ASSERT_FILE_CONTENT(tmpFile, "NewContent");
355
356 ASSERT_TRUE(rf.CreateBackupFile());
357
358 ASSERT_FILE_NOT_EXISTING(testFile);
359 ASSERT_FILE_EXISTING(backupFile);
360
361 ASSERT_TRUE(rf.CommitWorkFile());
362
363 ASSERT_FILE_EXISTING(backupFile);
364 ASSERT_FILE_CONTENT(testFile, "NewContent");
365
366 rf.RemoveBackupFile();
367
368 ASSERT_FILE_NOT_EXISTING(backupFile);
369 }
370
371 ASSERT_FILE_NOT_EXISTING(tmpFile);
372 ASSERT_FILE_CONTENT(testFile, "NewContent");
373 }
374
TEST_F(FileTest,TestRestorableFileCommittedWithOriginalAndOldTmp)375 TEST_F(FileTest, TestRestorableFileCommittedWithOriginalAndOldTmp) {
376 std::string testFile = GetTestFilePath(GetTestName());
377 std::string tmpFile = testFile + kTmpFileSuffix;
378 CreateTestFileWithContents(testFile, "OriginalContent");
379 CreateTestFileWithContents(testFile + kTmpFileSuffix, "OldTmp");
380
381 {
382 RestorableFile rf = RestorableFile::CreateWritableFile(testFile, 0600);
383 ASSERT_WRITE_TO_FD(rf.fd(), "NewContent");
384 ASSERT_FILE_CONTENT(tmpFile, "NewContent");
385
386 ASSERT_TRUE(rf.CommitWorkFile());
387
388 ASSERT_FILE_CONTENT(testFile, "NewContent");
389 }
390
391 ASSERT_FILE_NOT_EXISTING(tmpFile);
392 ASSERT_FILE_CONTENT(testFile, "NewContent");
393 }
394
TEST_F(FileTest,TestRestorableFileCommitFailureNoOriginal)395 TEST_F(FileTest, TestRestorableFileCommitFailureNoOriginal) {
396 std::string testFile = GetTestFilePath(GetTestName());
397 std::string tmpFile = testFile + kTmpFileSuffix;
398 std::string backupFile = testFile + kBackupFileSuffix;
399
400 {
401 RestorableFile rf = RestorableFile::CreateWritableFile(testFile, 0600);
402 ASSERT_WRITE_TO_FD(rf.fd(), "NewContent");
403
404 ASSERT_TRUE(rf.CreateBackupFile());
405
406 ASSERT_FILE_NOT_EXISTING(testFile);
407 ASSERT_FILE_NOT_EXISTING(backupFile);
408
409 // Now remove tmp file to force commit failure.
410 close(rf.fd());
411 ASSERT_EQ(0, unlink(tmpFile.c_str()));
412 ASSERT_FILE_NOT_EXISTING(tmpFile);
413
414 ASSERT_FALSE(rf.CommitWorkFile());
415
416 ASSERT_EQ(-1, rf.fd());
417 ASSERT_EQ(testFile, rf.path());
418 ASSERT_FILE_NOT_EXISTING(testFile);
419 ASSERT_FILE_NOT_EXISTING(tmpFile);
420
421 ASSERT_TRUE(rf.RestoreBackupFile());
422 }
423
424 ASSERT_FILE_NOT_EXISTING(testFile);
425 ASSERT_FILE_NOT_EXISTING(tmpFile);
426 ASSERT_FILE_NOT_EXISTING(backupFile);
427 }
428
TEST_F(FileTest,TestRestorableFileCommitFailureAndRollback)429 TEST_F(FileTest, TestRestorableFileCommitFailureAndRollback) {
430 std::string testFile = GetTestFilePath(GetTestName());
431 std::string tmpFile = testFile + kTmpFileSuffix;
432 std::string backupFile = testFile + kBackupFileSuffix;
433 CreateTestFileWithContents(testFile, "OriginalContent");
434
435 {
436 RestorableFile rf = RestorableFile::CreateWritableFile(testFile, 0600);
437 ASSERT_WRITE_TO_FD(rf.fd(), "NewContent");
438
439 ASSERT_TRUE(rf.CreateBackupFile());
440
441 ASSERT_FILE_NOT_EXISTING(testFile);
442 ASSERT_FILE_EXISTING(backupFile);
443
444 // Now remove tmp file to force commit failure.
445 close(rf.fd());
446 ASSERT_EQ(0, unlink(tmpFile.c_str()));
447 ASSERT_FILE_NOT_EXISTING(tmpFile);
448
449 ASSERT_FALSE(rf.CommitWorkFile());
450
451 ASSERT_EQ(-1, rf.fd());
452 ASSERT_EQ(testFile, rf.path());
453 ASSERT_FILE_NOT_EXISTING(testFile);
454 ASSERT_FILE_NOT_EXISTING(tmpFile);
455 ASSERT_FILE_EXISTING(backupFile);
456
457 ASSERT_TRUE(rf.RestoreBackupFile());
458 }
459
460 ASSERT_FILE_EXISTING(testFile);
461 ASSERT_FILE_NOT_EXISTING(tmpFile);
462 ASSERT_FILE_NOT_EXISTING(backupFile);
463 }
464
TEST_F(FileTest,TestRestorableFileResetAndRemoveAllFiles)465 TEST_F(FileTest, TestRestorableFileResetAndRemoveAllFiles) {
466 std::string testFile = GetTestFilePath(GetTestName());
467 std::string tmpFile = testFile + kTmpFileSuffix;
468 std::string backupFile = testFile + kBackupFileSuffix;
469 CreateTestFileWithContents(testFile, "OriginalContent");
470
471 {
472 RestorableFile rf = RestorableFile::CreateWritableFile(testFile, 0600);
473 ASSERT_WRITE_TO_FD(rf.fd(), "NewContent");
474
475 ASSERT_TRUE(rf.CreateBackupFile());
476
477 ASSERT_FILE_NOT_EXISTING(testFile);
478 ASSERT_FILE_EXISTING(backupFile);
479
480 rf.ResetAndRemoveAllFiles();
481
482 ASSERT_EQ(-1, rf.fd());
483 ASSERT_FILE_NOT_EXISTING(tmpFile);
484 ASSERT_FILE_NOT_EXISTING(testFile);
485 ASSERT_FILE_NOT_EXISTING(backupFile);
486 }
487
488 ASSERT_FILE_NOT_EXISTING(tmpFile);
489 ASSERT_FILE_NOT_EXISTING(testFile);
490 ASSERT_FILE_NOT_EXISTING(backupFile);
491 }
492
TEST_F(FileTest,TestRestorableFileRemoveFileAndTmpFileWithContentFile)493 TEST_F(FileTest, TestRestorableFileRemoveFileAndTmpFileWithContentFile) {
494 std::string testFile = GetTestFilePath(GetTestName());
495 std::string tmpFile = testFile + kTmpFileSuffix;
496 std::string backupFile = testFile + kBackupFileSuffix;
497 CreateTestFileWithContents(testFile, "OriginalContent");
498
499 RestorableFile::RemoveAllFiles(testFile);
500
501 ASSERT_FILE_NOT_EXISTING(tmpFile);
502 ASSERT_FILE_NOT_EXISTING(testFile);
503 ASSERT_FILE_NOT_EXISTING(backupFile);
504 }
505
TEST_F(FileTest,TestRestorableFileRemoveFileAndTmpFileWithContentAndTmpFile)506 TEST_F(FileTest, TestRestorableFileRemoveFileAndTmpFileWithContentAndTmpFile) {
507 std::string testFile = GetTestFilePath(GetTestName());
508 std::string tmpFile = testFile + kTmpFileSuffix;
509 std::string backupFile = testFile + kBackupFileSuffix;
510 CreateTestFileWithContents(testFile, "OriginalContent");
511 CreateTestFileWithContents(testFile + kTmpFileSuffix, "TmpContent");
512
513 RestorableFile::RemoveAllFiles(testFile);
514
515 ASSERT_FILE_NOT_EXISTING(tmpFile);
516 ASSERT_FILE_NOT_EXISTING(testFile);
517 ASSERT_FILE_NOT_EXISTING(backupFile);
518 }
519
520 } // namespace installd
521 } // namespace android
522