#ifndef _SECURITY_ATOMICFILE_H_
#define _SECURITY_ATOMICFILE_H_ 1
#include <security_utilities/refcount.h>
#include <Security/cssm.h>
#include <string>
#include <sys/stat.h>
namespace Security
{
class AtomicBufferedFile;
class AtomicLockedFile;
class AtomicTempFile;
class AtomicFile
{
public:
AtomicFile(const std::string &inPath);
~AtomicFile();
void performDelete();
void rename(const std::string &inNewPath);
RefPointer<AtomicTempFile> create(mode_t mode);
RefPointer<AtomicTempFile> write();
RefPointer<AtomicBufferedFile> read();
string path() const { return mPath; }
string dir() const { return mDir; }
string file() const { return mFile; }
string lockFileName() { return mLockFilePath; }
mode_t mode() const;
bool isOnLocalFileSystem() {return mIsLocalFileSystem;}
enum OffsetType
{
FromStart,
FromEnd };
static void pathSplit(const std::string &inFull, std::string &outDir, std::string &outFile);
static void mkpath(const std::string &inDir, mode_t mode = 0777);
static int ropen(const char *const name, int flags, mode_t mode);
static int rclose(int fd);
private:
bool mIsLocalFileSystem;
string mPath;
string mDir;
string mFile;
string mLockFilePath;
};
class AtomicBufferedFile : public RefCount
{
public:
AtomicBufferedFile(const std::string &inPath, bool isLocalFileSystem);
~AtomicBufferedFile();
off_t open();
const uint8 *read(off_t inOffset, off_t inLength, off_t &outLength);
mode_t mode();
void close();
off_t length() const { return mLength; }
private:
void loadBuffer();
void unloadBuffer();
private:
string mPath;
int mFileRef;
uint8 *mBuffer;
off_t mLength;
bool mIsMapped;
};
class AtomicTempFile : public RefCount
{
public:
AtomicTempFile(AtomicFile &inFile, const RefPointer<AtomicLockedFile> &inLockedFile, mode_t mode);
AtomicTempFile(AtomicFile &inFile, const RefPointer<AtomicLockedFile> &inLockedFile);
~AtomicTempFile();
void commit();
void write(AtomicFile::OffsetType inOffsetType, off_t inOffset, const uint32 *inData, uint32 inCount);
void write(AtomicFile::OffsetType inOffsetType, off_t inOffset, const uint8 *inData, size_t inLength);
void write(AtomicFile::OffsetType inOffsetType, off_t inOffset, const uint32 inData);
private:
void create(mode_t mode);
void fsync();
void close();
void rollback() throw();
private:
AtomicFile &mFile;
RefPointer<AtomicLockedFile> mLockedFile;
string mPath;
int mFileRef;
bool mCreating;
};
class FileLocker
{
public:
virtual ~FileLocker();
virtual void lock(mode_t mode) = 0;
virtual void unlock() = 0;
};
class LocalFileLocker : public FileLocker
{
public:
LocalFileLocker(AtomicFile &inFile);
virtual ~LocalFileLocker();
virtual void lock(mode_t mode);
virtual void unlock();
private:
int mLockFile;
string mPath;
};
class NetworkFileLocker : public FileLocker
{
public:
NetworkFileLocker(AtomicFile &inFile);
virtual ~NetworkFileLocker();
virtual void lock(mode_t mode);
virtual void unlock();
private:
std::string unique(mode_t mode);
int rlink(const char *const old, const char *const newn, struct stat &sto);
int myrename(const char *const old, const char *const newn);
int xcreat(const char *const name, mode_t mode, time_t &tim);
string mDir;
string mPath;
};
class AtomicLockedFile : public RefCount
{
public:
AtomicLockedFile(AtomicFile &inFile);
~AtomicLockedFile();
private:
void lock(mode_t mode = (S_IRUSR|S_IRGRP|S_IROTH) );
void unlock() throw();
private:
FileLocker* mFileLocker;
};
}
#endif // _SECURITY_ATOMICFILE_H_