Skip to content

Commit

Permalink
Functions to work with null delimited lists.
Browse files Browse the repository at this point in the history
copy_double_null() duplicates a null delimited list.

append_to_double_null() adds an entry to a list, or replaces an entry
which matches a given substring of the new value.

remove_from_double_null() removes an entry from a list, possibly only if
it matches a given substring.
  • Loading branch information
Iain Patterson committed Jul 28, 2016
1 parent c0bb728 commit ac8cdc8
Show file tree
Hide file tree
Showing 2 changed files with 158 additions and 5 deletions.
160 changes: 155 additions & 5 deletions registry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -260,16 +260,19 @@ int get_environment(TCHAR *service_name, HKEY key, TCHAR *value, TCHAR **env, un
return 2;
}

/* Probably not possible */
if (! envsize) return 0;
/* Minimum usable environment would be A= NULL NULL. */
if (envsize < 4 * sizeof(TCHAR)) {
*env = 0;
return 3;
}

/* Previously initialised? */
if (*env) HeapFree(GetProcessHeap(), 0, *env);

*env = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, envsize);
if (! *env) {
log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, value, _T("get_environment()"), 0);
return 3;
return 4;
}

/* Actually get the strings. */
Expand All @@ -278,11 +281,11 @@ int get_environment(TCHAR *service_name, HKEY key, TCHAR *value, TCHAR **env, un
log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_QUERYVALUE_FAILED, value, error_string(ret), 0);
HeapFree(GetProcessHeap(), 0, *env);
*env = 0;
return 4;
return 5;
}

/* Value retrieved by RegQueryValueEx() is SIZE not COUNT. */
*envlen = (unsigned long) environment_length(env);
*envlen = (unsigned long) environment_length(*env);

return 0;
}
Expand Down Expand Up @@ -497,6 +500,153 @@ int unformat_double_null(TCHAR *formatted, unsigned long formattedlen, TCHAR **d
return 0;
}

/* Copy a block. */
int copy_double_null(TCHAR *dn, unsigned long dnlen, TCHAR **newdn) {
if (! newdn) return 1;

*newdn = 0;
if (! dn) return 0;

*newdn = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, dnlen * sizeof(TCHAR));
if (! *newdn) {
log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, _T("dn"), _T("copy_double_null()"), 0);
return 2;
}

memmove(*newdn, dn, dnlen * sizeof(TCHAR));
return 0;
}

/*
Create a new block with all the strings of the first block plus a new string.
The new string may be specified as <key> <delimiter> <value> and the keylen
gives the offset into the string to compare against existing entries.
If the key is already present its value will be overwritten in place.
If the key is blank or empty the new block will still be allocated and have
non-zero length.
*/
int append_to_double_null(TCHAR *dn, unsigned long dnlen, TCHAR **newdn, unsigned long *newlen, TCHAR *append, size_t keylen, bool case_sensitive) {
if (! append || ! append[0]) return copy_double_null(dn, dnlen, newdn);
size_t appendlen = _tcslen(append);
int (*fn)(const TCHAR *, const TCHAR *, size_t) = (case_sensitive) ? _tcsncmp : _tcsnicmp;

/* Identify the key, if any, or treat the whole string as the key. */
TCHAR *key = 0;
if (! keylen || keylen > appendlen) keylen = appendlen;
key = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, (keylen + 1) * sizeof(TCHAR));
if (! key) {
log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, _T("key"), _T("append_to_double_null()"), 0);
return 1;
}
memmove(key, append, keylen * sizeof(TCHAR));
key[keylen] = _T('\0');

/* Find the length of the block not including any existing key. */
size_t len = 0;
TCHAR *s;
for (s = dn; *s; s++) {
if (fn(s, key, keylen)) len += _tcslen(s) + 1;
for ( ; *s; s++);
}

/* Account for new entry. */
len += _tcslen(append) + 1;

/* Account for trailing NULL. */
len++;

/* Allocate a new block. */
*newdn = (TCHAR *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(TCHAR));
if (! *newdn) {
log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, _T("newdn"), _T("append_to_double_null()"), 0);
HeapFree(GetProcessHeap(), 0, key);
return 2;
}

/* Copy existing entries.*/
*newlen = (unsigned long) len;
TCHAR *t = *newdn;
TCHAR *u;
bool replaced = false;
for (s = dn; *s; s++) {
if (fn(s, key, keylen)) u = s;
else {
u = append;
replaced = true;
}
len = _tcslen(u) + 1;
memmove(t, u, len * sizeof(TCHAR));
t += len;
for ( ; *s; s++);
}

/* Add the entry if it wasn't already replaced. The buffer was zeroed. */
if (! replaced) memmove(t, append, _tcslen(append) * sizeof(TCHAR));

HeapFree(GetProcessHeap(), 0, key);
return 0;
}

/*
Create a new block with all the string of the first block minus the given
string.
The keylen parameter gives the offset into the string to compare against
existing entries. If a substring of existing value matches the string to
the given length it will be removed.
If the last entry is removed the new block will still be allocated and
have non-zero length.
*/
int remove_from_double_null(TCHAR *dn, unsigned long dnlen, TCHAR **newdn, unsigned long *newlen, TCHAR *remove, size_t keylen, bool case_sensitive) {
if (! remove || !remove[0]) return copy_double_null(dn, dnlen, newdn);
size_t removelen = _tcslen(remove);
int (*fn)(const TCHAR *, const TCHAR *, size_t) = (case_sensitive) ? _tcsncmp : _tcsnicmp;

/* Identify the key, if any, or treat the whole string as the key. */
TCHAR *key = 0;
if (! keylen || keylen > removelen) keylen = removelen;
key = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, (keylen + 1) * sizeof(TCHAR));
if (! key) {
log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, _T("key"), _T("remove_from_double_null()"), 0);
return 1;
}
memmove(key, remove, keylen * sizeof(TCHAR));
key[keylen] = _T('\0');

/* Find the length of the block not including any existing key. */
size_t len = 0;
TCHAR *s;
for (s = dn; *s; s++) {
if (fn(s, key, keylen)) len += _tcslen(s) + 1;
for ( ; *s; s++);
}

/* Account for trailing NULL. */
if (++len < 2) len = 2;

/* Allocate a new block. */
*newdn = (TCHAR *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(TCHAR));
if (! *newdn) {
log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, _T("newdn"), _T("remove_from_double_null()"), 0);
HeapFree(GetProcessHeap(), 0, key);
return 2;
}

/* Copy existing entries.*/
*newlen = (unsigned long) len;
TCHAR *t = *newdn;
for (s = dn; *s; s++) {
if (fn(s, key, keylen)) {
len = _tcslen(s) + 1;
memmove(t, s, len * sizeof(TCHAR));
t += len;
}
for ( ; *s; s++);
}

HeapFree(GetProcessHeap(), 0, key);
return 0;
}

void override_milliseconds(TCHAR *service_name, HKEY key, TCHAR *value, unsigned long *buffer, unsigned long default_value, unsigned long event) {
unsigned long type = REG_DWORD;
unsigned long buflen = sizeof(unsigned long);
Expand Down
3 changes: 3 additions & 0 deletions registry.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ int get_number(HKEY, TCHAR *, unsigned long *, bool);
int get_number(HKEY, TCHAR *, unsigned long *);
int format_double_null(TCHAR *, unsigned long, TCHAR **, unsigned long *);
int unformat_double_null(TCHAR *, unsigned long, TCHAR **, unsigned long *);
int copy_double_null(TCHAR *, unsigned long, TCHAR **);
int append_to_double_null(TCHAR *, unsigned long, TCHAR **, unsigned long *, TCHAR *, size_t, bool);
int remove_from_double_null(TCHAR *, unsigned long, TCHAR **, unsigned long *, TCHAR *, size_t, bool);
void override_milliseconds(TCHAR *, HKEY, TCHAR *, unsigned long *, unsigned long, unsigned long);
int get_io_parameters(nssm_service_t *, HKEY);
int get_parameters(nssm_service_t *, STARTUPINFO *);
Expand Down

0 comments on commit ac8cdc8

Please sign in to comment.