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

Side by Side Diff: webkit/fileapi/file_util_helper.cc

Issue 9616033: Merge CrossFileUtilHelper to FileUtilHelper as Copy() and Move(). (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: test fix Created 8 years, 9 months 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 | Annotate | Revision Log
« no previous file with comments | « webkit/fileapi/file_util_helper.h ('k') | webkit/fileapi/webkit_fileapi.gypi » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "webkit/fileapi/file_util_helper.h" 5 #include "webkit/fileapi/file_util_helper.h"
6 6
7 #include "webkit/fileapi/file_system_file_util.h" 7 #include "webkit/fileapi/file_system_file_util.h"
8 #include "webkit/fileapi/file_system_operation_context.h" 8 #include "webkit/fileapi/file_system_operation_context.h"
9 #include "webkit/fileapi/file_system_path.h" 9 #include "webkit/fileapi/file_system_path.h"
10 10
11 using base::PlatformFileError; 11 using base::PlatformFileError;
12 12
13 namespace fileapi { 13 namespace fileapi {
14 14
15 namespace {
16
17 // A helper class for cross-FileUtil Copy/Move operations.
18 class CrossFileUtilHelper {
19 public:
20 enum Operation {
21 OPERATION_COPY,
22 OPERATION_MOVE
23 };
24
25 CrossFileUtilHelper(FileSystemOperationContext* context,
26 FileSystemFileUtil* src_util,
27 FileSystemFileUtil* dest_util,
28 const FileSystemPath& src_path,
29 const FileSystemPath& dest_path,
30 Operation operation);
31 ~CrossFileUtilHelper();
32
33 base::PlatformFileError DoWork();
34
35 private:
36 // Performs common pre-operation check and preparation.
37 // This may delete the destination directory if it's empty.
38 base::PlatformFileError PerformErrorCheckAndPreparation();
39
40 // This assumes that the root exists.
41 bool ParentExists(const FileSystemPath& path, FileSystemFileUtil* file_util);
42
43 // Performs recursive copy or move by calling CopyOrMoveFile for individual
44 // files. Operations for recursive traversal are encapsulated in this method.
45 // It assumes src_path and dest_path have passed
46 // PerformErrorCheckAndPreparationForMoveAndCopy().
47 base::PlatformFileError CopyOrMoveDirectory(
48 const FileSystemPath& src_path,
49 const FileSystemPath& dest_path);
50
51 // Determines whether a simple same-filesystem move or copy can be done. If
52 // so, it delegates to CopyOrMoveFile. Otherwise it looks up the true
53 // platform path of the source file, delegates to CopyInForeignFile, and [for
54 // move] calls DeleteFile on the source file.
55 base::PlatformFileError CopyOrMoveFile(
56 const FileSystemPath& src_path,
57 const FileSystemPath& dest_path);
58
59 FileSystemOperationContext* context_;
60 FileSystemFileUtil* src_util_; // Not owned.
61 FileSystemFileUtil* dest_util_; // Not owned.
62 const FileSystemPath& src_root_path_;
63 const FileSystemPath& dest_root_path_;
64 Operation operation_;
65 bool same_file_system_;
66
67 DISALLOW_COPY_AND_ASSIGN(CrossFileUtilHelper);
68 };
69
70 CrossFileUtilHelper::CrossFileUtilHelper(
71 FileSystemOperationContext* context,
72 FileSystemFileUtil* src_util,
73 FileSystemFileUtil* dest_util,
74 const FileSystemPath& src_path,
75 const FileSystemPath& dest_path,
76 Operation operation)
77 : context_(context),
78 src_util_(src_util),
79 dest_util_(dest_util),
80 src_root_path_(src_path),
81 dest_root_path_(dest_path),
82 operation_(operation) {
83 same_file_system_ =
84 src_root_path_.origin() == dest_root_path_.origin() &&
85 src_root_path_.type() == dest_root_path_.type();
86 }
87
88 CrossFileUtilHelper::~CrossFileUtilHelper() {}
89
90 base::PlatformFileError CrossFileUtilHelper::DoWork() {
91 base::PlatformFileError error = PerformErrorCheckAndPreparation();
92 if (error != base::PLATFORM_FILE_OK)
93 return error;
94 if (src_util_->DirectoryExists(context_, src_root_path_)) {
95 return CopyOrMoveDirectory(src_root_path_, dest_root_path_);
96 }
kinuko 2012/03/06 23:46:36 nit: looks like we can/should remove { } for singl
tzik 2012/03/07 00:27:13 Done.
97 return CopyOrMoveFile(src_root_path_, dest_root_path_);
98 }
99
100 PlatformFileError CrossFileUtilHelper::PerformErrorCheckAndPreparation() {
101 // Exits earlier if the source path does not exist.
102 if (!src_util_->PathExists(context_, src_root_path_))
103 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
104
105 // The parent of the |dest_root_path_| does not exist.
106 if (!ParentExists(dest_root_path_, dest_util_))
107 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
108
109 // It is an error to try to copy/move an entry into its child.
110 if (same_file_system_ && src_root_path_.IsParent(dest_root_path_))
111 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
112
113 // Now it is ok to return if the |dest_root_path_| does not exist.
114 if (!dest_util_->PathExists(context_, dest_root_path_))
115 return base::PLATFORM_FILE_OK;
116
117 // |src_root_path_| exists and is a directory.
118 // |dest_root_path_| exists and is a file.
119 bool src_is_directory = src_util_->DirectoryExists(context_, src_root_path_);
120 bool dest_is_directory =
121 dest_util_->DirectoryExists(context_, dest_root_path_);
122
123 // Either one of |src_root_path_| or |dest_root_path_| is directory,
124 // while the other is not.
125 if (src_is_directory != dest_is_directory)
126 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
127
128 // It is an error to copy/move an entry into the same path.
129 if (same_file_system_ && (src_root_path_.internal_path() ==
130 dest_root_path_.internal_path()))
kinuko 2012/03/06 23:46:36 indent looks slightly off?
tzik 2012/03/07 00:27:13 Done.
131 return base::PLATFORM_FILE_ERROR_EXISTS;
132
133 if (dest_is_directory) {
134 // It is an error to copy/move an entry to a non-empty directory.
135 // Otherwise the copy/move attempt must overwrite the destination, but
136 // the file_util's Copy or Move method doesn't perform overwrite
137 // on all platforms, so we delete the destination directory here.
138 if (base::PLATFORM_FILE_OK !=
139 dest_util_->DeleteSingleDirectory(context_, dest_root_path_)) {
140 if (!dest_util_->IsDirectoryEmpty(context_, dest_root_path_))
141 return base::PLATFORM_FILE_ERROR_NOT_EMPTY;
142 return base::PLATFORM_FILE_ERROR_FAILED;
143 }
144 }
145 return base::PLATFORM_FILE_OK;
146 }
147
148 bool CrossFileUtilHelper::ParentExists(
149 const FileSystemPath& path, FileSystemFileUtil* file_util) {
150 // If path is in the root, path.DirName() will be ".",
151 // since we use paths with no leading '/'.
152 FilePath parent = path.internal_path().DirName();
153 if (parent == FilePath(FILE_PATH_LITERAL(".")))
154 return true;
155 return file_util->DirectoryExists(
156 context_, path.WithInternalPath(parent));
157 }
158
159 PlatformFileError CrossFileUtilHelper::CopyOrMoveDirectory(
160 const FileSystemPath& src_path,
161 const FileSystemPath& dest_path) {
162 // At this point we must have gone through
163 // PerformErrorCheckAndPreparationForMoveAndCopy so this must be true.
164 DCHECK(!same_file_system_ ||
165 !src_path.IsParent(dest_path));
166
167 PlatformFileError error = dest_util_->CreateDirectory(
168 context_, dest_path, false, false);
169 if (error != base::PLATFORM_FILE_OK)
170 return error;
171
172 scoped_ptr<FileSystemFileUtil::AbstractFileEnumerator> file_enum(
173 src_util_->CreateFileEnumerator(context_, src_path));
174 FilePath src_file_path_each;
175 while (!(src_file_path_each = file_enum->Next()).empty()) {
176 FilePath dest_file_path_each(dest_path.internal_path());
177 src_path.internal_path().AppendRelativePath(
178 src_file_path_each, &dest_file_path_each);
179
180 if (file_enum->IsDirectory()) {
181 PlatformFileError error = dest_util_->CreateDirectory(
182 context_,
183 dest_path.WithInternalPath(dest_file_path_each),
184 true /* exclusive */, false /* recursive */);
185 if (error != base::PLATFORM_FILE_OK)
186 return error;
187 } else {
188 PlatformFileError error = CopyOrMoveFile(
189 src_path.WithInternalPath(src_file_path_each),
190 dest_path.WithInternalPath(dest_file_path_each));
191 if (error != base::PLATFORM_FILE_OK)
192 return error;
193 }
194 }
195
196 if (operation_ == OPERATION_MOVE) {
197 PlatformFileError error =
198 FileUtilHelper::Delete(context_, src_util_,
199 src_path, true /* recursive */);
200 if (error != base::PLATFORM_FILE_OK)
201 return error;
202 }
203
204 return base::PLATFORM_FILE_OK;
205 }
206
207 PlatformFileError CrossFileUtilHelper::CopyOrMoveFile(
208 const FileSystemPath& src_path,
209 const FileSystemPath& dest_path) {
210 if (same_file_system_) {
211 DCHECK(src_util_ == dest_util_);
212 // Source and destination are in the same FileSystemFileUtil; now we can
213 // safely call FileSystemFileUtil method on src_util_ (== dest_util_).
214 return src_util_->CopyOrMoveFile(context_, src_path, dest_path,
215 operation_ == OPERATION_COPY);
216 }
217
218 // Resolve the src_path's underlying file path.
219 base::PlatformFileInfo file_info;
220 FilePath platform_file_path;
221 PlatformFileError error = src_util_->GetFileInfo(
222 context_, src_path, &file_info, &platform_file_path);
223 if (error != base::PLATFORM_FILE_OK)
224 return error;
225
226 // Call CopyInForeignFile() on the dest_util_ with the resolved source path
227 // to perform limited cross-FileSystemFileUtil copy/move.
228 error = dest_util_->CopyInForeignFile(
229 context_, src_path.WithInternalPath(platform_file_path), dest_path);
230
231 if (operation_ == OPERATION_COPY || error != base::PLATFORM_FILE_OK)
232 return error;
233 return src_util_->DeleteFile(context_, src_path);
234 }
235
236 } // anonymous namespace
237
238 // static
239 base::PlatformFileError FileUtilHelper::Copy(
240 FileSystemOperationContext* context,
241 FileSystemFileUtil* src_file_util,
242 FileSystemFileUtil* dest_file_util,
243 const FileSystemPath& src_root_path,
244 const FileSystemPath& dest_root_path) {
245 return CrossFileUtilHelper(context, src_file_util, dest_file_util,
246 src_root_path, dest_root_path,
247 CrossFileUtilHelper::OPERATION_COPY).DoWork();
248 }
249
250 // static
251 base::PlatformFileError FileUtilHelper::Move(
252 FileSystemOperationContext* context,
253 FileSystemFileUtil* src_file_util,
254 FileSystemFileUtil* dest_file_util,
255 const FileSystemPath& src_root_path,
256 const FileSystemPath& dest_root_path) {
257 return CrossFileUtilHelper(context, src_file_util, dest_file_util,
258 src_root_path, dest_root_path,
259 CrossFileUtilHelper::OPERATION_MOVE).DoWork();
260 }
261
262 // static
15 base::PlatformFileError FileUtilHelper::Delete( 263 base::PlatformFileError FileUtilHelper::Delete(
16 FileSystemOperationContext* context, 264 FileSystemOperationContext* context,
17 FileSystemFileUtil* file_util, 265 FileSystemFileUtil* file_util,
18 const FileSystemPath& path, 266 const FileSystemPath& path,
19 bool recursive) { 267 bool recursive) {
20 if (file_util->DirectoryExists(context, path)) { 268 if (file_util->DirectoryExists(context, path)) {
21 if (!recursive) 269 if (!recursive)
22 return file_util->DeleteSingleDirectory(context, path); 270 return file_util->DeleteSingleDirectory(context, path);
23 else 271 else
24 return DeleteDirectoryRecursive(context, file_util, path); 272 return DeleteDirectoryRecursive(context, file_util, path);
25 } else { 273 } else {
26 return file_util->DeleteFile(context, path); 274 return file_util->DeleteFile(context, path);
27 } 275 }
28 } 276 }
29 277
278 // static
30 base::PlatformFileError FileUtilHelper::DeleteDirectoryRecursive( 279 base::PlatformFileError FileUtilHelper::DeleteDirectoryRecursive(
31 FileSystemOperationContext* context, 280 FileSystemOperationContext* context,
32 FileSystemFileUtil* file_util, 281 FileSystemFileUtil* file_util,
33 const FileSystemPath& path) { 282 const FileSystemPath& path) {
34 283
35 scoped_ptr<FileSystemFileUtil::AbstractFileEnumerator> file_enum( 284 scoped_ptr<FileSystemFileUtil::AbstractFileEnumerator> file_enum(
36 file_util->CreateFileEnumerator(context, path)); 285 file_util->CreateFileEnumerator(context, path));
37 FilePath file_path_each; 286 FilePath file_path_each;
38 std::stack<FilePath> directories; 287 std::stack<FilePath> directories;
39 while (!(file_path_each = file_enum->Next()).empty()) { 288 while (!(file_path_each = file_enum->Next()).empty()) {
(...skipping 13 matching lines...) Expand all
53 context, path.WithInternalPath(directories.top())); 302 context, path.WithInternalPath(directories.top()));
54 if (error != base::PLATFORM_FILE_ERROR_NOT_FOUND && 303 if (error != base::PLATFORM_FILE_ERROR_NOT_FOUND &&
55 error != base::PLATFORM_FILE_OK) 304 error != base::PLATFORM_FILE_OK)
56 return error; 305 return error;
57 directories.pop(); 306 directories.pop();
58 } 307 }
59 return file_util->DeleteSingleDirectory(context, path); 308 return file_util->DeleteSingleDirectory(context, path);
60 } 309 }
61 310
62 } // namespace fileapi 311 } // namespace fileapi
OLDNEW
« no previous file with comments | « webkit/fileapi/file_util_helper.h ('k') | webkit/fileapi/webkit_fileapi.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698