| 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 | |