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

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: rebase 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 return CopyOrMoveFile(src_root_path_, dest_root_path_);
97 }
98
99 PlatformFileError CrossFileUtilHelper::PerformErrorCheckAndPreparation() {
100 // Exits earlier if the source path does not exist.
101 if (!src_util_->PathExists(context_, src_root_path_))
102 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
103
104 // The parent of the |dest_root_path_| does not exist.
105 if (!ParentExists(dest_root_path_, dest_util_))
106 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
107
108 // It is an error to try to copy/move an entry into its child.
109 if (same_file_system_ && src_root_path_.IsParent(dest_root_path_))
110 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
111
112 // Now it is ok to return if the |dest_root_path_| does not exist.
113 if (!dest_util_->PathExists(context_, dest_root_path_))
114 return base::PLATFORM_FILE_OK;
115
116 // |src_root_path_| exists and is a directory.
117 // |dest_root_path_| exists and is a file.
118 bool src_is_directory = src_util_->DirectoryExists(context_, src_root_path_);
119 bool dest_is_directory =
120 dest_util_->DirectoryExists(context_, dest_root_path_);
121
122 // Either one of |src_root_path_| or |dest_root_path_| is directory,
123 // while the other is not.
124 if (src_is_directory != dest_is_directory)
125 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
126
127 // It is an error to copy/move an entry into the same path.
128 if (same_file_system_ &&
129 src_root_path_.internal_path() == dest_root_path_.internal_path())
130 return base::PLATFORM_FILE_ERROR_EXISTS;
131
132 if (dest_is_directory) {
133 // It is an error to copy/move an entry to a non-empty directory.
134 // Otherwise the copy/move attempt must overwrite the destination, but
135 // the file_util's Copy or Move method doesn't perform overwrite
136 // on all platforms, so we delete the destination directory here.
137 if (base::PLATFORM_FILE_OK !=
138 dest_util_->DeleteSingleDirectory(context_, dest_root_path_)) {
139 if (!dest_util_->IsDirectoryEmpty(context_, dest_root_path_))
140 return base::PLATFORM_FILE_ERROR_NOT_EMPTY;
141 return base::PLATFORM_FILE_ERROR_FAILED;
142 }
143 }
144 return base::PLATFORM_FILE_OK;
145 }
146
147 bool CrossFileUtilHelper::ParentExists(
148 const FileSystemPath& path, FileSystemFileUtil* file_util) {
149 // If path is in the root, path.DirName() will be ".",
150 // since we use paths with no leading '/'.
151 FilePath parent = path.internal_path().DirName();
152 if (parent == FilePath(FILE_PATH_LITERAL(".")))
153 return true;
154 return file_util->DirectoryExists(
155 context_, path.WithInternalPath(parent));
156 }
157
158 PlatformFileError CrossFileUtilHelper::CopyOrMoveDirectory(
159 const FileSystemPath& src_path,
160 const FileSystemPath& dest_path) {
161 // At this point we must have gone through
162 // PerformErrorCheckAndPreparationForMoveAndCopy so this must be true.
163 DCHECK(!same_file_system_ ||
164 !src_path.IsParent(dest_path));
165
166 PlatformFileError error = dest_util_->CreateDirectory(
167 context_, dest_path, false, false);
168 if (error != base::PLATFORM_FILE_OK)
169 return error;
170
171 scoped_ptr<FileSystemFileUtil::AbstractFileEnumerator> file_enum(
172 src_util_->CreateFileEnumerator(context_, src_path, true));
173 FilePath src_file_path_each;
174 while (!(src_file_path_each = file_enum->Next()).empty()) {
175 FilePath dest_file_path_each(dest_path.internal_path());
176 src_path.internal_path().AppendRelativePath(
177 src_file_path_each, &dest_file_path_each);
178
179 if (file_enum->IsDirectory()) {
180 PlatformFileError error = dest_util_->CreateDirectory(
181 context_,
182 dest_path.WithInternalPath(dest_file_path_each),
183 true /* exclusive */, false /* recursive */);
184 if (error != base::PLATFORM_FILE_OK)
185 return error;
186 } else {
187 PlatformFileError error = CopyOrMoveFile(
188 src_path.WithInternalPath(src_file_path_each),
189 dest_path.WithInternalPath(dest_file_path_each));
190 if (error != base::PLATFORM_FILE_OK)
191 return error;
192 }
193 }
194
195 if (operation_ == OPERATION_MOVE) {
196 PlatformFileError error =
197 FileUtilHelper::Delete(context_, src_util_,
198 src_path, true /* recursive */);
199 if (error != base::PLATFORM_FILE_OK)
200 return error;
201 }
202
203 return base::PLATFORM_FILE_OK;
204 }
205
206 PlatformFileError CrossFileUtilHelper::CopyOrMoveFile(
207 const FileSystemPath& src_path,
208 const FileSystemPath& dest_path) {
209 if (same_file_system_) {
210 DCHECK(src_util_ == dest_util_);
211 // Source and destination are in the same FileSystemFileUtil; now we can
212 // safely call FileSystemFileUtil method on src_util_ (== dest_util_).
213 return src_util_->CopyOrMoveFile(context_, src_path, dest_path,
214 operation_ == OPERATION_COPY);
215 }
216
217 // Resolve the src_path's underlying file path.
218 base::PlatformFileInfo file_info;
219 FilePath platform_file_path;
220 PlatformFileError error = src_util_->GetFileInfo(
221 context_, src_path, &file_info, &platform_file_path);
222 if (error != base::PLATFORM_FILE_OK)
223 return error;
224
225 // Call CopyInForeignFile() on the dest_util_ with the resolved source path
226 // to perform limited cross-FileSystemFileUtil copy/move.
227 error = dest_util_->CopyInForeignFile(
228 context_, src_path.WithInternalPath(platform_file_path), dest_path);
229
230 if (operation_ == OPERATION_COPY || error != base::PLATFORM_FILE_OK)
231 return error;
232 return src_util_->DeleteFile(context_, src_path);
233 }
234
235 } // anonymous namespace
236
237 // static
238 base::PlatformFileError FileUtilHelper::Copy(
239 FileSystemOperationContext* context,
240 FileSystemFileUtil* src_file_util,
241 FileSystemFileUtil* dest_file_util,
242 const FileSystemPath& src_root_path,
243 const FileSystemPath& dest_root_path) {
244 return CrossFileUtilHelper(context, src_file_util, dest_file_util,
245 src_root_path, dest_root_path,
246 CrossFileUtilHelper::OPERATION_COPY).DoWork();
247 }
248
249 // static
250 base::PlatformFileError FileUtilHelper::Move(
251 FileSystemOperationContext* context,
252 FileSystemFileUtil* src_file_util,
253 FileSystemFileUtil* dest_file_util,
254 const FileSystemPath& src_root_path,
255 const FileSystemPath& dest_root_path) {
256 return CrossFileUtilHelper(context, src_file_util, dest_file_util,
257 src_root_path, dest_root_path,
258 CrossFileUtilHelper::OPERATION_MOVE).DoWork();
259 }
260
261 // static
15 base::PlatformFileError FileUtilHelper::Delete( 262 base::PlatformFileError FileUtilHelper::Delete(
16 FileSystemOperationContext* context, 263 FileSystemOperationContext* context,
17 FileSystemFileUtil* file_util, 264 FileSystemFileUtil* file_util,
18 const FileSystemPath& path, 265 const FileSystemPath& path,
19 bool recursive) { 266 bool recursive) {
20 if (file_util->DirectoryExists(context, path)) { 267 if (file_util->DirectoryExists(context, path)) {
21 if (!recursive) 268 if (!recursive)
22 return file_util->DeleteSingleDirectory(context, path); 269 return file_util->DeleteSingleDirectory(context, path);
23 else 270 else
24 return DeleteDirectoryRecursive(context, file_util, path); 271 return DeleteDirectoryRecursive(context, file_util, path);
25 } else { 272 } else {
26 return file_util->DeleteFile(context, path); 273 return file_util->DeleteFile(context, path);
27 } 274 }
28 } 275 }
29 276
277 // static
30 base::PlatformFileError FileUtilHelper::DeleteDirectoryRecursive( 278 base::PlatformFileError FileUtilHelper::DeleteDirectoryRecursive(
31 FileSystemOperationContext* context, 279 FileSystemOperationContext* context,
32 FileSystemFileUtil* file_util, 280 FileSystemFileUtil* file_util,
33 const FileSystemPath& path) { 281 const FileSystemPath& path) {
34 282
35 scoped_ptr<FileSystemFileUtil::AbstractFileEnumerator> file_enum( 283 scoped_ptr<FileSystemFileUtil::AbstractFileEnumerator> file_enum(
36 file_util->CreateFileEnumerator(context, path, true /* recursive */)); 284 file_util->CreateFileEnumerator(context, path, true /* recursive */));
37 FilePath file_path_each; 285 FilePath file_path_each;
38 std::stack<FilePath> directories; 286 std::stack<FilePath> directories;
39 while (!(file_path_each = file_enum->Next()).empty()) { 287 while (!(file_path_each = file_enum->Next()).empty()) {
(...skipping 13 matching lines...) Expand all
53 context, path.WithInternalPath(directories.top())); 301 context, path.WithInternalPath(directories.top()));
54 if (error != base::PLATFORM_FILE_ERROR_NOT_FOUND && 302 if (error != base::PLATFORM_FILE_ERROR_NOT_FOUND &&
55 error != base::PLATFORM_FILE_OK) 303 error != base::PLATFORM_FILE_OK)
56 return error; 304 return error;
57 directories.pop(); 305 directories.pop();
58 } 306 }
59 return file_util->DeleteSingleDirectory(context, path); 307 return file_util->DeleteSingleDirectory(context, path);
60 } 308 }
61 309
62 } // namespace fileapi 310 } // 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