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 "chrome/installer/util/self_cleaning_temp_dir.h"
9 #include "base/files/file_util.h"
10 #include "base/logging.h"
11 #include "chrome/installer/util/delete_after_reboot_helper.h"
15 // Populates |base_dir| with the topmost directory in the hierarchy of
16 // |temp_parent_dir| that does not exist. If |temp_parent_dir| exists,
17 // |base_dir| is cleared.
19 void SelfCleaningTempDir::GetTopDirToCreate(
20 const base::FilePath
& temp_parent_dir
,
21 base::FilePath
* base_dir
) {
24 if (base::PathExists(temp_parent_dir
)) {
25 // Empty base_dir means that we didn't create any extra directories.
28 base::FilePath
parent_dir(temp_parent_dir
);
30 *base_dir
= parent_dir
;
31 parent_dir
= parent_dir
.DirName();
32 } while (parent_dir
!= *base_dir
&& !base::PathExists(parent_dir
));
33 LOG_IF(WARNING
, !base::DirectoryExists(parent_dir
))
34 << "A non-directory is at the base of the path leading to a desired "
35 "temp directory location: " << parent_dir
.value();
39 SelfCleaningTempDir::SelfCleaningTempDir() {
42 SelfCleaningTempDir::~SelfCleaningTempDir() {
43 if (!path().empty() && !Delete())
44 LOG(WARNING
) << "Failed to clean temp dir in dtor " << path().value();
47 bool SelfCleaningTempDir::Initialize(const base::FilePath
& parent_dir
,
48 const StringType
& temp_name
) {
49 DCHECK(parent_dir
.IsAbsolute());
50 DCHECK(!temp_name
.empty());
52 if (!path().empty()) {
53 LOG(DFATAL
) << "Attempting to re-initialize a SelfSelfCleaningTempDir.";
57 base::FilePath
temp_dir(parent_dir
.Append(temp_name
));
58 base::FilePath base_dir
;
59 GetTopDirToCreate(parent_dir
, &base_dir
);
61 if (base::CreateDirectory(temp_dir
)) {
70 bool SelfCleaningTempDir::Delete() {
72 LOG(DFATAL
) << "Attempting to Delete an uninitialized SelfCleaningTempDir.";
76 base::FilePath
next_dir(path().DirName());
77 bool schedule_deletes
= false;
79 // First try to recursively delete the leaf directory managed by our
80 // base::ScopedTempDir.
81 if (!base::DeleteFile(path(), true)) {
82 // That failed, so schedule the temp dir and its contents for deletion after
84 LOG(WARNING
) << "Failed to delete temporary directory " << path().value()
85 << ". Scheduling for deletion at reboot.";
86 schedule_deletes
= true;
87 if (!ScheduleDirectoryForDeletion(path()))
88 return false; // Entirely unexpected failure (Schedule logs the reason).
91 // Now delete or schedule all empty directories up to and including our
92 // base_dir_. Any that can't be deleted are scheduled for deletion at reboot.
93 // This is safe since they'll only be deleted in that case if they're empty.
94 if (!base_dir_
.empty()) {
96 if (!schedule_deletes
&& !RemoveDirectory(next_dir
.value().c_str())) {
97 PLOG_IF(WARNING
, GetLastError() != ERROR_DIR_NOT_EMPTY
)
98 << "Error removing directory " << next_dir
.value().c_str();
99 schedule_deletes
= true;
101 if (schedule_deletes
) {
102 // Ignore the return code. If we fail to schedule, go ahead and add the
103 // other parent directories anyway.
104 ScheduleFileSystemEntityForDeletion(next_dir
);
106 if (next_dir
== base_dir_
)
107 break; // We just processed the topmost directory we created.
108 next_dir
= next_dir
.DirName();
118 } // namespace installer