forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
mac: Zip packages when they are selected by the file opener.
When a package is selected in the file opener, it is automatically zipped, and the zipped file is passed to the render view host. This CL fixes 2 unrelated bugs in file_select_helper: - If the render_view_host_ was destroyed before the user finished with the file_select_helper, then Release() would never be called and the file_select_helper would leak. - If the render_view_host_ was destroyed before the user finished with the file_select_helper, the default directory would be updated if the user was opening multiple files, but it would not be updated if the user was opening a single file. Now both update the default directory. Note: When a large package is being zipped, the UI thread and renderer are still responsive, but display no indication of the ongoing work. BUG=33920 Review URL: https://codereview.chromium.org/634833003 Cr-Commit-Position: refs/heads/master@{#299143}
- Loading branch information
Showing
11 changed files
with
851 additions
and
41 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
// Copyright 2014 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/browser/file_select_helper.h" | ||
|
||
#include <Cocoa/Cocoa.h> | ||
#include <sys/stat.h> | ||
|
||
#include "base/files/file.h" | ||
#include "base/files/file_path.h" | ||
#include "base/files/file_util.h" | ||
#include "base/mac/foundation_util.h" | ||
#include "content/public/browser/browser_thread.h" | ||
#include "third_party/zlib/google/zip.h" | ||
#include "ui/shell_dialogs/selected_file_info.h" | ||
|
||
namespace { | ||
|
||
// Given the |path| of a package, returns the destination that the package | ||
// should be zipped to. Returns an empty path on any errors. | ||
base::FilePath ZipDestination(const base::FilePath& path) { | ||
NSMutableString* dest = | ||
[NSMutableString stringWithString:NSTemporaryDirectory()]; | ||
|
||
// Couldn't get the temporary directory. | ||
if (!dest) | ||
return base::FilePath(); | ||
|
||
[dest appendFormat:@"%@/zip_cache/%@", | ||
[[NSBundle mainBundle] bundleIdentifier], | ||
[[NSProcessInfo processInfo] globallyUniqueString]]; | ||
|
||
return base::mac::NSStringToFilePath(dest); | ||
} | ||
|
||
// Returns the path of the package and its components relative to the package's | ||
// parent directory. | ||
std::vector<base::FilePath> RelativePathsForPackage( | ||
const base::FilePath& package) { | ||
// Get the base directory. | ||
base::FilePath base_dir = package.DirName(); | ||
|
||
// Add the package as the first relative path. | ||
std::vector<base::FilePath> relative_paths; | ||
relative_paths.push_back(package.BaseName()); | ||
|
||
// Add the components of the package as relative paths. | ||
base::FileEnumerator file_enumerator( | ||
package, | ||
true /* recursive */, | ||
base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES); | ||
for (base::FilePath path = file_enumerator.Next(); !path.empty(); | ||
path = file_enumerator.Next()) { | ||
base::FilePath relative_path; | ||
bool success = base_dir.AppendRelativePath(path, &relative_path); | ||
if (success) | ||
relative_paths.push_back(relative_path); | ||
} | ||
|
||
return relative_paths; | ||
} | ||
|
||
} // namespace | ||
|
||
base::FilePath FileSelectHelper::ZipPackage(const base::FilePath& path) { | ||
base::FilePath dest(ZipDestination(path)); | ||
if (dest.empty()) | ||
return dest; | ||
|
||
if (!base::CreateDirectory(dest.DirName())) | ||
return base::FilePath(); | ||
|
||
base::File file(dest, base::File::FLAG_CREATE | base::File::FLAG_WRITE); | ||
if (!file.IsValid()) | ||
return base::FilePath(); | ||
|
||
std::vector<base::FilePath> files_to_zip(RelativePathsForPackage(path)); | ||
base::FilePath base_dir = path.DirName(); | ||
bool success = zip::ZipFiles(base_dir, files_to_zip, file.GetPlatformFile()); | ||
|
||
int result = -1; | ||
if (success) | ||
result = fchmod(file.GetPlatformFile(), S_IRUSR); | ||
|
||
return result >= 0 ? dest : base::FilePath(); | ||
} | ||
|
||
void FileSelectHelper::ProcessSelectedFilesMac( | ||
const std::vector<ui::SelectedFileInfo>& files) { | ||
DCHECK_CURRENTLY_ON(content::BrowserThread::FILE_USER_BLOCKING); | ||
|
||
// Make a mutable copy of the input files. | ||
std::vector<ui::SelectedFileInfo> files_out(files); | ||
std::vector<base::FilePath> temporary_files; | ||
|
||
for (auto& file_info : files_out) { | ||
NSString* filename = base::mac::FilePathToNSString(file_info.local_path); | ||
BOOL isPackage = | ||
[[NSWorkspace sharedWorkspace] isFilePackageAtPath:filename]; | ||
if (isPackage && base::DirectoryExists(file_info.local_path)) { | ||
base::FilePath result = ZipPackage(file_info.local_path); | ||
|
||
if (!result.empty()) { | ||
temporary_files.push_back(result); | ||
file_info.local_path = result; | ||
file_info.file_path = result; | ||
file_info.display_name.append(".zip"); | ||
} | ||
} | ||
} | ||
|
||
content::BrowserThread::PostTask( | ||
content::BrowserThread::UI, | ||
FROM_HERE, | ||
base::Bind(&FileSelectHelper::ProcessSelectedFilesMacOnUIThread, | ||
base::Unretained(this), | ||
files_out, | ||
temporary_files)); | ||
} | ||
|
||
void FileSelectHelper::ProcessSelectedFilesMacOnUIThread( | ||
const std::vector<ui::SelectedFileInfo>& files, | ||
const std::vector<base::FilePath>& temporary_files) { | ||
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | ||
|
||
if (!temporary_files.empty()) { | ||
temporary_files_.insert( | ||
temporary_files_.end(), temporary_files.begin(), temporary_files.end()); | ||
|
||
// Typically, |temporary_files| are deleted after |web_contents_| is | ||
// destroyed. If |web_contents_| is already NULL, then the temporary files | ||
// need to be deleted now. | ||
if (!web_contents_) { | ||
DeleteTemporaryFiles(); | ||
RunFileChooserEnd(); | ||
return; | ||
} | ||
} | ||
|
||
NotifyRenderViewHostAndEnd(files); | ||
} |
Oops, something went wrong.