Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Side by Side Diff: src/platform/update_engine/filesystem_copier_action.cc

Issue 465067: Missed new files in last commit
Patch Set: Created 11 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2009 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.
4
5 #include "update_engine/filesystem_copier_action.h"
6 #include <sys/stat.h>
7 #include <sys/types.h>
8 #include <errno.h>
9 #include <fcntl.h>
10 #include <stdlib.h>
11 #include <algorithm>
12 #include <string>
13 #include <vector>
14 #include "update_engine/filesystem_iterator.h"
15 #include "update_engine/subprocess.h"
16 #include "update_engine/utils.h"
17
18 using std::min;
19 using std::string;
20 using std::vector;
21
22 namespace chromeos_update_engine {
23
24 namespace {
25 const char* kMountpointTemplate = "/tmp/au_dest_mnt.XXXXXX";
26 const off_t kCopyFileBufferSize = 4 * 1024 * 1024;
27 const char* kCopyExclusionPrefix = "/lost+found";
28 } // namespace {}
29
30 void FilesystemCopierAction::PerformAction() {
31 if (!HasInputObject()) {
32 LOG(ERROR) << "No input object. Aborting.";
33 processor_->ActionComplete(this, false);
34 return;
35 }
36 install_plan_ = GetInputObject();
37
38 if (install_plan_.is_full_update) {
39 // No copy needed.
40 processor_->ActionComplete(this, true);
41 return;
42 }
43
44 {
45 // Set up dest_path_
46 char *dest_path_temp = strdup(kMountpointTemplate);
47 CHECK(dest_path_temp);
48 CHECK_EQ(mkdtemp(dest_path_temp), dest_path_temp);
49 CHECK_NE(dest_path_temp[0], '\0');
50 dest_path_ = dest_path_temp;
51 free(dest_path_temp);
52 }
53
54 // Make sure we're properly mounted
55 if (Mount(install_plan_.install_path, dest_path_)) {
56 bool done_early = false;
57 if (utils::FileExists(
58 (dest_path_ +
59 FilesystemCopierAction::kCompleteFilesystemMarker).c_str())) {
60 // We're done!
61 done_early = true;
62 skipped_copy_ = true;
63 if (HasOutputPipe())
64 SetOutputObject(install_plan_);
65 }
66 if (!Unmount(dest_path_)) {
67 LOG(ERROR) << "Unmount failed. Aborting.";
68 processor_->ActionComplete(this, false);
69 return;
70 }
71 if (done_early) {
72 CHECK(!is_mounted_);
73 if (rmdir(dest_path_.c_str()) != 0)
74 LOG(ERROR) << "Unable to remove " << dest_path_;
75 processor_->ActionComplete(this, true);
76 return;
77 }
78 }
79 LOG(ERROR) << "not mounted; spawning thread";
80 // If we get here, mount failed or we're not done yet. Reformat and copy.
81 CHECK_EQ(pthread_create(&helper_thread_, NULL, HelperThreadMainStatic, this),
82 0);
83 }
84
85 void FilesystemCopierAction::TerminateProcessing() {
86 if (is_mounted_) {
87 LOG(ERROR) << "Aborted processing, but left a filesystem mounted.";
88 }
89 }
90
91 bool FilesystemCopierAction::Mount(const string& device,
92 const string& mountpoint) {
93 CHECK(!is_mounted_);
94 if(utils::MountFilesystem(device, mountpoint))
95 is_mounted_ = true;
96 return is_mounted_;
97 }
98
99 bool FilesystemCopierAction::Unmount(const string& mountpoint) {
100 CHECK(is_mounted_);
101 if (utils::UnmountFilesystem(mountpoint))
102 is_mounted_ = false;
103 return !is_mounted_;
104 }
105
106 void* FilesystemCopierAction::HelperThreadMain() {
107 // First, format the drive
108 vector<string> cmd;
109 cmd.push_back("/sbin/mkfs.ext3");
110 cmd.push_back("-F");
111 cmd.push_back(install_plan_.install_path);
112 int return_code = 1;
113 bool success = Subprocess::SynchronousExec(cmd, &return_code);
114 if (return_code != 0) {
115 LOG(INFO) << "Format of " << install_plan_.install_path
116 << " failed. Exit code: " << return_code;
117 success = false;
118 }
119 if (success) {
120 if (!Mount(install_plan_.install_path, dest_path_)) {
121 LOG(ERROR) << "Mount failed. Aborting";
122 success = false;
123 }
124 }
125 if (success) {
126 success = CopySynchronously();
127 }
128 if (success) {
129 // Place our marker to avoid copies again in the future
130 int r = open((dest_path_ +
131 FilesystemCopierAction::kCompleteFilesystemMarker).c_str(),
132 O_CREAT | O_WRONLY, 0644);
133 if (r >= 0)
134 close(r);
135 }
136 // Unmount
137 if (!Unmount(dest_path_)) {
138 LOG(ERROR) << "Unmount failed. Aborting";
139 success = false;
140 }
141 if (HasOutputPipe())
142 SetOutputObject(install_plan_);
143
144 // Tell main thread that we're done
145 g_timeout_add(0, CollectThreadStatic, this);
146 return reinterpret_cast<void*>(success ? 0 : 1);
147 }
148
149 void FilesystemCopierAction::CollectThread() {
150 void *thread_ret_value = NULL;
151 CHECK_EQ(pthread_join(helper_thread_, &thread_ret_value), 0);
152 bool success = (thread_ret_value == 0);
153 CHECK(!is_mounted_);
154 if (rmdir(dest_path_.c_str()) != 0)
155 LOG(INFO) << "Unable to remove " << dest_path_;
156 LOG(INFO) << "FilesystemCopierAction done";
157 processor_->ActionComplete(this, success);
158 }
159
160 bool FilesystemCopierAction::CreateDirSynchronously(const std::string& new_path,
161 const struct stat& stbuf) {
162 int r = mkdir(new_path.c_str(), stbuf.st_mode);
163 TEST_AND_RETURN_FALSE_ERRNO(r == 0);
164 return true;
165 }
166
167 bool FilesystemCopierAction::CopyFileSynchronously(const std::string& old_path,
168 const std::string& new_path,
169 const struct stat& stbuf) {
170 int fd_out = open(new_path.c_str(), O_CREAT | O_EXCL | O_WRONLY,
171 stbuf.st_mode);
172 TEST_AND_RETURN_FALSE_ERRNO(fd_out >= 0);
173 ScopedFdCloser fd_out_closer(&fd_out);
174 int fd_in = open(old_path.c_str(), O_RDONLY, 0);
175 TEST_AND_RETURN_FALSE_ERRNO(fd_in >= 0);
176 ScopedFdCloser fd_in_closer(&fd_in);
177
178 vector<char> buf(min(kCopyFileBufferSize, stbuf.st_size));
179 off_t bytes_written = 0;
180 while (true) {
181 // Make sure we don't need to abort early:
182 TEST_AND_RETURN_FALSE(!g_atomic_int_get(&thread_should_exit_));
183
184 ssize_t read_size = read(fd_in, &buf[0], buf.size());
185 TEST_AND_RETURN_FALSE_ERRNO(read_size >= 0);
186 if (0 == read_size) // EOF
187 break;
188
189 ssize_t write_size = 0;
190 while (write_size < read_size) {
191 ssize_t r = write(fd_out, &buf[write_size], read_size - write_size);
192 TEST_AND_RETURN_FALSE_ERRNO(r >= 0);
193 write_size += r;
194 }
195 CHECK_EQ(write_size, read_size);
196 bytes_written += write_size;
197 CHECK_LE(bytes_written, stbuf.st_size);
198 if (bytes_written == stbuf.st_size)
199 break;
200 }
201 CHECK_EQ(bytes_written, stbuf.st_size);
202 return true;
203 }
204
205 bool FilesystemCopierAction::CreateHardLinkSynchronously(
206 const std::string& old_path,
207 const std::string& new_path) {
208 int r = link(old_path.c_str(), new_path.c_str());
209 TEST_AND_RETURN_FALSE_ERRNO(r == 0);
210 return true;
211 }
212
213 bool FilesystemCopierAction::CopySymlinkSynchronously(
214 const std::string& old_path,
215 const std::string& new_path,
216 const struct stat& stbuf) {
217 vector<char> buf(PATH_MAX + 1);
218 ssize_t r = readlink(old_path.c_str(), &buf[0], buf.size());
219 TEST_AND_RETURN_FALSE_ERRNO(r >= 0);
220 // Make sure we got the entire link
221 TEST_AND_RETURN_FALSE(static_cast<unsigned>(r) < buf.size());
222 buf[r] = '\0';
223 int rc = symlink(&buf[0], new_path.c_str());
224 TEST_AND_RETURN_FALSE_ERRNO(rc == 0);
225 return true;
226 }
227
228 bool FilesystemCopierAction::CreateNodeSynchronously(
229 const std::string& new_path,
230 const struct stat& stbuf) {
231 int r = mknod(new_path.c_str(), stbuf.st_mode, stbuf.st_rdev);
232 TEST_AND_RETURN_FALSE_ERRNO(r == 0);
233 return true;
234 }
235
236 // Returns true on success
237 bool FilesystemCopierAction::CopySynchronously() {
238 // This map is a map from inode # to new_path.
239 map<ino_t, string> hard_links;
240 FilesystemIterator iter(copy_source_,
241 utils::SetWithValue<string>(kCopyExclusionPrefix));
242 bool success = true;
243 for (; !g_atomic_int_get(&thread_should_exit_) &&
244 !iter.IsEnd(); iter.Increment()) {
245 const string old_path = iter.GetFullPath();
246 const string new_path = dest_path_ + iter.GetPartialPath();
247 LOG(INFO) << "copying " << old_path << " to " << new_path;
248 const struct stat stbuf = iter.GetStat();
249 success = false;
250
251 // Skip lost+found
252 CHECK_NE(kCopyExclusionPrefix, iter.GetPartialPath());
253
254 // Directories can't be hard-linked, so check for directories first
255 if (iter.GetPartialPath().empty()) {
256 // Root has an empty path.
257 // We don't need to create anything for the root, which is the first
258 // thing we get from the iterator.
259 success = true;
260 } else if (S_ISDIR(stbuf.st_mode)) {
261 success = CreateDirSynchronously(new_path, stbuf);
262 } else {
263 if (stbuf.st_nlink > 1 &&
264 utils::MapContainsKey(hard_links, stbuf.st_ino)) {
265 success = CreateHardLinkSynchronously(hard_links[stbuf.st_ino],
266 new_path);
267 } else {
268 if (stbuf.st_nlink > 1)
269 hard_links[stbuf.st_ino] = new_path;
270 if (S_ISREG(stbuf.st_mode)) {
271 success = CopyFileSynchronously(old_path, new_path, stbuf);
272 } else if (S_ISLNK(stbuf.st_mode)) {
273 success = CopySymlinkSynchronously(old_path, new_path, stbuf);
274 } else if (S_ISFIFO(stbuf.st_mode) ||
275 S_ISCHR(stbuf.st_mode) ||
276 S_ISBLK(stbuf.st_mode) ||
277 S_ISSOCK(stbuf.st_mode)) {
278 success = CreateNodeSynchronously(new_path, stbuf);
279 } else {
280 CHECK(false) << "Unable to copy file " << old_path << " with mode "
281 << stbuf.st_mode;
282 }
283 }
284 }
285 TEST_AND_RETURN_FALSE(success);
286
287 // chmod new file
288 if (!S_ISLNK(stbuf.st_mode)) {
289 int r = chmod(new_path.c_str(), stbuf.st_mode);
290 TEST_AND_RETURN_FALSE_ERRNO(r == 0);
291 }
292
293 // Set uid/gid.
294 int r = lchown(new_path.c_str(), stbuf.st_uid, stbuf.st_gid);
295 TEST_AND_RETURN_FALSE_ERRNO(r == 0);
296 }
297 TEST_AND_RETURN_FALSE(!iter.IsErr());
298 // Success!
299 return true;
300 }
301
302 const char* FilesystemCopierAction::kCompleteFilesystemMarker(
303 "/update_engine_copy_success");
304
305 } // namespace chromeos_update_engine
OLDNEW
« no previous file with comments | « src/platform/update_engine/filesystem_copier_action.h ('k') | src/platform/update_engine/filesystem_copier_action_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698