Line data Source code
1 : /**
2 : Copyright (c) 2016-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 : #ifndef WIN32
27 :
28 : #include <sys/time.h>
29 : #include <unistd.h>
30 : #include <sys/types.h>
31 : #include <sys/stat.h>
32 : #include <errno.h>
33 : #include <dirent.h>
34 : #include <utime.h>
35 :
36 : namespace STAPPLER_VERSIONIZED stappler::filesystem::native {
37 :
38 : template <>
39 0 : memory::PoolInterface::StringType nativeToPosix<memory::PoolInterface>(StringView path) {
40 0 : return path.str<memory::PoolInterface>();
41 : }
42 :
43 : template <>
44 25 : memory::PoolInterface::StringType posixToNative<memory::PoolInterface>(StringView path) {
45 25 : return path.str<memory::PoolInterface>();
46 : }
47 :
48 : template <>
49 0 : memory::StandartInterface::StringType nativeToPosix<memory::StandartInterface>(StringView path) {
50 0 : return path.str<memory::StandartInterface>();
51 : }
52 :
53 : template <>
54 750 : memory::StandartInterface::StringType posixToNative<memory::StandartInterface>(StringView path) {
55 750 : return path.str<memory::StandartInterface>();
56 : }
57 :
58 : template <>
59 200 : memory::PoolInterface::StringType getcwd_fn<memory::PoolInterface>() {
60 200 : char cwd[1024] = { 0 };
61 200 : if (getcwd(cwd, 1024 - 1) != NULL) {
62 200 : return memory::PoolInterface::StringType((const char *)cwd);
63 : }
64 0 : return memory::PoolInterface::StringType();
65 : }
66 :
67 : template <>
68 3209 : memory::StandartInterface::StringType getcwd_fn<memory::StandartInterface>() {
69 3209 : char cwd[1024] = { 0 };
70 3209 : if (getcwd(cwd, 1024 - 1) != NULL) {
71 3209 : return memory::StandartInterface::StringType((const char *)cwd);
72 : }
73 0 : return memory::StandartInterface::StringType();
74 : }
75 :
76 : #define SP_TERMINATED_DATA(view) (view.terminated()?view.data():view.str<memory::StandartInterface>().data())
77 :
78 2245 : bool remove_fn(StringView path) {
79 2245 : return ::remove(SP_TERMINATED_DATA(path)) == 0;
80 : }
81 :
82 200 : bool unlink_fn(StringView path) {
83 200 : return ::unlink(SP_TERMINATED_DATA(path)) == 0;
84 : }
85 :
86 475 : bool mkdir_fn(StringView path) {
87 475 : mode_t process_mask = ::umask(0);
88 475 : bool ret = ::mkdir(SP_TERMINATED_DATA(path), (mode_t)(S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) == 0;
89 475 : ::umask(process_mask);
90 475 : return ret;
91 : }
92 :
93 1463 : bool access_fn(StringView path, Access mode) {
94 1463 : int m = 0;
95 1463 : switch (mode) {
96 0 : case Access::Execute: m = X_OK; break;
97 1463 : case Access::Exists: m = F_OK; break;
98 0 : case Access::Read: m = R_OK; break;
99 0 : case Access::Write: m = W_OK; break;
100 : }
101 1463 : return ::access(SP_TERMINATED_DATA(path), m) == 0;
102 : }
103 :
104 1700 : bool stat_fn(StringView path, Stat &stat) {
105 : struct stat s;
106 1700 : if(::stat(SP_TERMINATED_DATA(path), &s) == 0 ) {
107 1475 : stat.size = size_t(s.st_size);
108 1475 : stat.isDir = (s.st_mode & S_IFDIR);
109 : #if LINUX || ANDROID
110 1475 : stat.atime = Time::microseconds(s.st_atime * 1000000 + s.st_atim.tv_nsec / 1000);
111 1475 : stat.ctime = Time::microseconds(s.st_ctime * 1000000 + s.st_ctim.tv_nsec / 1000);
112 1475 : stat.mtime = Time::microseconds(s.st_mtime * 1000000 + s.st_mtim.tv_nsec / 1000);
113 : #else
114 : // some fruit systems just made by assholes
115 : stat.atime = Time::seconds(s.st_atime);
116 : stat.ctime = Time::seconds(s.st_ctime);
117 : stat.mtime = Time::seconds(s.st_mtime);
118 : #endif
119 1475 : return true;
120 : } else {
121 225 : return false;
122 : }
123 : }
124 :
125 50 : bool touch_fn(StringView path) {
126 50 : return utime(SP_TERMINATED_DATA(path), NULL) == 0;
127 : }
128 :
129 17975 : void ftw_fn(StringView path, const Callback<void(StringView path, bool isFile)> &callback, int depth, bool dirFirst) {
130 17975 : auto dp = opendir(SP_TERMINATED_DATA(path));
131 17975 : if (dp == NULL) {
132 17525 : if (access(SP_TERMINATED_DATA(path), F_OK) != -1) {
133 17500 : callback(path, true);
134 : }
135 : } else {
136 450 : if (dirFirst) {
137 225 : callback(path, false);
138 : }
139 450 : if (depth < 0 || depth > 0) {
140 : struct dirent *entry;
141 18450 : while ((entry = readdir(dp))) {
142 18200 : if (strcmp(entry->d_name, "..") != 0 && strcmp(entry->d_name, ".") != 0) {
143 17700 : auto newPath = filepath::merge<memory::StandartInterface>(path, entry->d_name);
144 17700 : ftw_fn(newPath, callback, depth - 1, dirFirst);
145 17700 : }
146 : }
147 : }
148 450 : if (!dirFirst) {
149 225 : callback(path, false);
150 : }
151 450 : closedir(dp);
152 : }
153 17975 : }
154 593 : bool ftw_b_fn(StringView path, const Callback<bool(StringView path, bool isFile)> &callback, int depth, bool dirFirst) {
155 593 : auto dp = opendir(SP_TERMINATED_DATA(path));
156 593 : if (dp == NULL) {
157 412 : if (access(SP_TERMINATED_DATA(path), F_OK) != -1) {
158 389 : return callback(path, true);
159 : }
160 : } else {
161 181 : if (dirFirst) {
162 0 : if (!callback(path, false)) {
163 0 : closedir(dp);
164 0 : return false;
165 : }
166 : }
167 181 : if (depth < 0 || depth > 0) {
168 : struct dirent *entry;
169 1061 : while ((entry = readdir(dp))) {
170 880 : if (strcmp(entry->d_name, "..") != 0 && strcmp(entry->d_name, ".") != 0) {
171 518 : auto newPath = filepath::merge<memory::StandartInterface>(path, entry->d_name);
172 518 : if (!ftw_b_fn(newPath, callback, depth - 1, dirFirst)) {
173 0 : closedir(dp);
174 0 : return false;
175 : }
176 518 : }
177 : }
178 : }
179 181 : if (!dirFirst) {
180 181 : if (!callback(path, false)) {
181 0 : closedir(dp);
182 0 : return false;
183 : }
184 : }
185 181 : closedir(dp);
186 : }
187 204 : return true;
188 : }
189 :
190 225 : bool rename_fn(StringView source, StringView dest) {
191 225 : return rename(SP_TERMINATED_DATA(source), SP_TERMINATED_DATA(dest)) == 0;
192 : }
193 :
194 24334 : FILE *fopen_fn(StringView path, StringView mode) {
195 24334 : return fopen(SP_TERMINATED_DATA(path), SP_TERMINATED_DATA(mode));
196 : }
197 :
198 275 : bool write_fn(StringView path, const unsigned char *data, size_t len) {
199 275 : std::ofstream f(SP_TERMINATED_DATA(path));
200 275 : if (f.is_open()) {
201 275 : f.write((const char *)data, len);
202 275 : f.close();
203 275 : return true;
204 : }
205 0 : return false;
206 275 : }
207 :
208 : #undef SP_TERMINATED_DATA
209 :
210 : }
211 :
212 : #endif
|