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