base_paths_mac.mm 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  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
  3. // found in the LICENSE file.
  4. // Defines base::PathProviderMac which replaces base::PathProviderPosix for Mac
  5. // in base/path_service.cc.
  6. #include <dlfcn.h>
  7. #import <Foundation/Foundation.h>
  8. #include <mach-o/dyld.h>
  9. #include "base/base_paths.h"
  10. #include "base/compiler_specific.h"
  11. #include "base/file_util.h"
  12. #include "base/files/file_path.h"
  13. #include "base/logging.h"
  14. #include "base/mac/foundation_util.h"
  15. #include "base/path_service.h"
  16. #include "base/strings/string_util.h"
  17. #include "base/build_config.h"
  18. namespace {
  19. void GetNSExecutablePath(base::FilePath* path) {
  20. DCHECK(path);
  21. // Executable path can have relative references ("..") depending on
  22. // how the app was launched.
  23. uint32_t executable_length = 0;
  24. _NSGetExecutablePath(NULL, &executable_length);
  25. DCHECK_GT(executable_length, 1u);
  26. std::string executable_path;
  27. int rv = _NSGetExecutablePath(WriteInto(&executable_path, executable_length),
  28. &executable_length);
  29. DCHECK_EQ(rv, 0);
  30. // _NSGetExecutablePath may return paths containing ./ or ../ which makes
  31. // FilePath::DirName() work incorrectly, convert it to absolute path so that
  32. // paths such as DIR_SOURCE_ROOT can work, since we expect absolute paths to
  33. // be returned here.
  34. *path = base::MakeAbsoluteFilePath(base::FilePath(executable_path));
  35. }
  36. // Returns true if the module for |address| is found. |path| will contain
  37. // the path to the module. Note that |path| may not be absolute.
  38. bool GetModulePathForAddress(base::FilePath* path,
  39. const void* address) WARN_UNUSED_RESULT;
  40. bool GetModulePathForAddress(base::FilePath* path, const void* address) {
  41. Dl_info info;
  42. if (dladdr(address, &info) == 0)
  43. return false;
  44. *path = base::FilePath(info.dli_fname);
  45. return true;
  46. }
  47. } // namespace
  48. namespace base {
  49. bool PathProviderMac(int key, base::FilePath* result) {
  50. switch (key) {
  51. case base::FILE_EXE:
  52. GetNSExecutablePath(result);
  53. return true;
  54. case base::FILE_MODULE:
  55. return GetModulePathForAddress(result,
  56. reinterpret_cast<const void*>(&base::PathProviderMac));
  57. case base::DIR_APP_DATA: {
  58. bool success = base::mac::GetUserDirectory(NSApplicationSupportDirectory,
  59. result);
  60. #if defined(OS_IOS)
  61. // On IOS, this directory does not exist unless it is created explicitly.
  62. if (success && !base::PathExists(*result))
  63. success = base::CreateDirectory(*result);
  64. #endif // defined(OS_IOS)
  65. return success;
  66. }
  67. case base::DIR_SOURCE_ROOT:
  68. // Go through PathService to catch overrides.
  69. if (!PathService::Get(base::FILE_EXE, result))
  70. return false;
  71. // Start with the executable's directory.
  72. *result = result->DirName();
  73. #if !defined(OS_IOS)
  74. if (base::mac::AmIBundled()) {
  75. // The bundled app executables (Chromium, TestShell, etc) live five
  76. // levels down, eg:
  77. // src/xcodebuild/{Debug|Release}/Chromium.app/Contents/MacOS/Chromium
  78. *result = result->DirName().DirName().DirName().DirName().DirName();
  79. } else {
  80. // Unit tests execute two levels deep from the source root, eg:
  81. // src/xcodebuild/{Debug|Release}/base_unittests
  82. *result = result->DirName().DirName();
  83. }
  84. #endif
  85. return true;
  86. case base::DIR_USER_DESKTOP:
  87. #if defined(OS_IOS)
  88. // iOS does not have desktop directories.
  89. NOTIMPLEMENTED();
  90. return false;
  91. #else
  92. return base::mac::GetUserDirectory(NSDesktopDirectory, result);
  93. #endif
  94. case base::DIR_CACHE:
  95. return base::mac::GetUserDirectory(NSCachesDirectory, result);
  96. default:
  97. return false;
  98. }
  99. }
  100. } // namespace base