blob: a95a722946644735b467e8f1703ee2463b18459d (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
|
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/installer/util/self_cleaning_temp_dir.h"
#include <windows.h>
#include "base/file_util.h"
#include "base/logging.h"
#include "chrome/installer/util/delete_after_reboot_helper.h"
namespace installer {
// Populates |base_dir| with the topmost directory in the hierarchy of
// |temp_parent_dir| that does not exist. If |temp_parent_dir| exists,
// |base_dir| is cleared.
// static
void SelfCleaningTempDir::GetTopDirToCreate(const FilePath& temp_parent_dir,
FilePath* base_dir) {
DCHECK(base_dir);
if (file_util::PathExists(temp_parent_dir)) {
// Empty base_dir means that we didn't create any extra directories.
base_dir->clear();
} else {
FilePath parent_dir(temp_parent_dir);
do {
*base_dir = parent_dir;
parent_dir = parent_dir.DirName();
} while (parent_dir != *base_dir && !file_util::PathExists(parent_dir));
LOG_IF(WARNING, !file_util::DirectoryExists(parent_dir))
<< "A non-directory is at the base of the path leading to a desired "
"temp directory location: " << parent_dir.value();
}
}
SelfCleaningTempDir::SelfCleaningTempDir() {
}
SelfCleaningTempDir::~SelfCleaningTempDir() {
if (!path().empty() && !Delete())
LOG(WARNING) << "Failed to clean temp dir in dtor " << path().value();
}
bool SelfCleaningTempDir::Initialize(const FilePath& parent_dir,
const StringType& temp_name) {
DCHECK(parent_dir.IsAbsolute());
DCHECK(!temp_name.empty());
if (!path().empty()) {
LOG(DFATAL) << "Attempting to re-initialize a SelfSelfCleaningTempDir.";
return false;
}
FilePath temp_dir(parent_dir.Append(temp_name));
FilePath base_dir;
GetTopDirToCreate(parent_dir, &base_dir);
if (file_util::CreateDirectory(temp_dir)) {
base_dir_ = base_dir;
temp_dir_ = temp_dir;
return true;
}
return false;
}
bool SelfCleaningTempDir::Delete() {
if (path().empty()) {
LOG(DFATAL) << "Attempting to Delete an uninitialized SelfCleaningTempDir.";
return false;
}
FilePath next_dir(path().DirName());
bool schedule_deletes = false;
// First try to recursively delete the leaf directory managed by our
// ScopedTempDir.
if (!file_util::Delete(path(), true)) {
// That failed, so schedule the temp dir and its contents for deletion after
// reboot.
LOG(WARNING) << "Failed to delete temporary directory " << path().value()
<< ". Scheduling for deletion at reboot.";
schedule_deletes = true;
if (!ScheduleDirectoryForDeletion(path().value().c_str()))
return false; // Entirely unexpected failure (Schedule logs the reason).
}
// Now delete or schedule all empty directories up to and including our
// base_dir_. Any that can't be deleted are scheduled for deletion at reboot.
// This is safe since they'll only be deleted in that case if they're empty.
if (!base_dir_.empty()) {
do {
if (!schedule_deletes && !RemoveDirectory(next_dir.value().c_str())) {
PLOG_IF(WARNING, GetLastError() != ERROR_DIR_NOT_EMPTY)
<< "Error removing directory " << next_dir.value().c_str();
schedule_deletes = true;
}
if (schedule_deletes) {
// Ignore the return code. If we fail to schedule, go ahead and add the
// other parent directories anyway.
ScheduleFileSystemEntityForDeletion(next_dir.value().c_str());
}
if (next_dir == base_dir_)
break; // We just processed the topmost directory we created.
next_dir = next_dir.DirName();
} while (true);
}
base_dir_.clear();
temp_dir_.clear();
return true;
}
} // namespace installer
|