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

Unified Diff: chrome/browser/file_select_helper_mac.mm

Issue 634833003: mac: Zip packages when they are selected by the file opener. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Comments from avi. Created 6 years, 2 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/file_select_helper_mac.mm
diff --git a/chrome/browser/file_select_helper_mac.mm b/chrome/browser/file_select_helper_mac.mm
new file mode 100644
index 0000000000000000000000000000000000000000..84cd5f01468bbb86e6c9048cd4f7d2b812b4be05
--- /dev/null
+++ b/chrome/browser/file_select_helper_mac.mm
@@ -0,0 +1,161 @@
+// 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:@"%@/%@/%s.zip",
+ [[NSBundle mainBundle] bundleIdentifier],
+ [[NSProcessInfo processInfo] globallyUniqueString],
+ path.BaseName().value().c_str()];
+
+ 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();
+
+ // Get the number of components in the base directory.
+ std::vector<std::string> base_dir_components;
+ base_dir.GetComponents(&base_dir_components);
+ int count = base_dir_components.size();
Lei Zhang 2014/10/09 18:41:54 size_t
erikchen 2014/10/09 23:33:35 Done.
+
+ // 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.value().empty();
Lei Zhang 2014/10/09 18:41:54 nit: !path.empty()
erikchen 2014/10/09 23:33:35 Done.
+ path = file_enumerator.Next()) {
+ // Break the path into its components.
+ std::vector<std::string> path_components;
+ path.GetComponents(&path_components);
+
+ // Ignore the first |count| components to create the relative path.
Lei Zhang 2014/10/09 18:41:54 Are you reinventing FilePath::AppendRelativePath()
erikchen 2014/10/09 23:33:35 Alas...no. zip::ZipFiles() requires a list of rel
Lei Zhang 2014/10/10 01:32:28 I still suspect base_dir.AppendRelativePath(path,
erikchen 2014/10/10 17:21:38 You're right! The name of the method primed me to
+ base::FilePath relative_path;
+ for (std::vector<std::string>::iterator it =
+ path_components.begin() + count;
+ it != path_components.end();
+ ++it) {
+ relative_path = relative_path.Append(*it);
+ }
+
+ 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;
+
+ bool success = base::CreateDirectory(dest.DirName());
Lei Zhang 2014/10/09 18:41:54 nit: you don't really need |success|.
erikchen 2014/10/09 23:33:36 I removed this instance of success, but I kept the
+ if (!success)
+ 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();
+ success = zip::ZipFiles(base_dir, files_to_zip, file.GetPlatformFile());
+
+ int result = -1;
+ if (success)
+ result = fchmod(file.GetPlatformFile(), S_IRUSR);
Lei Zhang 2014/10/09 18:41:54 I'm surprised the destination file don't sane perm
erikchen 2014/10/09 23:33:35 Me too.
+
+ 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()) {
+ // The parent directory of the zipped file is a temporary directory with
+ // no other children.
+ temporary_files.push_back(result.DirName());
+ file_info.local_path = result;
+ file_info.file_path = result;
+ file_info.display_name = result.BaseName().value();
+ }
+ }
+ }
+
+ 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
Lei Zhang 2014/10/09 18:41:54 nit: |web_contents_|
erikchen 2014/10/09 23:33:36 Done.
+ // destroyed. If web_contents_ is already NULL, then the temporary files
+ // need to be deleted now.
+ if (!web_contents_) {
+ DeleteTemporaryFiles();
+ RunFileChooserEnd();
+ return;
+ }
+ }
+
+ NotifyRenderViewHostAndEnd(files);
+}

Powered by Google App Engine
This is Rietveld 408576698