jaulib v1.4.0-2-g788cf73
Jau Support Library (C++, Java, ..)
Loading...
Searching...
No Matches
test_fileutils01.cpp
Go to the documentation of this file.
1/*
2 * Author: Sven Gothel <sgothel@jausoft.com>
3 * Copyright (c) 2021 Gothel Software e.K.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
26
28#include <jau/io/file_util.hpp>
29#include <jau/secmem.hpp>
30
31extern "C" {
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <fcntl.h>
35 #include <sys/wait.h>
36 #include <unistd.h>
37}
38
40 public:
41
43 std::string cwd = jau::io::fs::get_cwd();
44 jau::io::fs::file_stats image_stats = getTestDataImageFile(executable_path); // optional
45 jau::io::fs::file_stats proot_stats_01 = getTestDataDirStats(executable_path);
46 std::string rel_project_root = getTestDataRelDir(executable_path);
47 jau::io::fs::file_stats proot_stats_02(rel_project_root);
48 jau::fprintf_td(stdout, "test00: cwd: %s\n", cwd.c_str());
49 jau::fprintf_td(stdout, "test00: 00: image.stat: %s\n", image_stats.toString().c_str());
50 jau::fprintf_td(stdout, "test00: 02: proot01.stats: %s\n", proot_stats_01.toString().c_str());
51 jau::fprintf_td(stdout, "test00: 02: proot02.rel: %s\n", rel_project_root.c_str());
52 jau::fprintf_td(stdout, "test00: 02: proot02.stats: %s\n", proot_stats_02.toString().c_str());
53 REQUIRE( proot_stats_01.exists() );
54 REQUIRE( proot_stats_02.exists() );
55 }
56
57 /**
58 *
59 */
60 void test01_cwd() {
61 const std::string cwd = jau::io::fs::get_cwd();
62 INFO_STR("\n\ntest01_cwd: cwd "+cwd+"\n");
63 REQUIRE( 0 < cwd.size() );
64 const size_t idx = cwd.find("/jaulib");
65 REQUIRE( 0 < idx );
66 REQUIRE( idx < cwd.size() );
67 REQUIRE( idx != std::string::npos );
68 }
69
70 /**
71 *
72 */
74 {
75 const std::string pathname0 = "/";
76 const std::string pathname1 = jau::io::fs::dirname(pathname0);
77 INFO_STR("\n\ntest02_dirname: cwd "+pathname0+" -> "+pathname1+"\n");
78 REQUIRE( 0 < pathname1.size() );
79 REQUIRE( pathname1 == "/" );
80 }
81 {
82 {
83 const std::string pathname0 = "lala.txt";
84 const std::string pathname1 = jau::io::fs::dirname(pathname0);
85 INFO_STR("\n\ntest02_dirname: cwd "+pathname0+" -> "+pathname1+"\n");
86 REQUIRE( 0 < pathname1.size() );
87 REQUIRE( pathname1 == "." );
88 }
89 {
90 const std::string pathname0 = "lala";
91 const std::string pathname1 = jau::io::fs::dirname(pathname0);
92 INFO_STR("\n\ntest02_dirname: cwd "+pathname0+" -> "+pathname1+"\n");
93 REQUIRE( 0 < pathname1.size() );
94 REQUIRE( pathname1 == "." );
95 }
96 {
97 const std::string pathname0 = "lala/";
98 const std::string pathname1 = jau::io::fs::dirname(pathname0);
99 INFO_STR("\n\ntest02_dirname: cwd "+pathname0+" -> "+pathname1+"\n");
100 REQUIRE( 0 < pathname1.size() );
101 REQUIRE( pathname1 == "." );
102 }
103 }
104 {
105 const std::string pathname0 = "/lala.txt";
106 const std::string pathname1 = jau::io::fs::dirname(pathname0);
107 INFO_STR("\n\ntest02_dirname: cwd "+pathname0+" -> "+pathname1+"\n");
108 REQUIRE( 0 < pathname1.size() );
109 REQUIRE( pathname1 == "/" );
110 }
111 {
112 const std::string pathname0 = "blabla/jaulib/test/sub.txt";
113 const std::string pathname1 = jau::io::fs::dirname(pathname0);
114 INFO_STR("\n\ntest02_dirname: cwd "+pathname0+" -> "+pathname1+"\n");
115 REQUIRE( 0 < pathname1.size() );
116 REQUIRE( pathname1 == "blabla/jaulib/test" );
117 }
118 {
119 const std::string pathname0 = "blabla/jaulib/test/sub";
120 const std::string pathname1 = jau::io::fs::dirname(pathname0);
121 INFO_STR("\n\ntest02_dirname: cwd "+pathname0+" -> "+pathname1+"\n");
122 REQUIRE( 0 < pathname1.size() );
123 REQUIRE( pathname1 == "blabla/jaulib/test" );
124 }
125 {
126 const std::string pathname0 = "blabla/jaulib/test/";
127 const std::string pathname1 = jau::io::fs::dirname(pathname0);
128 INFO_STR("\n\ntest02_dirname: cwd "+pathname0+" -> "+pathname1+"\n");
129 REQUIRE( 0 < pathname1.size() );
130 REQUIRE( pathname1 == "blabla/jaulib" );
131 }
132 {
133 const std::string pathname0 = "blabla/jaulib/test";
134 const std::string pathname1 = jau::io::fs::dirname(pathname0);
135 INFO_STR("\n\ntest02_dirname: cwd "+pathname0+" -> "+pathname1+"\n");
136 REQUIRE( 0 < pathname1.size() );
137 REQUIRE( pathname1 == "blabla/jaulib" );
138 }
139 }
140
142 {
143 const std::string pathname0 = "/";
144 const std::string pathname1 = jau::io::fs::basename(pathname0);
145 INFO_STR("\n\ntest03_basename: cwd "+pathname0+" -> "+pathname1+"\n");
146 REQUIRE( 0 < pathname1.size() );
147 REQUIRE( pathname1 == "/" );
148 REQUIRE( true == jau::io::fs::isAbsolute(pathname1));
149 }
150 {
151 {
152 const std::string pathname0 = "lala.txt";
153 const std::string pathname1 = jau::io::fs::basename(pathname0);
154 INFO_STR("\n\ntest03_basename: cwd "+pathname0+" -> "+pathname1+"\n");
155 REQUIRE( 0 < pathname1.size() );
156 REQUIRE( pathname1 == "lala.txt" );
157 REQUIRE( false == jau::io::fs::isAbsolute(pathname1));
158 }
159 {
160 const std::string pathname0 = "lala";
161 const std::string pathname1 = jau::io::fs::basename(pathname0);
162 INFO_STR("\n\ntest03_basename: cwd "+pathname0+" -> "+pathname1+"\n");
163 REQUIRE( 0 < pathname1.size() );
164 REQUIRE( pathname1 == "lala" );
165 REQUIRE( false == jau::io::fs::isAbsolute(pathname1));
166 }
167 {
168 const std::string pathname0 = "lala/";
169 const std::string pathname1 = jau::io::fs::basename(pathname0);
170 INFO_STR("\n\ntest03_basename: cwd "+pathname0+" -> "+pathname1+"\n");
171 REQUIRE( 0 < pathname1.size() );
172 REQUIRE( pathname1 == "lala" );
173 }
174 }
175 {
176 const std::string pathname0 = "/lala.txt";
177 const std::string pathname1 = jau::io::fs::basename(pathname0);
178 INFO_STR("\n\ntest03_basename: cwd "+pathname0+" -> "+pathname1+"\n");
179 REQUIRE( 0 < pathname1.size() );
180 REQUIRE( pathname1 == "lala.txt" );
181 }
182 {
183 const std::string pathname0 = "blabla/jaulib/test/sub.txt";
184 const std::string pathname1 = jau::io::fs::basename(pathname0);
185 INFO_STR("\n\ntest03_basename: cwd "+pathname0+" -> "+pathname1+"\n");
186 REQUIRE( 0 < pathname1.size() );
187 REQUIRE( pathname1 == "sub.txt" );
188 }
189
190 {
191 const std::string pathname0 = "blabla/jaulib/test/";
192 const std::string pathname1 = jau::io::fs::basename(pathname0);
193 INFO_STR("\n\ntest03_basename: cwd "+pathname0+" -> "+pathname1+"\n");
194 REQUIRE( 0 < pathname1.size() );
195 REQUIRE( pathname1 == "test" );
196 }
197
198 {
199 const std::string pathname0 = "blabla/jaulib/test";
200 const std::string pathname1 = jau::io::fs::basename(pathname0);
201 INFO_STR("\n\ntest03_basename: cwd "+pathname0+" -> "+pathname1+"\n");
202 REQUIRE( 0 < pathname1.size() );
203 REQUIRE( pathname1 == "test" );
204 }
205 }
206
208 {
209 std::string rel_project_root = getTestDataRelDir(executable_path);
210 jau::io::fs::file_stats proot_stats(rel_project_root);
211 jau::fprintf_td(stdout, "test03b_absolute: 01: cwd: %s\n", jau::io::fs::get_cwd().c_str());
212 jau::fprintf_td(stdout, "test03b_absolute: 01: rel_project_root %s\n", rel_project_root.c_str());
213 jau::fprintf_td(stdout, "test03b_absolute: 01: proot_stats %s\n", proot_stats.toString().c_str());
214 jau::fprintf_td(stdout, "test03b_absolute: 01: fields %s\n", jau::io::fs::to_string( proot_stats.fields() ).c_str());
215 REQUIRE( true == proot_stats.exists() );
216 REQUIRE( true == proot_stats.is_dir() );
217
218 std::string abs_project_root;
219 {
220 abs_project_root = jau::io::fs::absolute(rel_project_root);
221 jau::fprintf_td(stdout, "test03b_absolute: 02: %s\n", abs_project_root.c_str());
222 REQUIRE( 0 < abs_project_root.size() );
223 REQUIRE( false == jau::io::fs::isAbsolute(rel_project_root) );
224 REQUIRE( true == jau::io::fs::isAbsolute(abs_project_root) );
225
226 jau::io::fs::file_stats stats(abs_project_root);
227 jau::fprintf_td(stdout, "test03b_absolute: 02: %s\n", stats.toString().c_str());
228 jau::fprintf_td(stdout, "test03b_absolute: 02: fields %s\n", jau::io::fs::to_string( stats.fields() ).c_str());
229 REQUIRE( stats.exists() );
230 REQUIRE( stats.is_dir() );
231 }
232 {
233 std::string bname0 = jau::io::fs::basename(rel_project_root);
234 std::string bname1 = jau::io::fs::basename(abs_project_root);
235 jau::fprintf_td(stdout, "test03b_absolute: 03.0: %s\n", bname0.c_str());
236 jau::fprintf_td(stdout, "test03b_absolute: 03.1: %s\n", bname1.c_str());
237 REQUIRE( bname0 == bname1 );
238 }
239 }
240 }
241
243 {
244 const jau::io::fs::dir_item di;
245 INFO_STR("\n\ntest04_dir_item: 00 "+di.toString()+" -> '"+di.path()+"'\n");
246 REQUIRE( "." == di.dirname() );
247 REQUIRE( "." == di.basename() );
248 REQUIRE( "." == di.path() );
249 REQUIRE( true == di.empty() );
250 }
251 {
252 const std::string dirname_;
253 const jau::io::fs::dir_item di(dirname_);
254 INFO_STR("\n\ntest04_dir_item: 01 '"+dirname_+"' -> "+di.toString()+" -> '"+di.path()+"'\n");
255 REQUIRE( "." == di.dirname() );
256 REQUIRE( "." == di.basename() );
257 REQUIRE( "." == di.path() );
258 REQUIRE( true == di.empty() );
259 }
260 {
261 const std::string dirname_(".");
262 const jau::io::fs::dir_item di(dirname_);
263 INFO_STR("\n\ntest04_dir_item: 02 '"+dirname_+"' -> "+di.toString()+" -> '"+di.path()+"'\n");
264 REQUIRE( "." == di.dirname() );
265 REQUIRE( "." == di.basename() );
266 REQUIRE( "." == di.path() );
267 REQUIRE( false == di.empty() );
268 }
269 {
270 const std::string dirname_("/");
271 const jau::io::fs::dir_item di(dirname_);
272 INFO_STR("\n\ntest04_dir_item: 03 '"+dirname_+"' -> "+di.toString()+" -> '"+di.path()+"'\n");
273 REQUIRE( "/" == di.dirname() );
274 REQUIRE( "." == di.basename() );
275 REQUIRE( "/" == di.path() );
276 REQUIRE( false == di.empty() );
277 }
278
279 {
280 const std::string path1_ = "lala";
281 const jau::io::fs::dir_item di(path1_);
282 INFO_STR("\n\ntest04_dir_item: 10 '"+path1_+" -> "+di.toString()+" -> '"+di.path()+"'\n");
283 REQUIRE( "." == di.dirname() );
284 REQUIRE( "lala" == di.basename() );
285 REQUIRE( "lala" == di.path() );
286 REQUIRE( false == di.empty() );
287 }
288 {
289 const std::string path1_ = "lala/";
290 const jau::io::fs::dir_item di(path1_);
291 INFO_STR("\n\ntest04_dir_item: 11 '"+path1_+" -> "+di.toString()+" -> '"+di.path()+"'\n");
292 REQUIRE( "." == di.dirname() );
293 REQUIRE( "lala" == di.basename() );
294 REQUIRE( "lala" == di.path() );
295 REQUIRE( false == di.empty() );
296 }
297
298 {
299 const std::string path1_ = "/lala";
300 const jau::io::fs::dir_item di(path1_);
301 INFO_STR("\n\ntest04_dir_item: 12 '"+path1_+" -> "+di.toString()+" -> '"+di.path()+"'\n");
302 REQUIRE( "/" == di.dirname() );
303 REQUIRE( "lala" == di.basename() );
304 REQUIRE( "/lala" == di.path() );
305 REQUIRE( false == di.empty() );
306 }
307
308 {
309 const std::string path1_ = "dir0/lala";
310 const jau::io::fs::dir_item di(path1_);
311 INFO_STR("\n\ntest04_dir_item: 20 '"+path1_+" -> "+di.toString()+" -> '"+di.path()+"'\n");
312 REQUIRE( "dir0" == di.dirname() );
313 REQUIRE( "lala" == di.basename() );
314 REQUIRE( "dir0/lala" == di.path() );
315 }
316 {
317 const std::string path1_ = "dir0/lala/";
318 const jau::io::fs::dir_item di(path1_);
319 INFO_STR("\n\ntest04_dir_item: 21 '"+path1_+" -> "+di.toString()+" -> '"+di.path()+"'\n");
320 REQUIRE( "dir0" == di.dirname() );
321 REQUIRE( "lala" == di.basename() );
322 REQUIRE( "dir0/lala" == di.path() );
323 }
324 {
325 const std::string path1_ = "/dir0/lala";
326 const jau::io::fs::dir_item di(path1_);
327 INFO_STR("\n\ntest04_dir_item: 22 '"+path1_+" -> "+di.toString()+" -> '"+di.path()+"'\n");
328 REQUIRE( "/dir0" == di.dirname() );
329 REQUIRE( "lala" == di.basename() );
330 REQUIRE( "/dir0/lala" == di.path() );
331 }
332 {
333 const std::string path1_ = "/dir0/lala/";
334 const jau::io::fs::dir_item di(path1_);
335 INFO_STR("\n\ntest04_dir_item: 23 '"+path1_+" -> "+di.toString()+" -> '"+di.path()+"'\n");
336 REQUIRE( "/dir0" == di.dirname() );
337 REQUIRE( "lala" == di.basename() );
338 REQUIRE( "/dir0/lala" == di.path() );
339 }
340
341
342 {
343 const std::string path1_ = "/dir0/../lala";
344 const jau::io::fs::dir_item di(path1_);
345 INFO_STR("\n\ntest04_dir_item: 30 '"+path1_+" -> "+di.toString()+" -> '"+di.path()+"'\n");
346 REQUIRE( "/" == di.dirname() );
347 REQUIRE( "lala" == di.basename() );
348 REQUIRE( "/lala" == di.path() );
349 }
350 {
351 const std::string path1_ = "dir0/../lala";
352 const jau::io::fs::dir_item di(path1_);
353 INFO_STR("\n\ntest04_dir_item: 31 '"+path1_+" -> "+di.toString()+" -> '"+di.path()+"'\n");
354 REQUIRE( "." == di.dirname() );
355 REQUIRE( "lala" == di.basename() );
356 REQUIRE( "lala" == di.path() );
357 }
358 {
359 const std::string path1_ = "../../lala";
360 const jau::io::fs::dir_item di(path1_);
361 INFO_STR("\n\ntest04_dir_item: 32 '"+path1_+" -> "+di.toString()+" -> '"+di.path()+"'\n");
362 REQUIRE( "../.." == di.dirname() );
363 REQUIRE( "lala" == di.basename() );
364 REQUIRE( "../../lala" == di.path() );
365 }
366 {
367 const std::string path1_ = "./../lala";
368 const jau::io::fs::dir_item di(path1_);
369 INFO_STR("\n\ntest04_dir_item: 33 '"+path1_+" -> "+di.toString()+" -> '"+di.path()+"'\n");
370 REQUIRE( ".." == di.dirname() );
371 REQUIRE( "lala" == di.basename() );
372 REQUIRE( "../lala" == di.path() );
373 }
374 {
375 const std::string path1_ = "dir0/../../lala";
376 const jau::io::fs::dir_item di(path1_);
377 INFO_STR("\n\ntest04_dir_item: 34 '"+path1_+" -> "+di.toString()+" -> '"+di.path()+"'\n");
378 REQUIRE( ".." == di.dirname() );
379 REQUIRE( "lala" == di.basename() );
380 REQUIRE( "../lala" == di.path() );
381 }
382
383 {
384 const std::string path1_ = "dir0/dir1/../lala";
385 const jau::io::fs::dir_item di(path1_);
386 INFO_STR("\n\ntest04_dir_item: 40 '"+path1_+" -> "+di.toString()+" -> '"+di.path()+"'\n");
387 REQUIRE( "dir0" == di.dirname() );
388 REQUIRE( "lala" == di.basename() );
389 REQUIRE( "dir0/lala" == di.path() );
390 }
391 {
392 const std::string path1_ = "/dir0/dir1/../lala/";
393 const jau::io::fs::dir_item di(path1_);
394 INFO_STR("\n\ntest04_dir_item: 41 '"+path1_+" -> "+di.toString()+" -> '"+di.path()+"'\n");
395 REQUIRE( "/dir0" == di.dirname() );
396 REQUIRE( "lala" == di.basename() );
397 REQUIRE( "/dir0/lala" == di.path() );
398 }
399 {
400 const std::string path1_ = "dir0/dir1/../bbb/ccc/../lala";
401 const jau::io::fs::dir_item di(path1_);
402 INFO_STR("\n\ntest04_dir_item: 42 '"+path1_+" -> "+di.toString()+" -> '"+di.path()+"'\n");
403 REQUIRE( "dir0/bbb" == di.dirname() );
404 REQUIRE( "lala" == di.basename() );
405 REQUIRE( "dir0/bbb/lala" == di.path() );
406 }
407 {
408 const std::string path1_ = "dir0/dir1/bbb/../../lala";
409 const jau::io::fs::dir_item di(path1_);
410 INFO_STR("\n\ntest04_dir_item: 43 '"+path1_+" -> "+di.toString()+" -> '"+di.path()+"'\n");
411 REQUIRE( "dir0" == di.dirname() );
412 REQUIRE( "lala" == di.basename() );
413 REQUIRE( "dir0/lala" == di.path() );
414 }
415 {
416 const std::string path1_ = "dir0/dir1/bbb/../../../lala";
417 const jau::io::fs::dir_item di(path1_);
418 INFO_STR("\n\ntest04_dir_item: 44 '"+path1_+" -> "+di.toString()+" -> '"+di.path()+"'\n");
419 REQUIRE( "." == di.dirname() );
420 REQUIRE( "lala" == di.basename() );
421 REQUIRE( "lala" == di.path() );
422 }
423 {
424 const std::string path1_ = "dir0/dir1/bbb/../../../../lala";
425 const jau::io::fs::dir_item di(path1_);
426 INFO_STR("\n\ntest04_dir_item: 45 '"+path1_+" -> "+di.toString()+" -> '"+di.path()+"'\n");
427 REQUIRE( ".." == di.dirname() );
428 REQUIRE( "lala" == di.basename() );
429 REQUIRE( "../lala" == di.path() );
430 }
431 {
432 const std::string path1_ = "dir0/dir1/bbb/../../lala/..";
433 const jau::io::fs::dir_item di(path1_);
434 INFO_STR("\n\ntest04_dir_item: 46 '"+path1_+" -> "+di.toString()+" -> '"+di.path()+"'\n");
435 REQUIRE( "." == di.dirname() );
436 REQUIRE( "dir0" == di.basename() );
437 REQUIRE( "dir0" == di.path() );
438 }
439 {
440 const std::string path1_ = "dir0/./dir1/./bbb/../.././lala";
441 const jau::io::fs::dir_item di(path1_);
442 INFO_STR("\n\ntest04_dir_item: 50 '"+path1_+" -> "+di.toString()+" -> '"+di.path()+"'\n");
443 REQUIRE( "dir0" == di.dirname() );
444 REQUIRE( "lala" == di.basename() );
445 REQUIRE( "dir0/lala" == di.path() );
446 }
447 {
448 const std::string path1_ = "dir0/./dir1/./bbb/../.././lala/.";
449 const jau::io::fs::dir_item di(path1_);
450 INFO_STR("\n\ntest04_dir_item: 51 '"+path1_+" -> "+di.toString()+" -> '"+di.path()+"'\n");
451 REQUIRE( "dir0" == di.dirname() );
452 REQUIRE( "lala" == di.basename() );
453 REQUIRE( "dir0/lala" == di.path() );
454 }
455 {
456 const std::string path1_ = "./dir0/./dir1/./bbb/../.././lala/.";
457 const jau::io::fs::dir_item di(path1_);
458 INFO_STR("\n\ntest04_dir_item: 51 '"+path1_+" -> "+di.toString()+" -> '"+di.path()+"'\n");
459 REQUIRE( "dir0" == di.dirname() );
460 REQUIRE( "lala" == di.basename() );
461 REQUIRE( "dir0/lala" == di.path() );
462 }
463 {
464 const std::string path1_ = "/./dir0/./dir1/./bbb/../.././lala/.";
465 const jau::io::fs::dir_item di(path1_);
466 INFO_STR("\n\ntest04_dir_item: 52 '"+path1_+" -> "+di.toString()+" -> '"+di.path()+"'\n");
467 REQUIRE( "/dir0" == di.dirname() );
468 REQUIRE( "lala" == di.basename() );
469 REQUIRE( "/dir0/lala" == di.path() );
470 }
471
472 {
473 const std::string path1_ = "../../test_data/file_01_slink09R1.txt";
474 const jau::io::fs::dir_item di(path1_);
475 INFO_STR("\n\ntest04_dir_item: 60 '"+path1_+" -> "+di.toString()+" -> '"+di.path()+"'\n");
476 REQUIRE( "../../test_data" == di.dirname() );
477 REQUIRE( "file_01_slink09R1.txt" == di.basename() );
478 REQUIRE( path1_ == di.path() );
479 }
480
481 {
482 const std::string path1_ = "../../../jaulib/test_data";
483 const jau::io::fs::dir_item di(path1_);
484 INFO_STR("\n\ntest04_dir_item: 61 '"+path1_+" -> "+di.toString()+" -> '"+di.path()+"'\n");
485 REQUIRE( "../../../jaulib" == di.dirname() );
486 REQUIRE( "test_data" == di.basename() );
487 REQUIRE( path1_ == di.path() );
488 }
489
490 {
491 const std::string path1_ = "../../../../jaulib/test_data";
492 const jau::io::fs::dir_item di(path1_);
493 INFO_STR("\n\ntest04_dir_item: 62 '"+path1_+" -> "+di.toString()+" -> '"+di.path()+"'\n");
494 REQUIRE( "../../../../jaulib" == di.dirname() );
495 REQUIRE( "test_data" == di.basename() );
496 REQUIRE( path1_ == di.path() );
497 }
498
499 {
500 const std::string path1_ = "././././jaulib/test_data";
501 const jau::io::fs::dir_item di(path1_);
502 INFO_STR("\n\ntest04_dir_item: 63 '"+path1_+" -> "+di.toString()+" -> '"+di.path()+"'\n");
503 REQUIRE( "jaulib" == di.dirname() );
504 REQUIRE( "test_data" == di.basename() );
505 REQUIRE( "jaulib/test_data" == di.path() );
506 }
507 {
508 const std::string path1_ = "a/././././jaulib/test_data";
509 const jau::io::fs::dir_item di(path1_);
510 INFO_STR("\n\ntest04_dir_item: 64 '"+path1_+" -> "+di.toString()+" -> '"+di.path()+"'\n");
511 REQUIRE( "a/jaulib" == di.dirname() );
512 REQUIRE( "test_data" == di.basename() );
513 REQUIRE( "a/jaulib/test_data" == di.path() );
514 }
515
516 {
517 // Error
518 const std::string path1_ = "/../lala";
519 const jau::io::fs::dir_item di(path1_);
520 INFO_STR("\n\ntest04_dir_item: 99 '"+path1_+" -> "+di.toString()+" -> '"+di.path()+"'\n");
521 REQUIRE( "/.." == di.dirname() );
522 REQUIRE( "lala" == di.basename() );
523 REQUIRE( "/../lala" == di.path() );
524 }
525 }
526
528 errno = 0;
529 INFO_STR("\n\ntest05_file_stat\n");
530
531 {
533 jau::fprintf_td(stdout, "test05_file_stat: 0a: %s\n", stats.toString().c_str());
534 jau::fprintf_td(stdout, "test05_file_stat: 0a: fields %s\n", jau::io::fs::to_string( stats.fields() ).c_str());
535 REQUIRE( false == stats.exists() );
536 }
537 {
538 jau::io::fs::file_stats stats("");
539 jau::fprintf_td(stdout, "test05_file_stat: 0b: %s\n", stats.toString().c_str());
540 jau::fprintf_td(stdout, "test05_file_stat: 0b: fields %s\n", jau::io::fs::to_string( stats.fields() ).c_str());
541 REQUIRE( false == stats.exists() );
542 }
543 {
544 jau::io::fs::file_stats stats(project_root_ext+"/file_01.txt");
545 jau::fprintf_td(stdout, "test05_file_stat: 01: %s\n", stats.toString().c_str());
546 jau::fprintf_td(stdout, "test05_file_stat: 01: fields %s\n", jau::io::fs::to_string( stats.fields() ).c_str());
547 if( stats.exists() ) {
548 REQUIRE( stats.has_access() );
549 REQUIRE( !stats.is_dir() );
550 REQUIRE( stats.is_file() );
551 REQUIRE( !stats.is_link() );
552 REQUIRE( 15 == stats.size() );
553 }
554 }
555
556 jau::io::fs::file_stats proot_stats = getTestDataDirStats(executable_path);
557 jau::fprintf_td(stdout, "test05_file_stat: 11: %s\n", proot_stats.toString().c_str());
558 jau::fprintf_td(stdout, "test05_file_stat: 11: fields %s\n", jau::io::fs::to_string( proot_stats.fields() ).c_str());
559 REQUIRE( true == proot_stats.exists() );
560 REQUIRE( true == proot_stats.is_dir() );
561 {
562 jau::io::fs::file_stats stats(proot_stats.path()+"/file_01.txt");
563 jau::fprintf_td(stdout, "test05_file_stat: 12: %s\n", stats.toString().c_str());
564 jau::fprintf_td(stdout, "test05_file_stat: 12: fields %s\n", jau::io::fs::to_string( stats.fields() ).c_str());
565 REQUIRE( stats.exists() );
566 REQUIRE( stats.has_access() );
567 REQUIRE( !stats.is_dir() );
568 REQUIRE( stats.is_file() );
569 REQUIRE( !stats.is_link() );
570 REQUIRE( 15 == stats.size() );
571
572 size_t link_count;
573 const jau::io::fs::file_stats* final_target = stats.final_target(&link_count);
574 jau::fprintf_td(stdout, "test05_file_stat: 12: final_target (%zu link count): %s\n", link_count, final_target->toString().c_str());
575 REQUIRE( 0 == link_count );
576 REQUIRE( final_target == &stats );
577
578 {
579 jau::io::fs::file_stats stats2(proot_stats.path()+"/file_01.txt");
580 REQUIRE( stats2.exists() );
581 REQUIRE( stats2.has_access() );
582 REQUIRE( !stats2.is_dir() );
583 REQUIRE( stats2.is_file() );
584 REQUIRE( !stats2.is_link() );
585 REQUIRE( 15 == stats2.size() );
586 REQUIRE( stats == stats2 );
587 }
588 {
589 jau::io::fs::file_stats stats2(proot_stats.path()+"/dir_01/file_02.txt");
590 REQUIRE( stats2.exists() );
591 REQUIRE( stats2.has_access() );
592 REQUIRE( !stats2.is_dir() );
593 REQUIRE( stats2.is_file() );
594 REQUIRE( !stats2.is_link() );
595 REQUIRE( stats != stats2 );
596 }
597 }
598 {
599 jau::io::fs::file_stats stats(proot_stats.path()+"/dir_01");
600 jau::fprintf_td(stdout, "test05_file_stat: 13: %s\n", stats.toString().c_str());
601 jau::fprintf_td(stdout, "test05_file_stat: 13: fields %s\n", jau::io::fs::to_string( stats.fields() ).c_str());
602 REQUIRE( stats.exists() );
603 REQUIRE( stats.has_access() );
604 REQUIRE( stats.is_dir() );
605 REQUIRE( !stats.is_file() );
606 REQUIRE( !stats.is_link() );
607 REQUIRE( 0 == stats.size() );
608
609 size_t link_count;
610 const jau::io::fs::file_stats* final_target = stats.final_target(&link_count);
611 jau::fprintf_td(stdout, "test05_file_stat: 13: final_target (%zu link count): %s\n", link_count, final_target->toString().c_str());
612 REQUIRE( 0 == link_count );
613 REQUIRE( final_target == &stats );
614 }
615 {
616 jau::io::fs::file_stats stats(proot_stats.path()+"/does_not_exist");
617 jau::fprintf_td(stdout, "test05_file_stat: 14: %s\n", stats.toString().c_str());
618 jau::fprintf_td(stdout, "test05_file_stat: 14: fields %s\n", jau::io::fs::to_string( stats.fields() ).c_str());
619 REQUIRE( !stats.exists() );
620 REQUIRE( stats.has_access() );
621 REQUIRE( !stats.is_dir() );
622 REQUIRE( !stats.is_file() );
623 REQUIRE( !stats.is_link() );
624 REQUIRE( 0 == stats.size() );
625
626 size_t link_count;
627 const jau::io::fs::file_stats* final_target = stats.final_target(&link_count);
628 jau::fprintf_td(stdout, "test05_file_stat: 14: final_target (%zu link count): %s\n", link_count, final_target->toString().c_str());
629 REQUIRE( 0 == link_count );
630 REQUIRE( final_target == &stats );
631 }
632 }
633
635 errno = 0;
636 INFO_STR("\n\ntest06_file_stat_symlinks\n");
637
638 jau::io::fs::file_stats proot_stats = getTestDataDirStats(executable_path);
639 REQUIRE( true == proot_stats.exists() );
640 REQUIRE( true == proot_stats.is_dir() );
641 {
642 jau::io::fs::file_stats stats(proot_stats.path()+"/file_01_slink01.txt");
643 jau::fprintf_td(stdout, "test06_file_stat_symlinks: 13: %s\n", stats.toString().c_str());
644 jau::fprintf_td(stdout, "test06_file_stat_symlinks: 13: fields %s\n", jau::io::fs::to_string( stats.fields() ).c_str());
645 REQUIRE( stats.exists() );
646 REQUIRE( stats.has_access() );
647 REQUIRE( !stats.is_dir() );
648 REQUIRE( stats.is_file() );
649 REQUIRE( stats.is_link() );
650 REQUIRE( 15 == stats.size() );
651 REQUIRE( nullptr != stats.link_target_path() );
652 REQUIRE( "file_01.txt" == *stats.link_target_path() );
653
654 size_t link_count;
655 const jau::io::fs::file_stats* final_target = stats.final_target(&link_count);
656 jau::fprintf_td(stdout, "- final_target (%zu link count): %s\n", link_count, final_target->toString().c_str());
657 REQUIRE( 1 == link_count );
658 REQUIRE( final_target != &stats );
659 REQUIRE( proot_stats.path()+"/file_01.txt" == final_target->path() );
660
661 REQUIRE( nullptr != stats.link_target() );
662 const jau::io::fs::file_stats* link_target = stats.link_target().get();
663 REQUIRE( nullptr != link_target );
664 jau::fprintf_td(stdout, "- link_target %s\n", link_target->toString().c_str());
665 REQUIRE( final_target == link_target );
666 REQUIRE( !link_target->is_dir() );
667 REQUIRE( link_target->is_file() );
668 REQUIRE( !link_target->is_link() );
669 REQUIRE( nullptr == link_target->link_target_path() );
670 REQUIRE( nullptr == link_target->link_target() );
671 }
672 {
673 jau::io::fs::file_stats stats(proot_stats.path()+"/fstab_slink07_absolute");
674 jau::fprintf_td(stdout, "test06_file_stat_symlinks: 14: %s\n", stats.toString().c_str());
675 jau::fprintf_td(stdout, "test06_file_stat_symlinks: 14: fields %s\n", jau::io::fs::to_string( stats.fields() ).c_str());
676 REQUIRE( stats.exists() );
677 REQUIRE( stats.has_access() );
678 REQUIRE( !stats.is_dir() );
679 REQUIRE( stats.is_file() );
680 REQUIRE( stats.is_link() );
681 REQUIRE( 20 < stats.size() ); // greater than basename
682 REQUIRE( nullptr != stats.link_target_path() );
683 REQUIRE( "/etc/fstab" == *stats.link_target_path() );
684
685 size_t link_count;
686 const jau::io::fs::file_stats* final_target = stats.final_target(&link_count);
687 jau::fprintf_td(stdout, "- final_target (%zu link count): %s\n", link_count, final_target->toString().c_str());
688 REQUIRE( 1 == link_count );
689 REQUIRE( final_target != &stats );
690 REQUIRE( "/etc/fstab" == final_target->path() );
691
692 REQUIRE( nullptr != stats.link_target() );
693 const jau::io::fs::file_stats* link_target = stats.link_target().get();
694 REQUIRE( nullptr != link_target );
695 jau::fprintf_td(stdout, "- link_target %s\n", link_target->toString().c_str());
696 REQUIRE( final_target == link_target );
697 REQUIRE( !link_target->is_dir() );
698 REQUIRE( link_target->is_file() );
699 REQUIRE( !link_target->is_link() );
700 REQUIRE( nullptr == link_target->link_target_path() );
701 REQUIRE( nullptr == link_target->link_target() );
702 }
703 {
704 jau::io::fs::file_stats stats(proot_stats.path()+"/file_01_slink10R2.txt"); // -> file_01_slink09R1.txt -> file_01_slink01.txt -> file_01.txt
705 jau::fprintf_td(stdout, "test06_file_stat_symlinks: 20: %s\n", stats.toString().c_str());
706 jau::fprintf_td(stdout, "test06_file_stat_symlinks: 20: fields %s\n", jau::io::fs::to_string( stats.fields() ).c_str());
707 REQUIRE( stats.exists() );
708 REQUIRE( stats.has_access() );
709 REQUIRE( !stats.is_dir() );
710 REQUIRE( stats.is_file() );
711 REQUIRE( stats.is_link() );
712 REQUIRE( 15 == stats.size() );
713 REQUIRE( nullptr != stats.link_target_path() );
714 REQUIRE( "file_01_slink09R1.txt" == *stats.link_target_path() );
715
716 size_t link_count;
717 const jau::io::fs::file_stats* final_target = stats.final_target(&link_count);
718 jau::fprintf_td(stdout, "- final_target (%zu link count): %s\n", link_count, final_target->toString().c_str());
719 REQUIRE( 3 == link_count );
720 REQUIRE( final_target != &stats );
721 REQUIRE( proot_stats.path()+"/file_01.txt" == final_target->path() );
722
723 REQUIRE( nullptr != stats.link_target() );
724 const jau::io::fs::file_stats* link_target1 = stats.link_target().get();
725 jau::fprintf_td(stdout, "- link_target1 %s\n", link_target1->toString().c_str());
726 REQUIRE( final_target != link_target1 );
727 REQUIRE( proot_stats.path()+"/file_01_slink09R1.txt" == link_target1->path() );
728 REQUIRE( 15 == link_target1->size() );
729 REQUIRE( !link_target1->is_dir() );
730 REQUIRE( link_target1->is_file() );
731 REQUIRE( link_target1->is_link() );
732 REQUIRE( nullptr != link_target1->link_target_path() );
733 REQUIRE( "file_01_slink01.txt" == *link_target1->link_target_path() );
734 {
735 const jau::io::fs::file_stats* link_target2 = link_target1->link_target().get();
736 REQUIRE( nullptr != link_target2 );
737 jau::fprintf_td(stdout, " - link_target2 %s\n", link_target2->toString().c_str());
738 REQUIRE( final_target != link_target2 );
739 REQUIRE( link_target1 != link_target2 );
740 REQUIRE( proot_stats.path()+"/file_01_slink01.txt" == link_target2->path() );
741 REQUIRE( 15 == link_target2->size() );
742 REQUIRE( !link_target2->is_dir() );
743 REQUIRE( link_target2->is_file() );
744 REQUIRE( link_target2->is_link() );
745 REQUIRE( nullptr != link_target2->link_target_path() );
746 REQUIRE( "file_01.txt" == *link_target2->link_target_path() );
747
748 const jau::io::fs::file_stats* link_target3 = link_target2->link_target().get();
749 REQUIRE( nullptr != link_target3 );
750 jau::fprintf_td(stdout, " - link_target3 %s\n", link_target3->toString().c_str());
751 REQUIRE( final_target == link_target3 );
752 REQUIRE( link_target1 != link_target3 );
753 REQUIRE( link_target2 != link_target3 );
754 REQUIRE( 15 == link_target3->size() );
755 REQUIRE( !link_target3->is_dir() );
756 REQUIRE( link_target3->is_file() );
757 REQUIRE( !link_target3->is_link() );
758 REQUIRE( nullptr == link_target3->link_target_path() );
759 REQUIRE( nullptr == link_target3->link_target() );
760 }
761 }
762 {
763 jau::io::fs::file_stats stats(proot_stats.path()+"/dead_link23"); // -> not_existing_file
764 jau::fprintf_td(stdout, "test06_file_stat_symlinks: 30: %s\n", stats.toString().c_str());
765 jau::fprintf_td(stdout, "test06_file_stat_symlinks: 30: fields %s\n", jau::io::fs::to_string( stats.fields() ).c_str());
766 REQUIRE( !stats.exists() );
767 REQUIRE( stats.has_access() );
768 REQUIRE( !stats.is_dir() );
769 REQUIRE( !stats.is_file() );
770 REQUIRE( stats.is_link() );
771 REQUIRE( 0 == stats.size() );
772 REQUIRE( nullptr != stats.link_target_path() );
773 REQUIRE( "not_existing_file" == *stats.link_target_path() );
774 REQUIRE( nullptr == stats.link_target() );
775
776 size_t link_count;
777 const jau::io::fs::file_stats* final_target = stats.final_target(&link_count);
778 jau::fprintf_td(stdout, "- final_target (%zu link count): %s\n", link_count, final_target->toString().c_str());
779 REQUIRE( 0 == link_count );
780 REQUIRE( final_target == &stats );
781 }
782 {
783 jau::io::fs::file_stats stats(proot_stats.path()+"/dead_link22"); // LOOP: dead_link22 -> dead_link21 -> dead_link20 -> dead_link22 ...
784 jau::fprintf_td(stdout, "test06_file_stat_symlinks: 31: %s\n", stats.toString().c_str());
785 jau::fprintf_td(stdout, "test06_file_stat_symlinks: 31: fields %s\n", jau::io::fs::to_string( stats.fields() ).c_str());
786 REQUIRE( !stats.exists() );
787 REQUIRE( stats.has_access() );
788 REQUIRE( !stats.is_dir() );
789 REQUIRE( !stats.is_file() );
790 REQUIRE( stats.is_link() );
791 REQUIRE( 0 == stats.size() );
792 REQUIRE( nullptr != stats.link_target_path() );
793 REQUIRE( "dead_link21" == *stats.link_target_path() );
794 REQUIRE( nullptr == stats.link_target() );
795
796 size_t link_count;
797 const jau::io::fs::file_stats* final_target = stats.final_target(&link_count);
798 jau::fprintf_td(stdout, "- final_target (%zu link count): %s\n", link_count, final_target->toString().c_str());
799 REQUIRE( 0 == link_count );
800 REQUIRE( *final_target == stats );
801 REQUIRE( final_target == &stats );
802 }
803 }
804
805 static void test_file_stat_fd_item(const jau::io::fs::fmode_t exp_type, const int fd, const std::string& named_fd1, const std::string& named_fd_link) {
806 jau::fprintf_td(stdout, "test_file_stat_fd_item: expect '%s', fd %d, name_fd1 '%s', make_fd_link '%s'\n",
807 jau::io::fs::to_string(exp_type).c_str(), fd, named_fd1.c_str(), named_fd_link.c_str());
808 {
809 errno = 0;
810 jau::fprintf_td(stdout, "test_file_stat_fd_item.1: expect '%s', fd %d\n", jau::io::fs::to_string(exp_type).c_str(), fd);
811 jau::io::fs::file_stats stats(fd);
812 jau::fprintf_td(stdout, "fd: %s\n", stats.toString().c_str());
813 REQUIRE( stats.exists() );
814 REQUIRE( stats.has_access() );
815 REQUIRE( !stats.is_socket() );
816 REQUIRE( !stats.is_block() );
817 REQUIRE( !stats.is_dir() );
818 if( jau::io::fs::fmode_t::none == ( stats.type_mode() & exp_type ) ) {
819 jau::fprintf_td(stdout, "INFO: Not matching expected type '%s': fd: %s\n", jau::io::fs::to_string(exp_type).c_str(), stats.toString().c_str());
820 }
821 REQUIRE( stats.has_fd() );
822 REQUIRE( fd == stats.fd() );
823 if( !stats.is_file() ) {
824 REQUIRE( 0 == stats.size() );
825 }
826 jau::fprintf_td(stdout, "test_file_stat_fd_item.1: X\n\n");
827 }
828 if( !named_fd1.empty() ) {
829 errno = 0;
830 jau::fprintf_td(stdout, "test_file_stat_fd_item.2: expect '%s', fd %d, name_fd1 '%s'\n",
831 jau::io::fs::to_string(exp_type).c_str(), fd, named_fd1.c_str());
832 jau::io::fs::file_stats stats(named_fd1);
833 jau::fprintf_td(stdout, "fd_1: %s\n", stats.toString().c_str());
834 REQUIRE( stats.exists() );
835 REQUIRE( stats.has_access() );
836 REQUIRE( !stats.is_socket() );
837 REQUIRE( !stats.is_block() );
838 REQUIRE( !stats.is_dir() );
839 if( jau::io::fs::fmode_t::none == ( stats.type_mode() & exp_type ) ) {
840 jau::fprintf_td(stdout, "INFO: Not matching expected type '%s': fd: %s\n", jau::io::fs::to_string(exp_type).c_str(), stats.toString().c_str());
841 }
842 REQUIRE( stats.has_fd() );
843 REQUIRE( fd == stats.fd() );
844 if( !stats.is_file() ) {
845 REQUIRE( 0 == stats.size() );
846 }
847 jau::fprintf_td(stdout, "test_file_stat_fd_item.2: X\n\n");
848 }
849 if( !named_fd_link.empty() ) {
850 errno = 0;
851 jau::fprintf_td(stdout, "test_file_stat_fd_item.3: expect '%s', fd %d, make_fd_link '%s'\n",
852 jau::io::fs::to_string(exp_type).c_str(), fd, named_fd_link.c_str());
853 jau::io::fs::file_stats stats(named_fd_link);
854 jau::fprintf_td(stdout, "fd_link: %s\n", stats.toString().c_str());
855 REQUIRE( stats.exists() );
856 REQUIRE( stats.has_access() );
857 REQUIRE( !stats.is_socket() );
858 REQUIRE( !stats.is_block() );
859 REQUIRE( !stats.is_dir() );
860 if( jau::io::fs::fmode_t::none == ( stats.type_mode() & exp_type ) ) {
861 jau::fprintf_td(stdout, "INFO: Not matching expected type '%s': fd: %s\n", jau::io::fs::to_string(exp_type).c_str(), stats.toString().c_str());
862 }
863 REQUIRE( stats.has_fd() );
864 REQUIRE( fd == stats.fd() );
865 if( !stats.is_file() ) {
866 REQUIRE( 0 == stats.size() );
867 }
868
869 size_t link_count;
870 const jau::io::fs::file_stats* final_target = stats.final_target(&link_count);
871 REQUIRE( nullptr != final_target );
872 jau::fprintf_td(stdout, "- final_target (%zu link count): %s\n", link_count, final_target->toString().c_str());
873 REQUIRE( 1 <= link_count );
874 REQUIRE( 2 >= link_count );
875 jau::fprintf_td(stdout, "test_file_stat_fd_item.3: X\n\n");
876 }
877 }
878
880 jau::fprintf_td(stdout, "test07_file_stat_fd\n");
881
882 const std::string fd_stdin_1 = "/dev/fd/0";
883 const std::string fd_stdout_1 = "/dev/fd/1";
884 const std::string fd_stderr_1 = "/dev/fd/2";
885
886 const std::string fd_stdin_l = "/dev/stdin";
887 const std::string fd_stdout_l = "/dev/stdout";
888 const std::string fd_stderr_l = "/dev/stderr";
889
890 test_file_stat_fd_item(jau::io::fs::fmode_t::chr, 0, fd_stdin_1, fd_stdin_l);
891 test_file_stat_fd_item(jau::io::fs::fmode_t::chr, 1, fd_stdout_1, fd_stdout_l);
892 test_file_stat_fd_item(jau::io::fs::fmode_t::chr, 2, fd_stderr_1, fd_stderr_l);
893 {
894 int fd = ::open("test07_file_stat_fd_tmp", O_CREAT|O_WRONLY|O_NOCTTY, S_IRUSR | S_IWUSR | S_IRGRP );
895 REQUIRE( 0 <= fd );
897 ::close(fd);
898 }
899 {
900 int pipe_fds[2];
901 REQUIRE( 0 == ::pipe(pipe_fds) );
904 ::close(pipe_fds[0]);
905 ::close(pipe_fds[1]);
906 }
907 }
908
909 // 128 bytes
910 static constexpr const char* pipe_msg = "Therefore I say unto you, Take no thought for your life, what ye shall eat, or what ye shall drink; nor yet for your body, what.";
911 static const size_t pipe_msg_len = 128;
912 static const size_t pipe_msg_count = 10;
913
915 errno = 0;
916 jau::fprintf_td(stdout, "test08_pipe_01\n");
917
918 int pipe_fds[2];
919 REQUIRE( 0 == ::pipe(pipe_fds) );
920 ::pid_t pid = ::fork();
921
922 if( 0 == pid ) {
923 // child process: WRITE
924 ::close(pipe_fds[0]); // close unused read end
925 const int new_stdout = pipe_fds[1];
926 const std::string fd_stdout = jau::io::fs::to_named_fd(new_stdout);
927
928 jau::io::fs::file_stats stats_stdout(fd_stdout);
929 jau::fprintf_td(stdout, "Child: stats_stdout %s\n", stats_stdout.toString().c_str());
930 if( !stats_stdout.exists() || !stats_stdout.has_fd() || new_stdout != stats_stdout.fd() ) {
931 jau::fprintf_td(stdout, "Child: Error: stats_stdout %s\n", stats_stdout.toString().c_str());
932 ::_exit(EXIT_FAILURE);
933 }
935 if( !outfile.good() || !outfile.isOpen() ) {
936 jau::fprintf_td(stdout, "Child: Error: outfile bad: %s\n", outfile.toString().c_str());
937 ::_exit(EXIT_FAILURE);
938 }
939
940 // throttled w/ 64 bytes per 8_ms, i.e. 1280 / 64 * 8_ms ~ 160_ms (~20 chunks)
941 const size_t max_chunck = 64;
942 for(size_t count=0; count < pipe_msg_count; ++count) {
943 size_t sent=0;
944 while( sent < pipe_msg_len && !outfile.fail() ) {
945 const size_t chunck_sz = std::min(max_chunck, pipe_msg_len-sent);
946 if( chunck_sz != outfile.write(pipe_msg+sent, chunck_sz) ) {
947 count = pipe_msg_count;
948 break;
949 }
950 sent += chunck_sz;
951 jau::sleep_for( 8_ms );
952 }
953 }
954
955 outfile.close();
956 ::close(pipe_fds[1]);
957
958 if( outfile.fail() ) {
959 jau::fprintf_td(stdout, "Child: Error: outfile failed after write/closure: %s\n", outfile.toString().c_str());
960 ::_exit(EXIT_FAILURE);
961 }
962 jau::fprintf_td(stdout, "Child: Done\n");
963 ::_exit(EXIT_SUCCESS);
964
965 } else if( 0 < pid ) {
966 // parent process: READ
967 ::close(pipe_fds[1]); // close unused write end
968 const int new_stdin = pipe_fds[0]; // dup2(fd[0], 0);
969 const std::string fd_stdin = jau::io::fs::to_named_fd(new_stdin);
970
971 jau::io::fs::file_stats stats_stdin(fd_stdin);
972 jau::fprintf_td(stdout, "Parent: stats_stdin %s\n", stats_stdin.toString().c_str());
973 REQUIRE( stats_stdin.exists() );
974 REQUIRE( stats_stdin.has_access() );
975 REQUIRE( !stats_stdin.is_socket() );
976 REQUIRE( !stats_stdin.is_block() );
977 REQUIRE( !stats_stdin.is_dir() );
978 REQUIRE( !stats_stdin.is_file() );
979 const bool fifo_or_char = stats_stdin.is_fifo() || stats_stdin.is_char();
980 REQUIRE( true == fifo_or_char );
981 REQUIRE( stats_stdin.has_fd() );
982 REQUIRE( new_stdin == stats_stdin.fd() );
983 REQUIRE( 0 == stats_stdin.size() );
984
985 // capture stdin
987 jau::fprintf_td(stdout, "Parent: infile %s\n", infile.toString().c_str());
988 REQUIRE( !infile.fail() );
989
990 uint8_t buffer[pipe_msg_count * pipe_msg_len + 512];
991 jau::zero_bytes_sec(buffer, sizeof(buffer));
992 size_t total_read = 0;
993 {
994 while( infile.good() && total_read < sizeof(buffer) ) {
995 const size_t got = infile.read(buffer+total_read, sizeof(buffer)-total_read);
996 jau::fprintf_td(stdout, "Parent: infile.a_ %s\n", infile.toString().c_str());
997 REQUIRE( !infile.fail() );
998 total_read += got;
999 jau::fprintf_td(stdout, "Parent: Got %zu -> %zu\n", got, total_read);
1000 }
1001 jau::fprintf_td(stdout, "Parent: infile.a_1 %s\n", infile.toString().c_str());
1002 infile.close();
1003 jau::fprintf_td(stdout, "Parent: infile.a_2 %s\n", infile.toString().c_str());
1004 ::close(pipe_fds[0]);
1005 jau::fprintf_td(stdout, "Parent: infile.a_3 %s\n", infile.toString().c_str());
1006 REQUIRE( !infile.fail() );
1007 }
1008 // check actual transmitted content
1009 REQUIRE( total_read == pipe_msg_len*pipe_msg_count);
1010 for(size_t count=0; count < pipe_msg_count; ++count) {
1011 REQUIRE( 0 == ::memcmp(pipe_msg, buffer+(count*pipe_msg_len), pipe_msg_len) );
1012 }
1013
1014 int pid_status = 0;
1015 ::pid_t child_pid = ::waitpid(pid, &pid_status, 0);
1016 if( 0 > child_pid ) {
1017 jau::fprintf_td(stdout, "Parent: Error: wait(%d) failed: child_pid %d\n", pid, child_pid);
1018 REQUIRE_MSG("wait for child failed", false);
1019 } else {
1020 if( child_pid != pid ) {
1021 jau::fprintf_td(stdout, "Parent: Error: wait(%d) terminated child_pid pid %d\n", pid, child_pid);
1022 REQUIRE(child_pid == pid);
1023 }
1024 if( !WIFEXITED(pid_status) ) {
1025 jau::fprintf_td(stdout, "Parent: Error: wait(%d) terminated abnormally child_pid %d, pid_status %d\n", pid, child_pid, pid_status);
1026 REQUIRE(true == WIFEXITED(pid_status));
1027 }
1028 if( EXIT_SUCCESS != WEXITSTATUS(pid_status) ) {
1029 jau::fprintf_td(stdout, "Parent: Error: wait(%d) exit with failure child_pid %d, exit_code %d\n", pid, child_pid, WEXITSTATUS(pid_status));
1030 REQUIRE(EXIT_SUCCESS == WEXITSTATUS(pid_status));
1031 }
1032 }
1033 } else {
1034 // fork failed
1035 jau::fprintf_td(stdout, "fork failed %d, %s\n", errno, ::strerror(errno));
1036 REQUIRE_MSG( "fork failed", false );
1037 }
1038 }
1039
1040 /**
1041 *
1042 */
1044 INFO_STR("\n\ntest10_mkdir\n");
1045
1047 {
1049 INFO_STR("root_stats.pre: "+root_stats.toString()+"\n");
1050 REQUIRE( !root_stats.exists() );
1051 REQUIRE( root_stats.has_access() );
1052 REQUIRE( !root_stats.is_dir() );
1053 REQUIRE( !root_stats.is_file() );
1054 REQUIRE( !root_stats.is_link() );
1055 }
1057 {
1059 INFO_STR("root_stats.post: "+root_stats.toString()+"\n");
1060 REQUIRE( root_stats.exists() );
1061 REQUIRE( root_stats.has_access() );
1062 REQUIRE( root_stats.is_dir() );
1063 REQUIRE( !root_stats.is_file() );
1064 REQUIRE( !root_stats.is_link() );
1065 }
1068 }
1069
1071 const jau::fraction_timespec td_1s(1, 0);
1072
1073 INFO_STR("\n\ntest11_touch\n");
1074 const std::string file_01 = temp_root+"/data01.txt";
1075 const std::string file_02 = temp_root+"/data02.txt";
1077 {
1079 jau::fprintf_td(stdout, "root_stats1.post: %s\n", root_stats.toString().c_str());
1080 REQUIRE( root_stats.exists() );
1081 REQUIRE( root_stats.has_access() );
1082 REQUIRE( root_stats.is_dir() );
1083 REQUIRE( !root_stats.is_file() );
1084 REQUIRE( !root_stats.is_link() );
1085 }
1086
1087 REQUIRE( true == jau::io::fs::touch(file_01, jau::io::fs::fmode_t::def_file_prot) );
1088 {
1090 jau::io::fs::file_stats file_stats(file_01);
1091 jau::fprintf_td(stdout, "file_stats2.post: %s\n", file_stats.toString().c_str());
1092 const jau::fraction_timespec btime = file_stats.btime();
1093 const jau::fraction_timespec atime = file_stats.atime();
1094 const jau::fraction_timespec atime_td = jau::abs(now - atime);
1095 const jau::fraction_timespec mtime = file_stats.mtime();
1096 const jau::fraction_timespec mtime_td = jau::abs(now - mtime);
1097 jau::fprintf_td(stdout, "now: %s, %s\n", now.toISO8601String().c_str(), now.toString().c_str());
1098 jau::fprintf_td(stdout, "btime: %s, %s\n", btime.toISO8601String().c_str(), btime.toString().c_str());
1099 jau::fprintf_td(stdout, "atime: %s, %s, td_now %s\n",
1100 atime.toISO8601String().c_str(), atime.toString().c_str(), atime_td.toString().c_str());
1101 jau::fprintf_td(stdout, "mtime: %s, %s, td_now %s\n",
1102 mtime.toISO8601String().c_str(), mtime.toString().c_str(), mtime_td.toString().c_str());
1103 REQUIRE( file_stats.exists() );
1104 REQUIRE( file_stats.has_access() );
1105 REQUIRE( !file_stats.is_dir() );
1106 REQUIRE( file_stats.is_file() );
1107 REQUIRE( !file_stats.is_link() );
1108 if( file_stats.has( jau::io::fs::file_stats::field_t::atime ) ) {
1109 REQUIRE( td_1s >= atime_td );
1110 }
1111 if( file_stats.has( jau::io::fs::file_stats::field_t::mtime ) ) {
1112 REQUIRE( td_1s >= mtime_td );
1113 }
1114 }
1115
1116 REQUIRE( true == jau::io::fs::touch(file_02, jau::io::fs::fmode_t::def_file_prot) );
1117 {
1119 jau::io::fs::file_stats file_stats_pre(file_02);
1120 const jau::fraction_timespec btime_pre = file_stats_pre.btime();
1121 const jau::fraction_timespec atime_pre = file_stats_pre.atime();
1122 const jau::fraction_timespec atime_td = jau::abs(now - atime_pre);
1123 const jau::fraction_timespec mtime_pre = file_stats_pre.mtime();
1124 const jau::fraction_timespec mtime_td = jau::abs(now - mtime_pre);
1125 jau::fprintf_td(stdout, "now : %s, %s\n", now.toISO8601String().c_str(), now.toString().c_str());
1126 jau::fprintf_td(stdout, "btime.pre: %s, %s\n", btime_pre.toISO8601String().c_str(), btime_pre.toString().c_str());
1127 jau::fprintf_td(stdout, "atime.pre: %s, %s, td_now %s\n",
1128 atime_pre.toISO8601String().c_str(), atime_pre.toString().c_str(), atime_td.toString().c_str());
1129 jau::fprintf_td(stdout, "mtime.pre: %s, %s, td_now %s\n",
1130 mtime_pre.toISO8601String().c_str(), mtime_pre.toString().c_str(), mtime_td.toString().c_str());
1131 if( file_stats_pre.has( jau::io::fs::file_stats::field_t::atime ) ) {
1132 REQUIRE( td_1s >= atime_td );
1133 }
1134 if( file_stats_pre.has( jau::io::fs::file_stats::field_t::mtime ) ) {
1135 REQUIRE( td_1s >= mtime_td );
1136 }
1137
1138 const jau::fraction_timespec ts_20200101( 1577836800_s + 0_h); // 2020-01-01 00:00:00
1139 const jau::fraction_timespec atime_set( ts_20200101 + 1_d + 10_h );
1140 const jau::fraction_timespec mtime_set( ts_20200101 + 31_d + 10_h );
1141 INFO_STR("atime.set: "+atime_set.toISO8601String()+", "+atime_set.toString()+"\n");
1142 INFO_STR("mtime.set: "+mtime_set.toISO8601String()+", "+mtime_set.toString()+"\n");
1143 REQUIRE( true == jau::io::fs::touch(file_02, atime_set, mtime_set, jau::io::fs::fmode_t::def_file_prot) );
1144
1145 jau::io::fs::file_stats file_stats_post(file_02);
1146 const jau::fraction_timespec atime_post = file_stats_post.atime();
1147 const jau::fraction_timespec mtime_post = file_stats_post.mtime();
1148 INFO_STR("atime.post: "+atime_post.toISO8601String()+", "+atime_post.toString()+"\n");
1149 INFO_STR("mtime.post: "+mtime_post.toISO8601String()+", "+mtime_post.toString()+"\n");
1150 jau::fprintf_td(stdout, "test11_touch: 03: %s\n", file_stats_post.toString().c_str());
1151 {
1152 REQUIRE( file_stats_post.exists() );
1153 REQUIRE( file_stats_post.has_access() );
1154 REQUIRE( !file_stats_post.is_dir() );
1155 REQUIRE( file_stats_post.is_file() );
1156 REQUIRE( !file_stats_post.is_link() );
1157 if( file_stats_post.has( jau::io::fs::file_stats::field_t::atime ) ) {
1158 REQUIRE( atime_set == file_stats_post.atime() );
1159 }
1160 if( file_stats_post.has( jau::io::fs::file_stats::field_t::mtime ) ) {
1161 REQUIRE( mtime_set == file_stats_post.mtime() );
1162 }
1163 }
1164 }
1165
1167 }
1168
1169
1171 INFO_STR("\n\ntest21_visit_error\n");
1172 }
1173
1175 INFO_STR("\n\ntest20_visit\n");
1176
1177 std::string sub_dir1 = temp_root+"/sub1";
1178 std::string sub_dir2 = temp_root+"/sub2";
1179 std::string sub_dir3 = temp_root+"/sub1/sub3";
1180
1182 REQUIRE( true == jau::io::fs::touch(temp_root+"/data01.txt") );
1183 REQUIRE( true == jau::io::fs::touch(temp_root+"/data02.txt") );
1184 REQUIRE( true == jau::io::fs::mkdir(sub_dir1, jau::io::fs::fmode_t::def_dir_prot) );
1185 REQUIRE( true == jau::io::fs::mkdir(sub_dir2, jau::io::fs::fmode_t::def_dir_prot) );
1186 REQUIRE( true == jau::io::fs::mkdir(sub_dir3, jau::io::fs::fmode_t::def_dir_prot) );
1187 REQUIRE( true == jau::io::fs::touch(sub_dir1+"/data03.txt") );
1188 REQUIRE( true == jau::io::fs::touch(sub_dir1+"/data04.txt") );
1189 REQUIRE( true == jau::io::fs::touch(sub_dir2+"/data05.txt") );
1190 REQUIRE( true == jau::io::fs::touch(sub_dir2+"/data06.txt") );
1191 REQUIRE( true == jau::io::fs::touch(sub_dir3+"/data07.txt") );
1192 REQUIRE( true == jau::io::fs::touch(sub_dir3+"/data08.txt") );
1193
1197 visitor_stats stats_R_FSL_PDL(topts_R_FSL_PDL);
1198 {
1199 // Use an easy-code capturing lambda visitor
1200 const jau::io::fs::path_visitor pv = [&](jau::io::fs::traverse_event tevt, const jau::io::fs::file_stats& element_stats, size_t depth) -> bool {
1201 (void)tevt;
1202 (void)depth;
1203 stats_R_FSL_PDL.add(element_stats);
1204 return true;
1205 };
1206 REQUIRE( true == jau::io::fs::visit(temp_root, topts_R_FSL_PDL, pv) );
1207 jau::fprintf_td(stdout, "test20_visit[R, FSL, PDL]: %s\n%s\n", to_string(topts_R_FSL_PDL).c_str(), stats_R_FSL_PDL.toString().c_str());
1208 REQUIRE( 12 == stats_R_FSL_PDL.total_real );
1209 REQUIRE( 0 == stats_R_FSL_PDL.total_sym_links_existing );
1210 REQUIRE( 0 == stats_R_FSL_PDL.total_sym_links_not_existing );
1211 REQUIRE( 0 == stats_R_FSL_PDL.total_no_access );
1212 REQUIRE( 0 == stats_R_FSL_PDL.total_not_existing );
1213 REQUIRE( 0 == stats_R_FSL_PDL.total_file_bytes );
1214 REQUIRE( 8 == stats_R_FSL_PDL.files_real );
1215 REQUIRE( 0 == stats_R_FSL_PDL.files_sym_link );
1216 REQUIRE( 4 == stats_R_FSL_PDL.dirs_real );
1217 REQUIRE( 0 == stats_R_FSL_PDL.dirs_sym_link );
1218 }
1222 visitor_stats stats_R_FSL(topts_R_FSL);
1223 {
1224 // Use a harder to code internal capturing-reference type visitor
1225 const jau::io::fs::path_visitor pv = jau::bind_capref(&stats_R_FSL,
1226 ( bool(*)(visitor_stats*, jau::io::fs::traverse_event, const jau::io::fs::file_stats&, size_t) ) /* help template type deduction of function-ptr */
1227 ( [](visitor_stats* stats_ptr, jau::io::fs::traverse_event tevt, const jau::io::fs::file_stats& element_stats, size_t depth) -> bool {
1228 (void)tevt;
1229 (void)depth;
1230 stats_ptr->add(element_stats);
1231 return true;
1232 } ) );
1233 REQUIRE( true == jau::io::fs::visit(temp_root, topts_R_FSL, pv) );
1234 jau::fprintf_td(stdout, "test20_visit[R, FSL]: %s\n%s\n", to_string(topts_R_FSL).c_str(), stats_R_FSL.toString().c_str());
1235 REQUIRE( stats_R_FSL_PDL == stats_R_FSL );
1236 }
1237
1239 }
1240
1242 INFO_STR("\n\ntest22_visit_symlinks\n");
1243
1244 jau::io::fs::file_stats proot_stats = getTestDataDirStats(executable_path);
1245 REQUIRE( true == proot_stats.exists() );
1246 // recursive without symlinks
1247 {
1250 visitor_stats stats(topts);
1251
1252 // Use an easy-code capturing lambda visitor
1253 const jau::io::fs::path_visitor pv = [&](jau::io::fs::traverse_event tevt, const jau::io::fs::file_stats& element_stats, size_t depth) -> bool {
1254 (void)tevt;
1255 (void)depth;
1256 stats.add(element_stats);
1257 return true;
1258 };
1259 REQUIRE( true == jau::io::fs::visit(proot_stats, topts, pv) );
1260 jau::fprintf_td(stdout, "test22_visit[R]: %s\n%s\n", to_string(topts).c_str(), stats.toString().c_str());
1261 REQUIRE( 7 == stats.total_real );
1262 REQUIRE( 10 == stats.total_sym_links_existing );
1263 REQUIRE( 4 == stats.total_sym_links_not_existing );
1264 REQUIRE( 0 == stats.total_no_access );
1265 REQUIRE( 4 == stats.total_not_existing );
1266 REQUIRE( 60 == stats.total_file_bytes );
1267 REQUIRE( 4 == stats.files_real );
1268 REQUIRE( 9 == stats.files_sym_link );
1269 REQUIRE( 3 == stats.dirs_real );
1270 REQUIRE( 1 == stats.dirs_sym_link );
1271 }
1272 // recursive with symlinks
1273 {
1277 visitor_stats stats(topts);
1278
1279 // Use an easy-code capturing lambda visitor
1280 const jau::io::fs::path_visitor pv = [&](jau::io::fs::traverse_event tevt, const jau::io::fs::file_stats& element_stats, size_t depth) -> bool {
1281 (void)tevt;
1282 (void)depth;
1283 stats.add(element_stats);
1284 return true;
1285 };
1286 REQUIRE( true == jau::io::fs::visit(proot_stats, topts, pv) );
1287 jau::fprintf_td(stdout, "test22_visit[R, FSL]: %s\n%s\n", to_string(topts).c_str(), stats.toString().c_str());
1288 REQUIRE( 9 == stats.total_real );
1289 REQUIRE( 11 == stats.total_sym_links_existing );
1290 REQUIRE( 4 == stats.total_sym_links_not_existing );
1291 REQUIRE( 0 == stats.total_no_access );
1292 REQUIRE( 4 == stats.total_not_existing );
1293 REQUIRE( 60 < stats.total_file_bytes ); // some followed symlink files are of unknown size, e.g. /etc/fstab
1294 REQUIRE( 6 == stats.files_real );
1295 REQUIRE( 10 == stats.files_sym_link );
1296 REQUIRE( 3 == stats.dirs_real );
1297 REQUIRE( 1 == stats.dirs_sym_link );
1298 }
1299 // flat with symlinks
1300 {
1305 visitor_stats stats(topts);
1306
1307 // Use an easy-code capturing lambda visitor
1308 const jau::io::fs::path_visitor pv = [&](jau::io::fs::traverse_event tevt, const jau::io::fs::file_stats& element_stats, size_t depth) -> bool {
1309 (void)tevt;
1311 return false;
1312 }
1313 stats.add(element_stats);
1314 return true;
1315 };
1316 REQUIRE( true == jau::io::fs::visit(proot_stats, topts, pv) );
1317 jau::fprintf_td(stdout, "test22_visit[F, FSL]: %s\n%s\n", to_string(topts).c_str(), stats.toString().c_str());
1318 REQUIRE( 3 == stats.total_real );
1319 REQUIRE( 5 == stats.total_sym_links_existing );
1320 REQUIRE( 4 == stats.total_sym_links_not_existing );
1321 REQUIRE( 0 == stats.total_no_access );
1322 REQUIRE( 4 == stats.total_not_existing );
1323 REQUIRE( 60 < stats.total_file_bytes ); // some followed symlink files are of unknown size, e.g. /etc/fstab
1324 REQUIRE( 1 == stats.files_real );
1325 REQUIRE( 5 == stats.files_sym_link );
1326 REQUIRE( 2 == stats.dirs_real );
1327 REQUIRE( 0 == stats.dirs_sym_link );
1328 }
1329 }
1330
1332 INFO_STR("\n\ntest30_copy_file2dir\n");
1333
1334 jau::io::fs::file_stats root_orig_stats = getTestDataDirStats(executable_path);
1335 REQUIRE( true == root_orig_stats.exists() );
1336
1337 const std::string root_copy = temp_root+"_copy_test30";
1338 {
1339 // Fresh target folder
1341
1342 REQUIRE( true == jau::io::fs::mkdir(root_copy, jau::io::fs::fmode_t::def_dir_prot) );
1343 {
1344 jau::io::fs::file_stats stats(root_copy);
1345 REQUIRE( true == stats.exists() );
1346 REQUIRE( true == stats.ok() );
1347 REQUIRE( true == stats.is_dir() );
1348 }
1349 }
1350 jau::io::fs::file_stats source1_stats(root_orig_stats.path()+"/file_01.txt");
1351 jau::fprintf_td(stdout, "test30_copy_file2dir: source1: %s\n", source1_stats.toString().c_str());
1352 {
1353 REQUIRE( true == source1_stats.exists() );
1354 REQUIRE( true == source1_stats.ok() );
1355 REQUIRE( true == source1_stats.is_file() );
1356 }
1357 {
1358 // Copy file to folder
1361 {
1362 jau::io::fs::file_stats dest_stats(root_copy+"/file_01.txt");
1363 jau::fprintf_td(stdout, "test30_copy_file2dir: 01: dest.pre: %s\n", dest_stats.toString().c_str());
1364 REQUIRE( false == dest_stats.exists() );
1365 }
1366 REQUIRE( true == jau::io::fs::copy(source1_stats.path(), root_copy, copts) );
1367 {
1368 jau::io::fs::file_stats dest_stats(root_copy+"/file_01.txt");
1369 jau::fprintf_td(stdout, "test30_copy_file2dir: 01: dest.post: %s\n", dest_stats.toString().c_str());
1370 REQUIRE( true == dest_stats.exists() );
1371 REQUIRE( true == dest_stats.ok() );
1372 REQUIRE( true == dest_stats.is_file() );
1373 REQUIRE( source1_stats.size() == dest_stats.size() );
1374 REQUIRE( source1_stats.mode() == dest_stats.mode() );
1375 }
1376 }
1377 {
1378 // Error: already exists of 'Copy file to folder'
1381 {
1382 jau::io::fs::file_stats dest_stats(root_copy+"/file_01.txt");
1383 jau::fprintf_td(stdout, "test30_copy_file2dir: 02: dest.pre: %s\n", dest_stats.toString().c_str());
1384 REQUIRE( true == dest_stats.exists() );
1385 REQUIRE( true == dest_stats.ok() );
1386 REQUIRE( true == dest_stats.is_file() );
1387 }
1388 REQUIRE( false == jau::io::fs::copy(source1_stats.path(), root_copy, copts) );
1389 }
1390 {
1391 // Overwrite copy file to folder
1395
1396 jau::fprintf_td(stdout, "test30_copy_file2dir: 03: source: %s\n", source1_stats.toString().c_str());
1397 {
1398 jau::io::fs::file_stats dest_stats(root_copy+"/file_01.txt");
1399 jau::fprintf_td(stdout, "test30_copy_file2dir: 03: dest.pre: %s\n", dest_stats.toString().c_str());
1400 REQUIRE( true == dest_stats.exists() );
1401 REQUIRE( true == dest_stats.ok() );
1402 REQUIRE( true == dest_stats.is_file() );
1403 REQUIRE( source1_stats.size() == dest_stats.size() );
1404 REQUIRE( source1_stats.mode() == dest_stats.mode() );
1405 }
1406 REQUIRE( true == jau::io::fs::copy(source1_stats.path(), root_copy, copts) );
1407 {
1408 jau::io::fs::file_stats dest_stats(root_copy+"/file_01.txt");
1409 jau::fprintf_td(stdout, "test30_copy_file2dir: 03: dest.post: %s\n", dest_stats.toString().c_str());
1410 REQUIRE( true == dest_stats.exists() );
1411 REQUIRE( true == dest_stats.ok() );
1412 REQUIRE( true == dest_stats.is_file() );
1413 REQUIRE( source1_stats.size() == dest_stats.size() );
1414 REQUIRE( source1_stats.mode() == dest_stats.mode() );
1415 }
1416 }
1417 if constexpr ( _remove_target_test_dir ) {
1419 }
1420 }
1421
1423 INFO_STR("\n\ntest31_copy_file2file\n");
1424
1425 jau::io::fs::file_stats root_orig_stats = getTestDataDirStats(executable_path);
1426 REQUIRE( true == root_orig_stats.exists() );
1427
1428 const std::string root_copy = temp_root+"_copy_test31";
1429 {
1430 // Fresh target folder
1432
1433 REQUIRE( true == jau::io::fs::mkdir(root_copy, jau::io::fs::fmode_t::def_dir_prot) );
1434 {
1435 jau::io::fs::file_stats stats(root_copy);
1436 REQUIRE( true == stats.exists() );
1437 REQUIRE( true == stats.ok() );
1438 REQUIRE( true == stats.is_dir() );
1439 }
1440 }
1441 jau::io::fs::file_stats source1_stats(root_orig_stats.path()+"/file_01.txt");
1442 jau::fprintf_td(stdout, "test31_copy_file2file: source1: %s\n", source1_stats.toString().c_str());
1443 {
1444 REQUIRE( true == source1_stats.exists() );
1445 REQUIRE( true == source1_stats.ok() );
1446 REQUIRE( true == source1_stats.is_file() );
1447 }
1448 jau::io::fs::file_stats source2_stats(root_orig_stats.path()+"/README_slink08_relext.txt");
1449 jau::fprintf_td(stdout, "test31_copy_file2file: source2: %s\n", source2_stats.toString().c_str());
1450 {
1451 REQUIRE( true == source2_stats.exists() );
1452 REQUIRE( true == source2_stats.ok() );
1453 REQUIRE( true == source2_stats.is_file() );
1454 REQUIRE( true == source2_stats.is_link() );
1455 }
1456 {
1457 // Copy file to new file-name
1460 {
1461 jau::io::fs::file_stats dest_stats(root_copy+"/file_10.txt");
1462 jau::fprintf_td(stdout, "test31_copy_file2file: 10: dest.pre: %s\n", dest_stats.toString().c_str());
1463 REQUIRE( false == dest_stats.exists() );
1464 }
1465 REQUIRE( true == jau::io::fs::copy(source1_stats.path(), root_copy+"/file_10.txt", copts) );
1466 jau::io::fs::sync(); // just check API
1467 {
1468 jau::io::fs::file_stats dest_stats(root_copy+"/file_10.txt");
1469 jau::fprintf_td(stdout, "test31_copy_file2file: 10: dest.post: %s\n", dest_stats.toString().c_str());
1470 REQUIRE( true == dest_stats.exists() );
1471 REQUIRE( true == dest_stats.ok() );
1472 REQUIRE( true == dest_stats.is_file() );
1473 REQUIRE( source1_stats.size() == dest_stats.size() );
1474 REQUIRE( source1_stats.mode() == dest_stats.mode() );
1475 }
1476 }
1477 {
1478 // Error: already exists of 'Copy file to file'
1481 {
1482 jau::io::fs::file_stats dest_stats(root_copy+"/file_10.txt");
1483 jau::fprintf_td(stdout, "test31_copy_file2file: 11: dest.pre: %s\n", dest_stats.toString().c_str());
1484 REQUIRE( true == dest_stats.exists() );
1485 REQUIRE( true == dest_stats.ok() );
1486 REQUIRE( true == dest_stats.is_file() );
1487 }
1488 REQUIRE( false == jau::io::fs::copy(source1_stats.path(), root_copy+"/file_10.txt", copts) );
1489 jau::io::fs::sync(); // just check API
1490 }
1491 {
1492 // Overwrite copy file to file
1497
1498 {
1499 jau::io::fs::file_stats dest_stats(root_copy+"/file_10.txt");
1500 jau::fprintf_td(stdout, "test31_copy_file2file: 12: dest.pre: %s\n", dest_stats.toString().c_str());
1501 REQUIRE( true == dest_stats.exists() );
1502 REQUIRE( true == dest_stats.ok() );
1503 REQUIRE( true == dest_stats.is_file() );
1504 REQUIRE( source1_stats.size() == dest_stats.size() );
1505 REQUIRE( source1_stats.mode() == dest_stats.mode() );
1506 }
1507 REQUIRE( true == jau::io::fs::copy(source2_stats.path(), root_copy+"/file_10.txt", copts) );
1508 jau::io::fs::sync(); // just check API
1509 {
1510 jau::io::fs::file_stats dest_stats(root_copy+"/file_10.txt");
1511 jau::fprintf_td(stdout, "test31_copy_file2file: 12: dest.post: %s\n", dest_stats.toString().c_str());
1512 REQUIRE( true == dest_stats.exists() );
1513 REQUIRE( true == dest_stats.ok() );
1514 REQUIRE( true == dest_stats.is_file() );
1515 REQUIRE( false == dest_stats.is_link() );
1516 REQUIRE( source2_stats.size() == dest_stats.size() );
1517 REQUIRE( source2_stats.link_target()->prot_mode() == dest_stats.prot_mode() );
1518 }
1519 }
1520 if constexpr ( _remove_target_test_dir ) {
1522 }
1523 }
1524
1526 INFO_STR("\n\ntest40_copy_ext_r_p\n");
1527
1528 jau::io::fs::file_stats root_orig_stats = getTestDataDirStats(executable_path);
1529 REQUIRE( true == root_orig_stats.exists() );
1530
1535 const std::string root_copy = temp_root+"_copy_test40";
1537 testxx_copy_r_p("test40_copy_ext_r_p", root_orig_stats, 0 /* source_added_dead_links */, root_copy, copts, false /* dest_is_vfat */);
1539 }
1540
1542 INFO_STR("\n\ntest41_copy_ext_r_p_below\n");
1543
1544 jau::io::fs::file_stats root_orig_stats = getTestDataDirStats(executable_path);
1545 REQUIRE( true == root_orig_stats.exists() );
1546
1551 const std::string root_copy_parent = temp_root+"_copy_test41_parent";
1553 REQUIRE( true == jau::io::fs::mkdir(root_copy_parent, jau::io::fs::fmode_t::def_dir_prot) );
1554 testxx_copy_r_p("test41_copy_ext_r_p_below", root_orig_stats, 0 /* source_added_dead_links */, root_copy_parent, copts, false /* dest_is_vfat */);
1555 REQUIRE( true == jau::io::fs::remove(root_copy_parent, jau::io::fs::traverse_options::recursive) );
1556 }
1557
1559 INFO_STR("\n\ntest41_copy_ext_r_p_into\n");
1560
1561 jau::io::fs::file_stats root_orig_stats = getTestDataDirStats(executable_path);
1562 REQUIRE( true == root_orig_stats.exists() );
1563
1569 const std::string root_copy = temp_root+"_copy_test42_into";
1571 REQUIRE( true == jau::io::fs::mkdir(root_copy, jau::io::fs::fmode_t::def_dir_prot) );
1572 testxx_copy_r_p("test42_copy_ext_r_p_into", root_orig_stats, 0 /* source_added_dead_links */, root_copy, copts, false /* dest_is_vfat */);
1574 }
1575
1577 INFO_STR("\n\ntest43_copy_ext_r_p_over\n");
1578
1579 jau::io::fs::file_stats root_orig_stats = getTestDataDirStats(executable_path);
1580 REQUIRE( true == root_orig_stats.exists() );
1581
1586 const std::string root_copy = temp_root+"_copy_test43_over";
1588 REQUIRE( true == jau::io::fs::mkdir(root_copy, jau::io::fs::fmode_t::def_dir_prot) );
1589 const std::string root_copy_sub = root_copy+"/"+root_orig_stats.item().basename();
1590 REQUIRE( true == jau::io::fs::mkdir(root_copy_sub, jau::io::fs::fmode_t::def_dir_prot) );
1591 testxx_copy_r_p("test43_copy_ext_r_p_over", root_orig_stats, 0 /* source_added_dead_links */, root_copy, copts, false /* dest_is_vfat */);
1593 }
1594
1596 INFO_STR("\n\ntest49_copy_ext_r_p_vfat\n");
1597
1598 // Query and prepare vfat data sink
1599 jau::io::fs::file_stats dest_fs_vfat_stats(dest_fs_vfat);
1600 if( !dest_fs_vfat_stats.is_dir() ) {
1601 jau::fprintf_td(stdout, "test49_copy_ext_r_p_vfat: Skipped, no vfat dest-dir %s\n", dest_fs_vfat_stats.toString().c_str());
1602 return;
1603 }
1604 const std::string dest_vfat_parent = dest_fs_vfat+"/test49_data_sink";
1606 if( !jau::io::fs::mkdir(dest_vfat_parent, jau::io::fs::fmode_t::def_dir_prot) ) {
1607 jau::fprintf_td(stdout, "test49_copy_ext_r_p_vfat: Skipped, couldn't create vfat dest folder %s\n", dest_vfat_parent.c_str());
1608 return;
1609 }
1610
1611 // Source
1612 jau::io::fs::file_stats root_orig_stats = getTestDataDirStats(executable_path);
1613 REQUIRE( true == root_orig_stats.exists() );
1614
1620 const std::string dest_vfat_dir = dest_vfat_parent+"/"+temp_root;
1621 testxx_copy_r_p("test49_copy_ext_r_p_vfat", root_orig_stats, 0 /* source_added_dead_links */, dest_vfat_dir, copts, true /* dest_is_vfat */);
1622
1623 REQUIRE( true == jau::io::fs::remove(dest_vfat_parent, jau::io::fs::traverse_options::recursive) );
1624 }
1625
1627 INFO_STR("\n\ntest50_copy_ext_r_p_fsl\n");
1628
1629 jau::io::fs::file_stats root_orig_stats = getTestDataDirStats(executable_path);
1630 REQUIRE( true == root_orig_stats.exists() );
1631
1632 const std::string root_copy = temp_root+"_copy_test50";
1638 {
1640
1641 REQUIRE( true == jau::io::fs::copy(root_orig_stats.path(), root_copy, copts) );
1642 }
1643 jau::io::fs::file_stats root_copy_stats(root_copy);
1644 REQUIRE( true == root_copy_stats.exists() );
1645 REQUIRE( true == root_copy_stats.ok() );
1646 REQUIRE( true == root_copy_stats.is_dir() );
1647
1648 bool(*pv_capture)(visitor_stats*, jau::io::fs::traverse_event, const jau::io::fs::file_stats&, size_t) =
1649 ( [](visitor_stats* stats_ptr, jau::io::fs::traverse_event tevt, const jau::io::fs::file_stats& element_stats, size_t depth) -> bool {
1650 (void)tevt;
1651 (void)depth;
1652 stats_ptr->add(element_stats);
1653 return true;
1654 } );
1655 {
1659
1662 visitor_stats stats(topts_orig);
1663 visitor_stats stats_copy(topts_copy);
1664 const jau::io::fs::path_visitor pv_orig = jau::bind_capref(&stats, pv_capture);
1665 const jau::io::fs::path_visitor pv_copy = jau::bind_capref(&stats_copy, pv_capture);
1666 REQUIRE( true == jau::io::fs::visit(root_orig_stats, topts_orig, pv_orig) );
1667 REQUIRE( true == jau::io::fs::visit(root_copy_stats, topts_copy, pv_copy) );
1668
1669 jau::fprintf_td(stdout, "test50_copy_ext_r_p_fsl: copy %s, traverse_orig %s, traverse_copy %s\n",
1670 to_string(copts).c_str(), to_string(topts_orig).c_str(), to_string(topts_copy).c_str());
1671
1672 jau::fprintf_td(stdout, "test50_copy_ext_r_p_fsl: source visitor stats\n%s\n", stats.toString().c_str());
1673 jau::fprintf_td(stdout, "test50_copy_ext_r_p_fsl: destination visitor stats\n%s\n", stats_copy.toString().c_str());
1674
1675 REQUIRE( 9 == stats.total_real );
1676 REQUIRE( 11 == stats.total_sym_links_existing );
1677 REQUIRE( 4 == stats.total_sym_links_not_existing );
1678 REQUIRE( 0 == stats.total_no_access );
1679 REQUIRE( 4 == stats.total_not_existing );
1680 REQUIRE( 60 < stats.total_file_bytes ); // some followed symlink files are of unknown size, e.g. /etc/fstab
1681 REQUIRE( 6 == stats.files_real );
1682 REQUIRE( 10 == stats.files_sym_link );
1683 REQUIRE( 3 == stats.dirs_real );
1684 REQUIRE( 1 == stats.dirs_sym_link );
1685
1686 REQUIRE( 20 == stats_copy.total_real );
1687 REQUIRE( 0 == stats_copy.total_sym_links_existing );
1688 REQUIRE( 0 == stats_copy.total_sym_links_not_existing );
1689 REQUIRE( 0 == stats_copy.total_no_access );
1690 REQUIRE( 0 == stats_copy.total_not_existing );
1691 REQUIRE( 60 < stats_copy.total_file_bytes ); // some followed symlink files are of unknown size, e.g. /etc/fstab
1692 REQUIRE( 16 == stats_copy.files_real );
1693 REQUIRE( 0 == stats_copy.files_sym_link );
1694 REQUIRE( 4 == stats_copy.dirs_real );
1695 REQUIRE( 0 == stats_copy.dirs_sym_link );
1696 }
1697
1698 const std::string root_copy_renamed = temp_root+"_copy_test50_renamed";
1699 {
1700 REQUIRE( true == jau::io::fs::rename(root_copy, root_copy_renamed) );
1701 }
1702 jau::io::fs::file_stats root_copy_stats2(root_copy);
1703 REQUIRE( false == root_copy_stats2.exists() );
1704
1705 jau::io::fs::file_stats root_copy_renamed_stats(root_copy_renamed);
1706 REQUIRE( true == root_copy_renamed_stats.exists() );
1707 REQUIRE( true == root_copy_renamed_stats.ok() );
1708 REQUIRE( true == root_copy_renamed_stats.is_dir() );
1709
1710 {
1713 visitor_stats stats_copy(topts_copy);
1714 const jau::io::fs::path_visitor pv_copy = jau::bind_capref(&stats_copy, pv_capture);
1715 REQUIRE( true == jau::io::fs::visit(root_copy_renamed_stats, topts_copy, pv_copy) );
1716
1717 jau::fprintf_td(stdout, "test50_copy_ext_r_p_fsl: renamed: traverse_copy %s\n", to_string(topts_copy).c_str());
1718
1719 jau::fprintf_td(stdout, "test50_copy_ext_r_p_fsl: renamed: visitor stats\n%s\n", stats_copy.toString().c_str());
1720
1721 REQUIRE( 20 == stats_copy.total_real );
1722 REQUIRE( 0 == stats_copy.total_sym_links_existing );
1723 REQUIRE( 0 == stats_copy.total_sym_links_not_existing );
1724 REQUIRE( 0 == stats_copy.total_no_access );
1725 REQUIRE( 0 == stats_copy.total_not_existing );
1726 REQUIRE( 60 < stats_copy.total_file_bytes ); // some followed symlink files are of unknown size, e.g. /etc/fstab
1727 REQUIRE( 16 == stats_copy.files_real );
1728 REQUIRE( 0 == stats_copy.files_sym_link );
1729 REQUIRE( 4 == stats_copy.dirs_real );
1730 REQUIRE( 0 == stats_copy.dirs_sym_link );
1731 }
1732
1733 if constexpr ( _remove_target_test_dir ) {
1734 REQUIRE( true == jau::io::fs::remove(root_copy_renamed, jau::io::fs::traverse_options::recursive) );
1735 }
1736 }
1737};
1738
1739METHOD_AS_TEST_CASE( TestFileUtil01::test00_testfiles, "Test TestFileUtil01 - test00_testfiles");
1740METHOD_AS_TEST_CASE( TestFileUtil01::test01_cwd, "Test TestFileUtil01 - test01_cwd");
1741METHOD_AS_TEST_CASE( TestFileUtil01::test02_dirname, "Test TestFileUtil01 - test02_dirname");
1742METHOD_AS_TEST_CASE( TestFileUtil01::test03_basename, "Test TestFileUtil01 - test03_basename");
1743METHOD_AS_TEST_CASE( TestFileUtil01::test03b_absolute, "Test TestFileUtil01 - test03b_absolute");
1744METHOD_AS_TEST_CASE( TestFileUtil01::test04_dir_item, "Test TestFileUtil01 - test04_dir_item");
1745METHOD_AS_TEST_CASE( TestFileUtil01::test05_file_stat, "Test TestFileUtil01 - test05_file_stat");
1746METHOD_AS_TEST_CASE( TestFileUtil01::test06_file_stat_symlinks, "Test TestFileUtil01 - test06_file_stat_symlinks");
1747METHOD_AS_TEST_CASE( TestFileUtil01::test07_file_stat_fd, "Test TestFileUtil01 - test07_file_stat_fd");
1748METHOD_AS_TEST_CASE( TestFileUtil01::test08_pipe_01, "Test TestFileUtil01 - test08_pipe_01");
1749
1750METHOD_AS_TEST_CASE( TestFileUtil01::test10_mkdir, "Test TestFileUtil01 - test10_mkdir");
1751METHOD_AS_TEST_CASE( TestFileUtil01::test11_touch, "Test TestFileUtil01 - test11_touch");
1752
1753METHOD_AS_TEST_CASE( TestFileUtil01::test20_visit, "Test TestFileUtil01 - test20_visit");
1754METHOD_AS_TEST_CASE( TestFileUtil01::test22_visit_symlinks, "Test TestFileUtil01 - test22_visit_symlinks");
1755
1756METHOD_AS_TEST_CASE( TestFileUtil01::test30_copy_file2dir, "Test TestFileUtil01 - test30_copy_file2dir");
1757METHOD_AS_TEST_CASE( TestFileUtil01::test31_copy_file2file, "Test TestFileUtil01 - test31_copy_file2file");
1758
1759METHOD_AS_TEST_CASE( TestFileUtil01::test40_copy_ext_r_p, "Test TestFileUtil01 - test40_copy_ext_r_p");
1760METHOD_AS_TEST_CASE( TestFileUtil01::test41_copy_ext_r_p_below, "Test TestFileUtil01 - test41_copy_ext_r_p_below");
1761METHOD_AS_TEST_CASE( TestFileUtil01::test42_copy_ext_r_p_into, "Test TestFileUtil01 - test42_copy_ext_r_p_into");
1762METHOD_AS_TEST_CASE( TestFileUtil01::test43_copy_ext_r_p_over, "Test TestFileUtil01 - test43_copy_ext_r_p_over");
1763
1764METHOD_AS_TEST_CASE( TestFileUtil01::test49_copy_ext_r_p_vfat, "Test TestFileUtil01 - test49_copy_ext_r_p_vfat");
1765
1766METHOD_AS_TEST_CASE( TestFileUtil01::test50_copy_ext_r_p_fsl, "Test TestFileUtil01 - test50_copy_ext_r_p_fsl");
static void test_file_stat_fd_item(const jau::io::fs::fmode_t exp_type, const int fd, const std::string &named_fd1, const std::string &named_fd_link)
static const size_t pipe_msg_count
static const size_t pipe_msg_len
static constexpr const char * pipe_msg
const std::string temp_root
jau::io::fs::file_stats getTestDataDirStats(const std::string &test_exe_path) noexcept
jau::io::fs::file_stats getTestDataImageFile(const std::string &test_exe_path) noexcept
const std::string dest_fs_vfat
std::string getTestDataRelDir(const std::string &test_exe_path) noexcept
const std::string project_root_ext
File based byte input stream, including named file descriptor.
void close() noexcept override
Close the stream if supported by the underlying mechanism.
bool isOpen() const noexcept override
Checks if the stream has an associated file.
size_t write(const void *, size_t) noexcept override
Write to the data sink.
std::string toString() const noexcept override
size_t read(void *, size_t) noexcept override
Read from the source.
bool fail() const noexcept
Checks if an error has occurred.
bool good() const noexcept
Checks if no error nor eof() has occurred i.e.
Representing a directory item split into dirname() and basename().
std::string path() const noexcept
Returns a full unix path representation combining dirname() and basename().
const std::string & dirname() const noexcept
Returns the dirname, shall not be empty and denotes .
const std::string & basename() const noexcept
Return the basename, shall not be empty nor contain a dirname.
bool empty() const noexcept
Returns true if bot, dirname() and basename() refer to .
std::string toString() const noexcept
Returns a comprehensive string representation of this item.
Platform agnostic representation of POSIX ::lstat() and ::stat() for a given pathname.
fmode_t mode() const noexcept
Returns the fmode_t, file type and mode.
constexpr bool is_dir() const noexcept
Returns true if entity is a directory, might be in combination with is_link().
constexpr bool is_file() const noexcept
Returns true if entity is a file, might be in combination with is_link().
uint64_t size() const noexcept
Returns the size in bytes of this element if is_file(), otherwise zero.
const fraction_timespec & mtime() const noexcept
Returns the last modification time of this element since Unix Epoch.
const std::shared_ptr< file_stats > & link_target() const noexcept
Returns the link-target this symbolic-link points to if instance is a symbolic-link,...
std::string path() const noexcept
Returns the unix path representation.
const file_stats * final_target(size_t *link_count=nullptr) const noexcept
Returns the final target element, either a pointer to this instance if not a symbolic-link or the fin...
constexpr bool ok() const noexcept
Returns true if no error occurred.
const fraction_timespec & btime() const noexcept
Returns the birth time of this element since Unix Epoch, i.e.
const dir_item & item() const noexcept
Returns the dir_item.
bool has(const field_t fields) const noexcept
Returns true if the given field_t fields were retrieved, otherwise false.
fmode_t prot_mode() const noexcept
Returns the POSIX protection bit portion of fmode_t, i.e.
constexpr bool has_access() const noexcept
Returns true if entity allows access to user, exclusive bit.
constexpr bool is_char() const noexcept
Returns true if entity is a character device, might be in combination with is_link().
constexpr bool is_socket() const noexcept
Returns true if entity is a socket, might be in combination with is_link().
fmode_t type_mode() const noexcept
Returns the type bit portion of fmode_t, i.e.
constexpr bool is_fifo() const noexcept
Returns true if entity is a fifo/pipe, might be in combination with is_link().
constexpr bool is_block() const noexcept
Returns true if entity is a block device, might be in combination with is_link().
std::string toString() const noexcept
Returns a comprehensive string representation of this element.
constexpr bool is_link() const noexcept
Returns true if entity is a symbolic link, might be in combination with is_file(),...
int fd() const noexcept
Returns the file descriptor if has_fd(), otherwise -1 for no file descriptor.
constexpr field_t fields() const noexcept
Returns the retrieved field_t fields.
constexpr bool exists() const noexcept
Returns true if entity does not exist, exclusive bit.
const fraction_timespec & atime() const noexcept
Returns the last access time of this element since Unix Epoch.
constexpr bool has_fd() const noexcept
Returns true if entity has a file descriptor.
const std::shared_ptr< std::string > & link_target_path() const noexcept
Returns the stored link-target path this symbolic-link points to if instance is a symbolic-link,...
constexpr bool is_set(const E mask, const E bits) noexcept
std::string absolute(const std::string_view &relpath) noexcept
Returns the absolute path of given relpath if existing, otherwise an empty string.
traverse_event
Filesystem traverse event used to call path_visitor for path elements from visit().
std::string basename(const std::string_view &path) noexcept
Return stripped leading directory components from given path separated by /.
bool visit(const std::string &path, const traverse_options topts, const path_visitor &visitor, std::vector< int > *dirfds=nullptr) noexcept
Visit element(s) of a given path, see traverse_options for detailed settings.
std::string dirname(const std::string_view &path) noexcept
Return stripped last component from given path separated by /, excluding the trailing separator /.
bool touch(const std::string &path, const jau::fraction_timespec &atime, const jau::fraction_timespec &mtime, const fmode_t mode=fmode_t::def_file_prot) noexcept
Touch the file with given atime and mtime and create file if not existing yet.
bool isAbsolute(const std::string_view &path) noexcept
Returns true if first character is / or - in case of Windows - \\.
fmode_t
Generic file type and POSIX protection mode bits as used in file_stats, touch(), mkdir() etc.
bool copy(const std::string &source_path, const std::string &dest_path, const copy_options copts=copy_options::none) noexcept
Copy the given source_path to dest_path using copy_options.
copy_options
Filesystem copy options used to copy() path elements.
std::string get_cwd() noexcept
Return the current working directory or empty on failure.
Definition file_util.cpp:85
std::string to_string(const fmode_t mask, const bool show_rwx) noexcept
Return the string representation of fmode_t.
traverse_options
Filesystem traverse options used to visit() path elements.
void sync() noexcept
Synchronizes filesystems, i.e.
bool mkdir(const std::string &path, const fmode_t mode=fmode_t::def_dir_prot, const bool verbose=false) noexcept
Create directory.
std::string to_named_fd(const int fd) noexcept
Returns platform dependent named file descriptor of given file descriptor, if supported.
bool remove(const std::string &path, const traverse_options topts=traverse_options::none) noexcept
Remove the given path.
jau::function< bool(traverse_event, const file_stats &, size_t)> path_visitor
path_visitor jau::FunctionDef definition
bool rename(const std::string &oldpath, const std::string &newpath) noexcept
Rename oldpath to newpath using POSIX rename(), with the following combinations.
@ dir_check_entry
Visiting a directory on entry, see traverse_options::dir_check_entry.
@ def_file_prot
Default file protection bit: Safe default: POSIX S_IRUSR | S_IWUSR | S_IRGRP or read_usr | write_usr ...
@ none
No mode bit set.
@ chr
Type: Entity is a character device, might be in combination with link.
@ file
Type: Entity is a file, might be in combination with link.
@ fifo
Type: Entity is a fifo/pipe, might be in combination with link.
@ def_dir_prot
Default directory protection bit: Safe default: POSIX S_IRWXU | S_IRGRP | S_IXGRP or rwx_usr | read_g...
@ ignore_symlink_errors
Ignore errors from erroneous symlinks, e.g.
@ verbose
Enable verbosity mode, show error messages on stderr.
@ follow_symlinks
Copy referenced symbolic linked files or directories instead of just the symbolic link with property ...
@ sync
Ensure data and meta-data file synchronization is performed via ::fsync() after asynchronous copy ope...
@ overwrite
Overwrite existing destination files.
@ preserve_all
Preserve uid and gid if allowed and access- and modification-timestamps, i.e.
@ into_existing_dir
Copy source dir content into an already existing destination directory as if destination directory di...
@ recursive
Traverse through directories, i.e.
@ verbose
Enable verbosity mode, potentially used by a path_visitor implementation like remove().
@ follow_symlinks
Traverse through symbolic linked directories if traverse_options::recursive is set,...
@ dir_check_entry
Call path_visitor at directory entry, allowing path_visitor to skip traversal of this directory if re...
@ dir_entry
Call path_visitor at directory entry.
@ dir_exit
Call path_visitor at directory exit.
@ recursive
Traverse through directories, i.e.
fraction_timespec getWallClockTime() noexcept
Returns current wall-clock real-time since Unix Epoch 00:00:00 UTC on 1970-01-01.
jau::function< R(A...)> bind_capref(I *data_ptr, R(*func)(I *, A...)) noexcept
Bind given data by passing the captured reference (pointer) to the value and non-void function to an ...
@ read
Read capabilities.
@ write
Write capabilities.
constexpr T abs(const T x) noexcept
Returns the absolute value of an arithmetic number (w/ branching) in O(1)
void zero_bytes_sec(void *s, size_t n) noexcept __attrdecl_no_optimize__
Wrapper to ::explicit_bzero(), ::bzero() or ::memset(), whichever is available in that order.
int fprintf_td(const uint64_t elapsed_ms, FILE *stream, const char *format,...) noexcept
Convenient fprintf() invocation, prepending the given elapsed_ms timestamp.
Definition debug.cpp:276
std::string to_string(const bit_order_t v) noexcept
Return std::string representation of the given bit_order_t.
bool sleep_for(const fraction_timespec &relative_time, const bool monotonic=true, const bool ignore_irq=true) noexcept
sleep_for causes the current thread to block until a specific amount of time has passed.
Timespec structure using int64_t for its components in analogy to struct timespec_t on 64-bit platfor...
std::string toISO8601String(bool space_separator=false, bool muteTime=false) const noexcept
Convenience string conversion interpreted since Unix Epoch in UTC to ISO 8601 YYYY-mm-ddTHH:MM:SS....
std::string toString() const noexcept
Return simple string representation in seconds and nanoseconds.
void add(const jau::io::fs::file_stats &element_stats)
int total_sym_links_not_existing
std::string toString() const noexcept
METHOD_AS_TEST_CASE(TestFileUtil01::test00_testfiles, "Test TestFileUtil01 - test00_testfiles")
static constexpr const bool _remove_target_test_dir
void testxx_copy_r_p(const std::string &title, const jau::io::fs::file_stats &source, const int source_added_dead_links, const std::string &dest, const jau::io::fs::copy_options copts, const bool dest_is_vfat)