file_select_helper_mac.mm 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. // Copyright 2014 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. #include "shell/browser/file_select_helper.h"
  5. #include <Cocoa/Cocoa.h>
  6. #include <sys/stat.h>
  7. #include <vector>
  8. #include "base/apple/foundation_util.h"
  9. #include "base/files/file.h"
  10. #include "base/files/file_path.h"
  11. #include "base/files/file_util.h"
  12. #include "base/functional/bind.h"
  13. #include "content/public/browser/browser_task_traits.h"
  14. #include "content/public/browser/browser_thread.h"
  15. #include "third_party/zlib/google/zip.h"
  16. #include "ui/shell_dialogs/selected_file_info.h"
  17. namespace {
  18. // Given the |path| of a package, returns the destination that the package
  19. // should be zipped to. Returns an empty path on any errors.
  20. base::FilePath ZipDestination(const base::FilePath& path) {
  21. base::FilePath dest;
  22. if (!base::GetTempDir(&dest)) {
  23. // Couldn't get the temporary directory.
  24. return base::FilePath();
  25. }
  26. // TMPDIR/<bundleID>/zip_cache/<guid>
  27. NSString* bundleID = [[NSBundle mainBundle] bundleIdentifier];
  28. dest = dest.Append([bundleID fileSystemRepresentation]);
  29. dest = dest.Append("zip_cache");
  30. NSString* guid = [[NSProcessInfo processInfo] globallyUniqueString];
  31. dest = dest.Append([guid fileSystemRepresentation]);
  32. return dest;
  33. }
  34. // Returns the path of the package and its components relative to the package's
  35. // parent directory.
  36. std::vector<base::FilePath> RelativePathsForPackage(
  37. const base::FilePath& package) {
  38. // Get the base directory.
  39. base::FilePath base_dir = package.DirName();
  40. // Add the package as the first relative path.
  41. std::vector<base::FilePath> relative_paths;
  42. relative_paths.push_back(package.BaseName());
  43. // Add the components of the package as relative paths.
  44. base::FileEnumerator file_enumerator(
  45. package, true /* recursive */,
  46. base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES);
  47. for (base::FilePath path = file_enumerator.Next(); !path.empty();
  48. path = file_enumerator.Next()) {
  49. base::FilePath relative_path;
  50. bool success = base_dir.AppendRelativePath(path, &relative_path);
  51. if (success)
  52. relative_paths.push_back(relative_path);
  53. }
  54. return relative_paths;
  55. }
  56. } // namespace
  57. base::FilePath FileSelectHelper::ZipPackage(const base::FilePath& path) {
  58. base::FilePath dest(ZipDestination(path));
  59. if (dest.empty())
  60. return dest;
  61. if (!base::CreateDirectory(dest.DirName()))
  62. return base::FilePath();
  63. base::File file(dest, base::File::FLAG_CREATE | base::File::FLAG_WRITE);
  64. if (!file.IsValid())
  65. return base::FilePath();
  66. std::vector<base::FilePath> files_to_zip(RelativePathsForPackage(path));
  67. base::FilePath base_dir = path.DirName();
  68. bool success = zip::ZipFiles(base_dir, files_to_zip, file.GetPlatformFile());
  69. int result = -1;
  70. if (success)
  71. result = fchmod(file.GetPlatformFile(), S_IRUSR);
  72. return result >= 0 ? dest : base::FilePath();
  73. }
  74. void FileSelectHelper::ProcessSelectedFilesMac(
  75. const std::vector<ui::SelectedFileInfo>& files) {
  76. // Make a mutable copy of the input files.
  77. std::vector<ui::SelectedFileInfo> files_out(files);
  78. std::vector<base::FilePath> temporary_files;
  79. for (auto& file_info : files_out) {
  80. NSString* filename = base::apple::FilePathToNSString(file_info.local_path);
  81. BOOL isPackage =
  82. [[NSWorkspace sharedWorkspace] isFilePackageAtPath:filename];
  83. if (isPackage && base::DirectoryExists(file_info.local_path)) {
  84. base::FilePath result = ZipPackage(file_info.local_path);
  85. if (!result.empty()) {
  86. temporary_files.push_back(result);
  87. file_info.local_path = result;
  88. file_info.file_path = result;
  89. file_info.display_name.append(".zip");
  90. }
  91. }
  92. }
  93. content::GetUIThreadTaskRunner({})->PostTask(
  94. FROM_HERE,
  95. base::BindOnce(&FileSelectHelper::ProcessSelectedFilesMacOnUIThread,
  96. base::Unretained(this), files_out, temporary_files));
  97. }
  98. void FileSelectHelper::ProcessSelectedFilesMacOnUIThread(
  99. const std::vector<ui::SelectedFileInfo>& files,
  100. const std::vector<base::FilePath>& temporary_files) {
  101. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  102. if (!temporary_files.empty()) {
  103. temporary_files_.insert(temporary_files_.end(), temporary_files.begin(),
  104. temporary_files.end());
  105. // Typically, |temporary_files| are deleted after |web_contents_| is
  106. // destroyed. If |web_contents_| is already nullptr, then the temporary
  107. // files need to be deleted now.
  108. if (!web_contents_) {
  109. DeleteTemporaryFiles();
  110. RunFileChooserEnd();
  111. return;
  112. }
  113. }
  114. ConvertToFileChooserFileInfoList(files);
  115. }