// Copyright (C) 1999-2005 Open Source Telecom Corporation.
// Copyright (C) 2006-2008 David Sugar, Tycho Softworks.
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// As a special exception, you may use this file as part of a free software
// library without restriction.  Specifically, if other files instantiate
// templates or use macros or inline functions from this file, or you compile
// this file and link it with other files to produce an executable, this
// file does not by itself cause the resulting executable to be covered by
// the GNU General Public License.  This exception does not however
// invalidate any other reasons why the executable file might be covered by
// the GNU General Public License.
//
// This exception applies only to the code released under the name GNU
// Common C++.  If you copy code from other releases into a copy of GNU
// Common C++, as the General Public License permits, the exception does
// not apply to the code that you add in this way.  To avoid misleading
// anyone as to the status of such modified files, you must delete
// this exception notice from them.
//
// If you write modifications of your own for GNU Common C++, it is your choice
// whether to permit this exception to apply to your modifications.
// If you do not wish that, delete this exception notice.
//

/**
 * @file file.h
 * @short Files and dynamic loader services.
 **/

#ifndef	CCXX_FILE_H_
#define	CCXX_FILE_H_

#ifndef CCXX_CONFIG_H_
#include <cc++/config.h>
#endif

#ifndef CCXX_MISSING_H_
#include <cc++/missing.h>
#endif

#ifndef	CCXX_THREAD_H_
#include <cc++/thread.h>
#endif

#ifndef	CCXX_EXCEPTION_H_
#include <cc++/exception.h>
#endif

#ifndef WIN32
# ifdef __BORLANDC__
#  include <stdio.h>
#  include <sys/types.h>
# else
#  include <cstdio>
# endif
# include <dirent.h>
# include <sys/stat.h>
# include <sys/mman.h>
#else
# if __BORLANDC__ >= 0x0560
#  include <dirent.h>
#  include <sys/stat.h>
# else
#  include <direct.h>
# endif
#endif

#ifdef	HAVE_SHL_LOAD
#include <dl.h>
#endif

#ifdef  HAVE_MACH_DYLD
#include <mach-o/dyld.h>
#endif

#ifdef	CCXX_NAMESPACES
namespace ost {
#endif

typedef	unsigned long pos_t;
#ifndef WIN32
// use a define so that if the sys/types.h header already defines caddr_t
// as it may on BSD systems, we do not break it by redefining again.
#undef  caddr_t
#define	caddr_t	char *
typedef size_t ccxx_size_t;
#else
#if	!defined(__BORLANDC__) || __BORLANDC__ >= 0x0560
typedef LONG off_t;
#endif
typedef void* caddr_t;
typedef DWORD ccxx_size_t;
#endif

#ifndef	PATH_MAX
#define	PATH_MAX	256
#endif

#ifndef	NAME_MAX
#define	NAME_MAX	64
#endif

class __EXPORT File
{
public:
	enum Error {
		errSuccess = 0,
		errNotOpened,
		errMapFailed,
		errInitFailed,
		errOpenDenied,
		errOpenFailed,
		errOpenInUse,
		errReadInterrupted,
		errReadIncomplete,
		errReadFailure,
		errWriteInterrupted,
		errWriteIncomplete,
		errWriteFailure,
		errLockFailure,
		errExtended
	};
	typedef enum Error Error;

	enum Access {
#ifndef WIN32
		accessReadOnly = O_RDONLY,
		accessWriteOnly= O_WRONLY,
		accessReadWrite = O_RDWR
#else
		accessReadOnly = GENERIC_READ,
		accessWriteOnly = GENERIC_WRITE,
		accessReadWrite = GENERIC_READ | GENERIC_WRITE
#endif
	};
	typedef enum Access Access;

protected:
	typedef struct _fcb {
		struct _fcb *next;
		caddr_t address;
		ccxx_size_t len;
		off_t pos;
		bool locked;
	} fcb_t;

public:
#ifdef	WIN32
	enum Open {
		openReadOnly, // = FILE_OPEN_READONLY,
		openWriteOnly, // = FILE_OPEN_WRITEONLY,
		openReadWrite, // = FILE_OPEN_READWRITE,
		openAppend, // = FILE_OPEN_APPEND,
		openTruncate // = FILE_OPEN_TRUNCATE
	};
	#else
	enum Open {
		openReadOnly = O_RDONLY,
		openWriteOnly = O_WRONLY,
		openReadWrite = O_RDWR,
		openAppend = O_WRONLY | O_APPEND,
#ifdef	O_SYNC
		openSync = O_RDWR | O_SYNC,
#else
		openSync = O_RDWR,
#endif
		openTruncate = O_RDWR | O_TRUNC
	};
	typedef enum Open Open;

/* to be used in future */

#ifndef	S_IRUSR
#define	S_IRUSR	0400
#define	S_IWUSR 0200
#define	S_IRGRP 0040
#define	S_IWGRP 0020
#define	S_IROTH 0004
#define	S_IWOTH	0002
#endif

#endif // !WIN32

#ifndef WIN32
	enum Attr {
		attrInvalid = 0,
		attrPrivate = S_IRUSR | S_IWUSR,
		attrGroup = attrPrivate | S_IRGRP | S_IWGRP,
		attrPublic = attrGroup | S_IROTH | S_IWOTH
	};
	#else // defined WIN32
	enum Attr {
		attrInvalid=0,
		attrPrivate,
		attrGroup,
		attrPublic
	};
#endif // !WIN32
	typedef enum Attr Attr;

#ifdef	WIN32
	enum Complete {
		completionImmediate, // = FILE_COMPLETION_IMMEDIATE,
		completionDelayed, // = FILE_COMPLETION_DELAYED,
		completionDeferred // = FILE_COMPLETION_DEFERRED
	};

	enum Mapping {
		mappedRead,
		mappedWrite,
		mappedReadWrite
	};
#else
	enum Mapping {
		mappedRead = accessReadOnly,
		mappedWrite = accessWriteOnly,
		mappedReadWrite = accessReadWrite
	};
	enum Complete {
		completionImmediate,
		completionDelayed,
		completionDeferred
	};
#endif
	typedef enum Complete Complete;
	typedef enum Mapping Mapping;

public:
	static const char *getExtension(const char *path);
	static const char *getFilename(const char *path);
	static char *getFilename(const char *path, char *buffer, size_t size = NAME_MAX);
	static char *getDirname(const char *path, char *buffer, size_t size = PATH_MAX);
	static char *getRealpath(const char *path, char *buffer, size_t size = PATH_MAX);
};

/**
 * A low level portable directory class.  Used to support ccstd Directory
 * container.  This provides a basic mechanism for allocating and
 * accessing file entries.
 *
 * @author David Sugar <dyfet@ostel.com>
 * @short low level directory access class.
 */
class __EXPORT Dir : public File
{
private:
#ifndef WIN32
	DIR *dir;
#ifdef	HAVE_READDIR_R
	struct dirent *save;
	char save_space[sizeof(struct dirent) + PATH_MAX + 1];
#endif
	struct dirent *entry;
#else
	HANDLE hDir;
	WIN32_FIND_DATA data, fdata;
	char *name;
#endif

public:
	Dir(const char *name = NULL);

	static bool create(const char *path, Attr attr = attrGroup);
	static bool remove(const char *path);
	static bool setPrefix(const char *path);
	static bool getPrefix(char *path, size_t size = PATH_MAX);

	void open(const char *name);
	void close(void);

	virtual ~Dir();

	const char *getName(void);

	const char *operator++()
		{return getName();};

	const char *operator++(int)
		{return getName();};

	const char *operator*();

	bool rewind(void);

	bool operator!()
#ifndef WIN32
		{return !dir;};
#else
		{return hDir != INVALID_HANDLE_VALUE;};
#endif

	bool isValid(void);
};

/**
 * A generic class to walk a hierarchical directory structure.
 *
 * @author David Sugar <dyfet@ostel.com>
 * @short Directory tree walking.
 */
class __EXPORT	DirTree
{
private:
	char path[PATH_MAX + 1];
	Dir *dir;
	unsigned max, current, prefixpos;

protected:
	/**
	 * Virtual method to filter results.  Virtual override methods
	 * should call baseclass method to assure . and .. names are
	 * stripped out.
	 *
	 * @return true if current filename is accepted.
	 * @param file path to examine
	 * @param ino info of type, date, etc.
	 */
	virtual bool filter(const char *file, struct stat *ino);

public:
	/**
	 * Construct a directory tree walk starting at the specified
	 * prefix.  A maximum subdirectory depth is also specified.
	 *
	 * @param prefix to start walk.
	 * @param maxdepth subdirectory depth to examine.
	 */
	DirTree(const char *prefix, unsigned maxdepth);

	/**
	 * Construct an un-opened directory tree of a known maximum depth
	 *
	 * @param maxdepth subdirectory subdirectory depth.
 	 */
	DirTree(unsigned maxdepth);

	virtual ~DirTree();

	/**
	 * Open a directory tree path.
	 *
	 * @param prefix directory path to open.
	 */
	void open(const char *prefix);

	/**
	 * Close the directory path.
	 */
	void close(void);

	/**
	 * Extract the next full pathname from the directory walk.
	 * When returning directories, a '/' is appended.  The
	 * returned string is a buffer of MAX_PATH size.
	 *
	 * @return path of next subdirectory entry or NULL.
	 */
	char *getPath(void);

	/**
	 * This is used to step through the filter virtual for an
	 * entire subtree, and is used for cases where a derived
	 * DirTree class performs it's primary operations through
	 * filter rather than externally by calling getPath().
	 *
	 * @return number of files and directories examined.
	 * @param prefix directory path to examine.
	 */
	unsigned perform(const char *prefix);
};

/**
 * The purpose of this class is to define a base class for low level
 * random file access that is portable between Win32 and Posix systems.
 * This class is a foundation both for optimized thread shared and
 * traditional locked file access that is commonly used to build
 * database services, rather than the standard C++ streaming file classes.
 *
 * @author David Sugar <dyfet@ostel.com>
 * @short Portable random disk file access.
 */
class __EXPORT RandomFile : protected Mutex, public File
{
private:
	Error errid;
	char *errstr;

protected:
#ifndef WIN32
	int fd;
	// FIXME: WIN32 as no access member
	Access access;
#else
	HANDLE fd;
#endif
	char *pathname;

	struct {
		unsigned count : 16;
		bool thrown : 1;
		bool initial : 1;
#ifndef WIN32
		bool immediate : 1;
#endif
		bool temp : 1;
	} flags;

	/**
	 * Create an unopened random access file.
	 */
	RandomFile(const char *name = NULL);

	/**
	 * Default copy constructor.
	 */
	RandomFile(const RandomFile &rf);

	/**
	 * Post an error event.
	 *
	 * @return error code.
	 * @param errid error code.
	 * @param errstr error message string.
	 */
	Error error(Error errid, char *errstr = NULL);

	/**
	 * Post an extended string error message.
	 *
	 * @return errExtended.
	 * @param err error string.
	 */
	inline Error error(char *err)
		{return error(errExtended, err);};

	/**
	 * Used to enable or disable throwing of exceptions on
	 * errors.
	 *
	 * @param enable true if errors will be thrown.
	 */
	inline void setError(bool enable)
		{flags.thrown = !enable;};

#ifndef WIN32
	/**
	 * Used to set file completion modes.
	 *
	 * @return errSuccess if okay.
	 * @param mode completion mode.
	 * @todo implement in win32
	 */
	Error setCompletion(Complete mode);
#endif

	/**
	 * Used to set the temporary attribute for the file.  Temporary
	 * files are automatically deleted when closed.
	 *
	 * @param enable true for marking as temporary.
	 */
	inline void setTemporary(bool enable)
		{flags.temp = enable;};

	/**
	 * This method is used to initialize a newly created file as
	 * indicated by the "initial" flag.  This method also returns
	 * the file access permissions that should be associated with
	 * the file.  This method should never be called directly, but
	 * is instead used to impliment the "Initial" method.  Typically
	 * one would use this to build an empty database shell when a
	 * previously empty database file is created.
	 *
	 * @return access, or attrInvalid if should be removed.
	 */
	virtual Attr initialize(void);

	/**
	 * Close the file.
	 */
	void final(void);

public:
	/**
	 * Destroy a random access file or it's derived class.
	 */
	virtual ~RandomFile();

	/**
	 * This method should be called right after a RandomFile derived
	 * object has been created.  This method will invoke initialize
	 * if the object is newly created, and set file access permissions
	 * appropriately.
	 *
	 * @return true if file had to be initialized.
	 */
	bool initial(void);

	/**
	 * Get current file capacity.
	 *
	 * @return total file size.
	 */
	off_t getCapacity(void);

	/**
	 * This method is commonly used to close and re-open an existing
	 * database.  This may be used when the database has been unlinked
	 * and an external process provides a new one to use.
	 */
	virtual Error restart(void);

	/**
	 * Return current error id.
	 *
	 * @return last error identifier set.
	 */
	inline Error getErrorNumber(void)
		{return errid;};

	/**
	 * Return current error string.
	 *
	 * @return last error string set.
	 */
	inline char *getErrorString(void)
		{return errstr;};

	bool operator!(void);
};

/**
 * This class defines a database I/O file service that can be shared
 * by multiple threads.  All threads access a global copy of the database
 * object, and mutex locks can be used to preserve transaction
 * integrety.  pread/pwrite calls can be used for optimized I/O when
 * supported.
 *
 * ThreadFile is meant for use by a threaded database server where multiple
 * threads may each perform semi-independent operations on a given database
 * table stored on disk.  A special "fcb" structure is used to hold file
 * "state", and pread/pwrite is used whenever possible for optimized I/O.  On
 * systems that do not offer pwread/pwrite, a Mutex lock is used to protect
 * concurrent lseek and read/write operations.  ThreadFile managed databases
 * are assumed to be used only by the local server and through a single file
 * descriptor.
 *
 * @author David Sugar <dyfet@ostel.com>
 * @short This class defines a database I/O file service that can be shared by multiple threads.
 */
class __EXPORT ThreadFile : public RandomFile
{
private:
	ThreadKey state;
	fcb_t *first;
	fcb_t *getFCB(void);
	Error open(const char *path);

public:
	/**
	 * Open or create a new database file.  You should also use
	 * Initial.
	 *
	 * @param path pathname of database to open.
	 */
	ThreadFile(const char *path);

	/**
	 * Close and finish a database file.
	 */
	virtual ~ThreadFile();

	/**
	 * Restart an existing database; close and re-open.
	 *
	 * @return errSuccess if successful.
	 */
	Error restart(void);

	/**
	 * Fetch a portion of the file into physical memory.  This can use
	 * state information to fetch the current record multiple times.
	 *
	 * @return errSuccess on success.
	 * @param address  address to use, or NULL if same as last I/O.
	 * @param length   length to use, or 0 if same as last I/O.
	 * @param position file position to use -1 if same as last I/O.
	 */
	Error fetch(caddr_t address = NULL, ccxx_size_t length = 0, off_t position = -1);

	/**
	 * Update a portion of a file from physical memory.  This can use
	 * state information to commit the last read record.
	 *
	 * @return errSuccess on success.
	 * @param address  address to use, or NULL if same as last I/O.
	 * @param length   length to use, or 0 if same as last I/O.
	 * @param position file position to use or -1 if same as last I/O.
	 */
	Error update(caddr_t address = NULL, ccxx_size_t length = 0, off_t position = -1);

	/**
	 * Add new data to the end of the file.
	 * @param address address to use, or NULL if same as last I/O.
	 * @param length  length to use, or 0 if same as last I/O.
	 */
	Error append(caddr_t address = NULL, ccxx_size_t length = 0);

	/**
	 * Fetch the current file position marker for this thread.
	 *
	 * @return file position offset.
	 */
	off_t getPosition(void);

	bool operator++(void);
	bool operator--(void);
};

/**
 * This class defines a database I/O file service that can be shared
 * by multiple processes.  Each thread should access a dup of the database
 * object, and mutex locks can be used to preserve transaction
 * integrety if multiple threads are used.
 *
 * SharedFile is used when a database may be shared between multiple
 * processes.  SharedFile automatically applies low level byte-range "file
 * locks", and provides an interface to fetch and release byte-range locked
 * portions of a file.
 *
 * @author David Sugar <dyfet@ostel.com>
 * @short This class defines a database I/O file service that can be shared by multiple processes.
 */
class __EXPORT SharedFile : public RandomFile
{
private:
	fcb_t fcb;
	Error open(const char *path);

public:
	/**
	 * Open or create a new database file.  You should also use
	 * Initial.
	 *
	 * @param path pathname of database to open.
	 */
	SharedFile(const char *path);

	/**
	 * Create a shared file as a duplicate of an existing shared
	 * file.
	 *
	 * @param file original file.
	 */
	SharedFile(const SharedFile &file);

	/**
	 * Close and finish a database file.
	 */
	virtual ~SharedFile();

	/**
	 * Restart an existing database; close and re-open.
	 *
	 * @return errSuccess if successful.
	 */
	Error restart(void)
		{return open(pathname);};

	/**
	 * Lock and Fetch a portion of the file into physical memory.
	 * This can use state information to fetch the current record
	 * multiple times.
	 *
	 * @return errSuccess on success.
	 * @param address  address to use, or NULL if same as last I/O.
	 * @param length   length to use, or 0 if same as last I/O.
	 * @param position file position to use -1 if same as last I/O.
	 */
	Error fetch(caddr_t address = NULL, ccxx_size_t length = 0, off_t position = -1);

	/**
	 * Update a portion of a file from physical memory.  This can use
	 * state information to commit the last read record.  The current
	 * lock is also cleared.
	 *
	 * @return errSuccess on success.
	 * @param address  address to use, or NULL if same as last I/O.
	 * @param length   length to use, or 0 if same as last I/O.
	 * @param position file position to use or -1 if same as last I/O.
	 */
	Error update(caddr_t address = NULL, ccxx_size_t length = 0, off_t position = -1);

	/**
	 * Clear a lock held from a previous fetch operation without
	 * updating.
	 *
	 * @return errSuccess on success.
	 * @param length length to use, or 0 if same as last I/O.
	 * @param pos    file position to use or -1 if same as last I/O.
	 */
	Error clear(ccxx_size_t length = 0, off_t pos = -1);

	/**
	 * Add new data to the end of the file.  Locks file during append.
	 *
	 * @param address address to use, or NULL if same as last I/O.
	 * @param length  length to use, or 0 if same as last I/O.
	 */
	Error append(caddr_t address = NULL, ccxx_size_t length = 0);

	/**
	 * Fetch the current file position marker for this thread.
	 *
	 * @return file position offset.
	 */
	off_t getPosition(void);

	bool operator++(void);
	bool operator--(void);
};

/**
 * Create and map a disk file into memory.  This portable class works
 * under both Posix via mmap and under the win32 API. A mapped file
 * can be referenced directly by it's memory segment. One can map
 * and unmap portions of a file on demand, and update
 * changed memory pages mapped from files immediately through sync().
 *
 * @author David Sugar <dyfet@ostel.com>
 * @short Map a named disk file into memory.
 */
class __EXPORT MappedFile : public RandomFile
{
private:
	fcb_t fcb;
	int prot;
#ifdef	WIN32
	HANDLE map;
	char mapname[64];
#endif

public:
	/**
	 * Open a file for mapping.  More than one segment of a file
	 * may be mapped into seperate regions of memory.
	 *
	 * @param fname file name to access for mapping.
	 * @param mode  access mode to map file.
	 */
	MappedFile(const char *fname, Access mode);

	/**
	 * Create if not exists, and map a file of specified size
	 * into memory.
	 *
	 * @param fname file name to access for mapping.
	 * @param mode access mode to map file.
	 * @param size of file to map.
	 */
	MappedFile(const char *fname, Access mode, size_t size);

	/**
	 * Map a portion or all of a specified file in the specified
	 * shared memory access mode.  Valid mapping modes include
	 * mappedRead, mappedWrite, and mappedReadWrite.
	 *
	 * @param fname pathname of file to map into memory.
	 * @param offset from start of file to begin mapping in bytes.
	 * @param size of mapped area in bytes.
	 * @param mode to map file.
	 */
	MappedFile(const char *fname, pos_t offset, size_t size, Access mode);

	/**
	 * Release a mapped section of memory associated with a file.  The
	 * mapped area is updated back to disk.
	 */
	virtual ~MappedFile();

	// FIXME: not use library function in header ??
	/**
	 * Synchronize the contents of the mapped portion of memory with
	 * the disk file and wait for completion.  This assures the memory
	 * mapped from the file is written back.
	 */
	void sync(void);

	/**
	 * Synchronize a segment of memory mapped from a segment fetch.
	 *
	 * @param address memory address to update.
	 * @param len size of segment.
	 */
	void sync(caddr_t address, size_t len);

	/**
	 * Map a portion of the memory mapped from the file back to the
	 * file and do not wait for completion.  This is useful when mapping
	 * a database file and updating a single record.
	 *
	 * @param offset offset into the mapped region of memory.
	 * @param len length of partial region (example, record length).
	 */
	void update(size_t offset = 0, size_t len = 0);

	/**
	 * Update a mapped region back to disk as specified by address
	 * and length.
	 *
	 * @param address address of segment.
	 * @param len length of segment.
	 */
	void update(caddr_t address, size_t len);

	/**
	 * Release (unmap) a memory segment.
	 *
	 * @param address address of memory segment to release.
	 * @param len length of memory segment to release.
	 */
	void release(caddr_t address, size_t len);

	/**
	 * Fetch a pointer to an offset within the memory mapped portion
	 * of the disk file.  This really is used for convience of matching
	 * operations between Update and Fetch, as one could simply have
	 * accessed the base pointer where the file was mapped directly.
	 *
	 * @param offset from start of mapped memory.
	 */
	inline caddr_t fetch(size_t offset = 0)
		{return ((char *)(fcb.address)) + offset;};

	/**
	 * Fetch and map a portion of a disk file to a logical memory
	 * block.
	 *
	 * @return pointer to memory segment.
	 * @param pos offset of file segment to map.
	 * @param len size of memory segment to map.
	 */
	caddr_t fetch(off_t pos, size_t len);

	/**
	 * Lock the currently mapped portion of a file.
	 *
	 * @return true if pages are locked.
	 */
	bool lock(void);

	/**
	 * Unlock a locked mapped portion of a file.
	 */
	void unlock(void);

	/**
	 * Compute map size to aligned page boundry.
	 *
	 * @param size request.
	 * @return page aligned size.
	 */
	size_t pageAligned(size_t size);
};


/**
 * The DSO dynamic loader class is used to load object files.  On
 * elf based systems this is typically done with dlopen.  A dummy
 * stub class is generated for non-dl capable systems.
 *
 * @author David Sugar <dyfet@ostel.com>
 * @short Dynamic class file loader.
 */
class __EXPORT DSO
{
private:
	const char *err;
#ifdef	HAVE_MODULES
	static Mutex mutex;
	static DSO *first;
	static DSO *last;
	DSO *next, *prev;
	const char *id;
#if	defined(HAVE_MACH_DYLD)
	NSModule oModule;
#elif   defined(HAVE_SHL_LOAD)
	shl_t image;
#elif	defined(WIN32)
	HINSTANCE hImage;
#else
	void *image;
#endif
	void loader(const char *filename, bool resolve);
#endif

public:
	/**
	 * Construct and load a DSO object file.
	 *
	 * @param filename pathname of object file to load.
	 */
#ifdef	HAVE_MODULES
	DSO(const char *filename)
		{loader(filename, true);};

	DSO(const char *filename, bool resolve)
		{loader(filename, resolve);};
#else
	DSO(const char *filename)
		{throw this;};
	DSO(const char *filename, bool resolve)
		{throw this;};
#endif

	/**
	 * Retrieve error indicator associated with DSO failure.  This
	 * is often used in catch handlers.
	 */
	inline const char *getError(void)
		{return err;};

	/**
	 * Detach a DSO object from running memory.
	 */
#ifdef	HAVE_MODULES
	virtual ~DSO();
#endif

	/**
	 * Lookup a symbol in the loaded file.
	 */
#ifdef	HAVE_MODULES
	void* operator[](const char *sym);
#else
	void *operator[](const char *)
		{return NULL;};
#endif

#ifdef	HAVE_MODULES
	static void dynunload(void);
#else
	static void dynunload(void)
		{return;};
#endif

	/**
	 * Find a specific DSO object by filename.
	 *
	 * @param name of DSO object file (partial).
	 */
	static DSO *getObject(const char *name);

	/**
	 * See if DSO object is valid.
	 *
	 * @return true if valid.
	 */
	bool isValid(void);

	/**
	 * Install debug handler...
	 */
	static void setDebug(void);
};

/** @relates RandomFile */
bool __EXPORT isDir(const char *path);
/** @relates RandomFile */
bool __EXPORT isFile(const char *path);
#ifndef WIN32
/** @relates RandomFile */
bool __EXPORT isDevice(const char *path);
#else
/** @relates RandomFile */
inline bool isDevice(const char *path)
{ return false; }
#endif
/** @relates RandomFile */
bool __EXPORT canAccess(const char *path);
/** @relates RandomFile */
bool __EXPORT canModify(const char *path);
/** @relates RandomFile */
time_t __EXPORT lastModified(const char *path);
/** @relates RandomFile */
time_t __EXPORT lastAccessed(const char *path);

#ifdef	COMMON_STD_EXCEPTION

class DirException : public IOException
{
public:
	DirException(const String &str) : IOException(str) {};
};

class __EXPORT DSOException : public IOException
{
public:
	DSOException(const String &str) : IOException(str) {};
};

class __EXPORT FileException : public IOException
{
public:
	FileException(const String &str) : IOException(str) {};
};

#endif

#ifdef	CCXX_NAMESPACES
}
#endif

#endif

/** EMACS **
 * Local variables:
 * mode: c++
 * c-basic-offset: 8
 * End:
 */
