[APPHELP] Fix a possible out of bounds write.
[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 #if !defined(SDBWRITE_HOSTTOOL)
22
23 #define WIN32_NO_STATUS
24 #include "windows.h"
25 #include "ntndk.h"
26 #include "apphelp.h"
27 #include "wine/unicode.h"
28
29 #else
30
31 #include <typedefs.h>
32 #include <guiddef.h>
33
34 #include "sdbtypes.h"
35 #include "sdbpapi.h"
36 #include "sdbtagid.h"
37
38 #endif
39
40
41 static void WINAPI SdbpWrite(PDB db, const void* data, DWORD size)
42 {
43 if (db->write_iter + size > db->size)
44 {
45 /* Round to powers of two to prevent too many reallocations */
46 while (db->size < db->write_iter + size) db->size <<= 1;
47 db->data = SdbReAlloc(db->data, db->size);
48 }
49
50 memcpy(db->data + db->write_iter, data, size);
51 db->write_iter += size;
52 }
53
54 /**
55 * Creates new shim database file
56 *
57 * If a file already exists on specified path, that file shall be overwritten.
58 *
59 * @note Use SdbCloseDatabasWrite to close the database opened with this function.
60 *
61 * @param [in] path Path to the new shim database.
62 * @param [in] type Type of path. Either DOS_PATH or NT_PATH.
63 *
64 * @return Success: Handle to the newly created shim database, NULL otherwise.
65 */
66 PDB WINAPI SdbCreateDatabase(LPCWSTR path, PATH_TYPE type)
67 {
68 static const DWORD version_major = 2, version_minor = 1;
69 static const char* magic = "sdbf";
70 PDB db;
71
72 db = SdbpCreate(path, type, TRUE);
73 if (!db)
74 return NULL;
75
76 db->size = sizeof(DWORD) + sizeof(DWORD) + strlen(magic);
77 db->data = SdbAlloc(db->size);
78
79 SdbpWrite(db, &version_major, sizeof(DWORD));
80 SdbpWrite(db, &version_minor, sizeof(DWORD));
81 SdbpWrite(db, magic, strlen(magic));
82
83 return db;
84 }
85
86 /**
87 * Closes specified database and writes data to file.
88 *
89 * @param [in] db Handle to the shim database.
90 */
91 void WINAPI SdbCloseDatabaseWrite(PDB db)
92 {
93 SdbpFlush(db);
94 SdbCloseDatabase(db);
95 }
96
97 /**
98 * Writes a tag-only (NULL) entry to the specified shim database.
99 *
100 * @param [in] db Handle to the shim database.
101 * @param [in] tag A tag for the entry.
102 *
103 * @return TRUE if it succeeds, FALSE if it fails.
104 */
105 BOOL WINAPI SdbWriteNULLTag(PDB db, TAG tag)
106 {
107 if (!SdbpCheckTagType(tag, TAG_TYPE_NULL))
108 return FALSE;
109
110 SdbpWrite(db, &tag, sizeof(TAG));
111 return TRUE;
112 }
113
114 /**
115 * Writes a WORD entry to the specified shim database.
116 *
117 * @param [in] db Handle to the shim database.
118 * @param [in] tag A tag for the entry.
119 * @param [in] data WORD entry which will be written to the database.
120 *
121 * @return TRUE if it succeeds, FALSE if it fails.
122 */
123 BOOL WINAPI SdbWriteWORDTag(PDB db, TAG tag, WORD data)
124 {
125 if (!SdbpCheckTagType(tag, TAG_TYPE_WORD))
126 return FALSE;
127
128 SdbpWrite(db, &tag, sizeof(TAG));
129 SdbpWrite(db, &data, sizeof(data));
130 return TRUE;
131 }
132
133 /**
134 * Writes a DWORD entry to the specified shim database.
135 *
136 * @param [in] db Handle to the shim database.
137 * @param [in] tag A tag for the entry.
138 * @param [in] data DWORD entry which will be written to the database.
139 *
140 * @return TRUE if it succeeds, FALSE if it fails.
141 */
142 BOOL WINAPI SdbWriteDWORDTag(PDB db, TAG tag, DWORD data)
143 {
144 if (!SdbpCheckTagType(tag, TAG_TYPE_DWORD))
145 return FALSE;
146
147 SdbpWrite(db, &tag, sizeof(TAG));
148 SdbpWrite(db, &data, sizeof(data));
149 return TRUE;
150 }
151
152 /**
153 * Writes a DWORD entry to the specified shim database.
154 *
155 * @param [in] db Handle to the shim database.
156 * @param [in] tag A tag for the entry.
157 * @param [in] data QWORD entry which will be written to the database.
158 *
159 * @return TRUE if it succeeds, FALSE if it fails.
160 */
161 BOOL WINAPI SdbWriteQWORDTag(PDB db, TAG tag, QWORD data)
162 {
163 if (!SdbpCheckTagType(tag, TAG_TYPE_QWORD))
164 return FALSE;
165
166 SdbpWrite(db, &tag, sizeof(TAG));
167 SdbpWrite(db, &data, sizeof(data));
168 return TRUE;
169 }
170
171 /**
172 * Writes a wide string entry to the specified shim database.
173 *
174 * @param [in] db Handle to the shim database.
175 * @param [in] tag A tag for the entry.
176 * @param [in] string Wide string entry which will be written to the database.
177 *
178 * @return TRUE if it succeeds, FALSE if it fails.
179 */
180 BOOL WINAPI SdbWriteStringTag(PDB db, TAG tag, LPCWSTR string)
181 {
182 DWORD size;
183
184 if (!SdbpCheckTagType(tag, TAG_TYPE_STRING))
185 return FALSE;
186
187 size = SdbpStrlen(string);
188 SdbpWrite(db, &tag, sizeof(TAG));
189 SdbpWrite(db, &size, sizeof(size));
190 SdbpWrite(db, string, size);
191 return TRUE;
192 }
193
194 /**
195 * Writes a stringref tag to specified database
196 * @note Reference (tagid) is not checked for validity.
197 *
198 * @param [in] db Handle to the shim database.
199 * @param [in] tag TAG which will be written.
200 * @param [in] tagid TAGID of the string tag refers to.
201 *
202 * @return TRUE if it succeeds, FALSE if it fails.
203 */
204 BOOL WINAPI SdbWriteStringRefTag(PDB db, TAG tag, TAGID tagid)
205 {
206 if (!SdbpCheckTagType(tag, TAG_TYPE_STRINGREF))
207 return FALSE;
208
209 SdbpWrite(db, &tag, sizeof(TAG));
210 SdbpWrite(db, &tagid, sizeof(tagid));
211 return TRUE;
212 }
213
214 /**
215 * Writes data the specified shim database.
216 *
217 * @param [in] db Handle to the shim database.
218 * @param [in] tag A tag for the entry.
219 * @param [in] data Pointer to data.
220 * @param [in] size Number of bytes to write.
221 *
222 * @return TRUE if it succeeds, FALSE if it fails.
223 */
224 BOOL WINAPI SdbWriteBinaryTag(PDB db, TAG tag, BYTE* data, DWORD size)
225 {
226 if (!SdbpCheckTagType(tag, TAG_TYPE_BINARY))
227 return FALSE;
228
229 SdbpWrite(db, &tag, sizeof(TAG));
230 SdbpWrite(db, &size, sizeof(size));
231 SdbpWrite(db, data, size);
232 return TRUE;
233 }
234
235 #if !defined(SDBWRITE_HOSTTOOL)
236 /**
237 * Writes data from a file to the specified shim database.
238 *
239 * @param [in] db Handle to the shim database.
240 * @param [in] tag A tag for the entry.
241 * @param [in] path Path of the input file.
242 *
243 * @return TRUE if it succeeds, FALSE if it fails.
244 */
245 BOOL WINAPI SdbWriteBinaryTagFromFile(PDB db, TAG tag, LPCWSTR path)
246 {
247 MEMMAPPED mapped;
248
249 if (!SdbpCheckTagType(tag, TAG_TYPE_BINARY))
250 return FALSE;
251
252 if (!SdbpOpenMemMappedFile(path, &mapped))
253 return FALSE;
254
255 SdbWriteBinaryTag(db, tag, mapped.view, mapped.size);
256 SdbpCloseMemMappedFile(&mapped);
257 return TRUE;
258 }
259 #endif
260
261 /**
262 * Writes a list tag to specified database All subsequent SdbWrite* functions shall write to
263 * newly created list untill TAGID of that list is passed to SdbEndWriteListTag.
264 *
265 * @param [in] db Handle to the shim database.
266 * @param [in] tag TAG for the list
267 *
268 * RETURNS Success: TAGID of the newly created list, or TAGID_NULL on failure.
269 *
270 * @return A TAGID.
271 */
272 TAGID WINAPI SdbBeginWriteListTag(PDB db, TAG tag)
273 {
274 TAGID list_id;
275 DWORD dum = 0;
276
277 if (!SdbpCheckTagType(tag, TAG_TYPE_LIST))
278 return TAGID_NULL;
279
280 list_id = db->write_iter;
281 SdbpWrite(db, &tag, sizeof(TAG));
282 SdbpWrite(db, &dum, sizeof(dum)); /* reserve some memory for storing list size */
283 return list_id;
284 }
285
286 /**
287 * Marks end of the specified list.
288 *
289 * @param [in] db Handle to the shim database.
290 * @param [in] tagid TAGID of the list.
291 *
292 * @return TRUE if it succeeds, FALSE if it fails.
293 */
294 BOOL WINAPI SdbEndWriteListTag(PDB db, TAGID tagid)
295 {
296 if (!SdbpCheckTagIDType(db, tagid, TAG_TYPE_LIST))
297 return FALSE;
298
299 /* Write size of list to list tag header */
300 *(DWORD*)&db->data[tagid + sizeof(TAG)] = db->write_iter - tagid - sizeof(TAG);
301 return TRUE;
302 }
303