blob: 549c92e64513eba907732285b9d429b9b72f94f8 [file] [log] [blame]
Alexandre Lisionddd731e2014-01-31 11:50:08 -05001// Copyright (C) 2006-2010 David Sugar, Tycho Softworks.
2//
3// This file is part of GNU uCommon C++.
4//
5// GNU uCommon C++ is free software: you can redistribute it and/or modify
6// it under the terms of the GNU Lesser General Public License as published
7// by the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// GNU uCommon C++ is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU Lesser General Public License for more details.
14//
15// You should have received a copy of the GNU Lesser General Public License
16// along with GNU uCommon C++. If not, see <http://www.gnu.org/licenses/>.
17
18/**
19 * Thread-aware file system manipulation class. This is used to provide
20 * generic file operations that are OS independent and thread-safe in
21 * behavior. This is used in particular to wrap posix calls internally
22 * to pth, and to create portable code between MSWINDOWS and Posix low-level
23 * file I/O operations.
24 * @file ucommon/fsys.h
25 */
26
27#ifndef _UCOMMON_FSYS_H_
28#define _UCOMMON_FSYS_H_
29
30#ifndef _UCOMMON_CONFIG_H_
31#include <ucommon/platform.h>
32#endif
33
34#ifndef _UCOMMON_PROTOCOLS_H_
35#include <ucommon/protocols.h>
36#endif
37
38#ifndef _UCOMMON_THREAD_H_
39#include <ucommon/thread.h>
40#endif
41
42#ifndef _UCOMMON_STRING_H_
43#include <ucommon/string.h>
44#endif
45
46#ifndef _UCOMMON_MEMORY_H_
47#include <ucommon/memory.h>
48#endif
49
50#ifndef _MSWINDOWS_
51#include <sys/stat.h>
52#else
53#include <io.h>
54#ifndef R_OK
55#define F_OK 0
56#define X_OK 1
57#define W_OK 2
58#define R_OK 4
59#endif
60#endif
61
62#include <errno.h>
63#include <stdio.h>
64
65#ifndef __S_ISTYPE
66#define __S_ISTYPE(mode, mask) (((mode) & S_IFMT) == (mask))
67#endif
68
69#if !defined(S_ISDIR) && defined(S_IFDIR)
70#define S_ISDIR(mode) __S_ISTYPE((mode), S_IFDIR)
71#endif
72
73#if !defined(S_ISCHR) && defined(S_IFCHR)
74#define S_ISCHR(mode) __S_ISTYPE((mode), S_IFCHR)
75#elif !defined(S_ISCHR)
76#define S_ISCHR(mode) 0
77#endif
78
79#if !defined(S_ISBLK) && defined(S_IFBLK)
80#define S_ISBLK(mode) __S_ISTYPE((mode), S_IFBLK)
81#elif !defined(S_ISBLK)
82#define S_ISBLK(mode) 0
83#endif
84
85#if !defined(S_ISREG) && defined(S_IFREG)
86#define S_ISREG(mode) __S_ISTYPE((mode), S_IFREG)
87#elif !defined(S_ISREG)
88#define S_ISREG(mode) 1
89#endif
90
91#if !defined(S_ISSOCK) && defined(S_IFSOCK)
92#define S_ISSOCK(mode) __S_ISTYPE((mode), S_IFSOCK)
93#elif !defined(S_ISSOCK)
94#define S_ISSOCK(mode) (0)
95#endif
96
97#if !defined(S_ISFIFO) && defined(S_IFIFO)
98#define S_ISFIFO(mode) __S_ISTYPE((mode), S_IFIFO)
99#elif !defined(S_ISFIFO)
100#define S_ISFIFO(mode) (0)
101#endif
102
103#if !defined(S_ISLNK) && defined(S_IFLNK)
104#define S_ISLNK(mode) __S_ISTYPE((mode), S_IFLNK)
105#elif !defined(S_ISLNK)
106#define S_ISLNK(mode) (0)
107#endif
108
109NAMESPACE_UCOMMON
110
111/**
112 * Convenience type for loader operations.
113 */
114typedef void *mem_t;
115
116/**
117 * A container for generic and o/s portable threadsafe file system functions.
118 * These are based roughly on their posix equivilents. For libpth, the
119 * system calls are wrapped. The native file descriptor or handle may be
120 * used, but it is best to use "class fsys" instead because it can capture
121 * the errno of a file operation in a threadsafe and platform independent
122 * manner, including for mswindows targets.
123 */
124class __EXPORT fsys
125{
126protected:
127 fd_t fd;
128 int error;
129
130public:
131 /**
132 * Most of the common chmod values are predefined.
133 */
134 enum {
135 OWNER_READONLY = 0400,
136 GROUP_READONLY = 0440,
137 PUBLIC_READONLY = 0444,
138 OWNER_PRIVATE = 0600,
139 OWNER_PUBLIC = 0644,
140 GROUP_PRIVATE = 0660,
141 GROUP_PUBLIC = 0664,
142 EVERYONE = 0666,
143 DIR_TEMPORARY = 01777
144 };
145
146 typedef struct stat fileinfo_t;
147
148#ifdef _MSWINDOWS_
149 static int remapError(void);
150#else
151 inline static int remapError(void)
152 {return errno;};
153#endif
154
155 /**
156 * Enumerated file access modes.
157 */
158 typedef enum {
159 RDONLY,
160 WRONLY,
161 REWRITE,
162 RDWR = REWRITE,
163 APPEND,
164 SHARED,
165 EXCLUSIVE,
166 DEVICE,
167 STREAM,
168 RANDOM
169 } access_t;
170
171 /**
172 * File offset type.
173 */
174 typedef long offset_t;
175
176 /**
177 * Used to mark "append" in set position operations.
178 */
179 static const offset_t end;
180
181 /**
182 * Construct an unattached fsys descriptor.
183 */
184 fsys();
185
186 /**
187 * Contruct fsys from raw file handle.
188 */
189 fsys(fd_t handle);
190
191 /**
192 * Copy (dup) an existing fsys descriptor.
193 * @param descriptor to copy from.
194 */
195 fsys(const fsys& descriptor);
196
197 /**
198 * Create a fsys descriptor by opening an existing file or directory.
199 * @param path of file to open for created descriptor.
200 * @param access mode of file.
201 */
202 fsys(const char *path, access_t access);
203
204 /**
205 * Create a fsys descriptor by creating a file.
206 * @param path of file to create for descriptor.
207 * @param access mode of file access.
208 * @param permission mode of file.
209 */
210 fsys(const char *path, unsigned permission, access_t access);
211
212 /**
213 * Close and release a file descriptor.
214 */
215 ~fsys();
216
217 /**
218 * Get the descriptor from the object by pointer reference.
219 * @return low level file handle.
220 */
221 inline fd_t operator*() const
222 {return fd;};
223
224 /**
225 * Get the descriptor from the object by casting reference.
226 * @return low level file handle.
227 */
228 inline operator fd_t() const
229 {return fd;}
230
231 /**
232 * Reset error flag.
233 */
234 inline void reset(void)
235 {error = 0;}
236
237 /**
238 * Test if file descriptor is open.
239 * @return true if open.
240 */
241 inline operator bool() const
242 {return fd != INVALID_HANDLE_VALUE;}
243
244 /**
245 * Test if file descriptor is closed.
246 * @return true if closed.
247 */
248 inline bool operator!() const
249 {return fd == INVALID_HANDLE_VALUE;}
250
251 /**
252 * Assign file descriptor by duplicating another descriptor.
253 * @param descriptor to dup from.
254 */
255 void operator=(const fsys& descriptor);
256
257 /**
258 * Replace current file descriptor with an external descriptor. This
259 * does not create a duplicate. The external descriptor object is
260 * marked as invalid.
261 */
262 void operator*=(fd_t& descriptor);
263
264 /**
265 * Assing file descriptor from system descriptor.
266 * @param descriptor to dup from.
267 */
268 void operator=(fd_t descriptor);
269
270 /**
271 * Get the native system descriptor handle of the file descriptor.
272 * @return native os descriptor.
273 */
274 inline fd_t handle(void) const
275 {return fd;};
276
277 /**
278 * Set with external descriptor. Closes existing file if open.
279 * @param descriptor of open file.
280 */
281 void set(fd_t descriptor);
282
283 /**
284 * Release descriptor, do not close.
285 * @return handle being released.
286 */
287 fd_t release(void);
288
289 /**
290 * Set the position of a file descriptor.
291 * @param offset from start of file or "end" to append.
292 * @return error number or 0 on success.
293 */
294 int seek(offset_t offset);
295
296 /**
297 * Drop cached data from start of file.
298 * @param size of region to drop or until end of file.
299 * @return error number or 0 on success.
300 */
301 int drop(offset_t size = 0);
302
303 /**
304 * See if current file stream is a tty device.
305 * @return true if device.
306 */
307 bool is_tty(void);
308
309 /**
310 * See if the file handle is a tty device.
311 * @return true if device.
312 */
313 static bool is_tty(fd_t fd);
314
315 /**
316 * Read data from descriptor or scan directory.
317 * @param buffer to read into.
318 * @param count of bytes to read.
319 * @return bytes transferred, -1 if error.
320 */
321 ssize_t read(void *buffer, size_t count);
322
323 /**
324 * Write data to descriptor.
325 * @param buffer to write from.
326 * @param count of bytes to write.
327 * @return bytes transferred, -1 if error.
328 */
329 ssize_t write(const void *buffer, size_t count);
330
331 /**
332 * Get status of open descriptor.
333 * @param buffer to save status info in.
334 * @return error number or 0 on success.
335 */
336 int info(fileinfo_t *buffer);
337
338 /**
339 * Truncate file to specified length. The file pointer is positioned
340 * to the new end of file.
341 * @param offset to truncate to.
342 * @return true if truncate successful.
343 */
344 int trunc(offset_t offset);
345
346 /**
347 * Commit changes to the filesystem.
348 * @return error number or 0 on success.
349 */
350 int sync(void);
351
352 /**
353 * Set directory prefix (chdir).
354 * @param path to change to.
355 * @return error number or 0 on success.
356 */
357 static int prefix(const char *path);
358
359 /**
360 * Get current directory prefix (pwd).
361 * @param path to save directory into.
362 * @param size of path we can save.
363 * @return error number or 0 on success.
364 */
365 static int prefix(char *path, size_t size);
366
367 static string_t prefix(void);
368
369 /**
370 * Stat a file.
371 * @param path of file to stat.
372 * @param buffer to save stat info.
373 * @return error number or 0 on success.
374 */
375 static int info(const char *path, fileinfo_t *buffer);
376
377 /**
378 * Erase (remove) a file only.
379 * @param path of file.
380 * @return error number or 0 on success.
381 */
382 static int erase(const char *path);
383
384 /**
385 * Copy a file.
386 * @param source file.
387 * @param target file.
388 * @param size of buffer.
389 * @return error number or 0 on success.
390 */
391 static int copy(const char *source, const char *target, size_t size = 1024);
392
393 /**
394 * Rename a file.
395 * @param oldpath to rename from.
396 * @param newpath to rename to.
397 * @return error number or 0 on success.
398 */
399 static int rename(const char *oldpath, const char *newpath);
400
401 /**
402 * Change file access mode.
403 * @param path to change.
404 * @param value of mode to assign.
405 * @return error number or 0 on success.
406 */
407 static int mode(const char *path, unsigned value);
408
409 /**
410 * Test if path exists.
411 * @param path to test.
412 * @return if true.
413 */
414 static bool is_exists(const char *path);
415
416 /**
417 * Test if path readable.
418 * @param path to test.
419 * @return if true.
420 */
421 static bool is_readable(const char *path);
422
423 /**
424 * Test if path writable.
425 * @param path to test.
426 * @return if true.
427 */
428 static bool is_writable(const char *path);
429
430 /**
431 * Test if path is executable.
432 * @param path to test.
433 * @return if true.
434 */
435 static bool is_executable(const char *path);
436
437 /**
438 * Test if path is a file.
439 * @param path to test.
440 * @return true if exists and is file.
441 */
442 static bool is_file(const char *path);
443
444 /**
445 * Test if path is a directory.
446 * @param path to test.
447 * @return true if exists and is directory.
448 */
449 static bool is_dir(const char *path);
450
451 /**
452 * Test if path is a symlink.
453 * @param path to test.
454 * @return true if exists and is symlink.
455 */
456 static bool is_link(const char *path);
457
458 /**
459 * Test if path is a device path.
460 * @param path to test.
461 * @return true of is a device path.
462 */
463 static bool is_device(const char *path);
464
465 /**
466 * Test if path is a hidden file.
467 * @param path to test.
468 * @return true if exists and is hidden.
469 */
470 static bool is_hidden(const char *path);
471
472 /**
473 * Open a file or directory.
474 * @param path of file to open.
475 * @param access mode of descriptor.
476 */
477 void open(const char *path, access_t access);
478
479 /**
480 * Assign descriptor directly.
481 * @param descriptor to assign.
482 */
483 inline void assign(fd_t descriptor)
484 {close(); fd = descriptor;};
485
486 /**
487 * Assign a descriptor directly.
488 * @param object to assign descriptor to.
489 * @param descriptor to assign.
490 */
491 inline static void assign(fsys& object, fd_t descriptor)
492 {object.close(); object.fd = descriptor;};
493
494 /**
495 * Open a file descriptor directly.
496 * @param path of file to create.
497 * @param access mode of descriptor.
498 * @param mode of file if created.
499 */
500 void open(const char *path, unsigned mode, access_t access);
501
502 /**
503 * Remove a symbolic link explicitly. Other kinds of files are also
504 * deleted. This should be used when uncertain about symlinks requiring
505 * special support.
506 * @param path to remove.
507 * @return error number or 0 on success.
508 */
509 static int unlink(const char *path);
510
511 /**
512 * Create a symbolic link.
513 * @param path to create.
514 * @param target of link.
515 * @return error number or 0 on success.
516 */
517 static int link(const char *path, const char *target);
518
519 /**
520 * Create a hard link.
521 * @param path to create link to.
522 * @param target of link.
523 * @return error number or 0 on success.
524 */
525 static int hardlink(const char *path, const char *target);
526
527 /**
528 * Read a symbolic link to get it's target.
529 * @param path of link.
530 * @param buffer to save target into.
531 * @param size of buffer.
532 */
533 static int linkinfo(const char *path, char *buffer, size_t size);
534
535 /**
536 * Close a fsys resource.
537 * @return error code as needed.
538 */
539 int close(void);
540
541 /**
542 * Get last error.
543 * @return error number.
544 */
545 inline int err(void) const
546 {return error;}
547
548 /**
549 * Direct means to open a read-only file path and return a descriptor.
550 * @param path to open.
551 * @return descriptor on success, invalid handle on failure.
552 */
553 static fd_t input(const char *path);
554
555 /**
556 * Direct means to create or access a writable path and return descriptor.
557 * @param path to create.
558 * @return descriptor on success, invalid handle on failure.
559 */
560 static fd_t output(const char *path);
561
562 /**
563 * Direct means to create or append a writable path and return descriptor.
564 * @param path to create.
565 * @return descriptor on success, invalid handle on failure.
566 */
567 static fd_t append(const char *path);
568
569 /**
570 * Release a file descriptor.
571 * @param descriptor to release.
572 */
573 static void release(fd_t descriptor);
574
575 /**
576 * Create pipe. These are created inheritable by default.
577 * @param input descriptor.
578 * @param output descriptor.
579 * @param size of buffer if supported.
580 * @return 0 or error code.
581 */
582 static int pipe(fd_t& input, fd_t& output, size_t size = 0);
583
584 /**
585 * Changle inheritable handle. On windows this is done by creating a
586 * duplicate handle and then closing the original. Elsewhere this
587 * is done simply by setting flags.
588 * @param descriptor to modify.
589 * @param enable child process inheritence.
590 * @return 0 on success, error on failure.
591 */
592 static int inherit(fd_t& descriptor, bool enable);
593
594 /**
595 * Create inheritable /dev/null handle.
596 * @return null device handle.
597 */
598 static fd_t null(void);
599
600 /**
601 * Load a library into memory.
602 * @param path to plugin.
603 * @return 0 on success, else error.
604 */
605 static int load(const char *path);
606
607 /**
608 * Execute a process and get exit code.
609 * @param path to execute.
610 * @param argv list.
611 * @param optional env.
612 * @return exit code.
613 */
614 static int exec(const char *path, char **argv, char **envp = NULL);
615
616 static inline bool is_file(struct stat *inode)
617 {return S_ISREG(inode->st_mode);}
618
619 static inline bool is_dir(struct stat *inode)
620 {return S_ISDIR(inode->st_mode);}
621
622 static inline bool is_link(struct stat *inode)
623 {return S_ISLNK(inode->st_mode);}
624
625 static inline bool is_dev(struct stat *inode)
626 {return S_ISBLK(inode->st_mode) || S_ISCHR(inode->st_mode);}
627
628 static inline bool is_char(struct stat *inode)
629 {return S_ISCHR(inode->st_mode);}
630
631 static inline bool is_disk(struct stat *inode)
632 {return S_ISBLK(inode->st_mode);}
633
634 static inline bool is_sys(struct stat *inode)
635 {return S_ISSOCK(inode->st_mode) || S_ISFIFO(inode->st_mode);}
636};
637
638/**
639 * Convenience class for library plugins.
640 * @author David Sugar <dyfet@gnutelephony.org>
641 */
642class __EXPORT dso
643{
644private:
645 friend class fsys;
646
647#ifdef _MSWINDOWS_
648 HINSTANCE ptr;
649#else
650 void *ptr;
651#endif
652 int error;
653
654public:
655#ifdef _MSWINDOWS_
656 typedef int (FAR WINAPI *addr_t)();
657#else
658 typedef void *addr_t;
659#endif
660
661 /**
662 * Create dso object for use by load functions.
663 */
664 dso();
665
666 /**
667 * Create and map a dso object.
668 * @param path of library to map.
669 */
670 dso(const char *path);
671
672 /**
673 * Destroy dso and release library.
674 */
675 ~dso();
676
677 /**
678 * Map library object with library.
679 * @param name of library to load.
680 */
681 void map(const char *path);
682
683 /**
684 * Release loaded library.
685 */
686 void release(void);
687
688 /**
689 * Find symbol in loaded module.
690 * @param module to search.
691 * @param symbol to search for.
692 * @return address of symbol or NULL if not found.
693 */
694 addr_t find(const char *symbol) const;
695
696 inline int err(void) const
697 {return error;}
698
699 inline addr_t operator[](const char *symbol) const
700 {return find(symbol);}
701
702 inline addr_t operator()(const char *symbol) const
703 {return find(symbol);}
704
705 inline operator bool()
706 {return ptr != NULL;}
707
708 inline bool operator!()
709 {return ptr == NULL;}
710};
711
712/**
713 * Convenience class for directories.
714 * @author David Sugar <dyfet@gnutelephony.org>
715 */
716class __EXPORT dir : private fsys
717{
718private:
719#ifdef _MSWINDOWS_
720 WIN32_FIND_DATA *ptr;
721 HINSTANCE mem;
722#else
723 void *ptr;
724#endif
725
726public:
727 /**
728 * Construct and open a directory path.
729 * @param path of directory.
730 */
731 dir(const char *path);
732
733 /**
734 * Construct an unopened directory.
735 */
736 dir();
737
738 /**
739 * Close and release directory.
740 */
741 ~dir();
742
743 /**
744 * Simple direct method to create a directory.
745 * @param path of directory to create.
746 * @param mode of directory.
747 * @return error number or 0 on success.
748 */
749 static int create(const char *path, unsigned mode);
750
751 /**
752 * Remove an empty directory.
753 * @param path of directory.
754 * @return error number or 0 on success.
755 */
756 static int remove(const char *path);
757
758 /**
759 * Open a directory path for reading.
760 * @param path to open.
761 */
762 void open(const char *path);
763
764 /**
765 * Read data from directory.
766 * @param buffer to read into.
767 * @param count of bytes to read.
768 * @return bytes transferred, -1 if error.
769 */
770 ssize_t read(char *buffer, size_t count);
771
772 /**
773 * Close and release directory object.
774 */
775 void close(void);
776
777 inline int err(void) const
778 {return fsys::err();}
779
780 inline void reset(void)
781 {fsys::reset();}
782
783 /**
784 * Test if file descriptor is open.
785 * @return true if open.
786 */
787 inline operator bool() const
788 {return ptr != NULL;};
789
790 /**
791 * Test if file descriptor is closed.
792 * @return true if closed.
793 */
794 inline bool operator!() const
795 {return ptr == NULL;};
796};
797
798/**
799 * Convience type for fsys.
800 */
801typedef fsys fsys_t;
802
803typedef dir dir_t;
804
805typedef dso dso_t;
806
807inline bool is_exists(const char *path)
808 {return fsys::is_exists(path);}
809
810inline bool is_readable(const char *path)
811 {return fsys::is_readable(path);}
812
813inline bool is_writable(const char *path)
814 {return fsys::is_writable(path);}
815
816inline bool is_executable(const char *path)
817 {return fsys::is_executable(path);}
818
819inline bool is_file(const char *path)
820 {return fsys::is_file(path);}
821
822inline bool is_dir(const char *path)
823 {return fsys::is_dir(path);}
824
825inline bool is_link(const char *path)
826 {return fsys::is_link(path);}
827
828inline bool is_device(const char *path)
829 {return fsys::is_device(path);}
830
831END_NAMESPACE
832
833#endif
834