]> git.saurik.com Git - apple/security.git/blob - cdsa/cdsa_utilities/AtomicFile.h
Security-30.1.tar.gz
[apple/security.git] / cdsa / cdsa_utilities / AtomicFile.h
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18
19 //
20 // AtomicFile.h - Description t.b.d.
21 //
22 #ifndef _H_ATOMICFILE
23 #define _H_ATOMICFILE
24
25 #include <Security/threading.h>
26
27 #include <map>
28 #include <string>
29
30 #if _USE_IO == _USE_IO_POSIX
31 #include <sys/types.h>
32 #include <machine/endian.h>
33 #elif _USE_IO == _USE_IO_MACOS
34 #define htonl(X) (X)
35 #define ntohl(X) (X)
36 #endif
37
38 #ifdef _CPP_ATOMICFILE
39 #pragma export on
40 #endif
41
42 namespace Security
43 {
44
45 class DbName;
46
47 class AtomicFile
48 {
49 public:
50 typedef int FileRef;
51 typedef int VersionId;
52
53 AtomicFile(const DbName &inDbName);
54 ~AtomicFile();
55
56 // Close the currently open AtomicFile. (If there are transactions outstanding this call
57 // has no effect until after they have completed.
58 void close();
59
60 // Start a read operation. Returns a mmaped region with the file in it. Return the size of the
61 // file in length. Each call to enterRead() *must* be paired with a call to exitRead.
62 VersionId enterRead(const uint8 *&outFileAddress, size_t &outLength);
63
64 // End a read operation.
65 void exitRead(VersionId inVersionId);
66
67 // Return true if inVersionId is not the most recent version of this file.
68 bool isDirty(VersionId inVersionId);
69
70 // Aquire the write lock and remove the file.
71 void performDelete();
72
73 // Create and lock the database file for writing, and set outWriteRef to a newly created
74 // file open for writing.
75 // Return the new VersionId this file will have after a succesful commit.
76 VersionId enterCreate(FileRef &outWriteRef);
77
78 // Lock the database file for writing, map the database file for reading and
79 // set outWriteRef to a newly created file open for writing.
80 // Return the VersionId or the file being modified.
81 VersionId enterWrite(const uint8 *&outFileAddress, size_t &outLength, FileRef &outWriteRef);
82
83 // Commit the current create or write and close the write file. Return the VersionId of the new file.
84 VersionId commit();
85
86 // Rollback the current create or write.
87 void rollback();
88
89 enum OffsetType {
90 None,
91 FromStart,
92 FromCurrent
93 };
94
95 void write(OffsetType inOffsetType, uint32 inOffset, const uint32 *inData, uint32 inCount);
96 void write(OffsetType inOffsetType, uint32 inOffset, const uint8 *inData, uint32 inLength);
97 void write(OffsetType inOffsetType, uint32 inOffset, const uint32 inData);
98 const string filename() const { return mReadFilename; }
99 private:
100 void endWrite();
101 void rename(const string &inSrcFilename, const string &inDestFilename);
102 void unlink(const string &inFilename);
103
104 class OpenFile
105 {
106 public:
107 OpenFile(const std::string &inFilename, bool write, bool lock, VersionId inVersionId);
108 ~OpenFile();
109
110 void close();
111 VersionId versionId() const { return mVersionId; }
112 FileRef fileRef() const { return mFileRef; }
113 const uint8 *address() const { return mAddress; }
114 size_t length() const { return mLength; }
115
116 // Check if the file has its dirty bit set.
117 bool isDirty();
118 // Set the files dirty bit (requires the file to be writeable and locked).
119 void setDirty();
120
121 void lock();
122 void unlock();
123
124 int mUseCount;
125 FileRef mFileRef;
126 private:
127 VersionId readVersionId();
128 void writeVersionId(VersionId inVersionId);
129 static void mkpath(const std::string &inFilename);
130
131 VersionId mVersionId;
132 const uint8 *mAddress;
133 size_t mLength;
134 bool mFcntlLock;
135 enum
136 {
137 Closed,
138 Read,
139 Write,
140 ReadWrite,
141 Create
142 } mState;
143 };
144
145 Mutex mReadLock;
146 OpenFile *mReadFile;
147 string mReadFilename;
148
149 Mutex mWriteLock;
150 OpenFile *mWriteFile;
151 string mWriteFilename;
152
153 typedef std::map<VersionId, OpenFile *> OpenFileMap;
154 OpenFileMap mOpenFileMap;
155
156 bool mCreating;
157 };
158
159
160 class AtomicFileRef
161 {
162 public:
163 virtual ~AtomicFileRef();
164
165 uint32 at(uint32 inOffset)
166 {
167 return ntohl(*reinterpret_cast<const uint32 *>(mAddress + inOffset));
168 }
169
170 uint32 operator[](uint32 inOffset)
171 {
172 if (inOffset + sizeof(uint32) > mLength)
173 CssmError::throwMe(CSSMERR_DL_DATABASE_CORRUPT);
174 return at(inOffset);
175 }
176
177 const uint8 *range(uint32 inOffset, uint32 inLength)
178 {
179 if (inOffset + inLength > mLength)
180 CssmError::throwMe(CSSMERR_DL_DATABASE_CORRUPT);
181 return mAddress + inOffset;
182 }
183
184 const AtomicFile::VersionId mVersionId;
185 protected:
186 struct InitArg;
187 AtomicFileRef(AtomicFile &inAtomicFile, const InitArg &inInitArg);
188
189 AtomicFile &mAtomicFile;
190 const uint8 *mAddress;
191 const size_t mLength;
192 };
193
194 // Use this class to open an AtomicFile for reading.
195 class AtomicFileReadRef : public AtomicFileRef
196 {
197 public:
198 AtomicFileReadRef(AtomicFile &inAtomicFile);
199 virtual ~AtomicFileReadRef();
200 private:
201 static InitArg enterRead(AtomicFile &inAtomicFile);
202 };
203
204 // Use this class to open an AtomicFile for writing.
205 class AtomicFileWriteRef : public AtomicFileRef
206 {
207 public:
208 AtomicFileWriteRef(AtomicFile &inAtomicFile);
209 virtual ~AtomicFileWriteRef();
210 AtomicFile::VersionId commit() { mOpen = false; return mAtomicFile.commit(); }
211
212 private:
213 static InitArg enterWrite(AtomicFile &inAtomicFile, AtomicFile::FileRef &outWriteFileRef);
214 AtomicFile::FileRef mFileRef;
215 bool mOpen;
216 };
217
218 } // end namespace Security
219
220 #ifdef _CPP_ATOMICFILE
221 #pragma export off
222 #endif
223
224 #endif //_H_ATOMICFILE