1 | // Licensed to the .NET Foundation under one or more agreements. |
2 | // The .NET Foundation licenses this file to you under the MIT license. |
3 | // See the LICENSE file in the project root for more information. |
4 | //***************************************************************************** |
5 | // StgIO.h |
6 | // |
7 | |
8 | // |
9 | // This module handles disk/memory i/o for a generic set of storage solutions, |
10 | // including: |
11 | // * File system handle (HFILE) |
12 | // * IStream |
13 | // * User supplied memory buffer (non-movable) |
14 | // |
15 | // The Read, Write, Seek, ... functions are all directed to the corresponding |
16 | // method for each type of file, allowing the consumer to use one set of api's. |
17 | // |
18 | // File system data can be paged fully into memory in two scenarios: |
19 | // read: Normal memory mapped file is created to manage paging. |
20 | // write: A custom paging system provides storage for pages as required. This |
21 | // data is invalidated when you call Rewrite on the file. |
22 | // |
23 | // Transactions and backups are handled in the existing file case only. The |
24 | // Rewrite function can make a backup of the current contents, and the Restore |
25 | // function can be used to recover the data into the current scope. The backup |
26 | // file is flushed to disk (which is slower but safer) after the copy. The |
27 | // Restore also flushed the recovered changes to disk. Worst case scenario you |
28 | // get a crash after calling Rewrite but before Restore, in which case you will |
29 | // have a foo.clb.txn file in the same directory as the source file, foo.clb in |
30 | // this example. |
31 | //<TODO> |
32 | // @FUTURE: issues, |
33 | // 1. For reading a .clb in an image, it would be great to memory map |
34 | // only the portion of the file with the .clb in it. |
35 | //</TODO> |
36 | //***************************************************************************** |
37 | #ifndef __STGIO_H_ |
38 | #define __STGIO_H_ |
39 | |
40 | #define MAXSHMEM 32 |
41 | |
42 | #define STGIO_READ 0x1 |
43 | #define STGIO_WRITE 0x2 |
44 | |
45 | enum DBPROPMODE |
46 | { DBPROP_TMODEF_READ = 0x1, |
47 | DBPROP_TMODEF_WRITE = 0x2, |
48 | DBPROP_TMODEF_EXCLUSIVE = 0x4, |
49 | // Shared memory uses ole32.dll - we cannot depend on it in the standalone WinRT Read-Only DLL |
50 | DBPROP_TMODEF_SHAREDMEM = 0x8, |
51 | DBPROP_TMODEF_CREATE = 0x10, |
52 | DBPROP_TMODEF_FAILIFTHERE = 0x20, |
53 | DBPROP_TMODEF_SLOWSAVE = 0x100, |
54 | // Means it is OK to use LoadLibrary to map the file. Used by code:ofTrustedImage. |
55 | // We prefer that because it is shared with loader's image loading. |
56 | DBPROP_TMODEF_TRYLOADLIBRARY = 0x400, |
57 | #if 0 // dead code |
58 | DBPROP_TMODEF_NOTXNBACKUPFILE = 0x200, |
59 | DBPROP_TMODEF_COMPLUS = 0x1000, |
60 | DBPROP_TMODEF_SMEMCREATE = 0x2000, |
61 | DBPROP_TMODEF_SMEMOPEN = 0x4000, |
62 | DBPROP_TMODEF_ALIGNBLOBS = 0x10000 |
63 | DBPROP_TMODEF_RESERVED = 0x80000000, |
64 | #endif |
65 | DBPROP_TMODEF_DFTWRITEMASK = 0x113, |
66 | DBPROP_TMODEF_DFTREADWRITEMASK = 0x103, |
67 | }; |
68 | |
69 | |
70 | // Types of IO we can handle. |
71 | enum STGIOTYPE |
72 | { |
73 | STGIO_NODATA = 0, // Currently not open. |
74 | STGIO_HFILE = 1, // File handle contains data. |
75 | STGIO_HMODULE = 2, // The file was loaded via LoadLibrary as module. |
76 | STGIO_STREAM = 3, // Stream pointer has data. |
77 | STGIO_MEM = 4, // In memory pointer has data. |
78 | // Shared memory uses ole32.dll - we cannot depend on it in the standalone WinRT Read-Only DLL |
79 | STGIO_SHAREDMEM = 5, // Shared memory handle. |
80 | STGIO_HFILEMEM = 6 // Handle open, but memory allocated. |
81 | }; |
82 | |
83 | class StgIO |
84 | { |
85 | friend class CLiteWeightStgdbRW; // for low-level access to data for metainfo and such. |
86 | friend class TiggerStorage; |
87 | public: |
88 | StgIO( |
89 | bool bAutoMap=true); // Memory map for read on open? |
90 | |
91 | ~StgIO(); |
92 | |
93 | //***************************************************************************** |
94 | // Open the base file on top of: (a) file, (b) memory buffer, or (c) stream. |
95 | // If create flag is specified, then this will create a new file with the |
96 | // name supplied. No data is read from an opened file. You must call |
97 | // MapFileToMem before doing direct pointer access to the contents. |
98 | //***************************************************************************** |
99 | HRESULT Open( // Return code. |
100 | LPCWSTR szName, // Name of the storage. |
101 | int fFlags, // How to open the file. |
102 | const void *pbBuff, // Optional buffer for memory. |
103 | ULONG cbBuff, // Size of buffer. |
104 | IStream *pIStream, // Stream for input. |
105 | LPSECURITY_ATTRIBUTES pAttributes); // Security token. |
106 | |
107 | //***************************************************************************** |
108 | // Shut down the file handles and allocated objects. |
109 | //***************************************************************************** |
110 | void Close(); |
111 | |
112 | //***************************************************************************** |
113 | // Read data from the storage source. This will handle all types of backing |
114 | // storage from mmf, streams, and file handles. No read ahead or MRU |
115 | // caching is done. |
116 | //***************************************************************************** |
117 | HRESULT Read( // Return code. |
118 | void *pbBuff, // Write buffer here. |
119 | ULONG cbBuff, // How much to read. |
120 | ULONG *pcbRead); // How much read. |
121 | |
122 | //***************************************************************************** |
123 | // Write to disk. This function will cache up to a page of data in a buffer |
124 | // and peridocially flush it on overflow and explicit request. This makes it |
125 | // safe to do lots of small writes without too much performance overhead. |
126 | //***************************************************************************** |
127 | HRESULT Write( // Return code. |
128 | const void *pbBuff, // Buffer to write. |
129 | ULONG cbWrite, // How much. |
130 | ULONG *pcbWritten); // Return how much written. |
131 | |
132 | //***************************************************************************** |
133 | // Moves the file pointer to the new location. This handles the different |
134 | // types of storage systems. |
135 | //***************************************************************************** |
136 | HRESULT Seek( // New offset. |
137 | int lVal, // How much to move. |
138 | ULONG fMoveType); // Direction, use Win32 FILE_xxxx. |
139 | |
140 | //***************************************************************************** |
141 | // Retrieves the current offset for the storage being used. This value is |
142 | // tracked based on Read, Write, and Seek operations. |
143 | //***************************************************************************** |
144 | ULONG GetCurrentOffset(); // Current offset. |
145 | |
146 | //***************************************************************************** |
147 | // Map the file contents to a memory mapped file and return a pointer to the |
148 | // data. For read/write with a backing store, map the file using an internal |
149 | // paging system. |
150 | //***************************************************************************** |
151 | HRESULT MapFileToMem( // Return code. |
152 | void *&ptr, // Return pointer to file data. |
153 | ULONG *pcbSize, // Return size of data. |
154 | LPSECURITY_ATTRIBUTES pAttributes=0); // Security token. |
155 | |
156 | //***************************************************************************** |
157 | // Free the mapping object for shared memory but keep the rest of the internal |
158 | // state intact. |
159 | //***************************************************************************** |
160 | HRESULT ReleaseMappingObject(); // Return code. |
161 | |
162 | //***************************************************************************** |
163 | // Resets the logical base address and size to the value given. This is for |
164 | // cases like finding a section embedded in another format, like the .clb inside |
165 | // of an image. GetPtrForMem, Read, and Seek will then behave as though only |
166 | // data from pbStart to cbSize is valid. |
167 | //***************************************************************************** |
168 | HRESULT SetBaseRange( // Return code. |
169 | void *pbStart, // Start of file data. |
170 | ULONG cbSize); // How big is the range. |
171 | |
172 | //***************************************************************************** |
173 | // For read/write case, get a pointer to a chunk of the file at cbStart for |
174 | // size cbSize. Return the pointer. This will page in parts of the file from |
175 | // disk if not already loaded. |
176 | //***************************************************************************** |
177 | HRESULT GetPtrForMem( // Return code. |
178 | ULONG cbStart, // Offset from beginning to load. |
179 | ULONG cbSize, // How much, rounded to page. |
180 | void *&ptr); // Return pointer on success. |
181 | |
182 | //***************************************************************************** |
183 | // For cached writes, flush the cache to the data store. |
184 | //***************************************************************************** |
185 | HRESULT FlushCache(); |
186 | |
187 | //***************************************************************************** |
188 | // Tells the file system to flush any cached data it may have. This is |
189 | // expensive, but if successful guarantees you won't lose writes short of |
190 | // a disk failure. |
191 | //***************************************************************************** |
192 | HRESULT FlushFileBuffers(); |
193 | |
194 | //***************************************************************************** |
195 | // Called after a successful rewrite of an existing file. The in memory |
196 | // backing store is no longer valid because all new data is in memory and |
197 | // on disk. This is essentially the same state as created, so free up some |
198 | // working set and remember this state. |
199 | //***************************************************************************** |
200 | HRESULT ResetBackingStore(); // Return code. |
201 | |
202 | FILETYPE GetFileType() |
203 | { return m_FileType; } |
204 | |
205 | int IsReadOnly() |
206 | { return ((m_fFlags & STGIO_WRITE) == 0); } |
207 | |
208 | ULONG GetFlags() |
209 | { return (m_fFlags); } |
210 | |
211 | ULONG SetFlags(ULONG fFlags) |
212 | { m_fFlags = fFlags; |
213 | return (m_fFlags); } |
214 | |
215 | ULONG GetDataSize() |
216 | { return (m_cbData); } |
217 | |
218 | LONG AddRef() |
219 | { |
220 | return (++m_cRef); |
221 | } |
222 | |
223 | LONG Release() |
224 | { |
225 | LONG cRef = --m_cRef; |
226 | if (cRef == 0) |
227 | delete this; |
228 | return (cRef); |
229 | } |
230 | |
231 | int IsAlignedPtr(ULONG_PTR Value, int iAlignment); |
232 | MAPPINGTYPE GetMemoryMappedType() |
233 | { return m_mtMappedType;} |
234 | |
235 | |
236 | //***************************************************************************** |
237 | // Called to read the data into allocated memory and release the backing store. |
238 | // Only available on read-only data. |
239 | //***************************************************************************** |
240 | HRESULT LoadFileToMemory(); |
241 | |
242 | |
243 | private: |
244 | int IsBackingStore() |
245 | { return (m_rgPageMap != 0); } |
246 | int IsMemoryMapped() |
247 | { return ((m_hMapping != NULL) || (m_hModule != NULL)); } |
248 | |
249 | void CtorInit(); |
250 | HRESULT WriteToDisk(const void *pbBuff, ULONG cbWrite, ULONG *pcbWritten); |
251 | HRESULT ReadFromDisk(void *pbBuff, ULONG cbBuff, ULONG *pcbRead); |
252 | HRESULT CopyFileInternal(LPCWSTR szTo, int bFailIfThere, int bWriteThrough); |
253 | void FreePageMap(); |
254 | |
255 | private: |
256 | |
257 | // Flags and state data. |
258 | FILETYPE m_FileType; // Cached type of the file (based on extension). |
259 | LONG m_cRef; // Ref count on this object. |
260 | bool m_bWriteThrough : 1; // true for write through mode. |
261 | bool m_bRewrite : 1; // State check for rewrite mode. |
262 | bool m_bAutoMap : 1; // true to automatically memory map file. |
263 | bool m_bFreeMem : 1; // true to free allocated memory. |
264 | |
265 | // Handles. |
266 | IStream * m_pIStream; // For save to stream instead of file. |
267 | HANDLE m_hFile; // The actual file with contents. |
268 | HANDLE m_hMapping; // Mapping handle. |
269 | HMODULE m_hModule; // If we load with LoadLibrary, this is the module (otherwise NULL). |
270 | void * m_pBaseData; // Base address for memory mapped file. |
271 | void * m_pData; // For memory mapped file read. |
272 | ULONG m_cbData; // Size of in memory data. |
273 | int m_fFlags; // Flags for open/create mode. |
274 | STGIOTYPE m_iType; // Where is the data. |
275 | MAPPINGTYPE m_mtMappedType; // How the file was memory mapped |
276 | |
277 | // File cache information. |
278 | BYTE * m_rgBuff; // Cache buffer for writing. |
279 | ULONG m_cbBuff; // Current cache size. |
280 | ULONG m_cbOffset; // Current offset in file. |
281 | |
282 | // Buffer read management. |
283 | static int m_iPageSize; // Size of an OS page. |
284 | static int m_iCacheSize; // How big a write back cache to use. |
285 | BYTE * m_rgPageMap; // Track loaded pages on read/write. |
286 | |
287 | }; // class StgIO |
288 | |
289 | #endif // __STGIO_H_ |
290 | |