#ifndef _H_ATOMICFILE
#define _H_ATOMICFILE
#include <Security/threading.h>
#include <map>
#include <string>
#if _USE_IO == _USE_IO_POSIX
#include <sys/types.h>
#include <machine/endian.h>
#elif _USE_IO == _USE_IO_MACOS
#define htonl(X) (X)
#define ntohl(X) (X)
#endif
#ifdef _CPP_ATOMICFILE
#pragma export on
#endif
namespace Security
{
class DbName;
class AtomicFile
{
public:
typedef int FileRef;
typedef int VersionId;
AtomicFile(const DbName &inDbName);
~AtomicFile();
void close();
VersionId enterRead(const uint8 *&outFileAddress, size_t &outLength);
void exitRead(VersionId inVersionId);
bool isDirty(VersionId inVersionId);
void performDelete();
VersionId enterCreate(FileRef &outWriteRef);
VersionId enterWrite(const uint8 *&outFileAddress, size_t &outLength, FileRef &outWriteRef);
VersionId commit();
void rollback();
enum OffsetType {
None,
FromStart,
FromCurrent
};
void write(OffsetType inOffsetType, uint32 inOffset, const uint32 *inData, uint32 inCount);
void write(OffsetType inOffsetType, uint32 inOffset, const uint8 *inData, uint32 inLength);
void write(OffsetType inOffsetType, uint32 inOffset, const uint32 inData);
const string filename() const { return mReadFilename; }
private:
void endWrite();
void rename(const string &inSrcFilename, const string &inDestFilename);
void unlink(const string &inFilename);
class OpenFile
{
public:
OpenFile(const std::string &inFilename, bool write, bool lock, VersionId inVersionId, mode_t mode);
~OpenFile();
void close();
VersionId versionId() const { return mVersionId; }
FileRef fileRef() const { return mFileRef; }
const uint8 *address() const { return mAddress; }
size_t length() const { return mLength; }
bool isDirty();
void setDirty();
void lock();
void unlock();
mode_t mode();
int mUseCount;
FileRef mFileRef;
private:
VersionId readVersionId();
void writeVersionId(VersionId inVersionId);
static void mkpath(const std::string &inFilename);
VersionId mVersionId;
const uint8 *mAddress;
size_t mLength;
bool mFcntlLock;
enum
{
Closed,
Read,
Write,
ReadWrite,
Create
} mState;
};
Mutex mReadLock;
OpenFile *mReadFile;
string mReadFilename;
Mutex mWriteLock;
OpenFile *mWriteFile;
string mWriteFilename;
typedef std::map<VersionId, OpenFile *> OpenFileMap;
OpenFileMap mOpenFileMap;
bool mCreating;
};
class AtomicFileRef
{
public:
virtual ~AtomicFileRef();
uint32 at(uint32 inOffset)
{
return ntohl(*reinterpret_cast<const uint32 *>(mAddress + inOffset));
}
uint32 operator[](uint32 inOffset)
{
if (inOffset + sizeof(uint32) > mLength)
CssmError::throwMe(CSSMERR_DL_DATABASE_CORRUPT);
return at(inOffset);
}
const uint8 *range(uint32 inOffset, uint32 inLength)
{
if (inOffset + inLength > mLength)
CssmError::throwMe(CSSMERR_DL_DATABASE_CORRUPT);
return mAddress + inOffset;
}
const AtomicFile::VersionId mVersionId;
protected:
struct InitArg;
AtomicFileRef(AtomicFile &inAtomicFile, const InitArg &inInitArg);
AtomicFile &mAtomicFile;
const uint8 *mAddress;
const size_t mLength;
};
class AtomicFileReadRef : public AtomicFileRef
{
public:
AtomicFileReadRef(AtomicFile &inAtomicFile);
virtual ~AtomicFileReadRef();
private:
static InitArg enterRead(AtomicFile &inAtomicFile);
};
class AtomicFileWriteRef : public AtomicFileRef
{
public:
AtomicFileWriteRef(AtomicFile &inAtomicFile);
virtual ~AtomicFileWriteRef();
AtomicFile::VersionId commit() { mOpen = false; return mAtomicFile.commit(); }
private:
static InitArg enterWrite(AtomicFile &inAtomicFile, AtomicFile::FileRef &outWriteFileRef);
AtomicFile::FileRef mFileRef;
bool mOpen;
};
}
#ifdef _CPP_ATOMICFILE
#pragma export off
#endif
#endif //_H_ATOMICFILE