1 #include "config.h"
2
3 #include <iostream>
4 #include <fstream>
5
6 #ifdef STAT_MACROS_BROKEN
7 #error Sorry, S_ISDIR, S_ISREG et. al. appear to be broken on this system.
8 #endif
9
10 #include <cstring>
11 #include <cerrno>
12
13 #ifdef HAVE_SYS_MKDEV_H
14 #include <sys/mkdev.h>
15 #endif
16 #ifdef HAVE_SYS_TYPES_H
17 #include <sys/types.h>
18 #endif
19 #ifdef HAVE_SYS_STAT_H
20 #include <sys/stat.h>
21 #endif
22 #ifdef HAVE_UNISTD_H
23 #include <unistd.h>
24 #endif
25
26 #ifdef TIME_WITH_SYS_TIME
27 #include <sys/time.h>
28 #include <time.h>
29 #else
30 #ifdef HAVE_SYS_TIME_H
31 #include <sys/time.h>
32 #else
33 #include <time.h>
34 #endif
35 #endif
36
37 #ifdef HAVE_DIRENT_H
38 #include <dirent.h>
39 #define NAMELEN(dirent) strlen((dirent)->d_name)
40 #else
41 #define dirent direct
42 #define NAMELEN(dirent) (dirent)->d_namlen
43 #ifdef HAVE_SYS_NDIR_H
44 #include <sys/ndir.h>
45 #endif
46 #ifdef HAVE_SYS_DIR_H
47 #include <sys/dir.h>
48 #endif
49 #ifdef HAVE_NDIR_H
50 #include <ndir.h>
51 #endif
52 #endif
53
54 #ifdef HAVE_FNMATCH_H
55 #include <fnmatch.h>
56 #endif
57
58 #include <stdio.h>
59
60 #include "asserts.h"
61 #include "error.h"
62 #include "estring.h"
63 #include "fs.h"
64
65 //
66 // Define certain file attribute elements if they don't already exist
67 //
68 #ifndef S_IFMT
69 #define S_IFMT (S_IFREG|S_IFCHR|S_IFBLK|S_IFIFO)
70 #endif
71
72 #ifndef S_IAMB
73 #define S_IAMB (S_ISUID|S_ISGID|S_ISVTX\
74 |S_IRUSR|S_IWUSR|S_IXUSR\
75 |S_IRGRP|S_IWGRP|S_IXGRP\
76 |S_IROTH|S_IWOTH|S_IXOTH\
77 )
78
79 #endif
80
81 #ifdef S_IFIFO
82 #ifndef S_ISFIFO
83 #define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO)
84 #endif
85 #endif
86
87 #ifdef S_IFCHR
88 #ifndef S_ISCHR
89 #define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)
90 #endif
91 #endif
92
93 #ifdef S_IFDIR
94 #ifndef S_ISDIR
95 #define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
96 #endif
97 #endif
98
99 #ifdef S_IFBLK
100 #ifndef S_ISBLK
101 #define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)
102 #endif
103 #endif
104
105 #ifdef S_IFREG
106 #ifndef S_ISREG
107 #define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
108 #endif
109 #endif
110
111 #ifdef S_IFLNK
112 #ifndef S_ISLNK
113 #define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
114 #endif
115 #endif
116
117 #ifdef S_IFSOCK
118 #ifndef S_ISSOCK
119 #define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
120 #endif
121 #endif
122
123 #ifdef S_IFDOOR
124 #ifndef S_ISDOOR
125 #define S_ISDOOR(mode) (((mode) & S_IFMT) == S_IFDOOR)
126 #endif
127 #endif
128
129 #ifndef S_IRWXU
130 #define S_IRWXU (S_IRUSR|S_IWUSR|S_IXUSR)
131 #endif
132
133 #ifndef S_IRWXG
134 #define S_IRWXG (S_IRGRP|S_IWGRP|S_IXGRP)
135 #endif
136
137 #ifndef S_IRWXO
138 #define S_IRWXO (S_IROTH|S_IWOTH|S_IXOTH)
139 #endif
140
141 #ifndef ACCESSPERMS
142 #define ACCESSPERMS (S_IRWXU|S_IRWXG|S_IRWXO)
143 #endif
144
145 //----------------------------------------------------------------------------
146
147 /** Return the current working directory */
cwd(void)148 const std::string cwd(void)
149 {
150 std::string s;
151 char buf[PATH_MAX] = { 0 };
152
153 if (getcwd(buf, PATH_MAX) == 0)
154 throw(ERROR(errno,"Could not determine current directory"));
155
156 TRY_nomem(s = buf);
157
158 return(s);
159 }
160
161 /** Return the PID of this process */
pid(void)162 const pid_t pid(void)
163 {
164 pid_t pid;
165
166 pid = getpid();
167 if (pid == -1)
168 throw(ERROR(errno,"Could not determine PID"));
169
170 return(pid);
171 }
172
173 /** Return the PID of the parent process */
parent_pid(void)174 const pid_t parent_pid(void)
175 {
176 pid_t pid;
177
178 pid = getppid();
179 if (pid == -1)
180 throw(ERROR(errno,"Could not determine PID"));
181
182 return(pid);
183 }
184
185 /** Return true if the string looks like an absolute path */
absolute_path(const std::string & a_path)186 bool absolute_path(const std::string& a_path)
187 {
188 if ((a_path.size() > 0) && (a_path[0] == '/')) {
189 return(true);
190 }
191 return(false);
192 }
193
194 /** Return true if the string looks like a relative path */
relative_path(const std::string & a_path)195 bool relative_path(const std::string& a_path)
196 {
197 bool value;
198
199 value = !absolute_path(a_path);
200
201 return(value);
202 }
203
204 /** Reformat a path to remove double slashes */
reform_path(const std::string & a_path)205 std::string reform_path(const std::string& a_path)
206 {
207 std::string::size_type idx;
208 std::string str;
209
210 TRY_nomem(str = a_path);
211 idx = str.find('/');
212 while (idx != std::string::npos) {
213 while ((idx != str.size()-1) && (str[idx+1] == '/'))
214 str.erase(idx+1,1);
215 idx = str.find('/',idx+1);
216 }
217
218 return(str);
219 }
220
221 /** Reformat a path to remove the begining and trailing slashes, and replace
222 all other slashes with underscores
223 */
permute_path(const std::string & a_path)224 std::string permute_path(const std::string& a_path)
225 {
226 std::string path;
227 std::string::size_type idx;
228
229 TRY_nomem(path = reform_path(a_path));
230 idx = path.find('/');
231 while (idx != std::string::npos) {
232 if ((idx == 0) || (idx == path.size()-1))
233 path.erase(idx,1);
234 else
235 path[idx] = '-';
236 idx = path.find('/');
237 }
238 if (path.size() == 0)
239 TRY_nomem(path = "root");
240 if (path.substr(0,2) == ".-")
241 path.erase(0,2);
242
243 return(path);
244 }
245
246 /** Return everything after the last slash from a path */
path_basename(const std::string & a_path)247 std::string path_basename(const std::string& a_path)
248 {
249 std::string path;
250 std::string::size_type idx;
251
252 idx = a_path.rfind('/');
253 if (idx == std::string::npos) {
254 TRY_nomem(path = a_path);
255 }
256 else {
257 TRY_nomem(path = a_path.substr(idx+1));
258 }
259
260 return(path);
261 }
262
263 /** Return everything up to the last slash from a path */
path_dirname(const std::string & a_path)264 std::string path_dirname(const std::string& a_path)
265 {
266 std::string path;
267 std::string::size_type idx;
268
269 idx = a_path.rfind('/');
270 if (idx == std::string::npos) {
271 TRY_nomem(path = ".");
272 }
273 else {
274 TRY_nomem(path = a_path.substr(0,idx));
275 }
276
277 return(path);
278 }
279
280 /** Make the path a_rel_path absolute with respect to a_path, where a_rel_path
281 * and a_path are directory names */
mk_absolute_path(const std::string a_path,const std::string a_rel_path)282 std::string mk_absolute_path(
283 const std::string a_path,
284 const std::string a_rel_path
285 )
286 {
287 std::string es;
288 std::string path;
289
290 if (a_rel_path.size() == 0) {
291 TRY_nomem(es = "Invalid relative path: \"");
292 TRY_nomem(es += a_rel_path);
293 TRY_nomem(es += "\"");
294 throw(ERROR(0,es));
295 }
296 if (relative_path(a_path)) {
297 TRY_nomem(es = "Invalid absolute reference path: \"");
298 TRY_nomem(es += a_path);
299 TRY_nomem(es += "\"");
300 throw(INTERNAL_ERROR(0,es));
301 }
302 if (relative_path(a_rel_path)) {
303 TRY_nomem(path = a_path);
304 TRY_nomem(path += "/");
305 }
306 TRY_nomem(path += a_rel_path);
307 path = reform_path(path);
308
309 return(path);
310 }
311
312 /** Make the path a_path_to relative from a_path_from, where a_path_to and
313 * a_path_from are directory names */
mk_relative_path(const std::string a_path_to,const std::string a_path_from)314 std::string mk_relative_path(
315 const std::string a_path_to,
316 const std::string a_path_from
317 )
318 {
319 std::string::size_type idx_to, idx_from, idx;
320 std::string path_to, path_from, path;
321 std::string path_to_substr, path_from_substr;
322
323 TRY_nomem(path_to = a_path_to);
324 TRY_nomem(path_from = a_path_from);
325 TRY_nomem(path = "");
326
327 idx_to = path_to.find("/");
328 if (idx_to != std::string::npos) {
329 TRY_nomem(path_to_substr = path_to.substr(0,idx_to));
330 }
331 else {
332 TRY_nomem(path_to_substr = path_to);
333 }
334 idx_from = path_from.find("/");
335 if (idx_from != std::string::npos) {
336 TRY_nomem(path_from_substr = path_from.substr(0,idx_from));
337 }
338 else {
339 TRY_nomem(path_from_substr = path_from);
340 }
341
342 while (
343 (path_to.size() > 0 && path_from.size() > 0)
344 && (path_to_substr == path_from_substr)
345 )
346 {
347 path_to.erase(0,path_to_substr.size());
348 if ((path_to.size() > 0) && (path_to[0] == '/'))
349 path_to.erase(0,1);
350 path_from.erase(0,path_from_substr.size());
351 if ((path_from.size() > 0) && (path_from[0] == '/'))
352 path_from.erase(0,1);
353
354 idx_to = path_to.find("/");
355 if (idx_to != std::string::npos) {
356 TRY_nomem(path_to_substr = path_to.substr(0,idx_to));
357 }
358 else {
359 TRY_nomem(path_to_substr = path_to);
360 }
361 idx_from = path_from.find("/");
362 if (idx_from != std::string::npos) {
363 TRY_nomem(path_from_substr = path_from.substr(0,idx_from));
364 }
365 else {
366 TRY_nomem(path_from_substr = path_from);
367 }
368 }
369
370 while (path_from.size() > 0) {
371 TRY_nomem(path += "../");
372 idx = path_from.find('/');
373 if (idx == std::string::npos)
374 path_from.erase();
375 else
376 path_from.erase(0,idx+1);
377 }
378 TRY_nomem(path += path_to);
379 TRY_nomem(path = reform_path(path));
380
381 return(path);
382 }
383
384 /** Return true if the file or directory exists */
exists(const std::string & a_path)385 bool exists(const std::string& a_path)
386 {
387 if (access(a_path.c_str(), F_OK) == 0) return(true);
388 errno = 0;
389 #ifdef S_ISFIFO
390 if (is_fifo_special(a_path)) return(true);
391 #endif
392 #ifdef S_ISCHR
393 if (is_char_special(a_path)) return(true);
394 #endif
395 #ifdef S_ISDIR
396 if (is_dir(a_path)) return(true);
397 #endif
398 #ifdef S_ISREG
399 if (is_file(a_path)) return(true);
400 #endif
401 #ifdef S_ISBLK
402 if (is_block_special(a_path)) return(true);
403 #endif
404 #ifdef S_ISLNK
405 if (is_link(a_path)) return(true);
406 #endif
407 #ifdef S_ISSOCK
408 if (is_socket(a_path)) return(true);
409 #endif
410 #ifdef S_ISDOOR
411 if (is_door(a_path)) return(true);
412 #endif
413 return(false);
414 }
415
416 /** Return true if the file or directory exists and is readable */
readable(const std::string & a_path)417 bool readable(const std::string& a_path)
418 {
419 if (access(a_path.c_str(), R_OK) != 0) {
420 errno = 0;
421 return(false);
422 }
423 return(true);
424 }
425
426 /** Return true if the file or directory exists and is writable */
writable(const std::string & a_path)427 bool writable(const std::string& a_path)
428 {
429 if (access(a_path.c_str(), W_OK) != 0) {
430 errno = 0;
431 return(false);
432 }
433 return(true);
434 }
435
436 /** Return true if the file or directory exists and is executable */
executable(const std::string & a_path)437 bool executable(const std::string& a_path)
438 {
439 if (access(a_path.c_str(), X_OK) != 0) {
440 errno = 0;
441 return(false);
442 }
443 return(true);
444 }
445
446 #ifdef S_ISFIFO
447 /** Return true if the file is a fifo-special */
is_fifo_special(const std::string & a_path)448 bool is_fifo_special(const std::string& a_path)
449 {
450 filestatus fstat;
451
452 try {
453 fstat.path(a_path);
454 if (fstat.is_fifo_special()) {
455 return(true);
456 }
457 }
458 catch(...) {
459 return(false);
460 }
461 return(false);
462 }
463 #endif
464
465 #ifdef S_ISCHR
466 /** Return true if the file is a char-special */
is_char_special(const std::string & a_path)467 bool is_char_special(const std::string& a_path)
468 {
469 filestatus fstat;
470
471 try {
472 fstat.path(a_path);
473 if (fstat.is_character_special()) {
474 return(true);
475 }
476 }
477 catch(...) {
478 return(false);
479 }
480 return(false);
481 }
482 #endif
483
484 #ifdef S_ISDIR
485 /** Return true if the file is a directory */
is_dir(const std::string & a_path)486 bool is_dir(const std::string& a_path)
487 {
488 filestatus fstat;
489
490 try {
491 fstat.path(a_path);
492 if (fstat.is_directory()) {
493 return(true);
494 }
495 }
496 catch(...) {
497 return(false);
498 }
499 return(false);
500 }
501 #endif
502
503 #ifdef S_ISREG
504 /** Return true if the file is a regular file */
is_file(const std::string & a_path)505 bool is_file(const std::string& a_path)
506 {
507 filestatus fstat;
508
509 try {
510 fstat.path(a_path);
511 if (fstat.is_regular_file()) {
512 return(true);
513 }
514 }
515 catch(...) {
516 return(false);
517 }
518 return(false);
519 }
520 #endif
521
522 #ifdef S_ISBLK
523 /** Return true if the file is a block-special */
is_block_special(const std::string & a_path)524 bool is_block_special(const std::string& a_path)
525 {
526 filestatus fstat;
527
528 try {
529 fstat.path(a_path);
530 if (fstat.is_block_special()) {
531 return(true);
532 }
533 }
534 catch(...) {
535 return(false);
536 }
537 return(false);
538 }
539 #endif
540
541 #ifdef S_ISLNK
542 /** Return true is the file is a link */
is_link(const std::string & a_path)543 bool is_link(const std::string& a_path)
544 {
545 filestatus fstat;
546
547 try {
548 fstat.path(a_path);
549 if (fstat.is_link()) {
550 return(true);
551 }
552 }
553 catch(...) {
554 return(false);
555 }
556 return(false);
557 }
558 #endif
559
560 #ifdef S_ISSOCK
561 /** Return true if the file is a socket */
is_socket(const std::string & a_path)562 bool is_socket(const std::string& a_path)
563 {
564 filestatus fstat;
565
566 try {
567 fstat.path(a_path);
568 if (fstat.is_socket()) {
569 return(true);
570 }
571 }
572 catch(...) {
573 return(false);
574 }
575 return(false);
576 }
577 #endif
578
579 #ifdef S_ISDOOR
580 /** Return true if the file is a door */
is_door(const std::string & a_path)581 bool is_door(const std::string& a_path)
582 {
583 filestatus fstat;
584
585 try {
586 fstat.path(a_path);
587 if (fstat.is_door()) {
588 return(true);
589 }
590 }
591 catch(...) {
592 return(false);
593 }
594 return(false);
595 }
596 #endif
597
598 /** Create a directory */
mk_dir(const std::string & a_path)599 void mk_dir(const std::string& a_path)
600 {
601 std::string es;
602
603 if (mkdir(a_path.c_str(), ACCESSPERMS) != 0) {
604 TRY_nomem(es = "Could not create directory: \"");
605 TRY_nomem(es += a_path);
606 TRY_nomem(es += "\"");
607 throw(ERROR(errno,es));
608 }
609 }
610
611 /** Remove a directory */
rm_dir(const std::string a_path)612 void rm_dir(const std::string a_path)
613 {
614 if (!exists(a_path)) return;
615 if ((rmdir(a_path.c_str()) != 0) && exists(a_path)) {
616 std::string es;
617
618 TRY_nomem(es = "Could not remove directory: \"");
619 TRY_nomem(es += a_path);
620 TRY_nomem(es += "\"");
621
622 if (exists(a_path)) {
623 if (writable(a_path)) {
624 throw(ERROR(errno,es));
625 }
626 else {
627 error e = ERROR(errno,es);
628
629 e.push_back(ERROR_INSTANCE("No write permissions"));
630 throw(e);
631 }
632 }
633 }
634 }
635
636 /** Remove a file */
rm_file(const std::string a_path)637 void rm_file(const std::string a_path)
638 {
639 if (!exists(a_path)) return;
640 if ((unlink(a_path.c_str()) != 0) && exists(a_path)) {
641 std::string es;
642
643 TRY_nomem(es = "Could not remove file: \"");
644 TRY_nomem(es += a_path);
645 TRY_nomem(es += "\"");
646
647 if (exists(a_path)) {
648 if (writable(a_path)) {
649 throw(ERROR(errno,es));
650 }
651 else {
652 error e = ERROR(errno,es);
653
654 e.push_back(ERROR_INSTANCE("No write permissions"));
655 throw(e);
656 }
657 }
658 }
659 }
660
661 /** Recursively create a directory heirarchy */
mk_dirhier_recursive_(const std::string a_path)662 void mk_dirhier_recursive_(const std::string a_path)
663 {
664 std::string parent_dir;
665 int ce;
666
667 if (a_path.size() == 0)
668 return;
669 if (exists(a_path))
670 return;
671
672 for (ce = a_path.size()-1; ((ce > 0) && (a_path[ce] != '/')); ce--);
673
674 if (ce > 0) {
675 TRY_nomem(parent_dir = a_path.substr(0,ce));
676 mk_dirhier_recursive_(parent_dir);
677 }
678 if (!exists(a_path))
679 mk_dir(a_path);
680 }
681
682 /** Recursively create a directory heirarchy */
mk_dirhier(const std::string a_path)683 void mk_dirhier(const std::string a_path)
684 {
685 if (a_path.size() == 0)
686 return;
687 if (exists(a_path))
688 return;
689
690 try {
691 mk_dirhier_recursive_(a_path);
692 }
693 catch(error e) {
694 std::string es;
695
696 TRY_nomem(es = "Could not create directory hierarchy: \"");
697 TRY_nomem(es += a_path);
698 TRY_nomem(es += "\"");
699
700 e.push_back(ERROR_INSTANCE(es));
701 throw(e);
702 }
703 catch(...) {
704 throw(err_unknown);
705 }
706 }
707
708 /** Rename a file or directory */
rename_file(const std::string a_from,const std::string a_to)709 void rename_file(const std::string a_from, const std::string a_to)
710 {
711 std::string es;
712
713 if (a_from.size() == 0) {
714 TRY_nomem(es = "Illegal from filename: \"");
715 TRY_nomem(es += a_from);
716 TRY_nomem(es += "\"");
717 throw(INTERNAL_ERROR(0,es));
718 }
719 if (!exists(a_from)) {
720 TRY_nomem(es = "From filename does not exist: \"");
721 TRY_nomem(es += a_from);
722 TRY_nomem(es += "\"");
723 throw(ERROR(0,es));
724 }
725 if (a_to.size() == 0) {
726 TRY_nomem(es = "Illegal to filename: \"");
727 TRY_nomem(es += a_to);
728 TRY_nomem(es += "\"");
729 throw(INTERNAL_ERROR(0,es));
730 }
731 if (exists(a_to)) {
732 TRY_nomem(es = "To filename already exists: \"");
733 TRY_nomem(es += a_to);
734 TRY_nomem(es += "\"");
735 throw(ERROR(0,es));
736 }
737 if (!writable(a_from)) {
738 TRY_nomem(es = "From filename is not writable: \"");
739 TRY_nomem(es += a_from);
740 TRY_nomem(es += "\"");
741 throw(ERROR(0,es));
742 }
743 if (rename(a_from.c_str(), a_to.c_str()) != 0) {
744 TRY_nomem(es = "Could not rename file: \"");
745 TRY_nomem(es += a_from);
746 TRY_nomem(es += "\" to \"");
747 TRY_nomem(es += a_to);
748 TRY_nomem(es += "\"");
749 throw(ERROR(errno,es));
750 }
751 }
752
753 /** Create a symbolic link */
mk_symlink(const std::string a_from,const std::string a_to)754 void mk_symlink(const std::string a_from, const std::string a_to)
755 {
756 if (symlink(a_from.c_str(), a_to.c_str()) != 0) {
757 std::string es;
758
759 TRY_nomem(es = "Could not link: \"");
760 TRY_nomem(es += a_from);
761 TRY_nomem(es += "\" to: \"");
762 TRY_nomem(es += a_to);
763 TRY_nomem(es += "\"");
764
765 throw(ERROR(errno,es));
766 }
767 }
768
769 /** Given a from and to path, create a relative symbolic link */
mk_relative_symlink(const std::string a_from,const std::string a_to)770 void mk_relative_symlink(const std::string a_from, const std::string a_to)
771 {
772 std::string from_dirname, to_dirname, from_basename;
773 std::string rel;
774
775 TRY_nomem(from_dirname = path_dirname(a_from));
776 TRY_nomem(to_dirname = path_dirname(a_to));
777 TRY_nomem(from_basename = path_basename(a_from));
778 TRY_nomem(rel = mk_relative_path(from_dirname, to_dirname));
779 if (rel.size() != 0) {
780 TRY_nomem(rel += "/");
781 }
782 TRY_nomem(rel += from_basename);
783 TRY_nomem(rel = reform_path(rel));
784
785 try {
786 mk_symlink(rel,a_to);
787 }
788 catch(error e) {
789 std::string es;
790
791 TRY_nomem(es = "Could not link: \"");
792 TRY_nomem(es += a_to);
793 TRY_nomem(es += "\" as: \"");
794 TRY_nomem(es += rel);
795 TRY_nomem(es += "\"");
796
797 e.push_back(ERROR_INSTANCE(es));
798 throw(e);
799 }
800 catch(...) {
801 throw(err_unknown);
802 }
803 }
804
805 //----------------------------------------------------------------------------
806
807 /** C'tor */
filestatus()808 filestatus::filestatus()
809 {
810 }
811
812 /** C'tor */
filestatus(const std::string a_path)813 filestatus::filestatus(const std::string a_path)
814 {
815 path(a_path);
816 }
817
818 /** D'tor */
~filestatus()819 filestatus::~filestatus()
820 {
821 }
822
823 /** Retrieve information about a pathname */
path(const std::string a_path)824 void filestatus::path(const std::string a_path)
825 {
826 std::string es;
827 struct passwd *passwd_ptr = 0;
828 struct group *group_ptr = 0;
829 struct stat statbuf;
830 char path_buf[PATH_MAX] = { 0 };
831
832 clear();
833 TRY_nomem(m_path = reform_path(a_path));
834 if (lstat(m_path.c_str(), &statbuf) < 0) {
835 TRY_nomem(es = "For path: \"");
836 TRY_nomem(es += a_path);
837 TRY_nomem(es += "\"");
838 throw(ERROR(errno,es));
839 }
840 if (lstat(m_path.c_str(), &m_stat) == -1) {
841 TRY_nomem(es = "For path: \"");
842 TRY_nomem(es += a_path);
843 TRY_nomem(es += "\"");
844 throw(ERROR(errno,es));
845 }
846 #ifdef S_ISFIFO
847 if (S_ISFIFO(m_stat.st_mode)) {
848 m_major = major(m_stat.st_rdev);
849 m_minor = minor(m_stat.st_rdev);
850 }
851 #endif
852 #ifdef S_ISCHR
853 if (S_ISCHR(m_stat.st_mode)) {
854 m_major = major(m_stat.st_rdev);
855 m_minor = minor(m_stat.st_rdev);
856 }
857 #endif
858 #ifdef S_ISBLK
859 if (S_ISBLK(m_stat.st_mode)) {
860 m_major = major(m_stat.st_rdev);
861 m_minor = minor(m_stat.st_rdev);
862 }
863 #endif
864 #ifdef S_ISLNK
865 if (S_ISLNK(m_stat.st_mode)) {
866 if (readlink(a_path.c_str(), path_buf, PATH_MAX) < 0) {
867 TRY_nomem(es = "Could not read path's link: \"");
868 TRY_nomem(es += a_path);
869 TRY_nomem(es += "\"");
870 throw(ERROR(errno,es));
871 }
872 TRY_nomem(m_link = path_buf);
873 }
874 #endif
875 passwd_ptr = getpwuid(m_stat.st_uid);
876 if (passwd_ptr != 0) {
877 m_uidfound = true;
878 TRY_nomem(m_uname = passwd_ptr->pw_name);
879 }
880 group_ptr = getgrgid(m_stat.st_gid);
881 if (group_ptr != 0) {
882 m_gidfound = true;
883 TRY_nomem(m_gname = group_ptr->gr_name);
884 }
885 }
886
887 /** Return the pathname that this filestatus object has information about */
path(void) const888 const std::string filestatus::path(void) const
889 {
890 return(m_path);
891 }
892
893 /** Return the type of file */
type(void) const894 const filestatus::filetype filestatus::type(void) const
895 {
896 #ifdef S_ISFIFO
897 if (S_ISFIFO(m_stat.st_mode)) {
898 return(type_fifo_special);
899 }
900 #endif
901 #ifdef S_ISCHR
902 if (S_ISCHR(m_stat.st_mode)) {
903 return(type_character_special);
904 }
905 #endif
906 #ifdef S_ISDIR
907 if (S_ISDIR(m_stat.st_mode)) {
908 return(type_directory);
909 }
910 #endif
911 #ifdef S_ISBLK
912 if (S_ISBLK(m_stat.st_mode)) {
913 return(type_block_special);
914 }
915 #endif
916 #ifdef S_ISREG
917 if (S_ISREG(m_stat.st_mode)) {
918 return(type_regular_file);
919 }
920 #endif
921 #ifdef S_ISLNK
922 if (S_ISLNK(m_stat.st_mode)) {
923 return(type_link);
924 }
925 #endif
926 #ifdef S_ISSOCK
927 if (S_ISSOCK(m_stat.st_mode)) {
928 return(type_socket);
929 }
930 #endif
931 #ifdef S_ISDOOR
932 if (S_ISDOOR(m_stat.st_mode)) {
933 return(type_door);
934 }
935 #endif
936 return(type_unknown);
937 }
938
939 /** If the pathname is a link, return the path it is linked to */
link(void) const940 const std::string filestatus::link(void) const
941 {
942 return(m_link);
943 }
944
945 /** Return the file mode */
mode(void) const946 const filestatus::mode_type filestatus::mode(void) const
947 {
948 return(m_stat.st_mode);
949 }
950
951 /** Return the file inode */
inode(void) const952 const filestatus::inode_type filestatus::inode(void) const
953 {
954 return(m_stat.st_ino);
955 }
956
957 /** Return the file's device */
dev(void) const958 const filestatus::device_type filestatus::dev(void) const
959 {
960 return(m_stat.st_dev);
961 }
962
963 /** Return the file's raw device */
rdev(void) const964 const filestatus::device_type filestatus::rdev(void) const
965 {
966 return(m_stat.st_rdev);
967 }
968
969 /** If the pathname is a special file, return it's major number */
get_major(void) const970 const filestatus::major_type filestatus::get_major(void) const
971 {
972 return(m_major);
973 }
974
975 /** If the pathname is a special file, return it's minor number */
get_minor(void) const976 const filestatus::minor_type filestatus::get_minor(void) const
977 {
978 return(m_minor);
979 }
980
981 /** Return the number of links to this file */
num_links(void) const982 const filestatus::num_links_type filestatus::num_links(void) const
983 {
984 return(m_stat.st_nlink);
985 }
986
987 /** Return the file's owner's UID */
uid(void) const988 const filestatus::uid_type filestatus::uid(void) const
989 {
990 return(m_stat.st_uid);
991 }
992
993 /** Return the file's owner's GID */
gid(void) const994 const filestatus::gid_type filestatus::gid(void) const
995 {
996 return(m_stat.st_gid);
997 }
998
999 /** Return the file size in bytes */
size(void) const1000 const filestatus::size_type filestatus::size(void) const
1001 {
1002 size_type value;
1003
1004 value = static_cast<uint64>(m_stat.st_size);
1005
1006 return(value);
1007 }
1008
1009 /** Return the last access time of this file */
last_access_time(void) const1010 const filestatus::time_type filestatus::last_access_time(void) const
1011 {
1012 return(m_stat.st_atime);
1013 }
1014
1015 /** Return the last modification time of this file */
last_modification_time(void) const1016 const filestatus::time_type filestatus::last_modification_time(void) const
1017 {
1018 return(m_stat.st_mtime);
1019 }
1020
1021 /** Return the last status change time of this file */
last_status_change_time(void) const1022 const filestatus::time_type filestatus::last_status_change_time(void) const
1023 {
1024 return(m_stat.st_ctime);
1025 }
1026
1027 /** Return the blocksize used to store this file */
blocksize(void) const1028 const filestatus::size_type filestatus::blocksize(void) const
1029 {
1030 size_type value;
1031
1032 value = static_cast<uint64>(m_stat.st_blksize);
1033
1034 return(value);
1035 }
1036
1037 /** Return the number of blocks used to store this file */
blocks(void) const1038 const filestatus::size_type filestatus::blocks(void) const
1039 {
1040 size_type value;
1041
1042 value = static_cast<uint64>(m_stat.st_blocks);
1043
1044 return(value);
1045 }
1046
1047 /** If the file's owner's UID is found in the passwd file, return true */
uid_is_found(void) const1048 const bool filestatus::uid_is_found(void) const
1049 {
1050 return(m_uidfound);
1051 }
1052
1053 /** If the file's owner's GID is found in the passwd file, return true */
gid_is_found(void) const1054 const bool filestatus::gid_is_found(void) const
1055 {
1056 return(m_gidfound);
1057 }
1058
1059 /** Return the file's owner's user name (from UID) */
uid_name(void) const1060 const std::string filestatus::uid_name(void) const
1061 {
1062 return(m_uname);
1063 }
1064
1065 /** Return the file's owner's group name (from UID) */
gid_name(void) const1066 const std::string filestatus::gid_name(void) const
1067 {
1068 return(m_gname);
1069 }
1070
1071 #ifdef S_ISFIFO
1072 /** Return true if the file is a fifo-special */
is_fifo_special(void) const1073 const bool filestatus::is_fifo_special(void) const
1074 {
1075 bool value;
1076
1077 value = (type() == type_fifo_special);
1078
1079 return(value);
1080 }
1081 #endif
1082
1083 #ifdef S_ISCHR
1084 /** Return true if the file is a char-special */
is_character_special(void) const1085 const bool filestatus::is_character_special(void) const
1086 {
1087 bool value;
1088
1089 value = (type() == type_character_special);
1090
1091 return(value);
1092 }
1093 #endif
1094
1095 #ifdef S_ISBLK
1096 /** Return true if the file is a block-special */
is_block_special(void) const1097 const bool filestatus::is_block_special(void) const
1098 {
1099 bool value;
1100
1101 value = (type() == type_block_special);
1102
1103 return(value);
1104 }
1105 #endif
1106
1107 #ifdef S_ISLNK
1108 /** Return true if the file is a link */
is_link(void) const1109 const bool filestatus::is_link(void) const
1110 {
1111 bool value;
1112
1113 value = (type() == type_link);
1114
1115 return(value);
1116 }
1117 #endif
1118
1119 #ifdef S_ISSOCK
1120 /** Return true if the file is a socket */
is_socket(void) const1121 const bool filestatus::is_socket(void) const
1122 {
1123 bool value;
1124
1125 value = (type() == type_socket);
1126
1127 return(value);
1128 }
1129 #endif
1130
1131 #ifdef S_ISDOOR
1132 /** Return true if the file is a door */
is_door(void) const1133 const bool filestatus::is_door(void) const
1134 {
1135 bool value;
1136
1137 value = (type() == type_door);
1138
1139 return(value);
1140 }
1141 #endif
1142
1143 #ifdef S_ISDIR
1144 /** Return true if the file is a directory */
is_directory(void) const1145 const bool filestatus::is_directory(void) const
1146 {
1147 bool value;
1148
1149 value = (type() == type_directory);
1150
1151 return(value);
1152 }
1153 #endif
1154
1155 #ifdef S_ISREG
1156 /** Return true if the file is a regular file */
is_regular_file(void) const1157 const bool filestatus::is_regular_file(void) const
1158 {
1159 bool value;
1160
1161 value = (type() == type_regular_file);
1162
1163 return(value);
1164 }
1165 #endif
1166
1167 #ifdef S_IRUSR
1168 /** Return true if the file is readable by it's owner */
user_can_read(void) const1169 const bool filestatus::user_can_read(void) const
1170 {
1171 bool value;
1172
1173 value = ((m_stat.st_mode & S_IRUSR) != 0);
1174
1175 return(value);
1176 }
1177 #endif
1178
1179 #ifdef S_IWUSR
1180 /** Return true if the file is writable by it's owner */
user_can_write(void) const1181 const bool filestatus::user_can_write(void) const
1182 {
1183 bool value;
1184
1185 value = ((m_stat.st_mode & S_IWUSR) != 0);
1186
1187 return(value);
1188 }
1189 #endif
1190
1191 #ifdef S_IXUSR
1192 /** Return true if the file is executable by it's owner */
user_can_execute(void) const1193 const bool filestatus::user_can_execute(void) const
1194 {
1195 bool value;
1196
1197 value = ((m_stat.st_mode & S_IXUSR) != 0);
1198
1199 return(value);
1200 }
1201 #endif
1202
1203 #ifdef S_IRGRP
1204 /** Return true if the file is readable by users in the same group */
group_can_read(void) const1205 const bool filestatus::group_can_read(void) const
1206 {
1207 bool value;
1208
1209 value = ((m_stat.st_mode & S_IRGRP) != 0);
1210
1211 return(value);
1212 }
1213 #endif
1214
1215 #ifdef S_IWGRP
1216 /** Return true if the file is writable by users in the same group */
group_can_write(void) const1217 const bool filestatus::group_can_write(void) const
1218 {
1219 bool value;
1220
1221 value = ((m_stat.st_mode & S_IWGRP) != 0);
1222
1223 return(value);
1224 }
1225 #endif
1226
1227 #ifdef S_IXGRP
1228 /** Return true if the file is executable by users in the same group */
group_can_execute(void) const1229 const bool filestatus::group_can_execute(void) const
1230 {
1231 bool value;
1232
1233 value = ((m_stat.st_mode & S_IXGRP) != 0);
1234
1235 return(value);
1236 }
1237 #endif
1238
1239 #ifdef S_IROTH
1240 /** Return true if the file is readable by others */
other_can_read(void) const1241 const bool filestatus::other_can_read(void) const
1242 {
1243 bool value;
1244
1245 value = ((m_stat.st_mode & S_IROTH) != 0);
1246
1247 return(value);
1248 }
1249 #endif
1250
1251 #ifdef S_IWOTH
1252 /** Return true if the file is writable by others */
other_can_write(void) const1253 const bool filestatus::other_can_write(void) const
1254 {
1255 bool value;
1256
1257 value = ((m_stat.st_mode & S_IWOTH) != 0);
1258
1259 return(value);
1260 }
1261 #endif
1262
1263 #ifdef S_IXOTH
1264 /** Return true if the file is executable by others */
other_can_execute(void) const1265 const bool filestatus::other_can_execute(void) const
1266 {
1267 bool value;
1268
1269 value = ((m_stat.st_mode & S_IXOTH) != 0);
1270
1271 return(value);
1272 }
1273 #endif
1274
1275 #ifdef S_ISUID
1276 /** Return true if the file's mode has it's set-uid bit set */
is_set_uid(void) const1277 const bool filestatus::is_set_uid(void) const
1278 {
1279 bool value;
1280
1281 value = ((m_stat.st_mode & S_ISUID) != 0);
1282
1283 return(value);
1284 }
1285 #endif
1286
1287 #ifdef S_ISGID
1288 /** Return true if the file's mode has it's set-gid bit set */
is_set_gid(void) const1289 const bool filestatus::is_set_gid(void) const
1290 {
1291 bool value;
1292
1293 value = ((m_stat.st_mode & S_ISGID) != 0);
1294
1295 return(value);
1296 }
1297 #endif
1298
1299 #ifdef S_ISVTX
1300 /** Return true if the file's mode has it's sticky bit set */
is_set_sticky(void) const1301 const bool filestatus::is_set_sticky(void) const
1302 {
1303 bool value;
1304
1305 value = ((m_stat.st_mode & S_ISVTX) != 0);
1306
1307 return(value);
1308 }
1309 #endif
1310
1311 /** Clear all values */
clear(void)1312 void filestatus::clear(void)
1313 {
1314 TRY_nomem(m_path = "");
1315 memset(&m_stat, 0, sizeof(m_stat));
1316 m_major = 0;
1317 m_minor = 0;
1318 m_uidfound = false;
1319 m_gidfound = false;
1320 TRY_nomem(m_uname = "");
1321 TRY_nomem(m_gname = "");
1322 }
1323
1324 //----------------------------------------------------------------------------
1325
1326 /** C'tor */
subdirectory()1327 subdirectory::subdirectory()
1328 {
1329 }
1330
1331 /** C'tor */
subdirectory(const subdirectory & a_class)1332 subdirectory::subdirectory(const subdirectory& a_class)
1333 {
1334 assign(a_class);
1335 }
1336
1337 /** C'or */
subdirectory(const std::string a_path,const std::string a_filter)1338 subdirectory::subdirectory(
1339 const std::string a_path, const std::string a_filter)
1340 {
1341 path(a_path, a_filter);
1342 }
1343
1344 /** D'tor */
~subdirectory()1345 subdirectory::~subdirectory()
1346 {
1347 }
1348
1349 /** Assign the contents of a given subdirectory to this subdirectory */
assign(const subdirectory & a_class)1350 void subdirectory::assign(const subdirectory& a_class)
1351 {
1352 type::assign(a_class.begin(), a_class.end());
1353 }
1354
1355 /** Return a vector of strings of a list of files in a subdirectory
1356
1357 Files in the list do not contain the pathname to the file. Only filenames
1358 that match the given wildcard filter will be listed.
1359 */
1360 const subdirectory::type&
path(const std::string a_path,const std::string a_filter)1361 subdirectory::path(const std::string a_path, const std::string a_filter)
1362 {
1363 std::string es;
1364 std::string name;
1365 DIR *dp = 0;
1366 struct dirent *dirp = 0;
1367 filestatus filestat;
1368
1369 clear();
1370
1371 TRY(filestat.path(a_path),"Could not stat directory");
1372
1373 dp = opendir(a_path.c_str());
1374 if (dp == 0) {
1375 TRY_nomem(es = "For path: \"");
1376 TRY_nomem(es += a_path);
1377 TRY_nomem(es += "\"");
1378 throw(ERROR(errno,es));
1379 }
1380 while ( (dirp = readdir(dp)) != 0 ) {
1381 name = dirp->d_name;
1382 if (
1383 ((a_filter != ".") && (a_filter != ".."))
1384 &&
1385 ((name == ".") || (name == ".."))
1386 )
1387 continue;
1388 if (fnmatch(a_filter.c_str(), name.c_str(), 0) == 0) {
1389 TRY_nomem(type::push_back(name));
1390 }
1391 }
1392 if (closedir(dp) < 0) {
1393 TRY_nomem(es = "Error closing directory \"");
1394 TRY_nomem(es += a_path);
1395 TRY_nomem(es += "\"");
1396 throw(ERROR(errno,es));
1397 }
1398
1399 std::sort(begin(), end());
1400
1401 return(*this);
1402 }
1403
operator =(const subdirectory & a_class)1404 subdirectory& subdirectory::operator=(const subdirectory& a_class)
1405 {
1406 assign(a_class);
1407
1408 return(*this);
1409 }
1410
1411 //----------------------------------------------------------------------------
1412
1413 /** Recursively delete the contents of a directory */
rm_recursive(const std::string a_path)1414 void rm_recursive(const std::string a_path)
1415 {
1416 subdirectory d;
1417 subdirectory::const_iterator di;
1418 filestatus f;
1419 std::string pathstr;
1420 std::string es;
1421 mode_t mode = 0;
1422
1423 mode = 0;
1424 mode |= S_IWUSR|S_IXUSR;
1425 mode |= S_IWGRP|S_IXGRP;
1426 mode |= S_IWOTH|S_IXOTH;
1427
1428 TRY_nomem(es = "Could not recursively delete: \"");
1429 TRY_nomem(es += a_path);
1430 TRY_nomem(es += "\"");
1431
1432 if (!exists(a_path)) {
1433 if (is_link(a_path)) {
1434 if (!writable(a_path)) {
1435 if (chmod(a_path.c_str(), mode) != 0)
1436 throw(ERROR(errno,es));
1437 }
1438 TRY(rm_file(a_path),es);
1439 }
1440 return;
1441 }
1442 TRY(f.path(a_path),es);
1443 if (f.is_directory()) {
1444 TRY(d.path(a_path),es);
1445 if (d.size() != 0) {
1446
1447 for (di = d.begin(); di != d.end(); ++di) {
1448 TRY_nomem(
1449 pathstr = static_cast<std::string>(a_path)
1450 + static_cast<std::string>("/")
1451 + static_cast<std::string>(*di)
1452 );
1453 TRY(f.path(pathstr),es);
1454 if (f.is_directory()) {
1455 if (!writable(a_path)) {
1456 if (chmod(a_path.c_str(), mode) != 0)
1457 throw(ERROR(errno,es));
1458 }
1459 TRY(rm_recursive(pathstr),es);
1460 }
1461 else {
1462 if (!writable(a_path)) {
1463 if (chmod(a_path.c_str(), mode) != 0)
1464 throw(ERROR(errno,es));
1465 }
1466 rm_file(pathstr);
1467 }
1468 }
1469 }
1470 if (!writable(a_path)) {
1471 if (chmod(a_path.c_str(), mode) != 0)
1472 throw(ERROR(errno,es));
1473 }
1474 rm_dir(a_path);
1475 }
1476 else {
1477 if (!writable(a_path)) {
1478 if (chmod(a_path.c_str(), mode) != 0)
1479 throw(ERROR(errno,es));
1480 }
1481 rm_file(a_path);
1482 }
1483 }
1484
1485 //----------------------------------------------------------------------------
1486
1487 /** C'tor */
directory()1488 directory::directory()
1489 {
1490 }
1491
1492 /** C'tor */
directory(const directory & a_class)1493 directory::directory(const directory& a_class)
1494 {
1495 // TODO: Isn't this supposed to do something!?
1496 }
1497
1498 /** C'tor */
directory(const std::string & a_str)1499 directory::directory(const std::string& a_str)
1500 {
1501 path(a_str);
1502 }
1503
1504 /** D'tor */
~directory()1505 directory::~directory()
1506 {
1507 }
1508
1509 /** Retrieve a list of paths that match the wildcard path given */
path(const std::string & a_path)1510 const directory::type& directory::path(const std::string& a_path)
1511 {
1512 std::string es;
1513 std::string::size_type idx;
1514 std::string path;
1515 std::string subdir_path;
1516 std::string new_subdir_path;
1517 subdirectory subdir;
1518 subdirectory::const_iterator sdi;
1519 filestatus filestat;
1520 const_iterator di;
1521 type list;
1522
1523 TRY_nomem(path = reform_path(a_path));
1524 if (path.size() == 0) {
1525 return(*this);
1526 }
1527
1528 idx = path.find('/');
1529 if (idx != std::string::npos) {
1530 TRY_nomem(subdir_path = path.substr(0,idx));
1531 path.erase(0,idx+1);
1532 }
1533 else {
1534 TRY_nomem(subdir_path = path);
1535 path.erase();
1536 }
1537 if (subdir_path.size() == 0)
1538 TRY_nomem(subdir_path = "/");
1539
1540 if (!exists(subdir_path)) {
1541 return(*this);
1542 }
1543 TRY_nomem(push_back(subdir_path));
1544
1545 while (path.size() != 0) {
1546 idx = path.find('/');
1547 if (idx != std::string::npos) {
1548 TRY_nomem(subdir_path = path.substr(0,idx));
1549 path.erase(0,idx+1);
1550 }
1551 else {
1552 TRY_nomem(subdir_path = path);
1553 path.erase();
1554 }
1555 list.clear();
1556 for (di = begin(); di != end(); di++) {
1557 TRY_nomem(list.push_back(*di));
1558 }
1559 clear();
1560 for (di = list.begin(); di != list.end(); di++) {
1561 filestat.path(*di);
1562 if (!filestat.is_directory())
1563 continue;
1564 subdir.path(*di, subdir_path);
1565 for (sdi = subdir.begin(); sdi != subdir.end(); sdi++) {
1566 TRY_nomem(new_subdir_path = *di);
1567 TRY_nomem(new_subdir_path += "/");
1568 TRY_nomem(new_subdir_path += *sdi);
1569 TRY_nomem(new_subdir_path = reform_path(new_subdir_path));
1570 TRY_nomem(push_back(new_subdir_path));
1571 }
1572 }
1573 }
1574 return(*this);
1575 }
1576
1577 //----------------------------------------------------------------------------
1578
1579 /** C'tor */
filesystem()1580 filesystem::filesystem()
1581 {
1582 clear();
1583 }
1584
1585 /** C'tor */
filesystem(const std::string & a_path)1586 filesystem::filesystem(const std::string& a_path)
1587 {
1588 clear();
1589 path(a_path);
1590 }
1591
1592 /** Clear the filesystem object */
clear(void)1593 void filesystem::clear(void)
1594 {
1595 TRY_nomem(m_path = "");
1596 memset(&m_statfs, 0, sizeof(m_statfs));
1597 }
1598
1599 /** Retrieve information about the filesystem on which the given path resides */
path(const std::string & a_path)1600 void filesystem::path(const std::string& a_path)
1601 {
1602 std::string es;
1603
1604 TRY_nomem(m_path = reform_path(a_path));
1605 if (STATFS(a_path.c_str(), &m_statfs) != 0) {
1606 TRY_nomem(es = "Could not stat filesystem: \"");
1607 TRY_nomem(es += a_path);
1608 TRY_nomem(es += "\"");
1609 throw(ERROR(errno,es));
1610 }
1611 }
1612
1613 /** Return the path from which this filesystem information was obtained */
path(void) const1614 const std::string filesystem::path(void) const
1615 {
1616 return(m_path);
1617 }
1618
1619 /** Return the filesystem block size */
blocksize(void) const1620 const filesystem::size_type filesystem::blocksize(void) const
1621 {
1622 size_type value;
1623
1624 value = static_cast<uint64>(m_statfs.f_bsize);
1625
1626 return(value);
1627 }
1628
1629 /** Return the filesystem's total number of blocks */
total_blocks(void) const1630 const filesystem::size_type filesystem::total_blocks(void) const
1631 {
1632 size_type value;
1633
1634 value = static_cast<uint64>(m_statfs.f_blocks);
1635
1636 return(value);
1637 }
1638
1639 /** Return the filesystem's number of free blocks */
free_blocks(void) const1640 const filesystem::size_type filesystem::free_blocks(void) const
1641 {
1642 size_type value;
1643
1644 value = static_cast<uint64>(m_statfs.f_bfree);
1645
1646 return(value);
1647 }
1648
1649 /** Return the filesystem's number of used blocks */
used_blocks(void) const1650 const filesystem::size_type filesystem::used_blocks(void) const
1651 {
1652 size_type value;
1653
1654 value = total_blocks() - free_blocks();
1655
1656 return(value);
1657 }
1658
1659 /** Return the filesystem's total number of inodes, if supported by the
1660 filesystem, otherwise the result is system-dependent, but usually 0.
1661 */
total_inodes(void) const1662 const filesystem::size_type filesystem::total_inodes(void) const
1663 {
1664 size_type value;
1665
1666 value = static_cast<uint64>(m_statfs.f_files);
1667
1668 return(value);
1669 }
1670
1671 /** Return the filesystem's total number of free inodes, if supported by the
1672 filesystem, otherwise the result is system-dependent, but usually 0.
1673 */
free_inodes(void) const1674 const filesystem::size_type filesystem::free_inodes(void) const
1675 {
1676 size_type value;
1677
1678 value = static_cast<uint64>(m_statfs.f_ffree);
1679
1680 return(value);
1681 }
1682
1683 /** Return the filesystem's number of used inodes */
used_inodes(void) const1684 const filesystem::size_type filesystem::used_inodes(void) const
1685 {
1686 size_type value;
1687
1688 value = total_inodes() - free_inodes();
1689
1690 return(value);
1691 }
1692
1693 /** Copy values from another instance */
operator =(const filesystem & a_class)1694 filesystem& filesystem::operator=(const filesystem& a_class)
1695 {
1696 TRY_nomem(m_path = a_class.m_path);
1697 memcpy(&m_statfs, &a_class.m_statfs, sizeof(m_statfs));
1698
1699 return(*this);
1700 }
1701
1702 //----------------------------------------------------------------------------
1703
1704 /** C'tor */
simple_lock()1705 simple_lock::simple_lock()
1706 {
1707 clear();
1708 }
1709
1710 /** C'tor */
simple_lock(const std::string & a_lockfile)1711 simple_lock::simple_lock(const std::string& a_lockfile)
1712 {
1713 clear();
1714 lockfile(a_lockfile);
1715 }
1716
1717 /** D'tor */
~simple_lock()1718 simple_lock::~simple_lock()
1719 {
1720 clear();
1721 }
1722
1723 /** Clear the simple_lock object */
clear(void)1724 void simple_lock::clear(void)
1725 {
1726 if (is_locked() && (locked_by() == getpid())) {
1727 unlock();
1728 }
1729 m_lockfile.clear();
1730 }
1731
1732 /** Set the lockfile path */
lockfile(const std::string & a_lockfile)1733 void simple_lock::lockfile(const std::string& a_lockfile)
1734 {
1735 clear();
1736 m_lockfile = a_lockfile;
1737 }
1738
1739 /** Get the lockfile path */
lockfile(void) const1740 const std::string simple_lock::lockfile(void) const
1741 {
1742 return(m_lockfile);
1743 }
1744
1745 /** Get the PID of the locking process */
locked_by(void) const1746 const simple_lock::pid_type simple_lock::locked_by(void) const
1747 {
1748 simple_lock::pid_type pid;
1749 std::ifstream in;
1750
1751 pid = 0;
1752 if (m_lockfile.size() == 0) return(0);
1753 if (!exists(m_lockfile)) return(0);
1754 in.open(m_lockfile.c_str());
1755 if (!in.is_open()) return(0);
1756 in >> pid;
1757 if (!in) {
1758 in.close();
1759 return(0);
1760 }
1761 return(pid);
1762 }
1763
1764 /** Find out whether or not the lock is in place */
is_locked(void) const1765 const bool simple_lock::is_locked(void) const
1766 {
1767 simple_lock::pid_type pid;
1768
1769 pid = locked_by();
1770 if (pid == 0) return(false);
1771 if (pid == getpid()) return(true);
1772 if (kill(pid,0) >= 0) return(true);
1773 errno = 0;
1774 return(false);
1775 }
1776
1777 /** Lock */
lock(void)1778 bool simple_lock::lock(void)
1779 {
1780 std::ofstream out;
1781 simple_lock::pid_type pid;
1782
1783 if (is_locked()) return(false);
1784 if (m_lockfile.size() == 0) return(false);
1785 out.open(m_lockfile.c_str());
1786 if (!out.is_open()) return(false);
1787 pid = getpid();
1788 out << pid << std::endl;
1789 if (!out) {
1790 clear();
1791 return(false);
1792 }
1793 out.close();
1794 return(true);
1795 }
1796
1797 /** Unlock */
unlock(void)1798 void simple_lock::unlock(void)
1799 {
1800 std::string es;
1801
1802 if (m_lockfile.size() == 0) return;
1803 if (!exists(m_lockfile)) return;
1804 TRY_nomem(es = "Cannot unlock: \"");
1805 TRY_nomem(es += m_lockfile);
1806 TRY_nomem(es += "\"");
1807 TRY(rm_file(m_lockfile),es);
1808 }
1809
1810 //----------------------------------------------------------------------------
1811
1812