forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathbase_paths_mac.mm
137 lines (123 loc) · 4.66 KB
/
base_paths_mac.mm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// Copyright (c) 2012 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.
// Defines base::PathProviderMac which replaces base::PathProviderPosix for Mac
// in base/path_service.cc.
#include <dlfcn.h>
#import <Foundation/Foundation.h>
#include <mach-o/dyld.h>
#include <stdint.h>
#include "base/base_paths.h"
#include "base/check_op.h"
#include "base/compiler_specific.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/mac/bundle_locations.h"
#include "base/mac/foundation_util.h"
#include "base/notreached.h"
#include "base/path_service.h"
#include "base/strings/string_util.h"
#include "base/threading/thread_restrictions.h"
#include "build/build_config.h"
namespace {
void GetNSExecutablePath(base::FilePath* path) {
DCHECK(path);
// Executable path can have relative references ("..") depending on
// how the app was launched.
uint32_t executable_length = 0;
_NSGetExecutablePath(NULL, &executable_length);
DCHECK_GT(executable_length, 1u);
std::string executable_path;
int rv = _NSGetExecutablePath(
base::WriteInto(&executable_path, executable_length),
&executable_length);
DCHECK_EQ(rv, 0);
// _NSGetExecutablePath may return paths containing ./ or ../ which makes
// FilePath::DirName() work incorrectly, convert it to absolute path so that
// paths such as DIR_SRC_TEST_DATA_ROOT can work, since we expect absolute
// paths to be returned here.
// TODO(bauerb): http://crbug.com/259796, http://crbug.com/373477
base::ThreadRestrictions::ScopedAllowIO allow_io;
*path = base::MakeAbsoluteFilePath(base::FilePath(executable_path));
}
// Returns true if the module for |address| is found. |path| will contain
// the path to the module. Note that |path| may not be absolute.
bool GetModulePathForAddress(base::FilePath* path,
const void* address) WARN_UNUSED_RESULT;
bool GetModulePathForAddress(base::FilePath* path, const void* address) {
Dl_info info;
if (dladdr(address, &info) == 0)
return false;
*path = base::FilePath(info.dli_fname);
return true;
}
} // namespace
namespace base {
bool PathProviderMac(int key, base::FilePath* result) {
switch (key) {
case base::FILE_EXE:
GetNSExecutablePath(result);
return true;
case base::FILE_MODULE:
return GetModulePathForAddress(result,
reinterpret_cast<const void*>(&base::PathProviderMac));
case base::DIR_APP_DATA: {
bool success = base::mac::GetUserDirectory(NSApplicationSupportDirectory,
result);
#if defined(OS_IOS)
// On IOS, this directory does not exist unless it is created explicitly.
if (success && !base::PathExists(*result))
success = base::CreateDirectory(*result);
#endif // defined(OS_IOS)
return success;
}
case base::DIR_SRC_TEST_DATA_ROOT:
#if defined(OS_IOS)
// On iOS, there is no access to source root, however, the necessary
// resources are packaged into the test as assets.
return PathService::Get(base::DIR_ASSETS, result);
#else
// Go through PathService to catch overrides.
if (!PathService::Get(base::FILE_EXE, result))
return false;
// Start with the executable's directory.
*result = result->DirName();
if (base::mac::AmIBundled()) {
// The bundled app executables (Chromium, TestShell, etc) live five
// levels down, eg:
// src/xcodebuild/{Debug|Release}/Chromium.app/Contents/MacOS/Chromium
*result = result->DirName().DirName().DirName().DirName().DirName();
} else {
// Unit tests execute two levels deep from the source root, eg:
// src/xcodebuild/{Debug|Release}/base_unittests
*result = result->DirName().DirName();
}
return true;
#endif // !defined(OS_IOS)
case base::DIR_USER_DESKTOP:
#if defined(OS_IOS)
// iOS does not have desktop directories.
NOTIMPLEMENTED();
return false;
#else
return base::mac::GetUserDirectory(NSDesktopDirectory, result);
#endif
case base::DIR_ASSETS:
#if defined(OS_IOS)
// On iOS, the assets are located next to the module binary.
return PathService::Get(base::DIR_MODULE, result);
#else
if (!base::mac::AmIBundled()) {
return PathService::Get(base::DIR_MODULE, result);
}
*result = base::mac::FrameworkBundlePath().Append(
FILE_PATH_LITERAL("Resources"));
return true;
#endif // !defined(OS_IOS)
case base::DIR_CACHE:
return base::mac::GetUserDirectory(NSCachesDirectory, result);
default:
return false;
}
}
} // namespace base