Line data Source code
1 : /**
2 : Copyright (c) 2022 Roman Katuntsev <sbkarr@stappler.org>
3 : Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
4 :
5 : Permission is hereby granted, free of charge, to any person obtaining a copy
6 : of this software and associated documentation files (the "Software"), to deal
7 : in the Software without restriction, including without limitation the rights
8 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 : copies of the Software, and to permit persons to whom the Software is
10 : furnished to do so, subject to the following conditions:
11 :
12 : The above copyright notice and this permission notice shall be included in
13 : all copies or substantial portions of the Software.
14 :
15 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 : THE SOFTWARE.
22 : **/
23 :
24 : #include "SPFilesystem.h"
25 :
26 : #if LINUX
27 :
28 : #include <limits.h>
29 :
30 : #if LINUX
31 : #include <unistd.h>
32 : #endif
33 :
34 : namespace STAPPLER_VERSIONIZED stappler::filesystem::platform {
35 :
36 : template <>
37 25 : auto _getApplicationPath<memory::StandartInterface>() -> memory::StandartInterface::StringType {
38 25 : char fullpath[PATH_MAX] = {0};
39 25 : ssize_t length = ::readlink("/proc/self/exe", fullpath, sizeof(fullpath)-1);
40 25 : return memory::StandartInterface::StringType(fullpath, length);
41 : }
42 :
43 : template <>
44 0 : auto _getApplicationPath<memory::PoolInterface>() -> memory::PoolInterface::StringType {
45 0 : char fullpath[PATH_MAX] = {0};
46 0 : ssize_t length = ::readlink("/proc/self/exe", fullpath, sizeof(fullpath)-1);
47 0 : return memory::PoolInterface::StringType(fullpath, length);
48 : }
49 :
50 : struct PathSource {
51 : memory::StandartInterface::StringType _appPath;
52 : memory::StandartInterface::StringType _platformPath;
53 : memory::StandartInterface::StringType _cachePath;
54 : memory::StandartInterface::StringType _documentsPath;
55 : memory::StandartInterface::StringType _writablePath;
56 :
57 : bool _platformInit = false;
58 : bool _cacheInit = false;
59 : bool _documentsInit = false;
60 : bool _writableInit = false;
61 :
62 857 : static PathSource *getInstance() {
63 : static PathSource *s_paths = nullptr;
64 857 : if (!s_paths) {
65 25 : s_paths = new PathSource;
66 : }
67 857 : return s_paths;
68 : }
69 :
70 25 : PathSource() {
71 25 : _appPath = _getApplicationPath<memory::StandartInterface>();
72 25 : if (!_appPath.empty()) {
73 25 : _writablePath = _platformPath = _appPath.substr(0, _appPath.find_last_of("/")) + "/AppData";
74 25 : _documentsPath = _platformPath + "/Documents";
75 25 : _cachePath = _platformPath + "/Caches";
76 : }
77 :
78 25 : auto newWD = ::getenv("SP_CWD_OVERRIDE");
79 25 : if (newWD && ::strlen(newWD) != 0) {
80 0 : if (filesystem::native::access_fn(newWD, Access::Exists)) {
81 0 : ::chdir(newWD);
82 : }
83 : }
84 25 : }
85 :
86 238 : StringView getPlatformPath(bool readOnly) {
87 238 : if (!readOnly) {
88 238 : if (!_platformInit) {
89 25 : filesystem::mkdir(_platformPath);
90 25 : _platformInit = true;
91 : }
92 : }
93 238 : return _platformPath;
94 : }
95 0 : StringView getDocumentsPath(bool readOnly) {
96 0 : if (!readOnly) {
97 0 : if (!_platformInit) {
98 0 : filesystem::mkdir(_platformPath);
99 0 : _platformInit = true;
100 : }
101 0 : if (!_documentsInit) {
102 0 : filesystem::mkdir(_documentsPath);
103 0 : _documentsInit = true;
104 : }
105 : }
106 0 : return _documentsPath;
107 : }
108 150 : StringView getCachePath(bool readOnly) {
109 150 : if (!readOnly) {
110 0 : if (!_platformInit) {
111 0 : filesystem::mkdir(_platformPath);
112 0 : _platformInit = true;
113 : }
114 0 : if (!_cacheInit) {
115 0 : filesystem::mkdir(_cachePath);
116 0 : _cacheInit = true;
117 : }
118 : }
119 150 : return _cachePath;
120 : }
121 469 : StringView getWritablePath(bool readOnly) {
122 469 : if (!readOnly) {
123 0 : if (!_platformInit) {
124 0 : filesystem::mkdir(_writablePath);
125 0 : _platformInit = true;
126 : }
127 : }
128 469 : return _writablePath;
129 : }
130 : };
131 :
132 : template <typename Interface>
133 238 : auto _getPlatformPath(StringView path, bool readOnly) -> typename Interface::StringType {
134 238 : if (filepath::isBundled(path)) {
135 0 : return filepath::merge<Interface>(PathSource::getInstance()->getPlatformPath(readOnly), path.sub("%PLATFORM%:"_len));
136 : }
137 238 : return filepath::merge<Interface>(PathSource::getInstance()->getPlatformPath(readOnly), path);
138 : }
139 :
140 : template <>
141 269 : auto _getWritablePath<memory::StandartInterface>(bool readOnly) -> typename memory::StandartInterface::StringType {
142 538 : return PathSource::getInstance()->getWritablePath(readOnly).str<memory::StandartInterface>();
143 : }
144 :
145 : template <>
146 200 : auto _getWritablePath<memory::PoolInterface>(bool readOnly) -> typename memory::PoolInterface::StringType {
147 200 : return StringView(PathSource::getInstance()->getWritablePath(readOnly)).str<memory::PoolInterface>();
148 : }
149 :
150 : template <>
151 0 : auto _getDocumentsPath<memory::StandartInterface>(bool readOnly) -> typename memory::StandartInterface::StringType {
152 0 : return PathSource::getInstance()->getDocumentsPath(readOnly).str<memory::StandartInterface>();
153 : }
154 :
155 : template <>
156 0 : auto _getDocumentsPath<memory::PoolInterface>(bool readOnly) -> typename memory::PoolInterface::StringType {
157 0 : return StringView(PathSource::getInstance()->getDocumentsPath(readOnly)).str<memory::PoolInterface>();
158 : }
159 :
160 : template <>
161 150 : auto _getCachesPath<memory::StandartInterface>(bool readOnly) -> typename memory::StandartInterface::StringType {
162 300 : return PathSource::getInstance()->getCachePath(readOnly).str<memory::StandartInterface>();
163 : }
164 :
165 : template <>
166 0 : auto _getCachesPath<memory::PoolInterface>(bool readOnly) -> typename memory::PoolInterface::StringType {
167 0 : return StringView(PathSource::getInstance()->getCachePath(readOnly)).str<memory::PoolInterface>();
168 : }
169 :
170 238 : bool _exists(StringView path, bool) {
171 238 : if (path.empty() || path.front() == '/' || path.starts_with("..", 2) || path.find("/..") != maxOf<size_t>()) {
172 0 : return false;
173 : }
174 :
175 238 : return ::access(_getPlatformPath<memory::StandartInterface>(path, false).data(), F_OK) != -1;
176 : }
177 :
178 0 : bool _stat(StringView ipath, Stat &stat, bool) {
179 0 : auto path = _getPlatformPath<memory::StandartInterface>(ipath, false);
180 0 : return filesystem::native::stat_fn(path, stat);
181 0 : }
182 :
183 0 : File _openForReading(StringView path) {
184 0 : return filesystem::openForReading(_getPlatformPath<memory::StandartInterface>(path, false));
185 : }
186 :
187 0 : size_t _read(void *, uint8_t *buf, size_t nbytes) { return 0; }
188 0 : size_t _seek(void *, int64_t offset, io::Seek s) { return maxOf<size_t>(); }
189 0 : size_t _tell(void *) { return 0; }
190 0 : bool _eof(void *) { return true; }
191 0 : void _close(void *) { }
192 :
193 0 : void _ftw(StringView path, const Callback<void(StringView path, bool isFile)> &cb, int depth, bool dirFirst, bool assetsRoot) {
194 0 : return filesystem::native::ftw_fn(path, cb, depth, dirFirst);
195 : }
196 :
197 0 : bool _ftw_b(StringView path, const Callback<bool(StringView path, bool isFile)> &cb, int depth, bool dirFirst, bool assetsRoot) {
198 0 : return filesystem::native::ftw_b_fn(path, cb, depth, dirFirst);
199 : }
200 :
201 : }
202 :
203 : #endif
|