The `git_buf_init` function has an optional length parameter, which will
cause the buffer to be initialized and allocated in one step. This can
be used instead of static initialization with `GIT_BUF_INIT` followed by
a `git_buf_grow`. This patch does so for two functions where it is
applicable.
The current code in `parse_section_header_ext` is only prepared to
properly handle out-of-memory conditions for the `git_buf` structure.
While very unlikely and probably caused by a programming error, it is
also possible to run into error conditions other than out-of-memory
previous to reaching the actual parsing loop. In these cases, we will
run into undefined behavior as the `rpos` variable is only initialized
after these triggerable errors, but we use it in the cleanup-routine.
Fix the issue by unifying the function's cleanup code with an
`end_error` section, which will not use the `rpos` variable.
The config and attrcache file reading code would attempt to load a file
in a home directory by expanding the `~` and looking for the file, using
`git_sysdir_find_global_file`. If the file was not found, the error
handling would look for the literal path, eg `~/filename.txt`.
Use the new `git_config_expand_global_file` instead, which allows us to
get the path to the file separately, when the path is prefixed with
`~/`, and fail with a not found error without falling back to looking
for the literal path.
While parsing section headers, we use a buffer to store the actual
section name. We do not check though if the buffer runs out of memory at
any stage. Do so.
Error messages should be sentence fragments, and therefore:
1. Should not begin with a capital letter,
2. Should not conclude with punctuation, and
3. Should not end a sentence and begin a new one
If we hit the EOF while trying to write a new value, it may be that
we're already in the section that we were looking for. If so, do not
write a (duplicate) section header, just write the value.
This special-casing ignores that we might have a locked file, so the
hashtable does not represent the contents of the file we want to
write. This causes multivar writes to overwrite entries instead of add
to them when under lock.
There is no need for this as the normal code-path will write to the file
just fine, so simply get rid of it.
Accessing the current values map is handled through the
`refcounder_strmap_take` function, which first acquires a mutex
before accessing its values. While this assures everybody is
trying to access the values with the mutex only we do not check
if the locking actually succeeds.
Fix the issue by checking if acquiring the lock succeeds and
returning `NULL` if we encounter an error. Adjust callers.
When parsing a section header we expect something along the
format of '[section "subsection"]'. When a section is
mal-formated and is entirely missing its quotation marks we catch
this case by observing that `strchr(line, '"') - strrchr(line,
'"') = NULL - NULL = 0` and error out. Unfortunately, the error
message is misleading though, as we state that we are missing the
closing quotation mark while we in fact miss both quotation
marks.
Improve the error message by explicitly checking if the first
quotation mark could be found and, if not, stating that quotation
marks are completely missing.
Instead of relying on the size and timestamp, which can hide changes
performed in the same second, hash the file content's when we care about
detecting changes.
When there is a comment at the end of a section, git keeps it there,
while we write the new variable right at the end.
Keep comments buffered and dump them when we're going to output a
variable or section, or reach EOF. This puts us in line with the config
files which git produces.
When a configuration file is locked, any updates made to it will be done
to the in-memory copy of the file. This allows for multiple updates to
happen while we hold the lock, preventing races during complex
config-file manipulation.
Instead of writing into the filebuf directly, make the functions to
write the modified config file write into a buffer which can then be
dumped into the lockfile for committing.
This allows us to re-use the same code for modifying a locked
configuration, as we can simply skip the last step of dumping the data
to disk.
Some brain damaged tolower() implementations appear to want to
take the locale into account, and this may require taking some
insanely aggressive lock on the locale and slowing down what should
be the most trivial of trivial calls for people who just want to
downcase ASCII.
When writing a configuration file, we want to take a lock on the
new file (eg, `config.lock`) before opening the configuration file
(`config`) for reading so that we can prevent somebody from changing
the contents underneath us.
When updating a configuration file, we want to copy the old data
from the file to preserve comments and funny whitespace, instead
of writing it in some "canonical" format. Thus, we keep a
pointer to the start of the line and the line length to preserve
these things we don't care to rewrite.
Previously we would try to be clever when writing the configuration
file and try to stop parsing (and simply copy the rest of the old
file) when we either found the value we were trying to write,
or when we left the section that value was in, the assumption being
that there was no more work to do.
Regrettably, you can have another section with the same name later
in the file, and we must cope with that gracefully, thus we read the
whole file in order to write a new file.
Now, writing a file looks even more than reading. Pull the config
parsing out into its own function that can be used by both reading
and writing the configuration.
If git_config_delete is to work properly in the presence of duplicate section
headers, it cannot stop searching at the end of the first matching section, as
there may be another matching section later.
When config_write is used for deletion (value = NULL), it may only terminate
when the desired key is found or there are no sections left to parse.
The regcomp function returns a non-zero value if compilation of
a regular expression fails. In most places we only check for
negative values, but positive values indicate an error, as well.
Fix this tree-wide, fixing a segmentation fault when calling
git_config_iterator_glob_new with an invalid regexp.
This changes the get_entry() method to return a refcounted version of
the config entry, which you have to free when you're done.
This allows us to avoid freeing the memory in which the entry is stored
on a refresh, which may happen at any time for a live config.
For this reason, get_string() has been forbidden on live configs and a
new function get_string_buf() has been added, which stores the string in
a git_buf which the user then owns.
The functions which parse the string value takea advantage of the
borrowing to parse safely and then release the entry.
Make our overflow checking look more like gcc and clang's, so that
we can substitute it out with the compiler instrinsics on platforms
that support it. This means dropping the ability to pass `NULL` as
an out parameter.
As a result, the macros also get updated to reflect this as well.
Fixes#2869. If included file includes more files, it may reallocate
cfg_file->readers, hence invalidate not only `r` pointer, but `result`
pointer as well.
* Error-handling is cleaned up to only let a file-not-found error
through, not other sorts of errors. And when a file-not-found
error happens, we clean up the error.
* Test now checks that file-not-found introduces no error. And
other minor cleanups.
For example, if you have
[include]
path = foo
and foo didn't exist, git_config_open_ondisk() would just give up
on the rest of the file. Now it ignores the unresolved include
without error and continues reading the rest of the file.