// Copyright (C) 1999 Open Source Telecom Corporation.
//
// 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 to the GNU General Public License, permission is
// granted for additional uses of the text contained in its release
// of APE.
//
// The exception is that, if you link the APE library with other files
// to produce an executable, this does not by itself cause the
// resulting executable to be covered by the GNU General Public License.
// Your use of that executable is in no way restricted on account of
// linking the APE library code into it.
//
// 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 APE. If you copy code from other releases into a copy of
// APE, 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 APE, it is your choice
// whether to permit this exception to apply to your modifications.
// If you do not wish that, delete this exception notice.
#ifndef __APE_FILE_H__
#define __APE_FILE_H__
#ifndef __APE_THREAD_H__
#include <APE/thread.h>
#endif
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>
typedef unsigned long pos_t;
enum
{
FILE_OPEN_READONLY = O_RDONLY,
FILE_OPEN_WRITEONLY = O_WRONLY,
FILE_OPEN_READWRITE = O_RDWR,
FILE_OPEN_APPEND = O_WRONLY | O_APPEND,
#ifdef O_SYNC
FILE_OPEN_SYNC = O_RDWR | O_SYNC,
#else
FILE_OPEN_SYNC = O_RDWR,
#endif
FILE_OPEN_TRUNCATE = O_RDWR | O_TRUNC
};
enum
{
FILE_MAPPED_READ = O_RDONLY,
FILE_MAPPED_WRITE = O_WRONLY,
FILE_MAPPED_RDWR = O_RDWR
};
enum
{
FILE_PERM_PRIVATE = S_IRUSR | S_IWUSR,
FILE_PERM_GROUP = FILE_PERM_PRIVATE | S_IRGRP | S_IWGRP,
FILE_PERM_PUBLIC = FILE_PERM_GROUP | S_IROTH | S_IWOTH
};
/**
* The purpose of this class is to define a low level file access
* class that is portable between Win32 and Posix systems. In fact
* win32 lacks certain critical concepts related to multi-user file
* ownership and yet introduces some very odd concepts of cache control
* and configuration based on assumed application usage. These combine
* to make this and the other related portable file access classes a
* little odd, and certainly in need of further work.
*
* @author David Sugar <dyfet@ostel.com>
* @short Portable disk file access.
*/
class File
{
protected:
int _fd;
public:
/**
* Open an existing file of the given name with the given access
* mode. Valid access modes include FILE_OPEN_READONLY, FILE_OPEN_WRITEONLY,
* FILE_OPEN_APPEND, FILE_OPEN_READWRITE, FILE_OPEN_SYNC, and FILE_OPEN_TRUNCATE.
* A File "exception" is thrown if the file open fails.
*
* @param fname name of file path to open.
* @param access mode for access to the given file.
*/
File(const char *fname, int access);
/**
* Create a new file and access for use by the File class. Valid modes
* include FILE_OPEN_WRITEONLY, FILE_OPEN_APPEND, FILE_OPEN_SYNC,
* and FILE_OPEN_READWRITE. The most generic permissions for your
* newly created file include FILE_PERM_PRIVATE, FILE_PERM_GROUP, and
* FILE_PERM_PUBIC. On Posix systems, the standard chmod() permission
* values may be directly used, as well as the stat.h defines. As
* with all APE classes, an exception is thrown if the create fails.
*
* @param fname name of file path to create and open.
*/
File(const char *fname, int access, int perm);
/**
* Open a copy of an existing "File" through a duplicate object. This
* essentially uses the Posix dup() call to duplicate the file
* descriptor involved.
*
* @param f an existing File class to duplicate from.
*/
File(const File &f);
/**
* Create a File "class" to reference an existing and already open
* file descriptor. This is kind of like "fdopen" in purpose, and
* simply allows any existing file descriptor to be manipulated
* by the File methods.
*
* @param fd an existing and already open file descriptor.
*/
File(int fd);
/**
* The destructor normally closes the File descriptor and should
* also release any allocated resources in a derived class.
*/
virtual ~File()
{close(_fd);};
/**
* Read an arbitrary number of bytes from the File object.
*
* @return number of bytes read with success, or -1 on error.
* @param buf pointer to hold read data.
* @param len number of bytes to read.
*/
int Read(void *buf, size_t len)
{return read(_fd, (char *)buf, len);};
/**
* Write an arbitrary number of bytes to the File object.
*
* @return number of bytes written on success, -1 on error.
* @param buf pointer to data that will be written.
* @param len number of butes to write.
*/
int Write(void *buf, size_t len)
{return write(_fd, (char *)buf, len);};
/**
* A quick and easy way to write a null terminated C string to
* a file.
*
* @return number of bytes written on success, -1 on error.
* @param pointer to null terminated string to write to the file.
*/
int Write(char *buf)
{return write(_fd, buf, strlen(buf));};
/**
* Set the current file position. This is an absolute position
* from the start of the file.
*
* @return current file position after operation.
* @param pos new file position to set file to.
*/
pos_t Position(pos_t pos)
{return (pos_t)lseek(_fd, pos, SEEK_SET);};
/**
* Set the current file position to the end of the file.
*
* @return file position (length) of the end of the file.
*/
pos_t Append(void)
{return (pos_t)lseek(_fd, 0l, SEEK_END);};
File &operator=(const File &f);
friend int read(File &f, void *buf, size_t len)
{return read(f._fd, (char *)buf, len);};
friend int write(File &f, void *buf, size_t len)
{return write(f._fd, (char *)buf, len);};
friend int write(File &f, char *buf)
{return write(f._fd, buf, strlen(buf));};
friend pos_t append(File &f)
{return (pos_t)lseek(f._fd, 0l, SEEK_END);};
friend pos_t position(File &f, pos_t pos)
{return (pos_t)lseek(f._fd, pos, SEEK_SET);};
};
/**
* Create a new file always on the specified path. If a file already
* exists on the specified path name, it is removed.
*
* @author David Sugar <dyfet@ostel.com>
* @short create a new file pathname.
*/
class File.html">NewFile : public File
{
protected:
void Initial(char *fname, int perm)
{remove(fname);};
public:
NewFile(const char *fname, int access, int perms);
};
/**
* Create a new file as a FIFO device (named pipe) on the current
* file system and then opens it.
*
* @author David Sugar <dyfet@ostel.com>
* @short Create and open a named pipe.
*/
class NamedPipe : public File
{
protected:
void Initial(char *fname, int perm);
public:
NamedPipe(const char *fname, int perms);
};
/**
* 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.
*
* @author David Sugar
* @short map a named disk file into memory.
*/
class File.html">MappedFile : protected File
{
private:
size_t _len;
char *_mem;
public:
/**
* Map a portion or all of a specified file in the specified
* shared memory access mode. Valid mapping modes include
* FILE_MAPPED_READ, FILE_MAPPED_WRITE, and FILE_MAPPED_RDWR.
*
* @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, int mode);
/**
* Release a mapped section of memory associated with a file. The
* mapped area is updated back to disk.
*/
virtual ~MappedFile();
/**
* 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.
*/
inline void Sync(void)
{msync(_mem, _len, MS_SYNC);};
/**
* 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 into the mapped region of memory.
* @param len of partial region (example, record length).
*/
inline void Update(unsigned offset, size_t len)
{msync(_mem + offset, len, MS_ASYNC);};
/**
* 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 void *Fetch(unsigned offset)
{return _mem + offset;};
friend inline void sync(MappedFile &m)
{msync(m._mem, m._len, MS_SYNC);};
friend inline void update(MappedFile &m, unsigned offset, size_t len)
{msync(m._mem + offset, len, MS_ASYNC);};
friend inline void *fetch(MappedFile &m, unsigned offset = 0)
{return m._mem + offset;};
};
/**
* Locked files are presumed to be shared between different processes.
* File locks are used to protect file access and specifically defined
* operations which must occur exclusivily by a single process, such as
* for logical record locks in a database. Record locking is assumed
* to be a blocking operation.
*
* @author David Sugar <dyfet@ostel.com>
* @short shared file access between different processes.
*/
class File.html">LockedFile : protected File
{
public:
/**
* Open an existing and named data file that may be shared by
* multiple processes. Throw an exception if the file doesn't
* exist or cannot be accessed.
*
* @param fname path name of disk file to open.
* @param access access mode (read, write, or rdwr) to use.
* @see File#File
*/
LockedFile(const char *fname, int access);
/**
* Duplicate an existing locked file's descriptor, but do not
* duplicate any outstanding locks.
*
* @param f reference to another LockedFile.
*/
LockedFile(const LockedFile &f);
/**
* Release the locked file and any locks held by this object.
*/
~LockedFile()
{close(_fd);};
/**
* Recieve a lock from the end of the current file to inf and
* when successful write the specified data to the end. Upon
* completion, release the file lock.
*
* @return number of bytes written on success, -1 on error.
* @param buf pointer to data to write to the file.
* @param len number of bytes to write.
*/
int Append(void *buf, size_t len);
/**
* Request a lock for a portion of the datafile and then read
* the exclusivily locked portion of the file into memory.
*
* @return number of bytes read on success, -1 on error.
* @param pos offset to portion of file to read.
* @param buf pointer to memory to read data into.
* @param len number of bytes to read.
*/
int Request(pos_t pos, void *buf, size_t len);
/**
* Copy a presumably modified memory block back to a locked
* portion of a file as retrieved from a previous request, and
* then clear the file lock so that another process may now
* access that region. No check is made to assure the Update
* actually matches a previous Request.
*
* @return number of bytes written on success, -1 on error.
* @param pos offset to portion of file to write.
* @param buf pointer to memory to write data from.
* @param len number of bytes to write.
*/
int Update(pos_t pos, void *buf, size_t len);
/**
* Release a lock held from a request without modifying any
* data in the file so that another process may now access the
* locked region. No check is made to assure the Clear actually
* matches an existing Request.
*
* @return 0 on success, -1 on error.
* @param pos offset to portion of file that was locked.
* @param len number of bytes originally requested.
*/
int Clear(pos_t pos, size_t len);
};
/**
* Locked files provide clean access to a database file that is shared
* between multiple processes via file locking. A seperate and more
* efficient methodology is provided here to enable multiple threads to
* access the same file descriptor concurrently. While shared files do
* not include thread exclusive file region locking, such locking can be
* established with in memory based tables rather than kernel file locks
* for speed if needed.
*
* @author David Sugar <dyfet@ostel.com>
* @short Shared concurrent file access from multiple threads.
*/
class File.html">SharedFile : public File, public Mutex
{
public:
/**
* Create a new disk file that will be shared between multiple
* threads. A file name, access mode, and file permissions to
* use when creating a new file are specified. On failure an
* exception is thrown.
*
* @param fname path name of disk file to open or create.
* @param access file access mode.
* @param perm file permission to assign when creating a new file.
* @see File#File
*/
SharedFile(const char *fname, int access, int perm);
/**
* Open an existing disk file for shared access between multiple
* threads. A file name and file access mode must be specified.
* If the file does not exist or cannot be opened, an exception is
* thrown.
*
* @param fname path name of disk file to open.
* @param access file access mode.
*/
SharedFile(const char *fname, int access);
/**
* Open a copy of an existing "File" through a duplicate object for
* shared access from multiple threads. This essentially uses the
* Posix dup() call to duplicate the file descriptor involved.
*
* @param f an existing File class to duplicate from.
*/
SharedFile(const SharedFile &f);
/**
* Create a shared file "class" to reference an existing and already
* open file descriptor from multiple threads. This is kind of like
* "fdopen" in purpose, and simply allows any existing file descriptor
* to be manipulated by the thread shared methods.
*
* @param fd an existing and already open file descriptor.
*/
SharedFile(int fd);
/**
* Close the existing shared file object and release any used
* resources.
*/
~SharedFile()
{close(_fd);};
/**
* Write data to the end of a specified share file exclusivily.
* The mutex lock is used to assure the write operation is not
* interfered with by other threads until it completes.
*
* @return number of bytes written on success, -1 on failure.
* @param buf pointer to data to write to the file.
* @param len number of bytes to write.
*/
int Append(void *buf, size_t len);
/**
* Read data from a specified file offset exclusivily. The Mutex
* lock is used to assure the read operation can complete without
* interference by other threads. While the current file offset
* must be specified and tracked seperately by each thread on it's
* own, an enhanced version may soon use a ThreadKey for this purpose.
*
* @return number of bytes read on success, -1 on error.
* @param pos file offset to start read from file.
* @param buf pointer to store data read from file.
* @param len number of bytes to read.
*/
int Read(pos_t pos, void *buf, size_t len);
/**
* Write data to a specified file offset exclusivily. The Mutex
* lock is used to assure the write operation can complete without
* interference by other threads. While the current file offset
* must be specified and tracked seperately by each thread on it's
* own, an enhanced version may soon use a ThreadKey for this purpose.
*
* @return number of bytes written on success, -1 on error.
* @param pos file offset to start file write.
* @param buf pointer to data to write to the file.
* @param len number of bytes to write.
*/
int Write(pos_t pos, void *buf, size_t len);
SharedFile &operator=(SharedFile &f);
friend inline int read(SharedFile &f, pos_t pos, void *buf, size_t len)
{return f.Read(pos, buf, len);};
friend inline int write(SharedFile &f, pos_t pos, void *buf, size_t len)
{return f.Write(pos, buf, len);};
friend inline int append(SharedFile &f, void *buf, size_t len)
{return f.Append(buf, len);};
};
inline int clear(LockedFile &f, pos_t pos, size_t len)
{return f.Clear(pos, len);};
inline int append(LockedFile &f, void *buf, size_t len)
{return f.Append(buf, len);};
inline int request(LockedFile &f, pos_t pos, void *buf, size_t len)
{return f.Request(pos, buf, len);};
inline int update(LockedFile &f, pos_t pos, void *buf, size_t len)
{return f.Update(pos, buf, len);};
#endif
Documentation generated by dyfet@home.sys on Thu Dec 16 09:54:26 EST 1999