1 /* 2 * PROJECT: ReactOS Application compatibility module 3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) 4 * PURPOSE: Shim database manipulation functions 5 * COPYRIGHT: Copyright 2011 André Hentschel 6 * Copyright 2013 Mislav Blažević 7 * Copyright 2015-2017 Mark Jansen (mark.jansen@reactos.org) 8 */ 9 10 #if !defined(SDBWRITE_HOSTTOOL) 11 #define WIN32_NO_STATUS 12 #include "windef.h" 13 #include "ntndk.h" 14 #else 15 #include <typedefs.h> 16 #include <guiddef.h> 17 #endif 18 19 #include "sdbtypes.h" 20 #include "sdbpapi.h" 21 #include "sdbtagid.h" 22 #include "sdbstringtable.h" 23 24 25 /* Local functions */ 26 BOOL WINAPI SdbWriteStringRefTag(PDB pdb, TAG tag, TAGID tagid); 27 BOOL WINAPI SdbWriteStringTag(PDB pdb, TAG tag, LPCWSTR string); 28 TAGID WINAPI SdbBeginWriteListTag(PDB pdb, TAG tag); 29 BOOL WINAPI SdbEndWriteListTag(PDB pdb, TAGID tagid); 30 31 /* sdbapi.c */ 32 void WINAPI SdbCloseDatabase(PDB); 33 34 /* Copy data to the allocated database */ 35 static void WINAPI SdbpWrite(PDB pdb, const void* data, DWORD size) 36 { 37 ASSERT(pdb->for_write); 38 if (pdb->write_iter + size > pdb->size) 39 { 40 DWORD oldSize = pdb->size; 41 /* Round to powers of two to prevent too many reallocations */ 42 while (pdb->size < pdb->write_iter + size) pdb->size <<= 1; 43 pdb->data = SdbReAlloc(pdb->data, pdb->size, oldSize); 44 } 45 46 memcpy(pdb->data + pdb->write_iter, data, size); 47 pdb->write_iter += size; 48 } 49 50 /* Add a string to the string table (creating it when it did not exist yet), 51 returning if it succeeded or not */ 52 static BOOL WINAPI SdbpGetOrAddStringRef(PDB pdb, LPCWSTR string, TAGID* tagid) 53 { 54 PDB buf = pdb->string_buffer; 55 ASSERT(pdb->for_write); 56 57 if (pdb->string_buffer == NULL) 58 { 59 pdb->string_buffer = buf = SdbAlloc(sizeof(DB)); 60 if (buf == NULL) 61 return FALSE; 62 buf->size = 128; 63 buf->data = SdbAlloc(buf->size); 64 buf->for_write = TRUE; 65 if (buf->data == NULL) 66 return FALSE; 67 } 68 69 *tagid = buf->write_iter + sizeof(TAG) + sizeof(DWORD); 70 if (SdbpAddStringToTable(&pdb->string_lookup, string, tagid)) 71 return SdbWriteStringTag(buf, TAG_STRINGTABLE_ITEM, string); 72 73 return pdb->string_lookup != NULL; 74 } 75 76 /* Write the in-memory stringtable to the specified db */ 77 static BOOL WINAPI SdbpWriteStringtable(PDB pdb) 78 { 79 TAGID table; 80 PDB buf = pdb->string_buffer; 81 if (buf == NULL || pdb->string_lookup == NULL) 82 return FALSE; 83 84 table = SdbBeginWriteListTag(pdb, TAG_STRINGTABLE); 85 SdbpWrite(pdb, buf->data, buf->write_iter); 86 return SdbEndWriteListTag(pdb, table); 87 } 88 89 /** 90 * Creates new shim database file 91 * 92 * If a file already exists on specified path, that file shall be overwritten. 93 * 94 * @note Use SdbCloseDatabaseWrite to close the database opened with this function. 95 * 96 * @param [in] path Path to the new shim database. 97 * @param [in] type Type of path. Either DOS_PATH or NT_PATH. 98 * 99 * @return Success: Handle to the newly created shim database, NULL otherwise. 100 */ 101 PDB WINAPI SdbCreateDatabase(LPCWSTR path, PATH_TYPE type) 102 { 103 static const DWORD version_major = 2, version_minor = 1; 104 static const char* magic = "sdbf"; 105 PDB pdb; 106 107 pdb = SdbpCreate(path, type, TRUE); 108 if (!pdb) 109 return NULL; 110 111 pdb->size = sizeof(DWORD) + sizeof(DWORD) + strlen(magic); 112 pdb->data = SdbAlloc(pdb->size); 113 114 SdbpWrite(pdb, &version_major, sizeof(DWORD)); 115 SdbpWrite(pdb, &version_minor, sizeof(DWORD)); 116 SdbpWrite(pdb, magic, strlen(magic)); 117 118 return pdb; 119 } 120 121 /** 122 * Closes specified database and writes data to file. 123 * 124 * @param [in] pdb Handle to the shim database. 125 */ 126 void WINAPI SdbCloseDatabaseWrite(PDB pdb) 127 { 128 ASSERT(pdb->for_write); 129 SdbpWriteStringtable(pdb); 130 SdbpFlush(pdb); 131 SdbCloseDatabase(pdb); 132 } 133 134 /** 135 * Writes a tag-only (NULL) entry to the specified shim database. 136 * 137 * @param [in] pdb Handle to the shim database. 138 * @param [in] tag A tag for the entry. 139 * 140 * @return TRUE if it succeeds, FALSE if it fails. 141 */ 142 BOOL WINAPI SdbWriteNULLTag(PDB pdb, TAG tag) 143 { 144 if (!SdbpCheckTagType(tag, TAG_TYPE_NULL)) 145 return FALSE; 146 147 SdbpWrite(pdb, &tag, sizeof(TAG)); 148 return TRUE; 149 } 150 151 /** 152 * Writes a WORD entry to the specified shim database. 153 * 154 * @param [in] pdb Handle to the shim database. 155 * @param [in] tag A tag for the entry. 156 * @param [in] data WORD entry which will be written to the database. 157 * 158 * @return TRUE if it succeeds, FALSE if it fails. 159 */ 160 BOOL WINAPI SdbWriteWORDTag(PDB pdb, TAG tag, WORD data) 161 { 162 if (!SdbpCheckTagType(tag, TAG_TYPE_WORD)) 163 return FALSE; 164 165 SdbpWrite(pdb, &tag, sizeof(TAG)); 166 SdbpWrite(pdb, &data, sizeof(data)); 167 return TRUE; 168 } 169 170 /** 171 * Writes a DWORD entry to the specified shim database. 172 * 173 * @param [in] pdb Handle to the shim database. 174 * @param [in] tag A tag for the entry. 175 * @param [in] data DWORD entry which will be written to the database. 176 * 177 * @return TRUE if it succeeds, FALSE if it fails. 178 */ 179 BOOL WINAPI SdbWriteDWORDTag(PDB pdb, TAG tag, DWORD data) 180 { 181 if (!SdbpCheckTagType(tag, TAG_TYPE_DWORD)) 182 return FALSE; 183 184 SdbpWrite(pdb, &tag, sizeof(TAG)); 185 SdbpWrite(pdb, &data, sizeof(data)); 186 return TRUE; 187 } 188 189 /** 190 * Writes a DWORD entry to the specified shim database. 191 * 192 * @param [in] pdb Handle to the shim database. 193 * @param [in] tag A tag for the entry. 194 * @param [in] data QWORD entry which will be written to the database. 195 * 196 * @return TRUE if it succeeds, FALSE if it fails. 197 */ 198 BOOL WINAPI SdbWriteQWORDTag(PDB pdb, TAG tag, QWORD data) 199 { 200 if (!SdbpCheckTagType(tag, TAG_TYPE_QWORD)) 201 return FALSE; 202 203 SdbpWrite(pdb, &tag, sizeof(TAG)); 204 SdbpWrite(pdb, &data, sizeof(data)); 205 return TRUE; 206 } 207 208 /** 209 * Writes a wide string entry to the specified shim database. 210 * 211 * @param [in] pdb Handle to the shim database. 212 * @param [in] tag A tag for the entry. 213 * @param [in] string Wide string entry which will be written to the database. 214 * 215 * @return TRUE if it succeeds, FALSE if it fails. 216 */ 217 BOOL WINAPI SdbWriteStringTag(PDB pdb, TAG tag, LPCWSTR string) 218 { 219 DWORD size; 220 221 if (SdbpCheckTagType(tag, TAG_TYPE_STRINGREF)) 222 { 223 TAGID tagid = 0; 224 if (!SdbpGetOrAddStringRef(pdb, string, &tagid)) 225 return FALSE; 226 227 return SdbWriteStringRefTag(pdb, tag, tagid); 228 } 229 230 if (!SdbpCheckTagType(tag, TAG_TYPE_STRING)) 231 return FALSE; 232 233 size = SdbpStrsize(string); 234 SdbpWrite(pdb, &tag, sizeof(TAG)); 235 SdbpWrite(pdb, &size, sizeof(size)); 236 SdbpWrite(pdb, string, size); 237 return TRUE; 238 } 239 240 /** 241 * Writes a stringref tag to specified database 242 * @note Reference (tagid) is not checked for validity. 243 * 244 * @param [in] pdb Handle to the shim database. 245 * @param [in] tag TAG which will be written. 246 * @param [in] tagid TAGID of the string tag refers to. 247 * 248 * @return TRUE if it succeeds, FALSE if it fails. 249 */ 250 BOOL WINAPI SdbWriteStringRefTag(PDB pdb, TAG tag, TAGID tagid) 251 { 252 if (!SdbpCheckTagType(tag, TAG_TYPE_STRINGREF)) 253 return FALSE; 254 255 SdbpWrite(pdb, &tag, sizeof(TAG)); 256 SdbpWrite(pdb, &tagid, sizeof(tagid)); 257 return TRUE; 258 } 259 260 /** 261 * Writes data the specified shim database. 262 * 263 * @param [in] pdb Handle to the shim database. 264 * @param [in] tag A tag for the entry. 265 * @param [in] data Pointer to data. 266 * @param [in] size Number of bytes to write. 267 * 268 * @return TRUE if it succeeds, FALSE if it fails. 269 */ 270 BOOL WINAPI SdbWriteBinaryTag(PDB pdb, TAG tag, const BYTE* data, DWORD size) 271 { 272 if (!SdbpCheckTagType(tag, TAG_TYPE_BINARY)) 273 return FALSE; 274 275 SdbpWrite(pdb, &tag, sizeof(TAG)); 276 SdbpWrite(pdb, &size, sizeof(size)); 277 SdbpWrite(pdb, data, size); 278 return TRUE; 279 } 280 281 #if !defined(SDBWRITE_HOSTTOOL) 282 /** 283 * Writes data from a file to the specified shim database. 284 * 285 * @param [in] pdb Handle to the shim database. 286 * @param [in] tag A tag for the entry. 287 * @param [in] path Path of the input file. 288 * 289 * @return TRUE if it succeeds, FALSE if it fails. 290 */ 291 BOOL WINAPI SdbWriteBinaryTagFromFile(PDB pdb, TAG tag, LPCWSTR path) 292 { 293 MEMMAPPED mapped; 294 295 if (!SdbpCheckTagType(tag, TAG_TYPE_BINARY)) 296 return FALSE; 297 298 if (!SdbpOpenMemMappedFile(path, &mapped)) 299 return FALSE; 300 301 SdbWriteBinaryTag(pdb, tag, mapped.view, mapped.size); 302 SdbpCloseMemMappedFile(&mapped); 303 return TRUE; 304 } 305 #endif 306 307 /** 308 * Writes a list tag to specified database All subsequent SdbWrite* functions shall write to 309 * newly created list untill TAGID of that list is passed to SdbEndWriteListTag. 310 * 311 * @param [in] pdb Handle to the shim database. 312 * @param [in] tag TAG for the list 313 * 314 * RETURNS Success: TAGID of the newly created list, or TAGID_NULL on failure. 315 * 316 * @return A TAGID. 317 */ 318 TAGID WINAPI SdbBeginWriteListTag(PDB pdb, TAG tag) 319 { 320 TAGID list_id; 321 DWORD dum = 0; 322 323 if (!SdbpCheckTagType(tag, TAG_TYPE_LIST)) 324 return TAGID_NULL; 325 326 list_id = pdb->write_iter; 327 SdbpWrite(pdb, &tag, sizeof(TAG)); 328 SdbpWrite(pdb, &dum, sizeof(dum)); /* reserve some memory for storing list size */ 329 return list_id; 330 } 331 332 /** 333 * Marks end of the specified list. 334 * 335 * @param [in] pdb Handle to the shim database. 336 * @param [in] tagid TAGID of the list. 337 * 338 * @return TRUE if it succeeds, FALSE if it fails. 339 */ 340 BOOL WINAPI SdbEndWriteListTag(PDB pdb, TAGID tagid) 341 { 342 ASSERT(pdb->for_write); 343 344 if (!SdbpCheckTagIDType(pdb, tagid, TAG_TYPE_LIST)) 345 return FALSE; 346 347 /* Write size of list to list tag header */ 348 *(DWORD*)&pdb->data[tagid + sizeof(TAG)] = pdb->write_iter - tagid - sizeof(TAG) - sizeof(TAGID); 349 return TRUE; 350 } 351 352