1 /*************************************************************************/
2 /* dir_access_unix.cpp */
3 /*************************************************************************/
4 /* This file is part of: */
5 /* GODOT ENGINE */
6 /* https://godotengine.org */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
9 /* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
10 /* */
11 /* Permission is hereby granted, free of charge, to any person obtaining */
12 /* a copy of this software and associated documentation files (the */
13 /* "Software"), to deal in the Software without restriction, including */
14 /* without limitation the rights to use, copy, modify, merge, publish, */
15 /* distribute, sublicense, and/or sell copies of the Software, and to */
16 /* permit persons to whom the Software is furnished to do so, subject to */
17 /* the following conditions: */
18 /* */
19 /* The above copyright notice and this permission notice shall be */
20 /* included in all copies or substantial portions of the Software. */
21 /* */
22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29 /*************************************************************************/
30 #include "dir_access_unix.h"
31
32 #if defined(UNIX_ENABLED) || defined(LIBC_FILEIO_ENABLED)
33
34 #ifndef ANDROID_ENABLED
35 #include <sys/statvfs.h>
36 #endif
37
38 #include "os/memory.h"
39 #include "print_string.h"
40 #include <errno.h>
41 #include <stdio.h>
42
create_fs()43 DirAccess *DirAccessUnix::create_fs() {
44
45 return memnew(DirAccessUnix);
46 }
47
list_dir_begin()48 bool DirAccessUnix::list_dir_begin() {
49
50 list_dir_end(); //close any previous dir opening!
51
52 // char real_current_dir_name[2048]; //is this enough?!
53 //getcwd(real_current_dir_name,2048);
54 //chdir(curent_path.utf8().get_data());
55 dir_stream = opendir(current_dir.utf8().get_data());
56 //chdir(real_current_dir_name);
57 if (!dir_stream)
58 return true; //error!
59
60 return false;
61 }
62
file_exists(String p_file)63 bool DirAccessUnix::file_exists(String p_file) {
64
65 GLOBAL_LOCK_FUNCTION
66
67 if (p_file.is_rel_path())
68 p_file = current_dir.plus_file(p_file);
69
70 p_file = fix_path(p_file);
71
72 struct stat flags;
73 bool success = (stat(p_file.utf8().get_data(), &flags) == 0);
74
75 if (success && S_ISDIR(flags.st_mode)) {
76 success = false;
77 }
78
79 return success;
80 }
81
dir_exists(String p_dir)82 bool DirAccessUnix::dir_exists(String p_dir) {
83
84 GLOBAL_LOCK_FUNCTION
85
86 if (p_dir.is_rel_path())
87 p_dir = get_current_dir().plus_file(p_dir);
88
89 p_dir = fix_path(p_dir);
90
91 struct stat flags;
92 bool success = (stat(p_dir.utf8().get_data(), &flags) == 0);
93
94 if (success && S_ISDIR(flags.st_mode))
95 return true;
96
97 return false;
98 }
99
get_modified_time(String p_file)100 uint64_t DirAccessUnix::get_modified_time(String p_file) {
101
102 if (p_file.is_rel_path())
103 p_file = current_dir.plus_file(p_file);
104
105 p_file = fix_path(p_file);
106
107 struct stat flags;
108 bool success = (stat(p_file.utf8().get_data(), &flags) == 0);
109
110 if (success) {
111 return flags.st_mtime;
112 } else {
113
114 ERR_FAIL_V(0);
115 };
116 return 0;
117 };
118
get_next()119 String DirAccessUnix::get_next() {
120
121 if (!dir_stream)
122 return "";
123 dirent *entry;
124
125 entry = readdir(dir_stream);
126
127 if (entry == NULL) {
128
129 list_dir_end();
130 return "";
131 }
132
133 //typedef struct stat Stat;
134 struct stat flags;
135
136 String fname = fix_unicode_name(entry->d_name);
137
138 String f = current_dir.plus_file(fname);
139
140 if (stat(f.utf8().get_data(), &flags) == 0) {
141
142 if (S_ISDIR(flags.st_mode)) {
143
144 _cisdir = true;
145
146 } else {
147
148 _cisdir = false;
149 }
150
151 } else {
152
153 _cisdir = false;
154 }
155
156 _cishidden = (fname != "." && fname != ".." && fname.begins_with("."));
157
158 return fname;
159 }
160
current_is_dir() const161 bool DirAccessUnix::current_is_dir() const {
162
163 return _cisdir;
164 }
165
current_is_hidden() const166 bool DirAccessUnix::current_is_hidden() const {
167
168 return _cishidden;
169 }
170
list_dir_end()171 void DirAccessUnix::list_dir_end() {
172
173 if (dir_stream)
174 closedir(dir_stream);
175 dir_stream = 0;
176 _cisdir = false;
177 }
178
get_drive_count()179 int DirAccessUnix::get_drive_count() {
180
181 return 0;
182 }
get_drive(int p_drive)183 String DirAccessUnix::get_drive(int p_drive) {
184
185 return "";
186 }
187
make_dir(String p_dir)188 Error DirAccessUnix::make_dir(String p_dir) {
189
190 GLOBAL_LOCK_FUNCTION
191
192 if (p_dir.is_rel_path())
193 p_dir = get_current_dir().plus_file(p_dir);
194
195 p_dir = fix_path(p_dir);
196
197 #if 1
198
199 bool success = (mkdir(p_dir.utf8().get_data(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == 0);
200 int err = errno;
201
202 #else
203 char real_current_dir_name[2048];
204 getcwd(real_current_dir_name, 2048);
205 chdir(current_dir.utf8().get_data()); //ascii since this may be unicode or wathever the host os wants
206
207 bool success = (mkdir(p_dir.utf8().get_data(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == 0);
208 int err = errno;
209
210 chdir(real_current_dir_name);
211 #endif
212 if (success) {
213 return OK;
214 };
215
216 if (err == EEXIST) {
217 return ERR_ALREADY_EXISTS;
218 };
219
220 return ERR_CANT_CREATE;
221 }
222
change_dir(String p_dir)223 Error DirAccessUnix::change_dir(String p_dir) {
224
225 GLOBAL_LOCK_FUNCTION
226 p_dir = fix_path(p_dir);
227
228 char real_current_dir_name[2048];
229 getcwd(real_current_dir_name, 2048);
230 String prev_dir;
231 if (prev_dir.parse_utf8(real_current_dir_name))
232 prev_dir = real_current_dir_name; //no utf8, maybe latin?
233
234 chdir(current_dir.utf8().get_data()); //ascii since this may be unicode or wathever the host os wants
235 bool worked = (chdir(p_dir.utf8().get_data()) == 0); // we can only give this utf8
236
237 String base = _get_root_path();
238 if (base != "") {
239
240 getcwd(real_current_dir_name, 2048);
241 String new_dir;
242 new_dir.parse_utf8(real_current_dir_name);
243 if (!new_dir.begins_with(base))
244 worked = false;
245 }
246
247 if (worked) {
248
249 getcwd(real_current_dir_name, 2048);
250 if (current_dir.parse_utf8(real_current_dir_name))
251 current_dir = real_current_dir_name; //no utf8, maybe latin?
252 }
253
254 chdir(prev_dir.utf8().get_data());
255 return worked ? OK : ERR_INVALID_PARAMETER;
256 }
257
get_current_dir()258 String DirAccessUnix::get_current_dir() {
259
260 String base = _get_root_path();
261 if (base != "") {
262
263 String bd = current_dir.replace_first(base, "");
264 if (bd.begins_with("/"))
265 return _get_root_string() + bd.substr(1, bd.length());
266 else
267 return _get_root_string() + bd;
268 }
269 return current_dir;
270 }
271
rename(String p_path,String p_new_path)272 Error DirAccessUnix::rename(String p_path, String p_new_path) {
273
274 if (p_path.is_rel_path())
275 p_path = get_current_dir().plus_file(p_path);
276
277 p_path = fix_path(p_path);
278
279 if (p_new_path.is_rel_path())
280 p_new_path = get_current_dir().plus_file(p_new_path);
281
282 p_new_path = fix_path(p_new_path);
283
284 return ::rename(p_path.utf8().get_data(), p_new_path.utf8().get_data()) == 0 ? OK : FAILED;
285 }
remove(String p_path)286 Error DirAccessUnix::remove(String p_path) {
287
288 if (p_path.is_rel_path())
289 p_path = get_current_dir().plus_file(p_path);
290
291 p_path = fix_path(p_path);
292
293 struct stat flags;
294 if ((stat(p_path.utf8().get_data(), &flags) != 0))
295 return FAILED;
296
297 if (S_ISDIR(flags.st_mode))
298 return ::rmdir(p_path.utf8().get_data()) == 0 ? OK : FAILED;
299 else
300 return ::unlink(p_path.utf8().get_data()) == 0 ? OK : FAILED;
301 }
302
get_space_left()303 size_t DirAccessUnix::get_space_left() {
304
305 #ifndef NO_STATVFS
306 struct statvfs vfs;
307 if (statvfs(current_dir.utf8().get_data(), &vfs) != 0) {
308
309 return 0;
310 };
311
312 return vfs.f_bfree * vfs.f_bsize;
313 #else
314 #warning THIS IS BROKEN
315 return 0;
316 #endif
317 };
318
DirAccessUnix()319 DirAccessUnix::DirAccessUnix() {
320
321 dir_stream = 0;
322 current_dir = ".";
323 _cisdir = false;
324
325 /* determine drive count */
326
327 change_dir(current_dir);
328 }
329
~DirAccessUnix()330 DirAccessUnix::~DirAccessUnix() {
331
332 list_dir_end();
333 }
334
335 #endif //posix_enabled
336