ReactOS 0.4.17-dev-37-g0bfb40d
ntldropts.c
Go to the documentation of this file.
1/*
2 * PROJECT: FreeLoader
3 * LICENSE: Dual-licensed:
4 * GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
5 * MIT (https://spdx.org/licenses/MIT)
6 * PURPOSE: NT Kernel Load Options Support Functions
7 * COPYRIGHT: Copyright 2020-2026 Hermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
8 */
9
10/* INCLUDES ******************************************************************/
11
12#include <freeldr.h>
13#include "ntldropts.h"
14
15/* FUNCTIONS *****************************************************************/
16
20 _Out_opt_ PULONG OptionLength)
21{
23 PCSTR Option = NULL;
24 ULONG Length = 0;
25
26 if (OptionLength)
27 *OptionLength = 0;
28
29 if (!Options || !*Options)
30 return NULL;
31
32 /* Loop over each option */
34 while (*NextOption)
35 {
36 /* Skip possible initial whitespace */
37 NextOption += strspn(NextOption, " \t");
38
39 /* Stop now if we have already found an option.
40 * NextOption points to the next following option. */
41 if (Option)
42 break;
43
44 /* Check whether a new option starts. Options are delimited
45 * with an option separator '/' or with whitespace. */
46 if (*NextOption == '/')
47 ++NextOption;
48
49 /* Get the actual length of the option until
50 * the next whitespace or option separator. */
51 Length = (ULONG)strcspn(NextOption, " \t/");
52
53 /* Retrieve the option if present and go to the beginning of the next one */
54 if (Length != 0)
55 Option = NextOption;
56
57 /* Restart after the end of the option */
59 }
60
62 if (Option && OptionLength)
63 *OptionLength = Length;
64 return Option;
65}
66
67/*
68 * OptionName specifies the option name, without any leading
69 * option separator '/', to search for within the Options.
70 * The search is made case-insensitive.
71 */
75 _In_reads_(OptNameLength) PCCH OptionName,
76 _In_ ULONG OptNameLength,
77 _Out_opt_ PULONG OptionLength)
78{
79 PCSTR NextOptions;
80 PCSTR Option = NULL;
81 ULONG OptLength = 0;
82
83 if (OptionLength)
84 *OptionLength = 0;
85
86 if (!Options || !*Options)
87 return NULL;
88 if (!OptionName || (OptNameLength == 0) || !*OptionName)
89 return NULL;
90
91 NextOptions = Options;
92 while ((Option = NtLdrGetNextOption(&NextOptions, &OptLength)))
93 {
94 /*
95 * Check whether the option to find exactly matches the current
96 * load option, or is a prefix thereof if this is an option with
97 * appended data.
98 */
99 if ((OptLength >= OptNameLength) &&
100 (_strnicmp(Option, OptionName, OptNameLength) == 0))
101 {
102 if ((OptLength == OptNameLength) ||
103 (OptionName[OptNameLength-1] == '=') ||
104 (OptionName[OptNameLength-1] == ':'))
105 {
106 break;
107 }
108 }
109 }
110
111 if (Option && OptionLength)
112 *OptionLength = OptLength;
113 return Option;
114}
115
116PCSTR
119 _In_ PCSTR OptionName,
120 _Out_opt_ PULONG OptionLength)
121{
122 return NtLdrGetOptionExN(Options, OptionName,
123 (ULONG)strlen(OptionName),
124 OptionLength);
125}
126
127PCSTR
130 _In_ PCSTR OptionName)
131{
132 return NtLdrGetOptionEx(Options, OptionName, NULL);
133}
134
140VOID
144 _In_ BOOLEAN Append,
145 _In_opt_ PCSTR NewOptions)
146{
147 ULONG OptionsLength;
148 ULONG NewOptsLength;
150
151 if (!Options || (BufferSize == 0))
152 return;
153 // ASSERT(strlen(Options) + 1 <= BufferSize);
154
155 if (!NewOptions || !*NewOptions)
156 return;
157
158 if (Append)
159 {
160 OptionsLength = (ULONG)strlen(Options);
161 OptionsLength = min(OptionsLength, BufferSize-1);
162
163 /* Add a whitespace separator if needed */
164 if (OptionsLength != 0 &&
165 (Options[OptionsLength-1] != ' ') &&
166 (Options[OptionsLength-1] != '\t') &&
167 (*NewOptions != '\0') &&
168 (*NewOptions != ' ') &&
169 (*NewOptions != '\t'))
170 {
171 RtlStringCbCatA(Options, BufferSize * sizeof(CHAR), " ");
172 }
173
174 /* Append the options */
175 RtlStringCbCatA(Options, BufferSize * sizeof(CHAR), NewOptions);
176 }
177 else
178 {
179 NewOptsLength = (ULONG)strlen(NewOptions);
180 NewOptsLength = min(NewOptsLength, BufferSize-1);
181
182 /* Add a whitespace separator if needed */
184 if (NewOptsLength != 0 &&
185 (NewOptions[NewOptsLength-1] != ' ') &&
186 (NewOptions[NewOptsLength-1] != '\t') &&
187 (*Options != '\0') &&
188 (*Options != ' ') &&
189 (*Options != '\t'))
190 {
192 ++NewOptsLength;
193 }
194
195 /*
196 * Move the original load options forward (possibly truncating them
197 * at the end if the buffer is not large enough) to make place for
198 * the options to prepend.
199 */
200 OptionsLength = (ULONG)strlen(Options) + 1;
201 OptionsLength = min(OptionsLength, BufferSize - NewOptsLength);
202 RtlMoveMemory(Options + NewOptsLength,
203 Options,
204 OptionsLength * sizeof(CHAR));
205 /* NULL-terminate */
206 (Options + NewOptsLength)[OptionsLength-1] = '\0';
207
208 /* Restore the new options length back to its original value */
209 if (AddSeparator)
210 --NewOptsLength;
211 /* Prepend the options and add the whitespace separator if needed */
212 strncpy(Options, NewOptions, NewOptsLength);
213 if (AddSeparator)
214 Options[NewOptsLength] = ' ';
215 }
216}
217
243VOID
245 _Inout_updates_z_(BufferSize) PSTR LoadOptions,
247 _In_ BOOLEAN Append,
248 _In_opt_ PCSTR OptionsToAdd[],
249 _In_opt_ PCSTR OptionsToRemove[])
250{
251 PCSTR NextOptions, NextOpt;
252 PSTR Options, Option;
253 ULONG NextOptLength;
254 ULONG OptionLength;
255
256 if (!LoadOptions || (BufferSize == 0))
257 return;
258 // ASSERT(strlen(LoadOptions) + 1 <= BufferSize);
259
260 /* Loop over the options to remove */
261 for (; OptionsToRemove && *OptionsToRemove; ++OptionsToRemove)
262 {
263 NextOptions = *OptionsToRemove;
264 while ((NextOpt = NtLdrGetNextOption(&NextOptions, &NextOptLength)))
265 {
266 /* Scan the load options */
267 Options = LoadOptions;
268 while ((Option = (PSTR)NtLdrGetNextOption((PCSTR*)&Options, &OptionLength)))
269 {
270 /*
271 * Check whether the option to find exactly matches the current
272 * load option, or is a prefix thereof if this is an option with
273 * appended data.
274 */
275 if ((OptionLength >= NextOptLength) &&
276 (_strnicmp(Option, NextOpt, NextOptLength) == 0))
277 {
278 if ((OptionLength == NextOptLength) ||
279 (NextOpt[NextOptLength-1] == '=') ||
280 (NextOpt[NextOptLength-1] == ':'))
281 {
282 /* Eat any skipped option or whitespace separators */
283 while ((Option > LoadOptions) &&
284 (Option[-1] == '/' ||
285 Option[-1] == ' ' ||
286 Option[-1] == '\t'))
287 {
288 --Option;
289 }
290
291 /* If the option was not preceded by a whitespace
292 * separator, insert one and advance the pointer. */
293 if ((Option > LoadOptions) &&
294 (Option[-1] != ' ') &&
295 (Option[-1] != '\t') &&
296 (*Options != '\0') /* &&
297 ** Not necessary since NtLdrGetNextOption() **
298 ** stripped any leading separators. **
299 (*Options != ' ') &&
300 (*Options != '\t') */)
301 {
302 *Option++ = ' ';
303 }
304
305 /* Move the remaining options back, erasing the current one */
306 ASSERT(Option <= Options);
307 RtlMoveMemory(Option,
308 Options,
309 (strlen(Options) + 1) * sizeof(CHAR));
310
311 /* Reset the iterator */
312 Options = Option;
313 }
314 }
315 }
316 }
317 }
318
319 /* Now loop over the options to add */
320 for (; OptionsToAdd && *OptionsToAdd; ++OptionsToAdd)
321 {
322 NtLdrAddOptions(LoadOptions,
324 Append,
325 *OptionsToAdd);
326 }
327}
unsigned char BOOLEAN
Definition: actypes.h:127
static void AddSeparator(HWND hwndToolBar)
Definition: wordpad.c:169
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define _strnicmp(_String1, _String2, _MaxCount)
Definition: compat.h:23
_ACRTIMP size_t __cdecl strlen(const char *)
Definition: string.c:1592
_ACRTIMP size_t __cdecl strcspn(const char *, const char *)
Definition: string.c:3493
_ACRTIMP size_t __cdecl strspn(const char *, const char *)
Definition: string.c:3515
#define ASSERT(a)
Definition: mode.c:44
static char * NextOption(const char *const ostr)
Definition: getopt.c:31
#define min(a, b)
Definition: monoChain.cc:55
#define _In_reads_(s)
Definition: no_sal2.h:168
#define _Out_opt_
Definition: no_sal2.h:214
#define _Inout_
Definition: no_sal2.h:162
#define _Inout_updates_z_(s)
Definition: no_sal2.h:186
#define _In_
Definition: no_sal2.h:158
#define _In_opt_
Definition: no_sal2.h:212
CONST CHAR * PCCH
Definition: ntbasedef.h:404
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
PCSTR NtLdrGetOptionEx(_In_ PCSTR Options, _In_ PCSTR OptionName, _Out_opt_ PULONG OptionLength)
Definition: ntldropts.c:117
PCSTR NtLdrGetNextOption(_Inout_ PCSTR *Options, _Out_opt_ PULONG OptionLength)
Definition: ntldropts.c:18
VOID NtLdrUpdateOptions(_Inout_updates_z_(BufferSize) PSTR LoadOptions, _In_ ULONG BufferSize, _In_ BOOLEAN Append, _In_opt_ PCSTR OptionsToAdd[], _In_opt_ PCSTR OptionsToRemove[])
Updates the options in the buffer pointed by LoadOptions, of maximum size BufferSize,...
Definition: ntldropts.c:244
VOID NtLdrAddOptions(_Inout_updates_z_(BufferSize) PSTR Options, _In_ ULONG BufferSize, _In_ BOOLEAN Append, _In_opt_ PCSTR NewOptions)
Appends or prepends new options to the ones originally contained in the buffer pointed by Options,...
Definition: ntldropts.c:141
PCSTR NtLdrGetOptionExN(_In_ PCSTR Options, _In_reads_(OptNameLength) PCCH OptionName, _In_ ULONG OptNameLength, _Out_opt_ PULONG OptionLength)
Definition: ntldropts.c:73
PCSTR NtLdrGetOption(_In_ PCSTR Options, _In_ PCSTR OptionName)
Definition: ntldropts.c:128
NTSTRSAFEAPI RtlStringCbCatA(_Inout_updates_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PSTR pszDest, _In_ size_t cbDest, _In_ NTSTRSAFE_PCSTR pszSrc)
Definition: ntstrsafe.h:625
char CHAR
Definition: pedump.c:57
strncpy
Definition: string.h:335
uint32_t * PULONG
Definition: typedefs.h:59
char * PSTR
Definition: typedefs.h:51
const char * PCSTR
Definition: typedefs.h:52
#define RtlMoveMemory(Destination, Source, Length)
Definition: typedefs.h:264
uint32_t ULONG
Definition: typedefs.h:59
_In_ PWDFDEVICE_INIT _In_ PWDF_REMOVE_LOCK_OPTIONS Options
Definition: wdfdevice.h:3540
_In_ WDFMEMORY _Out_opt_ size_t * BufferSize
Definition: wdfmemory.h:254