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