blob: 4e2dd6da6568b80c7046df3ef68c28b6774482cf [file] [log] [blame]
Alexandre Lisionddd731e2014-01-31 11:50:08 -05001// Copyright (C) 1999-2005 Open Source Telecom Corporation.
2// Copyright (C) 2006-2010 David Sugar, Tycho Softworks.
3//
4// This program is free software; you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation; either version 2 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program; if not, write to the Free Software
16// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17//
18// As a special exception, you may use this file as part of a free software
19// library without restriction. Specifically, if other files instantiate
20// templates or use macros or inline functions from this file, or you compile
21// this file and link it with other files to produce an executable, this
22// file does not by itself cause the resulting executable to be covered by
23// the GNU General Public License. This exception does not however
24// invalidate any other reasons why the executable file might be covered by
25// the GNU General Public License.
26//
27// This exception applies only to the code released under the name GNU
28// Common C++. If you copy code from other releases into a copy of GNU
29// Common C++, as the General Public License permits, the exception does
30// not apply to the code that you add in this way. To avoid misleading
31// anyone as to the status of such modified files, you must delete
32// this exception notice from them.
33//
34// If you write modifications of your own for GNU Common C++, it is your choice
35// whether to permit this exception to apply to your modifications.
36// If you do not wish that, delete this exception notice.
37//
38
39/**
40 * @file file.h
41 * @short Files and dynamic loader services.
42 **/
43
44#ifndef COMMONCPP_FILE_H_
45#define COMMONCPP_FILE_H_
46
47#ifndef COMMONCPP_CONFIG_H_
48#include <commoncpp/config.h>
49#endif
50
51#ifndef COMMONCPP_THREAD_H_
52#include <commoncpp/thread.h>
53#endif
54
55#ifndef COMMONCPP_EXCEPTION_H_
56#include <commoncpp/exception.h>
57#endif
58
59#ifndef WIN32
60# ifdef __BORLANDC__
61# include <stdio.h>
62# include <sys/types.h>
63# else
64# include <fcntl.h>
65# include <cstdio>
66# endif
67# include <dirent.h>
68# include <sys/stat.h>
69# include <sys/mman.h>
70#else
71# if __BORLANDC__ >= 0x0560
72# include <dirent.h>
73# include <sys/stat.h>
74# else
75# include <direct.h>
76# endif
77#endif
78
79NAMESPACE_COMMONCPP
80
81typedef unsigned long pos_t;
82#ifndef _MSWINDOWS_
83// use a define so that if the sys/types.h header already defines caddr_t
84// as it may on BSD systems, we do not break it by redefining again.
85#undef caddr_t
86#define caddr_t char *
87typedef size_t ccxx_size_t;
88#else
89typedef DWORD ccxx_size_t;
90#endif
91
92#ifndef PATH_MAX
93#define PATH_MAX 256
94#endif
95
96#ifndef NAME_MAX
97#define NAME_MAX 64
98#endif
99
100class __EXPORT File
101{
102public:
103 enum Error {
104 errSuccess = 0,
105 errNotOpened,
106 errMapFailed,
107 errInitFailed,
108 errOpenDenied,
109 errOpenFailed,
110 errOpenInUse,
111 errReadInterrupted,
112 errReadIncomplete,
113 errReadFailure,
114 errWriteInterrupted,
115 errWriteIncomplete,
116 errWriteFailure,
117 errLockFailure,
118 errExtended
119 };
120 typedef enum Error Error;
121
122 enum Access {
123#ifndef _MSWINDOWS_
124 accessReadOnly = O_RDONLY,
125 accessWriteOnly= O_WRONLY,
126 accessReadWrite = O_RDWR
127#else
128 accessReadOnly = GENERIC_READ,
129 accessWriteOnly = GENERIC_WRITE,
130 accessReadWrite = GENERIC_READ | GENERIC_WRITE
131#endif
132 };
133 typedef enum Access Access;
134
135protected:
136 typedef struct _fcb {
137 struct _fcb *next;
138 caddr_t address;
139 ccxx_size_t len;
140 off_t pos;
141 bool locked;
142 } fcb_t;
143
144public:
145#ifdef _MSWINDOWS_
146 enum Open {
147 openReadOnly, // = FILE_OPEN_READONLY,
148 openWriteOnly, // = FILE_OPEN_WRITEONLY,
149 openReadWrite, // = FILE_OPEN_READWRITE,
150 openAppend, // = FILE_OPEN_APPEND,
151 openTruncate // = FILE_OPEN_TRUNCATE
152 };
153#else
154 enum Open {
155 openReadOnly = O_RDONLY,
156 openWriteOnly = O_WRONLY,
157 openReadWrite = O_RDWR,
158 openAppend = O_WRONLY | O_APPEND,
159#ifdef O_SYNC
160 openSync = O_RDWR | O_SYNC,
161#else
162 openSync = O_RDWR,
163#endif
164 openTruncate = O_RDWR | O_TRUNC
165 };
166 typedef enum Open Open;
167
168/* to be used in future */
169
170#ifndef S_IRUSR
171#define S_IRUSR 0400
172#define S_IWUSR 0200
173#define S_IRGRP 0040
174#define S_IWGRP 0020
175#define S_IROTH 0004
176#define S_IWOTH 0002
177#endif
178
179#endif // !WIN32
180
181#ifndef _MSWINDOWS_
182 enum Attr {
183 attrInvalid = 0,
184 attrPrivate = S_IRUSR | S_IWUSR,
185 attrGroup = attrPrivate | S_IRGRP | S_IWGRP,
186 attrPublic = attrGroup | S_IROTH | S_IWOTH
187 };
188#else // defined WIN32
189 enum Attr {
190 attrInvalid=0,
191 attrPrivate,
192 attrGroup,
193 attrPublic
194 };
195#endif // !WIN32
196 typedef enum Attr Attr;
197
198#ifdef _MSWINDOWS_
199 enum Complete {
200 completionImmediate, // = FILE_COMPLETION_IMMEDIATE,
201 completionDelayed, // = FILE_COMPLETION_DELAYED,
202 completionDeferred // = FILE_COMPLETION_DEFERRED
203 };
204
205 enum Mapping {
206 mappedRead,
207 mappedWrite,
208 mappedReadWrite
209 };
210#else
211 enum Mapping {
212 mappedRead = accessReadOnly,
213 mappedWrite = accessWriteOnly,
214 mappedReadWrite = accessReadWrite
215 };
216 enum Complete {
217 completionImmediate,
218 completionDelayed,
219 completionDeferred
220 };
221#endif
222 typedef enum Complete Complete;
223 typedef enum Mapping Mapping;
224
225public:
226 static const char *getExtension(const char *path);
227 static const char *getFilename(const char *path);
228 static char *getFilename(const char *path, char *buffer, size_t size = NAME_MAX);
229 static char *getDirname(const char *path, char *buffer, size_t size = PATH_MAX);
230 static char *getRealpath(const char *path, char *buffer, size_t size = PATH_MAX);
231};
232
233/**
234 * A low level portable directory class. Used to support ccstd Directory
235 * container. This provides a basic mechanism for allocating and
236 * accessing file entries.
237 *
238 * @author David Sugar <dyfet@ostel.com>
239 * @short low level directory access class.
240 */
241class __EXPORT Dir : public File
242{
243private:
244#ifndef _MSWINDOWS_
245 DIR *dir;
246 struct dirent *save;
247 char save_space[sizeof(struct dirent) + PATH_MAX + 1];
248 struct dirent *entry;
249#else
250 HANDLE hDir;
251 WIN32_FIND_DATA data, fdata;
252 char *name;
253#endif
254
255public:
256 Dir(const char *name = NULL);
257
258 static bool create(const char *path, Attr attr = attrGroup);
259 static bool remove(const char *path);
260 static bool setPrefix(const char *path);
261 static bool getPrefix(char *path, size_t size = PATH_MAX);
262
263 void open(const char *name);
264 void close(void);
265
266 virtual ~Dir();
267
268 const char *getName(void);
269
270 const char *operator++()
271 {return getName();};
272
273 const char *operator++(int)
274 {return getName();};
275
276 const char *operator*();
277
278 bool rewind(void);
279
280 bool operator!()
281#ifndef _MSWINDOWS_
282 {return !dir;};
283#else
284 {return hDir != INVALID_HANDLE_VALUE;};
285#endif
286
287 bool isValid(void);
288};
289
290/**
291 * A generic class to walk a hierarchical directory structure.
292 *
293 * @author David Sugar <dyfet@ostel.com>
294 * @short Directory tree walking.
295 */
296class __EXPORT DirTree
297{
298private:
299 char path[PATH_MAX + 1];
300 Dir *dir;
301 unsigned max, current, prefixpos;
302
303protected:
304 /**
305 * Virtual method to filter results. Virtual override methods
306 * should call baseclass method to assure . and .. names are
307 * stripped out.
308 *
309 * @return true if current filename is accepted.
310 * @param file path to examine
311 * @param ino info of type, date, etc.
312 */
313 virtual bool filter(const char *file, struct stat *ino);
314
315public:
316 /**
317 * Construct a directory tree walk starting at the specified
318 * prefix. A maximum subdirectory depth is also specified.
319 *
320 * @param prefix to start walk.
321 * @param maxdepth subdirectory depth to examine.
322 */
323 DirTree(const char *prefix, unsigned maxdepth);
324
325 /**
326 * Construct an un-opened directory tree of a known maximum depth
327 *
328 * @param maxdepth subdirectory subdirectory depth.
329 */
330 DirTree(unsigned maxdepth);
331
332 virtual ~DirTree();
333
334 /**
335 * Open a directory tree path.
336 *
337 * @param prefix directory path to open.
338 */
339 void open(const char *prefix);
340
341 /**
342 * Close the directory path.
343 */
344 void close(void);
345
346 /**
347 * Extract the next full pathname from the directory walk.
348 * When returning directories, a '/' is appended. The
349 * returned string is a buffer of MAX_PATH size.
350 *
351 * @return path of next subdirectory entry or NULL.
352 */
353 char *getPath(void);
354
355 /**
356 * This is used to step through the filter virtual for an
357 * entire subtree, and is used for cases where a derived
358 * DirTree class performs it's primary operations through
359 * filter rather than externally by calling getPath().
360 *
361 * @return number of files and directories examined.
362 * @param prefix directory path to examine.
363 */
364 unsigned perform(const char *prefix);
365};
366
367/**
368 * The purpose of this class is to define a base class for low level
369 * random file access that is portable between Win32 and Posix systems.
370 * This class is a foundation both for optimized thread shared and
371 * traditional locked file access that is commonly used to build
372 * database services, rather than the standard C++ streaming file classes.
373 *
374 * @author David Sugar <dyfet@ostel.com>
375 * @short Portable random disk file access.
376 */
377class __EXPORT RandomFile : protected Mutex, public File
378{
379private:
380 Error errid;
381 char *errstr;
382
383protected:
384#ifndef _MSWINDOWS_
385 int fd;
386 // FIXME: WIN32 as no access member
387 Access access;
388#else
389 HANDLE fd;
390#endif
391 char *pathname;
392
393 struct {
394 unsigned count : 16;
395 bool thrown : 1;
396 bool initial : 1;
397#ifndef _MSWINDOWS_
398 bool immediate : 1;
399#endif
400 bool temp : 1;
401 } flags;
402
403 /**
404 * Create an unopened random access file.
405 */
406 RandomFile(const char *name = NULL);
407
408 /**
409 * Default copy constructor.
410 */
411 RandomFile(const RandomFile &rf);
412
413 /**
414 * Post an error event.
415 *
416 * @return error code.
417 * @param errid error code.
418 * @param errstr error message string.
419 */
420 Error error(Error errid, char *errstr = NULL);
421
422 /**
423 * Post an extended string error message.
424 *
425 * @return errExtended.
426 * @param err error string.
427 */
428 inline Error error(char *err)
429 {return error(errExtended, err);};
430
431 /**
432 * Used to enable or disable throwing of exceptions on
433 * errors.
434 *
435 * @param enable true if errors will be thrown.
436 */
437 inline void setError(bool enable)
438 {flags.thrown = !enable;};
439
440#ifndef _MSWINDOWS_
441 /**
442 * Used to set file completion modes.
443 *
444 * @return errSuccess if okay.
445 * @param mode completion mode.
446 * @todo implement in win32
447 */
448 Error setCompletion(Complete mode);
449#endif
450
451 /**
452 * Used to set the temporary attribute for the file. Temporary
453 * files are automatically deleted when closed.
454 *
455 * @param enable true for marking as temporary.
456 */
457 inline void setTemporary(bool enable)
458 {flags.temp = enable;};
459
460 /**
461 * This method is used to initialize a newly created file as
462 * indicated by the "initial" flag. This method also returns
463 * the file access permissions that should be associated with
464 * the file. This method should never be called directly, but
465 * is instead used to impliment the "Initial" method. Typically
466 * one would use this to build an empty database shell when a
467 * previously empty database file is created.
468 *
469 * @return access, or attrInvalid if should be removed.
470 */
471 virtual Attr initialize(void);
472
473 /**
474 * Close the file.
475 */
476 void final(void);
477
478public:
479 /**
480 * Destroy a random access file or it's derived class.
481 */
482 virtual ~RandomFile();
483
484 /**
485 * This method should be called right after a RandomFile derived
486 * object has been created. This method will invoke initialize
487 * if the object is newly created, and set file access permissions
488 * appropriately.
489 *
490 * @return true if file had to be initialized.
491 */
492 bool initial(void);
493
494 /**
495 * Get current file capacity.
496 *
497 * @return total file size.
498 */
499 off_t getCapacity(void);
500
501 /**
502 * This method is commonly used to close and re-open an existing
503 * database. This may be used when the database has been unlinked
504 * and an external process provides a new one to use.
505 */
506 virtual Error restart(void);
507
508 /**
509 * Return current error id.
510 *
511 * @return last error identifier set.
512 */
513 inline Error getErrorNumber(void)
514 {return errid;};
515
516 /**
517 * Return current error string.
518 *
519 * @return last error string set.
520 */
521 inline char *getErrorString(void)
522 {return errstr;};
523
524 bool operator!(void);
525};
526
527/**
528 * This class defines a database I/O file service that can be shared
529 * by multiple processes. Each thread should access a dup of the database
530 * object, and mutex locks can be used to preserve transaction
531 * integrety if multiple threads are used.
532 *
533 * SharedFile is used when a database may be shared between multiple
534 * processes. SharedFile automatically applies low level byte-range "file
535 * locks", and provides an interface to fetch and release byte-range locked
536 * portions of a file.
537 *
538 * @author David Sugar <dyfet@ostel.com>
539 * @short This class defines a database I/O file service that can be shared by multiple processes.
540 */
541class __EXPORT SharedFile : public RandomFile
542{
543private:
544 fcb_t fcb;
545 Error open(const char *path);
546
547public:
548 /**
549 * Open or create a new database file. You should also use
550 * Initial.
551 *
552 * @param path pathname of database to open.
553 */
554 SharedFile(const char *path);
555
556 /**
557 * Create a shared file as a duplicate of an existing shared
558 * file.
559 *
560 * @param file original file.
561 */
562 SharedFile(const SharedFile &file);
563
564 /**
565 * Close and finish a database file.
566 */
567 virtual ~SharedFile();
568
569 /**
570 * Restart an existing database; close and re-open.
571 *
572 * @return errSuccess if successful.
573 */
574 Error restart(void)
575 {return open(pathname);};
576
577 /**
578 * Lock and Fetch a portion of the file into physical memory.
579 * This can use state information to fetch the current record
580 * multiple times.
581 *
582 * @return errSuccess on success.
583 * @param address address to use, or NULL if same as last I/O.
584 * @param length length to use, or 0 if same as last I/O.
585 * @param position file position to use -1 if same as last I/O.
586 */
587 Error fetch(caddr_t address = NULL, ccxx_size_t length = 0, off_t position = -1);
588
589 /**
590 * Update a portion of a file from physical memory. This can use
591 * state information to commit the last read record. The current
592 * lock is also cleared.
593 *
594 * @return errSuccess on success.
595 * @param address address to use, or NULL if same as last I/O.
596 * @param length length to use, or 0 if same as last I/O.
597 * @param position file position to use or -1 if same as last I/O.
598 */
599 Error update(caddr_t address = NULL, ccxx_size_t length = 0, off_t position = -1);
600
601 /**
602 * Clear a lock held from a previous fetch operation without
603 * updating.
604 *
605 * @return errSuccess on success.
606 * @param length length to use, or 0 if same as last I/O.
607 * @param pos file position to use or -1 if same as last I/O.
608 */
609 Error clear(ccxx_size_t length = 0, off_t pos = -1);
610
611 /**
612 * Add new data to the end of the file. Locks file during append.
613 *
614 * @param address address to use, or NULL if same as last I/O.
615 * @param length length to use, or 0 if same as last I/O.
616 */
617 Error append(caddr_t address = NULL, ccxx_size_t length = 0);
618
619 /**
620 * Fetch the current file position marker for this thread.
621 *
622 * @return file position offset.
623 */
624 off_t getPosition(void);
625
626 bool operator++(void);
627 bool operator--(void);
628};
629
630/**
631 * Create and map a disk file into memory. This portable class works
632 * under both Posix via mmap and under the win32 API. A mapped file
633 * can be referenced directly by it's memory segment. One can map
634 * and unmap portions of a file on demand, and update
635 * changed memory pages mapped from files immediately through sync().
636 *
637 * @author David Sugar <dyfet@ostel.com>
638 * @short Map a named disk file into memory.
639 */
640class __EXPORT MappedFile : public RandomFile
641{
642private:
643 fcb_t fcb;
644 int prot;
645#ifdef _MSWINDOWS_
646 HANDLE map;
647 char mapname[64];
648#endif
649
650public:
651 /**
652 * Open a file for mapping. More than one segment of a file
653 * may be mapped into seperate regions of memory.
654 *
655 * @param fname file name to access for mapping.
656 * @param mode access mode to map file.
657 */
658 MappedFile(const char *fname, Access mode);
659
660 /**
661 * Create if not exists, and map a file of specified size
662 * into memory.
663 *
664 * @param fname file name to access for mapping.
665 * @param mode access mode to map file.
666 * @param size of file to map.
667 */
668 MappedFile(const char *fname, Access mode, size_t size);
669
670 /**
671 * Map a portion or all of a specified file in the specified
672 * shared memory access mode. Valid mapping modes include
673 * mappedRead, mappedWrite, and mappedReadWrite.
674 *
675 * @param fname pathname of file to map into memory.
676 * @param offset from start of file to begin mapping in bytes.
677 * @param size of mapped area in bytes.
678 * @param mode to map file.
679 */
680 MappedFile(const char *fname, pos_t offset, size_t size, Access mode);
681
682 /**
683 * Release a mapped section of memory associated with a file. The
684 * mapped area is updated back to disk.
685 */
686 virtual ~MappedFile();
687
688 // FIXME: not use library function in header ??
689 /**
690 * Synchronize the contents of the mapped portion of memory with
691 * the disk file and wait for completion. This assures the memory
692 * mapped from the file is written back.
693 */
694 void sync(void);
695
696 /**
697 * Synchronize a segment of memory mapped from a segment fetch.
698 *
699 * @param address memory address to update.
700 * @param len size of segment.
701 */
702 void sync(caddr_t address, size_t len);
703
704 /**
705 * Map a portion of the memory mapped from the file back to the
706 * file and do not wait for completion. This is useful when mapping
707 * a database file and updating a single record.
708 *
709 * @param offset offset into the mapped region of memory.
710 * @param len length of partial region (example, record length).
711 */
712 void update(size_t offset = 0, size_t len = 0);
713
714 /**
715 * Update a mapped region back to disk as specified by address
716 * and length.
717 *
718 * @param address address of segment.
719 * @param len length of segment.
720 */
721 void update(caddr_t address, size_t len);
722
723 /**
724 * Release (unmap) a memory segment.
725 *
726 * @param address address of memory segment to release.
727 * @param len length of memory segment to release.
728 */
729 void release(caddr_t address, size_t len);
730
731 /**
732 * Fetch a pointer to an offset within the memory mapped portion
733 * of the disk file. This really is used for convience of matching
734 * operations between Update and Fetch, as one could simply have
735 * accessed the base pointer where the file was mapped directly.
736 *
737 * @param offset from start of mapped memory.
738 */
739 inline caddr_t fetch(size_t offset = 0)
740 {return ((char *)(fcb.address)) + offset;};
741
742 /**
743 * Fetch and map a portion of a disk file to a logical memory
744 * block.
745 *
746 * @return pointer to memory segment.
747 * @param pos offset of file segment to map.
748 * @param len size of memory segment to map.
749 */
750 caddr_t fetch(off_t pos, size_t len);
751
752 /**
753 * Lock the currently mapped portion of a file.
754 *
755 * @return true if pages are locked.
756 */
757 bool lock(void);
758
759 /**
760 * Unlock a locked mapped portion of a file.
761 */
762 void unlock(void);
763
764 /**
765 * Compute map size to aligned page boundry.
766 *
767 * @param size request.
768 * @return page aligned size.
769 */
770 size_t pageAligned(size_t size);
771};
772
773
774/**
775 * The DSO dynamic loader class is used to load object files. On
776 * elf based systems this is typically done with dlopen. A dummy
777 * stub class is generated for non-dl capable systems.
778 *
779 * @author David Sugar <dyfet@ostel.com>
780 * @short Dynamic class file loader.
781 */
782class __EXPORT DSO
783{
784private:
785 const char *err;
786 static Mutex mutex;
787 static DSO *first;
788 static DSO *last;
789 DSO *next, *prev;
790 const char *id;
791 void *image;
792
793 typedef ucommon::dso::addr_t addr_t;
794
795protected:
796 void loader(const char *filename, bool resolve);
797
798public:
799 /**
800 * Construct and load a DSO object file.
801 *
802 * @param filename pathname of object file to load.
803 */
804 DSO(const char *filename)
805 {loader(filename, true);};
806
807 DSO(const char *filename, bool resolve)
808 {loader(filename, resolve);};
809
810 /**
811 * Retrieve error indicator associated with DSO failure. This
812 * is often used in catch handlers.
813 */
814 inline const char *getError(void)
815 {return err;};
816
817 /**
818 * Detach a DSO object from running memory.
819 */
820 virtual ~DSO();
821
822 /**
823 * Lookup a symbol in the loaded file.
824 */
825 addr_t operator[](const char *sym);
826
827 static void dynunload(void);
828
829 /**
830 * Find a specific DSO object by filename.
831 *
832 * @param name of DSO object file (partial).
833 */
834 static DSO *getObject(const char *name);
835
836 /**
837 * See if DSO object is valid.
838 *
839 * @return true if valid.
840 */
841 bool isValid(void);
842
843 /**
844 * Install debug handler...
845 */
846 static void setDebug(void);
847};
848
849/** @relates RandomFile */
850bool __EXPORT isDir(const char *path);
851/** @relates RandomFile */
852bool __EXPORT isFile(const char *path);
853#ifndef WIN32
854/** @relates RandomFile */
855bool __EXPORT isDevice(const char *path);
856#else
857/** @relates RandomFile */
858inline bool isDevice(const char *path)
859{ return false; }
860#endif
861/** @relates RandomFile */
862bool __EXPORT canAccess(const char *path);
863/** @relates RandomFile */
864bool __EXPORT canModify(const char *path);
865/** @relates RandomFile */
866time_t __EXPORT lastModified(const char *path);
867/** @relates RandomFile */
868time_t __EXPORT lastAccessed(const char *path);
869
870#ifdef COMMON_STD_EXCEPTION
871
872class DirException : public IOException
873{
874public:
875 DirException(const String &str) : IOException(str) {};
876};
877
878class __EXPORT DSOException : public IOException
879{
880public:
881 DSOException(const String &str) : IOException(str) {};
882};
883
884class __EXPORT FileException : public IOException
885{
886public:
887 FileException(const String &str) : IOException(str) {};
888};
889
890#endif
891
892END_NAMESPACE
893
894#endif
895
896/** EMACS **
897 * Local variables:
898 * mode: c++
899 * c-basic-offset: 4
900 * End:
901 */