When determining whether some file matches an attr pattern, do
not try to truncate the path to pass to fnmatch. When there is
no containing directory for an item (eg, from a .gitignore in the
root) this will cause us to truncate our path, which means that
we cannot do meaningful comparisons on it and we may have false
positives when trying to determine whether a given file is actually
a file or a folder (as we have lost the path's base information.)
This mangling was to allow fnmatch to compare a directory on disk to
the name of a directory, but it is unnecessary as our fnmatch accepts
FNM_LEADING_DIR.
We use a blocking socket and set the mode to AUTO_RETRY which means that
`SSL_write` and `SSL_read` will only return once the read or write has
been completed. We therefore don't need to handle partial writes or
re-try read due to a regenotiation.
While here, consider that a zero also indicates an error condition.
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.
When checking out with a case-insensitive working directory, we
want to change the case of items in the working directory to
reflect changes that occured in the checkout target. Diff now
has an option to break case-changing renames into delete/add.
Using FindFirstFile and FindNextFile in win32 allows us to
use the directory information that is returned, instead of
us having to get the file attributes all over again, which
is a distinct cost savings on win32.
The _next method shouldn't take a path pointer (and a path_len
pointer) as 100% of current users use the full path and ignore
the filename.
Plus let's add some docs and a unit test.
Changed win32/path_w32.c to utilize NTFS' FindFirst..FindNext data instead of doing an lstat per file. Avoiding unnecessary directory opens and file scans reduces IO, improving overall performance. Effect is magnified due to NTFS being a kernel mode file system (as opposed to user mode).
In checkout.c and filter.c we were casting a sub struct
to a parent struct which breaks the strict aliasing rules
in C. However we can use .parent or .base to access the
parent struct to avoid the build warnings.
In remote.c the local variable error was not initialized
or updated in some cases. For unintialized error a build
warning will be generated. So always keep error variable
up-to-date.
Do not automatically fail on a bad certificate, but let the caller
decide. This means we don't need our switch on errors anymore but can
return a string representation from the security framework.
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 idea...sometimes, a filemode is user-specified via an
explicit git_index_entry. In this case, believe the user, always.
Sometimes, it is instead built up by statting the file system. In
those cases, go with the existing logic we have to determine
whether the file system supports all filemodes and symlinks, and
make the best guess.
On file systems which have full filemode and symlink support, this
commit should make no difference. On others (most notably Windows),
this will fix problems things like:
* git_index_add and git_index_add_frombuffer() should be believed.
* As a consequence, git_checkout_tree should make the filemodes in
the index match the ones in the tree.
* And diffs with GIT_DIFF_UPDATE_INDEX don't write the wrong filemodes.
* And merges, and probably other downstream stuff now fixed, too.
This makes my previous changes to checkout.c unnecessary,
so they are now reverted.
Also, added a test for index_entry permissions from git_index_add
and git_index_add_frombuffer, both of which failed before these changes.
In `git_rebase_operation_current()`, indicate when a rebase has not
started (with `GIT_REBASE_NO_OPERATION`) rather than conflating that
with the first operation being in-progress.
It can be useful for the caller to know which update commands will be
sent to the server before the packfile is pushed up. git does this via
the pre-push hook.
We don't have hooks, but as it adds introspection into what is
happening, we can add a callback which performs the same function.
In the prior implementation, enabling GIT_DIFF_UPDATE_INDEX would overwrite
entries in the index with the ones generated from scanning the working if the
OID was the same.
Because this OID comparison ignores file modes, this means an file in the
workdir with only an exec bit difference with the one in the index would end
up being overwritten, resulting in the exec bit being loss. There might be
other related bugs but the fix of comparing OIDs and file modes should
address them all.
When walking backwards and marking parents uninteresting, make sure we
detect when the list of commits we have left has run out of
uninteresting commits so we can stop marking commits as
uninteresting. Failing to do so can mean that we walk the whole history
marking everything uninteresting, which eats up time, CPU and IO for
with useless work.
While pre-marking does look for this, we still need to check during the
main traversal as there are setups for which pre-marking does not leave
enough information in the commits. This can happen if we push a commit
and hide its parent.