903d8cf7f65119e947a02a82d570b79dad77ab69
[reactos.git] / reactos / dll / appcompat / apphelp / sdbwrite.c
1 /*
2 * Copyright 2011 André Hentschel
3 * Copyright 2013 Mislav Bla\9eevic
4 * Copyright 2015,2016 Mark Jansen
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #define WIN32_NO_STATUS
22 #include "windows.h"
23 #include "ntndk.h"
24 #include "apphelp.h"
25
26 #include "wine/unicode.h"
27
28
29 static void WINAPI SdbpFlush(PDB db)
30 {
31 IO_STATUS_BLOCK io;
32 NTSTATUS Status = NtWriteFile(db->file, NULL, NULL, NULL, &io,
33 db->data, db->write_iter, NULL, NULL);
34 if( !NT_SUCCESS(Status))
35 SHIM_WARN("failed with 0x%lx\n", Status);
36 }
37
38 static void WINAPI SdbpWrite(PDB db, LPCVOID data, DWORD size)
39 {
40 if (db->write_iter + size > db->size)
41 {
42 /* Round to powers of two to prevent too many reallocations */
43 while (db->size < db->write_iter + size) db->size <<= 1;
44 db->data = SdbReAlloc(db->data, db->size);
45 }
46
47 memcpy(db->data + db->write_iter, data, size);
48 db->write_iter += size;
49 }
50
51 /**
52 * Creates new shim database file
53 *
54 * If a file already exists on specified path, that file shall be overwritten.
55 *
56 * @note Use SdbCloseDatabasWrite to close the database opened with this function.
57 *
58 * @param [in] path Path to the new shim database.
59 * @param [in] type Type of path. Either DOS_PATH or NT_PATH.
60 *
61 * @return Success: Handle to the newly created shim database, NULL otherwise.
62 */
63 PDB WINAPI SdbCreateDatabase(LPCWSTR path, PATH_TYPE type)
64 {
65 static const DWORD version_major = 2, version_minor = 1;
66 static const char* magic = "sdbf";
67 NTSTATUS Status;
68 IO_STATUS_BLOCK io;
69 OBJECT_ATTRIBUTES attr;
70 UNICODE_STRING str;
71 PDB db;
72
73 if (type == DOS_PATH)
74 {
75 if (!RtlDosPathNameToNtPathName_U(path, &str, NULL, NULL))
76 return NULL;
77 }
78 else
79 RtlInitUnicodeString(&str, path);
80
81 db = SdbpCreate();
82 if (!db)
83 {
84 SHIM_ERR("Failed to allocate memory for shim database\n");
85 return NULL;
86 }
87
88 InitializeObjectAttributes(&attr, &str, OBJ_CASE_INSENSITIVE, NULL, NULL);
89
90 Status = NtCreateFile(&db->file, FILE_GENERIC_WRITE | SYNCHRONIZE,
91 &attr, &io, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ,
92 FILE_SUPERSEDE, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
93
94 if (type == DOS_PATH)
95 RtlFreeUnicodeString(&str);
96
97 if (!NT_SUCCESS(Status))
98 {
99 SdbCloseDatabase(db);
100 SHIM_ERR("Failed to create shim database file: %lx\n", Status);
101 return NULL;
102 }
103
104 db->size = sizeof(DWORD) + sizeof(DWORD) + strlen(magic);
105 db->data = SdbAlloc(db->size);
106
107 SdbpWrite(db, &version_major, sizeof(DWORD));
108 SdbpWrite(db, &version_minor, sizeof(DWORD));
109 SdbpWrite(db, magic, strlen(magic));
110
111 return db;
112 }
113
114 /**
115 * Closes specified database and writes data to file.
116 *
117 * @param [in] db Handle to the shim database.
118 */
119 void WINAPI SdbCloseDatabaseWrite(PDB db)
120 {
121 SdbpFlush(db);
122 SdbCloseDatabase(db);
123 }
124
125 /**
126 * Writes a tag-only (NULL) entry to the specified shim database.
127 *
128 * @param [in] db Handle to the shim database.
129 * @param [in] tag A tag for the entry.
130 *
131 * @return TRUE if it succeeds, FALSE if it fails.
132 */
133 BOOL WINAPI SdbWriteNULLTag(PDB db, TAG tag)
134 {
135 if (!SdbpCheckTagType(tag, TAG_TYPE_NULL))
136 return FALSE;
137
138 SdbpWrite(db, &tag, sizeof(TAG));
139 return TRUE;
140 }
141
142 /**
143 * Writes a WORD entry to the specified shim database.
144 *
145 * @param [in] db Handle to the shim database.
146 * @param [in] tag A tag for the entry.
147 * @param [in] data WORD entry which will be written to the database.
148 *
149 * @return TRUE if it succeeds, FALSE if it fails.
150 */
151 BOOL WINAPI SdbWriteWORDTag(PDB db, TAG tag, WORD data)
152 {
153 if (!SdbpCheckTagType(tag, TAG_TYPE_WORD))
154 return FALSE;
155
156 SdbpWrite(db, &tag, sizeof(TAG));
157 SdbpWrite(db, &data, sizeof(data));
158 return TRUE;
159 }
160
161 /**
162 * Writes a DWORD entry to the specified shim database.
163 *
164 * @param [in] db Handle to the shim database.
165 * @param [in] tag A tag for the entry.
166 * @param [in] data DWORD entry which will be written to the database.
167 *
168 * @return TRUE if it succeeds, FALSE if it fails.
169 */
170 BOOL WINAPI SdbWriteDWORDTag(PDB db, TAG tag, DWORD data)
171 {
172 if (!SdbpCheckTagType(tag, TAG_TYPE_DWORD))
173 return FALSE;
174
175 SdbpWrite(db, &tag, sizeof(TAG));
176 SdbpWrite(db, &data, sizeof(data));
177 return TRUE;
178 }
179
180 /**
181 * Writes a DWORD entry to the specified shim database.
182 *
183 * @param [in] db Handle to the shim database.
184 * @param [in] tag A tag for the entry.
185 * @param [in] data QWORD entry which will be written to the database.
186 *
187 * @return TRUE if it succeeds, FALSE if it fails.
188 */
189 BOOL WINAPI SdbWriteQWORDTag(PDB db, TAG tag, QWORD data)
190 {
191 if (!SdbpCheckTagType(tag, TAG_TYPE_QWORD))
192 return FALSE;
193
194 SdbpWrite(db, &tag, sizeof(TAG));
195 SdbpWrite(db, &data, sizeof(data));
196 return TRUE;
197 }
198
199 /**
200 * Writes a wide string entry to the specified shim database.
201 *
202 * @param [in] db Handle to the shim database.
203 * @param [in] tag A tag for the entry.
204 * @param [in] string Wide string entry which will be written to the database.
205 *
206 * @return TRUE if it succeeds, FALSE if it fails.
207 */
208 BOOL WINAPI SdbWriteStringTag(PDB db, TAG tag, LPCWSTR string)
209 {
210 DWORD size;
211
212 if (!SdbpCheckTagType(tag, TAG_TYPE_STRING))
213 return FALSE;
214
215 size = SdbpStrlen(string);
216 SdbpWrite(db, &tag, sizeof(TAG));
217 SdbpWrite(db, &size, sizeof(size));
218 SdbpWrite(db, string, size);
219 return TRUE;
220 }
221
222 /**
223 * Writes a stringref tag to specified database
224 * @note Reference (tagid) is not checked for validity.
225 *
226 * @param [in] db Handle to the shim database.
227 * @param [in] tag TAG which will be written.
228 * @param [in] tagid TAGID of the string tag refers to.
229 *
230 * @return TRUE if it succeeds, FALSE if it fails.
231 */
232 BOOL WINAPI SdbWriteStringRefTag(PDB db, TAG tag, TAGID tagid)
233 {
234 if (!SdbpCheckTagType(tag, TAG_TYPE_STRINGREF))
235 return FALSE;
236
237 SdbpWrite(db, &tag, sizeof(TAG));
238 SdbpWrite(db, &tagid, sizeof(tagid));
239 return TRUE;
240 }
241
242 /**
243 * Writes data the specified shim database.
244 *
245 * @param [in] db Handle to the shim database.
246 * @param [in] tag A tag for the entry.
247 * @param [in] data Pointer to data.
248 * @param [in] size Number of bytes to write.
249 *
250 * @return TRUE if it succeeds, FALSE if it fails.
251 */
252 BOOL WINAPI SdbWriteBinaryTag(PDB db, TAG tag, PBYTE data, DWORD size)
253 {
254 if (!SdbpCheckTagType(tag, TAG_TYPE_BINARY))
255 return FALSE;
256
257 SdbpWrite(db, &tag, sizeof(TAG));
258 SdbpWrite(db, &size, sizeof(size));
259 SdbpWrite(db, data, size);
260 return TRUE;
261 }
262
263 /**
264 * Writes data from a file to the specified shim database.
265 *
266 * @param [in] db Handle to the shim database.
267 * @param [in] tag A tag for the entry.
268 * @param [in] path Path of the input file.
269 *
270 * @return TRUE if it succeeds, FALSE if it fails.
271 */
272 BOOL WINAPI SdbWriteBinaryTagFromFile(PDB db, TAG tag, LPCWSTR path)
273 {
274 MEMMAPPED mapped;
275
276 if (!SdbpCheckTagType(tag, TAG_TYPE_BINARY))
277 return FALSE;
278
279 if (!SdbpOpenMemMappedFile(path, &mapped))
280 return FALSE;
281
282 SdbWriteBinaryTag(db, tag, mapped.view, mapped.size);
283 SdbpCloseMemMappedFile(&mapped);
284 return TRUE;
285 }
286
287 /**
288 * Writes a list tag to specified database All subsequent SdbWrite* functions shall write to
289 * newly created list untill TAGID of that list is passed to SdbEndWriteListTag.
290 *
291 * @param [in] db Handle to the shim database.
292 * @param [in] tag TAG for the list
293 *
294 * RETURNS Success: TAGID of the newly created list, or TAGID_NULL on failure.
295 *
296 * @return A TAGID.
297 */
298 TAGID WINAPI SdbBeginWriteListTag(PDB db, TAG tag)
299 {
300 TAGID list_id;
301
302 if (!SdbpCheckTagType(tag, TAG_TYPE_LIST))
303 return TAGID_NULL;
304
305 list_id = db->write_iter;
306 SdbpWrite(db, &tag, sizeof(TAG));
307 db->write_iter += sizeof(DWORD); /* reserve some memory for storing list size */
308 return list_id;
309 }
310
311 /**
312 * Marks end of the specified list.
313 *
314 * @param [in] db Handle to the shim database.
315 * @param [in] tagid TAGID of the list.
316 *
317 * @return TRUE if it succeeds, FALSE if it fails.
318 */
319 BOOL WINAPI SdbEndWriteListTag(PDB db, TAGID tagid)
320 {
321 if (!SdbpCheckTagIDType(db, tagid, TAG_TYPE_LIST))
322 return FALSE;
323
324 /* Write size of list to list tag header */
325 *(DWORD*)&db->data[tagid + sizeof(TAG)] = db->write_iter - tagid - sizeof(TAG);
326 return TRUE;
327 }
328