Lolly 1.4.28
Loading...
Searching...
No Matches
file.cpp
Go to the documentation of this file.
1
2/******************************************************************************
3* MODULE : file.cpp
4* DESCRIPTION: file handling
5* COPYRIGHT : (C) 1999 Joris van der Hoeven
6 2023 Darcy Shen
7*******************************************************************************
8* This software falls under the GNU general public license version 3 or later.
9* It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
10* in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
11******************************************************************************/
12
13#include "file.hpp"
14#include "analyze.hpp"
15#include "lolly/hash/uuid.hpp"
16#include "string.hpp"
17#include "sys_utils.hpp"
18
19#include "tbox/tbox.h"
20
21bool
23 string label = u.label ();
24 string protocol= u.protocol ();
25 return ((label == "") || (label == "concat") || (label == "root")) &&
26 (protocol == "default" || protocol == "file");
27}
28
29static string
31 if (is_rooted (u, "file")) {
32 return as_string (reroot (u, "default"));
33 }
34 return as_string (u);
35}
36
37bool
39 if (!is_local_and_single (u)) return false;
40
41 c_string path (as_local_path (u));
43 if (tb_file_info (path, &info)) {
44 switch (info.type) {
46 return true;
47 default:
48 return false;
49 }
50 }
51 else {
52 return false;
53 }
54}
55
56bool
58 if (!is_local_and_single (u)) return false;
59
60 c_string path (as_local_path (u));
62 if (tb_file_info (path, &info)) {
63 switch (info.type) {
65 return true;
66 default:
67 return false;
68 }
69 }
70 else {
71 return false;
72 }
73}
74
75bool
77 if (!is_local_and_single (u)) return false;
78
79 c_string path (as_local_path (u));
81 if (tb_file_info (path, &info)) {
82 return (info.flags & TB_FILE_FLAG_LINK) != 0;
83 }
84 else {
85 return false;
86 }
87}
88
89bool
91 if (!is_local_and_single (which)) return false;
92 if (!is_local_and_single (than)) return false;
93
97 return info1.mtime > info2.mtime;
98 }
99 else {
100 return false;
101 }
102}
103
104bool
106 if (is_ramdisc (name)) return true;
107
108 if (!is_local_and_single (name)) return false;
109
110 if (filter == "") return true;
111 int i, n= N (filter);
112
113 // Normal files
114 if (os_win () || os_mingw ()) {
115 string suf;
116 if (filter == "x") {
117 suf= suffix (name);
118 if ((suf != "exe") && (suf != "bat") && (suf != "com")) {
119 name= glue (name, ".exe");
120 suf = "exe";
121 }
122 }
123 }
124 c_string path (as_local_path (name));
126 if (!tb_file_info (path, &info)) {
127 return false;
128 }
129 for (i= 0; i < n; i++)
130 switch (filter[i]) {
131 // FIXME: should check user id and group id for r, w and x
132 case 'f':
133 if (info.type != TB_FILE_TYPE_FILE) return false;
134 break;
135 case 'd':
136 if (info.type != TB_FILE_TYPE_DIRECTORY) return false;
137 break;
138 case 'l':
139 if (info.flags != TB_FILE_FLAG_LINK) return false;
140 break;
141 case 'r':
142 if (!tb_file_access (path, TB_FILE_MODE_RO)) return false;
143 break;
144 case 'w':
145 if (!tb_file_access (path, TB_FILE_MODE_WO)) return false;
146 break;
147 case 'x':
148 if (!tb_file_access (path, TB_FILE_MODE_EXEC)) return false;
149 break;
150 }
151 return true;
152}
153
154int
156 if (!is_local_and_single (u)) return -1;
157
158 c_string path (as_local_path (u));
160 if (tb_file_info (path, &info)) {
161 return info.size;
162 }
163 else {
164 return -1;
165 }
166}
167
168int
170 if (!is_local_and_single (u)) return -1;
171
172 c_string path (as_local_path (u));
174 if (tb_file_info (path, &info)) {
175 return info.mtime;
176 }
177 else {
178 return -1;
179 }
180}
181
182static tb_long_t
192
195 if (!is_local_and_single (u)) {
196 error_flag= false;
197 return array<string> ();
198 }
199
200 c_string path (as_local_path (u));
203 if (error_flag) {
204 return arr_result;
205 }
207 return arr_result;
208}
209
210url
212 if (is_or (u)) return subdirectories (u[1]) | subdirectories (u[2]);
213 else if (is_directory (u)) {
214 url ret= u;
215 bool error_flag;
217 for (int i= 0; i < N (dir); i++)
218 if (!starts (dir[i], ".") && is_directory (u * dir[i]))
219 ret= ret | subdirectories (u * dir[i]);
220 return ret;
221 }
222 else return url_none ();
223}
224
225void
227 string label= u.label ();
228 if (label == "none" || label == "root" || label == "wildcard") return;
229 if (is_local_and_single (u)) { // label == "" or label == "concat"
230 c_string path (as_local_path (u));
231 tb_directory_create (path);
232 }
233 if (is_or (u)) { // label == "or"
234 mkdir (u[1]);
235 mkdir (u[2]);
236 }
237}
238
239void
241 if (is_none (which)) return;
242 if (!is_directory (which)) {
243 make_dir (head (which));
244 mkdir (which);
245 }
246}
247
248void
250 string label= u.label ();
251 if (label == "none" || label == "root" || label == "wildcard") return;
252 if (is_local_and_single (u)) { // label == "" or label == "concat"
253 c_string path (as_local_path (u));
254 tb_directory_remove (path);
255 }
256 if (is_or (u)) { // label == "or"
257 rmdir (u[1]);
258 rmdir (u[2]);
259 }
260}
261
262void
264 if (is_local_and_single (u)) {
265 c_string path (as_local_path (u));
266 if (tb_directory_current_set (path) != tb_true) {
267 TM_FAILED ("Failed to change the dir");
268 }
269 }
270 else TM_FAILED ("file path invalid");
271}
272
273url
274url_temp (string suffix) {
275 string file_name= replace (lolly::hash::uuid_make (), "-", "_");
276 if (!is_empty (suffix)) {
277 file_name= file_name * string (".") * suffix;
278 }
280 if (file_size (u) == -1) {
281 return u;
282 }
283 else {
284 return url_temp (suffix);
285 }
286}
287
288url
290#if defined(OS_WIN) || defined(OS_MINGW)
291 url main_tmp_dir= url_system ("$TMP") * url (".lolly");
292#else
293 url main_tmp_dir= url_system ("/tmp") * url (".lolly");
294#endif
296 return (tmp_dir);
297}
298
299url
301 static url u;
302 if (u == url_none ()) {
304 make_dir (u);
305 }
306 return u;
307}
308
309void
316
317void
324
325void
327 string label= u.label ();
328 if (label == "none" || label == "root" || label == "wildcard") return;
329 if (is_local_and_single (u)) {
330 c_string path (as_local_path (u));
331 tb_file_remove (path);
332 }
333 else if (is_or (u)) { // label == "or"
334 remove (u[1]);
335 remove (u[2]);
336 }
337}
338
339/******************************************************************************
340 * New style loading and saving
341 * Use two function to emulate using syntax and try-finally statement in C#
342 ******************************************************************************/
343
345 bool failed;
346 const char* error_msg;
347 const char* path;
349 file_status (bool failed_, const char* msg= "", const char* path_= NULL,
350 const tb_byte_t* buffer_= NULL)
352};
353
354/**
355 * \brief lookup the first exist path in a bunch of url,
356 * if all url does not exist, then the last one will be used.
357 */
358static url
360 url u_iter= expand (u);
361 // iterate to find the first existed file
362 while (is_or (u_iter)) {
363 if (is_regular (u_iter[1])) {
364 return u_iter[1];
365 }
366 u_iter= u_iter[2];
367 }
368 // if u_target does not exist, just return the last url
369 return u_iter;
370}
371
372static bool
373cleanup_and_return_finally (const file_status& status, const url& u, bool fatal,
374 const string& reason) {
375
376 if (status.buffer != NULL) {
377 tm_delete_array (status.buffer);
378 }
379 if (status.path != NULL) {
380 tm_delete_array (status.path);
381 }
382
383 if (!status.failed) {
384 return false;
385 }
386 cerr << "Failed to " << reason << " in [" << as_local_path (u) << "]" << LF;
387 if (fatal) {
388 TM_FAILED (status.error_msg);
389 }
390 return true;
391}
392
394load_string_try (url u, string& s) {
395 if (!is_local_and_single (u)) {
396 return file_status (true, "Must be a local and single file");
397 }
399 const char* path = as_charp (as_local_path (u_target));
400 if (!tb_file_access (path, TB_FILE_MODE_RO)) {
401 return file_status (true, "File is not readable", path);
402 }
404 if (file == tb_null) {
405 return file_status (true, "Failed to init the file", path);
406 }
407 tb_file_sync (file); // lock file
408 tb_size_t size= tb_file_size (file);
409 if (size == 0) {
410 s= "";
411 tb_file_exit (file);
412 return file_status (false, "", path);
413 }
414 tb_byte_t* buffer = tm_new_array<tb_byte_t> (size);
415 tb_size_t real_size = tb_file_read (file, buffer, size);
416 bool read_sz_equ= (real_size == size);
417 bool exit_suc = tb_file_exit (file); // exit file
418 if (read_sz_equ && exit_suc) {
419 s->resize (size);
420 // Copying char by char has roughly the same efficiency as constructing new
421 // string with buffer.
422 for (size_t seek= 0; seek < size; seek++) {
423 s[seek]= buffer[seek];
424 }
425 return file_status (false, "", path, buffer);
426 }
427 else {
428 return file_status (true, "Unexpected behavior during reading", path,
429 buffer);
430 }
431}
432
433bool
434load_string (url u, string& s, bool fatal) {
436 return cleanup_and_return_finally (stat, u, fatal, "load url");
437}
438
439string
441 string s;
442 // file_url f= u;
443 (void) load_string (u, s, false);
444 return s;
445}
446
448save_string_try (url u, const string& s) {
449 ASSERT (sizeof (tb_byte_t) == sizeof (char),
450 "invalid cast from tb_byte_t* to char*");
451 if (!is_local_and_single (u)) {
452 return file_status (true, "Must be an absolute path");
453 }
455 const char* path = as_charp (as_local_path (u_target));
456
457 // tb_file_access cannot check TB_FILE_MODE_CREAT on windows, so create
458 // directly
461 if (fout == tb_null) {
462 return file_status (true, "File not writeable", path);
463 }
464
465 // lock file
470 return file_status (true, "Fail to lock file", path);
471 }
472
474 const tb_byte_t* content = reinterpret_cast<const tb_byte_t*> (as_charp (s));
479 bool exit_suc= tb_file_exit (fout);
480 if (writ_sz_equ && exit_suc && release_suc) {
481 return file_status (false, "", path, content);
482 }
483 else {
484 return file_status (true, "Unexpected behavior during writting", path,
485 content);
486 }
487}
488
489bool
490save_string (url u, const string& s, bool fatal) {
492 return cleanup_and_return_finally (stat, u, fatal, "save to url");
493}
494
495void
496string_save (const string& s, url u) {
497 (void) save_string (u, s, false);
498}
499
501append_string_try (url u, const string& s) {
502 if (!is_local_and_single (u)) {
503 return file_status (true, "Must be a local and single file");
504 }
506 const char* path = as_charp (as_local_path (u_target));
507
508 // open the file
511 if (fout == NULL) {
512 return file_status (true, "File to append is not found or not appendable",
513 path);
514 }
515
516 // lock file
521 return file_status (true, "Fail to lock file", path);
522 }
523
524 // append string to file
526 const tb_byte_t* content = reinterpret_cast<const tb_byte_t*> (as_charp (s));
531 bool exit_suc= tb_file_exit (fout);
532
533 if (writ_sz_equ && exit_suc && release_suc) {
534 return file_status (false, "", path, content);
535 }
536 else {
537 return file_status (true, "Unexpected behavior during appending", path,
538 content);
539 }
540}
541
542bool
543append_string (url u, const string& s, bool fatal) {
545 return cleanup_and_return_finally (stat, u, fatal, "append to url");
546}
547
548void
549string_append_to_file (const string& s, url u) {
550 (void) append_string (u, s, false);
551}
552
553void
555 string what_s;
556 if (load_string (what, what_s, false) || append_string (to, what_s, false))
557 cerr << "Append failed for " << to << LF;
558}
bool starts(string s, const char *what)
Definition analyze.cpp:566
string replace(string s, string what, string by)
Definition analyze.cpp:899
int N(array< T > a)
Get the length of the array.
Definition array.hpp:170
#define TM_FAILED(msg)
Macro used to throw an exception with a specified error message.
Definition basic.hpp:93
#define ASSERT(cond, msg)
Macro used to assert that a condition is true, and throw an exception with an error message if the co...
Definition basic.hpp:85
@ LF
Definition basic.hpp:287
The list class represents a linked list.
Definition list.hpp:48
Definition url.hpp:37
void tm_delete_array(C *Ptr)
int last_modified(url u)
Definition file.cpp:169
bool is_regular(url u)
Definition file.cpp:57
void string_save(const string &s, url u)
Definition file.cpp:496
bool is_directory(url u)
Definition file.cpp:38
bool load_string(url u, string &s, bool fatal)
Definition file.cpp:434
url url_temp(string suffix)
Definition file.cpp:274
bool is_newer(url which, url than)
Definition file.cpp:90
url subdirectories(url u)
Definition file.cpp:211
void rmdir(url u)
Definition file.cpp:249
void move(url u1, url u2)
Definition file.cpp:310
bool append_string(url u, const string &s, bool fatal)
Definition file.cpp:543
static url find_the_first_exist(const url &u)
lookup the first exist path in a bunch of url, if all url does not exist, then the last one will be u...
Definition file.cpp:359
void chdir(url u)
Definition file.cpp:263
bool is_local_and_single(url u)
Definition file.cpp:22
bool is_symbolic_link(url u)
Definition file.cpp:76
url url_temp_dir()
Definition file.cpp:300
static tb_long_t tb_directory_walk_func(tb_char_t const *path, tb_file_info_t const *info, tb_cpointer_t priv)
Definition file.cpp:183
void make_dir(url which)
Definition file.cpp:240
void string_append_to_file(const string &s, url u)
Definition file.cpp:549
void copy(url u1, url u2)
Definition file.cpp:318
int file_size(url u)
Definition file.cpp:155
url url_temp_dir_sub()
Definition file.cpp:289
file_status append_string_try(url u, const string &s)
Definition file.cpp:501
static bool cleanup_and_return_finally(const file_status &status, const url &u, bool fatal, const string &reason)
Definition file.cpp:373
file_status save_string_try(url u, const string &s)
Definition file.cpp:448
bool save_string(url u, const string &s, bool fatal)
Definition file.cpp:490
string string_load(url u)
Definition file.cpp:440
file_status load_string_try(url u, string &s)
Definition file.cpp:394
void remove(url u)
Definition file.cpp:326
void mkdir(url u)
Definition file.cpp:226
void append_to(url what, url to)
Definition file.cpp:554
static string as_local_path(url u)
Definition file.cpp:30
bool is_of_type(url name, string filter)
Definition file.cpp:105
array< string > read_directory(url u, bool &error_flag)
Definition file.cpp:194
list< T > tail(list< T > l, int n=1)
Get all but the first n items of a list.
Definition list.ipp:193
list< T > head(list< T > l, int n=1)
Get the first n items of a list.
Definition list.ipp:185
string uuid_make()
Definition uuid.cpp:20
char * as_charp(string s)
Definition string.cpp:256
string as_string(int16_t i)
Definition string.cpp:272
bool is_empty(string s)
Definition string.cpp:316
const tb_byte_t * buffer
Definition file.cpp:348
const char * path
Definition file.cpp:347
const char * error_msg
Definition file.cpp:346
file_status(bool failed_, const char *msg="", const char *path_=NULL, const tb_byte_t *buffer_=NULL)
Definition file.cpp:349
bool failed
Definition file.cpp:345
bool os_mingw()
SN get_process_id()
bool os_win()
Definition sys_utils.cpp:94
tm_ostream & cerr
url url_none()
Definition url.cpp:91
string suffix(url u, bool use_locase)
Definition url.cpp:381
url url_system(string name)
Definition url.cpp:306
url reroot(url u, string protocol)
Definition url.cpp:490
bool is_rooted(url u)
Definition url.cpp:686
bool is_ramdisc(url u)
Definition url.cpp:724
static url expand(url u1, url u2)
Definition url.cpp:498
url glue(url u, string s)
Definition url.cpp:421
bool is_or(url u)
Definition url.hpp:178
bool is_none(url u)
Definition url.hpp:166