2005-11-17 22:32:36 +01:00
|
|
|
/*
|
|
|
|
* GIT - The information manager from hell
|
|
|
|
*
|
|
|
|
* Copyright (C) Linus Torvalds, 2005
|
|
|
|
* Copyright (C) Johannes Schindelin, 2005
|
|
|
|
*
|
|
|
|
*/
|
2005-10-11 01:31:08 +02:00
|
|
|
#include "cache.h"
|
2014-10-01 12:28:42 +02:00
|
|
|
#include "lockfile.h"
|
2007-11-13 21:05:06 +01:00
|
|
|
#include "exec_cmd.h"
|
2010-03-26 23:56:01 +01:00
|
|
|
#include "strbuf.h"
|
2010-08-23 21:16:00 +02:00
|
|
|
#include "quote.h"
|
2014-07-28 12:10:38 +02:00
|
|
|
#include "hashmap.h"
|
|
|
|
#include "string-list.h"
|
2005-10-11 01:31:08 +02:00
|
|
|
|
2013-07-12 00:44:39 +02:00
|
|
|
struct config_source {
|
|
|
|
struct config_source *prev;
|
|
|
|
union {
|
|
|
|
FILE *file;
|
2013-07-12 00:46:47 +02:00
|
|
|
struct config_buf {
|
|
|
|
const char *buf;
|
|
|
|
size_t len;
|
|
|
|
size_t pos;
|
|
|
|
} buf;
|
2013-07-12 00:44:39 +02:00
|
|
|
} u;
|
config.c: Make git_config() work correctly when called recursively
On Cygwin, this fixes a test failure in t3301-notes.sh (test 98,
"git notes copy --for-rewrite (disabled)").
The test failure is caused by a recursive call to git_config() which
has the effect of skipping to the end-of-file while processing the
"notes.rewriteref" config variable. Thus, any config variables that
appear after "notes.rewriteref" are simply ignored by git_config().
Also, we note that the original FILE handle is leaked as a result
of the recursive call.
The recursive call to git_config() is due to the "schizophrenic stat"
functions on cygwin, where one of two different implementations of
the l/stat functions is selected lazily, depending on some config
variables.
In this case, the init_copy_notes_for_rewrite() function calls
git_config() with the notes_rewrite_config() callback function.
This callback, while processing the "notes.rewriteref" variable,
in turn calls string_list_add_refs_by_glob() to process the
associated ref value. This eventually leads to a call to the
get_ref_dir() function, which in turn calls stat(). On cygwin,
the stat() macro leads to an indirect call to cygwin_stat_stub()
which, via init_stat(), then calls git_config() in order to
determine which l/stat implementation to bind to.
In order to solve this problem, we modify git_config() so that the
global state variables used by the config reading code is packaged
up and managed on a local state stack.
Signed-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-06-16 22:24:51 +02:00
|
|
|
const char *name;
|
2014-02-18 23:58:52 +01:00
|
|
|
const char *path;
|
2013-07-12 00:48:30 +02:00
|
|
|
int die_on_error;
|
config.c: Make git_config() work correctly when called recursively
On Cygwin, this fixes a test failure in t3301-notes.sh (test 98,
"git notes copy --for-rewrite (disabled)").
The test failure is caused by a recursive call to git_config() which
has the effect of skipping to the end-of-file while processing the
"notes.rewriteref" config variable. Thus, any config variables that
appear after "notes.rewriteref" are simply ignored by git_config().
Also, we note that the original FILE handle is leaked as a result
of the recursive call.
The recursive call to git_config() is due to the "schizophrenic stat"
functions on cygwin, where one of two different implementations of
the l/stat functions is selected lazily, depending on some config
variables.
In this case, the init_copy_notes_for_rewrite() function calls
git_config() with the notes_rewrite_config() callback function.
This callback, while processing the "notes.rewriteref" variable,
in turn calls string_list_add_refs_by_glob() to process the
associated ref value. This eventually leads to a call to the
get_ref_dir() function, which in turn calls stat(). On cygwin,
the stat() macro leads to an indirect call to cygwin_stat_stub()
which, via init_stat(), then calls git_config() in order to
determine which l/stat implementation to bind to.
In order to solve this problem, we modify git_config() so that the
global state variables used by the config reading code is packaged
up and managed on a local state stack.
Signed-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-06-16 22:24:51 +02:00
|
|
|
int linenr;
|
|
|
|
int eof;
|
|
|
|
struct strbuf value;
|
2012-09-30 21:44:36 +02:00
|
|
|
struct strbuf var;
|
config.c: Make git_config() work correctly when called recursively
On Cygwin, this fixes a test failure in t3301-notes.sh (test 98,
"git notes copy --for-rewrite (disabled)").
The test failure is caused by a recursive call to git_config() which
has the effect of skipping to the end-of-file while processing the
"notes.rewriteref" config variable. Thus, any config variables that
appear after "notes.rewriteref" are simply ignored by git_config().
Also, we note that the original FILE handle is leaked as a result
of the recursive call.
The recursive call to git_config() is due to the "schizophrenic stat"
functions on cygwin, where one of two different implementations of
the l/stat functions is selected lazily, depending on some config
variables.
In this case, the init_copy_notes_for_rewrite() function calls
git_config() with the notes_rewrite_config() callback function.
This callback, while processing the "notes.rewriteref" variable,
in turn calls string_list_add_refs_by_glob() to process the
associated ref value. This eventually leads to a call to the
get_ref_dir() function, which in turn calls stat(). On cygwin,
the stat() macro leads to an indirect call to cygwin_stat_stub()
which, via init_stat(), then calls git_config() in order to
determine which l/stat implementation to bind to.
In order to solve this problem, we modify git_config() so that the
global state variables used by the config reading code is packaged
up and managed on a local state stack.
Signed-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-06-16 22:24:51 +02:00
|
|
|
|
2013-08-26 23:57:18 +02:00
|
|
|
int (*do_fgetc)(struct config_source *c);
|
|
|
|
int (*do_ungetc)(int c, struct config_source *conf);
|
|
|
|
long (*do_ftell)(struct config_source *c);
|
2013-07-12 00:44:39 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct config_source *cf;
|
config.c: Make git_config() work correctly when called recursively
On Cygwin, this fixes a test failure in t3301-notes.sh (test 98,
"git notes copy --for-rewrite (disabled)").
The test failure is caused by a recursive call to git_config() which
has the effect of skipping to the end-of-file while processing the
"notes.rewriteref" config variable. Thus, any config variables that
appear after "notes.rewriteref" are simply ignored by git_config().
Also, we note that the original FILE handle is leaked as a result
of the recursive call.
The recursive call to git_config() is due to the "schizophrenic stat"
functions on cygwin, where one of two different implementations of
the l/stat functions is selected lazily, depending on some config
variables.
In this case, the init_copy_notes_for_rewrite() function calls
git_config() with the notes_rewrite_config() callback function.
This callback, while processing the "notes.rewriteref" variable,
in turn calls string_list_add_refs_by_glob() to process the
associated ref value. This eventually leads to a call to the
get_ref_dir() function, which in turn calls stat(). On cygwin,
the stat() macro leads to an indirect call to cygwin_stat_stub()
which, via init_stat(), then calls git_config() in order to
determine which l/stat implementation to bind to.
In order to solve this problem, we modify git_config() so that the
global state variables used by the config reading code is packaged
up and managed on a local state stack.
Signed-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-06-16 22:24:51 +02:00
|
|
|
|
Custom compression levels for objects and packs
Add config variables pack.compression and core.loosecompression ,
and switch --compression=level to pack-objects.
Loose objects will be compressed using core.loosecompression if set,
else core.compression if set, else Z_BEST_SPEED.
Packed objects will be compressed using --compression=level if seen,
else pack.compression if set, else core.compression if set,
else Z_DEFAULT_COMPRESSION. This is the "pack compression level".
Loose objects added to a pack undeltified will be recompressed
to the pack compression level if it is unequal to the current
loose compression level by the preceding rules, or if the loose
object was written while core.legacyheaders = true. Newly
deltified loose objects are always compressed to the current
pack compression level.
Previously packed objects added to a pack are recompressed
to the current pack compression level exactly when their
deltification status changes, since the previous pack data
cannot be reused.
In either case, the --no-reuse-object switch from the first
patch below will always force recompression to the current pack
compression level, instead of assuming the pack compression level
hasn't changed and pack data can be reused when possible.
This applies on top of the following patches from Nicolas Pitre:
[PATCH] allow for undeltified objects not to be reused
[PATCH] make "repack -f" imply "pack-objects --no-reuse-object"
Signed-off-by: Dana L. How <danahow@gmail.com>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-05-09 22:56:50 +02:00
|
|
|
static int zlib_compression_seen;
|
|
|
|
|
2014-07-28 12:10:38 +02:00
|
|
|
/*
|
|
|
|
* Default config_set that contains key-value pairs from the usual set of config
|
|
|
|
* config files (i.e repo specific .git/config, user wide ~/.gitconfig, XDG
|
|
|
|
* config file and the global /etc/gitconfig)
|
|
|
|
*/
|
|
|
|
static struct config_set the_config_set;
|
|
|
|
|
2013-07-12 00:44:39 +02:00
|
|
|
static int config_file_fgetc(struct config_source *conf)
|
|
|
|
{
|
|
|
|
return fgetc(conf->u.file);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int config_file_ungetc(int c, struct config_source *conf)
|
|
|
|
{
|
|
|
|
return ungetc(c, conf->u.file);
|
|
|
|
}
|
|
|
|
|
|
|
|
static long config_file_ftell(struct config_source *conf)
|
|
|
|
{
|
|
|
|
return ftell(conf->u.file);
|
|
|
|
}
|
|
|
|
|
2013-07-12 00:46:47 +02:00
|
|
|
|
|
|
|
static int config_buf_fgetc(struct config_source *conf)
|
|
|
|
{
|
|
|
|
if (conf->u.buf.pos < conf->u.buf.len)
|
|
|
|
return conf->u.buf.buf[conf->u.buf.pos++];
|
|
|
|
|
|
|
|
return EOF;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int config_buf_ungetc(int c, struct config_source *conf)
|
|
|
|
{
|
config_buf_ungetc: warn when pushing back a random character
Our config code simulates a stdio stream around a buffer,
but our fake ungetc() does not behave quite like the real
one. In particular, we only rewind the position by one
character, but do _not_ actually put the character from the
caller into position.
It turns out that this does not matter, because we only ever
push back the character we just read. In other words, such
an assignment would be a noop. But because the function is
called ungetc, and because it takes a character parameter,
it is a mistake waiting to happen.
Actually assigning the character into the buffer would be
ideal, but our pointer is actually a "const" copy of the
buffer. We do not know who the real owner of the buffer is
in this code, and would not want to munge their contents.
Instead, we can simply add an assertion that matches what
the current caller does, and will let us know if new callers
are added that violate the contract.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-02-05 22:00:24 +01:00
|
|
|
if (conf->u.buf.pos > 0) {
|
|
|
|
conf->u.buf.pos--;
|
|
|
|
if (conf->u.buf.buf[conf->u.buf.pos] != c)
|
|
|
|
die("BUG: config_buf can only ungetc the same character");
|
|
|
|
return c;
|
|
|
|
}
|
2013-07-12 00:46:47 +02:00
|
|
|
|
|
|
|
return EOF;
|
|
|
|
}
|
|
|
|
|
|
|
|
static long config_buf_ftell(struct config_source *conf)
|
|
|
|
{
|
|
|
|
return conf->u.buf.pos;
|
|
|
|
}
|
|
|
|
|
config: add include directive
It can be useful to split your ~/.gitconfig across multiple
files. For example, you might have a "main" file which is
used on many machines, but a small set of per-machine
tweaks. Or you may want to make some of your config public
(e.g., clever aliases) while keeping other data back (e.g.,
your name or other identifying information). Or you may want
to include a number of config options in some subset of your
repos without copying and pasting (e.g., you want to
reference them from the .git/config of participating repos).
This patch introduces an include directive for config files.
It looks like:
[include]
path = /path/to/file
This is syntactically backwards-compatible with existing git
config parsers (i.e., they will see it as another config
entry and ignore it unless you are looking up include.path).
The implementation provides a "git_config_include" callback
which wraps regular config callbacks. Callers can pass it to
git_config_from_file, and it will transparently follow any
include directives, passing all of the discovered options to
the real callback.
Include directives are turned on automatically for "regular"
git config parsing. This includes calls to git_config, as
well as calls to the "git config" program that do not
specify a single file (e.g., using "-f", "--global", etc).
They are not turned on in other cases, including:
1. Parsing of other config-like files, like .gitmodules.
There isn't a real need, and I'd rather be conservative
and avoid unnecessary incompatibility or confusion.
2. Reading single files via "git config". This is for two
reasons:
a. backwards compatibility with scripts looking at
config-like files.
b. inspection of a specific file probably means you
care about just what's in that file, not a general
lookup for "do we have this value anywhere at
all". If that is not the case, the caller can
always specify "--includes".
3. Writing files via "git config"; we want to treat
include.* variables as literal items to be copied (or
modified), and not expand them. So "git config
--unset-all foo.bar" would operate _only_ on
.git/config, not any of its included files (just as it
also does not operate on ~/.gitconfig).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-06 10:54:04 +01:00
|
|
|
#define MAX_INCLUDE_DEPTH 10
|
|
|
|
static const char include_depth_advice[] =
|
|
|
|
"exceeded maximum include depth (%d) while including\n"
|
|
|
|
" %s\n"
|
|
|
|
"from\n"
|
|
|
|
" %s\n"
|
|
|
|
"Do you have circular includes?";
|
|
|
|
static int handle_path_include(const char *path, struct config_include_data *inc)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
struct strbuf buf = STRBUF_INIT;
|
2014-01-28 02:37:30 +01:00
|
|
|
char *expanded;
|
2012-04-25 14:00:36 +02:00
|
|
|
|
2014-01-28 02:37:30 +01:00
|
|
|
if (!path)
|
|
|
|
return config_error_nonbool("include.path");
|
|
|
|
|
|
|
|
expanded = expand_user_path(path);
|
2012-04-25 14:00:36 +02:00
|
|
|
if (!expanded)
|
|
|
|
return error("Could not expand include path '%s'", path);
|
|
|
|
path = expanded;
|
config: add include directive
It can be useful to split your ~/.gitconfig across multiple
files. For example, you might have a "main" file which is
used on many machines, but a small set of per-machine
tweaks. Or you may want to make some of your config public
(e.g., clever aliases) while keeping other data back (e.g.,
your name or other identifying information). Or you may want
to include a number of config options in some subset of your
repos without copying and pasting (e.g., you want to
reference them from the .git/config of participating repos).
This patch introduces an include directive for config files.
It looks like:
[include]
path = /path/to/file
This is syntactically backwards-compatible with existing git
config parsers (i.e., they will see it as another config
entry and ignore it unless you are looking up include.path).
The implementation provides a "git_config_include" callback
which wraps regular config callbacks. Callers can pass it to
git_config_from_file, and it will transparently follow any
include directives, passing all of the discovered options to
the real callback.
Include directives are turned on automatically for "regular"
git config parsing. This includes calls to git_config, as
well as calls to the "git config" program that do not
specify a single file (e.g., using "-f", "--global", etc).
They are not turned on in other cases, including:
1. Parsing of other config-like files, like .gitmodules.
There isn't a real need, and I'd rather be conservative
and avoid unnecessary incompatibility or confusion.
2. Reading single files via "git config". This is for two
reasons:
a. backwards compatibility with scripts looking at
config-like files.
b. inspection of a specific file probably means you
care about just what's in that file, not a general
lookup for "do we have this value anywhere at
all". If that is not the case, the caller can
always specify "--includes".
3. Writing files via "git config"; we want to treat
include.* variables as literal items to be copied (or
modified), and not expand them. So "git config
--unset-all foo.bar" would operate _only_ on
.git/config, not any of its included files (just as it
also does not operate on ~/.gitconfig).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-06 10:54:04 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Use an absolute path as-is, but interpret relative paths
|
|
|
|
* based on the including config file.
|
|
|
|
*/
|
|
|
|
if (!is_absolute_path(path)) {
|
|
|
|
char *slash;
|
|
|
|
|
2014-02-18 23:58:52 +01:00
|
|
|
if (!cf || !cf->path)
|
config: add include directive
It can be useful to split your ~/.gitconfig across multiple
files. For example, you might have a "main" file which is
used on many machines, but a small set of per-machine
tweaks. Or you may want to make some of your config public
(e.g., clever aliases) while keeping other data back (e.g.,
your name or other identifying information). Or you may want
to include a number of config options in some subset of your
repos without copying and pasting (e.g., you want to
reference them from the .git/config of participating repos).
This patch introduces an include directive for config files.
It looks like:
[include]
path = /path/to/file
This is syntactically backwards-compatible with existing git
config parsers (i.e., they will see it as another config
entry and ignore it unless you are looking up include.path).
The implementation provides a "git_config_include" callback
which wraps regular config callbacks. Callers can pass it to
git_config_from_file, and it will transparently follow any
include directives, passing all of the discovered options to
the real callback.
Include directives are turned on automatically for "regular"
git config parsing. This includes calls to git_config, as
well as calls to the "git config" program that do not
specify a single file (e.g., using "-f", "--global", etc).
They are not turned on in other cases, including:
1. Parsing of other config-like files, like .gitmodules.
There isn't a real need, and I'd rather be conservative
and avoid unnecessary incompatibility or confusion.
2. Reading single files via "git config". This is for two
reasons:
a. backwards compatibility with scripts looking at
config-like files.
b. inspection of a specific file probably means you
care about just what's in that file, not a general
lookup for "do we have this value anywhere at
all". If that is not the case, the caller can
always specify "--includes".
3. Writing files via "git config"; we want to treat
include.* variables as literal items to be copied (or
modified), and not expand them. So "git config
--unset-all foo.bar" would operate _only_ on
.git/config, not any of its included files (just as it
also does not operate on ~/.gitconfig).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-06 10:54:04 +01:00
|
|
|
return error("relative config includes must come from files");
|
|
|
|
|
2014-02-18 23:58:52 +01:00
|
|
|
slash = find_last_dir_sep(cf->path);
|
config: add include directive
It can be useful to split your ~/.gitconfig across multiple
files. For example, you might have a "main" file which is
used on many machines, but a small set of per-machine
tweaks. Or you may want to make some of your config public
(e.g., clever aliases) while keeping other data back (e.g.,
your name or other identifying information). Or you may want
to include a number of config options in some subset of your
repos without copying and pasting (e.g., you want to
reference them from the .git/config of participating repos).
This patch introduces an include directive for config files.
It looks like:
[include]
path = /path/to/file
This is syntactically backwards-compatible with existing git
config parsers (i.e., they will see it as another config
entry and ignore it unless you are looking up include.path).
The implementation provides a "git_config_include" callback
which wraps regular config callbacks. Callers can pass it to
git_config_from_file, and it will transparently follow any
include directives, passing all of the discovered options to
the real callback.
Include directives are turned on automatically for "regular"
git config parsing. This includes calls to git_config, as
well as calls to the "git config" program that do not
specify a single file (e.g., using "-f", "--global", etc).
They are not turned on in other cases, including:
1. Parsing of other config-like files, like .gitmodules.
There isn't a real need, and I'd rather be conservative
and avoid unnecessary incompatibility or confusion.
2. Reading single files via "git config". This is for two
reasons:
a. backwards compatibility with scripts looking at
config-like files.
b. inspection of a specific file probably means you
care about just what's in that file, not a general
lookup for "do we have this value anywhere at
all". If that is not the case, the caller can
always specify "--includes".
3. Writing files via "git config"; we want to treat
include.* variables as literal items to be copied (or
modified), and not expand them. So "git config
--unset-all foo.bar" would operate _only_ on
.git/config, not any of its included files (just as it
also does not operate on ~/.gitconfig).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-06 10:54:04 +01:00
|
|
|
if (slash)
|
2014-02-18 23:58:52 +01:00
|
|
|
strbuf_add(&buf, cf->path, slash - cf->path + 1);
|
config: add include directive
It can be useful to split your ~/.gitconfig across multiple
files. For example, you might have a "main" file which is
used on many machines, but a small set of per-machine
tweaks. Or you may want to make some of your config public
(e.g., clever aliases) while keeping other data back (e.g.,
your name or other identifying information). Or you may want
to include a number of config options in some subset of your
repos without copying and pasting (e.g., you want to
reference them from the .git/config of participating repos).
This patch introduces an include directive for config files.
It looks like:
[include]
path = /path/to/file
This is syntactically backwards-compatible with existing git
config parsers (i.e., they will see it as another config
entry and ignore it unless you are looking up include.path).
The implementation provides a "git_config_include" callback
which wraps regular config callbacks. Callers can pass it to
git_config_from_file, and it will transparently follow any
include directives, passing all of the discovered options to
the real callback.
Include directives are turned on automatically for "regular"
git config parsing. This includes calls to git_config, as
well as calls to the "git config" program that do not
specify a single file (e.g., using "-f", "--global", etc).
They are not turned on in other cases, including:
1. Parsing of other config-like files, like .gitmodules.
There isn't a real need, and I'd rather be conservative
and avoid unnecessary incompatibility or confusion.
2. Reading single files via "git config". This is for two
reasons:
a. backwards compatibility with scripts looking at
config-like files.
b. inspection of a specific file probably means you
care about just what's in that file, not a general
lookup for "do we have this value anywhere at
all". If that is not the case, the caller can
always specify "--includes".
3. Writing files via "git config"; we want to treat
include.* variables as literal items to be copied (or
modified), and not expand them. So "git config
--unset-all foo.bar" would operate _only_ on
.git/config, not any of its included files (just as it
also does not operate on ~/.gitconfig).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-06 10:54:04 +01:00
|
|
|
strbuf_addstr(&buf, path);
|
|
|
|
path = buf.buf;
|
|
|
|
}
|
|
|
|
|
config: allow inaccessible configuration under $HOME
The changes v1.7.12.1~2^2~4 (config: warn on inaccessible files,
2012-08-21) and v1.8.1.1~22^2~2 (config: treat user and xdg config
permission problems as errors, 2012-10-13) were intended to prevent
important configuration (think "[transfer] fsckobjects") from being
ignored when the configuration is unintentionally unreadable (for
example with EIO on a flaky filesystem, or with ENOMEM due to a DoS
attack). Usually ~/.gitconfig and ~/.config/git are readable by the
current user, and if they aren't then it would be easy to fix those
permissions, so the damage from adding this check should have been
minimal.
Unfortunately the access() check often trips when git is being run as
a server. A daemon (such as inetd or git-daemon) starts as "root",
creates a listening socket, and then drops privileges, meaning that
when git commands are invoked they cannot access $HOME and die with
fatal: unable to access '/root/.config/git/config': Permission denied
Any patch to fix this would have one of three problems:
1. We annoy sysadmins who need to take an extra step to handle HOME
when dropping privileges (the current behavior, or any other
proposal that they have to opt into).
2. We annoy sysadmins who want to set HOME when dropping privileges,
either by making what they want to do impossible, or making them
set an extra variable or option to accomplish what used to work
(e.g., a patch to git-daemon to set HOME when --user is passed).
3. We loosen the check, so some cases which might be noteworthy are
not caught.
This patch is of type (3).
Treat user and xdg configuration that are inaccessible due to
permissions (EACCES) as though no user configuration was provided at
all.
An alternative method would be to check if $HOME is readable, but that
would not help in cases where the user who dropped privileges had a
globally readable HOME with only .config or .gitconfig being private.
This does not change the behavior when /etc/gitconfig or .git/config
is unreadable (since those are more serious configuration errors),
nor when ~/.gitconfig or ~/.config/git is unreadable due to problems
other than permissions.
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Improved-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-04-12 23:03:18 +02:00
|
|
|
if (!access_or_die(path, R_OK, 0)) {
|
config: add include directive
It can be useful to split your ~/.gitconfig across multiple
files. For example, you might have a "main" file which is
used on many machines, but a small set of per-machine
tweaks. Or you may want to make some of your config public
(e.g., clever aliases) while keeping other data back (e.g.,
your name or other identifying information). Or you may want
to include a number of config options in some subset of your
repos without copying and pasting (e.g., you want to
reference them from the .git/config of participating repos).
This patch introduces an include directive for config files.
It looks like:
[include]
path = /path/to/file
This is syntactically backwards-compatible with existing git
config parsers (i.e., they will see it as another config
entry and ignore it unless you are looking up include.path).
The implementation provides a "git_config_include" callback
which wraps regular config callbacks. Callers can pass it to
git_config_from_file, and it will transparently follow any
include directives, passing all of the discovered options to
the real callback.
Include directives are turned on automatically for "regular"
git config parsing. This includes calls to git_config, as
well as calls to the "git config" program that do not
specify a single file (e.g., using "-f", "--global", etc).
They are not turned on in other cases, including:
1. Parsing of other config-like files, like .gitmodules.
There isn't a real need, and I'd rather be conservative
and avoid unnecessary incompatibility or confusion.
2. Reading single files via "git config". This is for two
reasons:
a. backwards compatibility with scripts looking at
config-like files.
b. inspection of a specific file probably means you
care about just what's in that file, not a general
lookup for "do we have this value anywhere at
all". If that is not the case, the caller can
always specify "--includes".
3. Writing files via "git config"; we want to treat
include.* variables as literal items to be copied (or
modified), and not expand them. So "git config
--unset-all foo.bar" would operate _only_ on
.git/config, not any of its included files (just as it
also does not operate on ~/.gitconfig).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-06 10:54:04 +01:00
|
|
|
if (++inc->depth > MAX_INCLUDE_DEPTH)
|
|
|
|
die(include_depth_advice, MAX_INCLUDE_DEPTH, path,
|
|
|
|
cf && cf->name ? cf->name : "the command line");
|
|
|
|
ret = git_config_from_file(git_config_include, path, inc);
|
|
|
|
inc->depth--;
|
|
|
|
}
|
|
|
|
strbuf_release(&buf);
|
2012-04-25 14:00:36 +02:00
|
|
|
free(expanded);
|
config: add include directive
It can be useful to split your ~/.gitconfig across multiple
files. For example, you might have a "main" file which is
used on many machines, but a small set of per-machine
tweaks. Or you may want to make some of your config public
(e.g., clever aliases) while keeping other data back (e.g.,
your name or other identifying information). Or you may want
to include a number of config options in some subset of your
repos without copying and pasting (e.g., you want to
reference them from the .git/config of participating repos).
This patch introduces an include directive for config files.
It looks like:
[include]
path = /path/to/file
This is syntactically backwards-compatible with existing git
config parsers (i.e., they will see it as another config
entry and ignore it unless you are looking up include.path).
The implementation provides a "git_config_include" callback
which wraps regular config callbacks. Callers can pass it to
git_config_from_file, and it will transparently follow any
include directives, passing all of the discovered options to
the real callback.
Include directives are turned on automatically for "regular"
git config parsing. This includes calls to git_config, as
well as calls to the "git config" program that do not
specify a single file (e.g., using "-f", "--global", etc).
They are not turned on in other cases, including:
1. Parsing of other config-like files, like .gitmodules.
There isn't a real need, and I'd rather be conservative
and avoid unnecessary incompatibility or confusion.
2. Reading single files via "git config". This is for two
reasons:
a. backwards compatibility with scripts looking at
config-like files.
b. inspection of a specific file probably means you
care about just what's in that file, not a general
lookup for "do we have this value anywhere at
all". If that is not the case, the caller can
always specify "--includes".
3. Writing files via "git config"; we want to treat
include.* variables as literal items to be copied (or
modified), and not expand them. So "git config
--unset-all foo.bar" would operate _only_ on
.git/config, not any of its included files (just as it
also does not operate on ~/.gitconfig).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-06 10:54:04 +01:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int git_config_include(const char *var, const char *value, void *data)
|
|
|
|
{
|
|
|
|
struct config_include_data *inc = data;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Pass along all values, including "include" directives; this makes it
|
|
|
|
* possible to query information on the includes themselves.
|
|
|
|
*/
|
|
|
|
ret = inc->fn(var, value, inc->data);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
2014-08-30 18:07:05 +02:00
|
|
|
if (!strcmp(var, "include.path"))
|
config: add include directive
It can be useful to split your ~/.gitconfig across multiple
files. For example, you might have a "main" file which is
used on many machines, but a small set of per-machine
tweaks. Or you may want to make some of your config public
(e.g., clever aliases) while keeping other data back (e.g.,
your name or other identifying information). Or you may want
to include a number of config options in some subset of your
repos without copying and pasting (e.g., you want to
reference them from the .git/config of participating repos).
This patch introduces an include directive for config files.
It looks like:
[include]
path = /path/to/file
This is syntactically backwards-compatible with existing git
config parsers (i.e., they will see it as another config
entry and ignore it unless you are looking up include.path).
The implementation provides a "git_config_include" callback
which wraps regular config callbacks. Callers can pass it to
git_config_from_file, and it will transparently follow any
include directives, passing all of the discovered options to
the real callback.
Include directives are turned on automatically for "regular"
git config parsing. This includes calls to git_config, as
well as calls to the "git config" program that do not
specify a single file (e.g., using "-f", "--global", etc).
They are not turned on in other cases, including:
1. Parsing of other config-like files, like .gitmodules.
There isn't a real need, and I'd rather be conservative
and avoid unnecessary incompatibility or confusion.
2. Reading single files via "git config". This is for two
reasons:
a. backwards compatibility with scripts looking at
config-like files.
b. inspection of a specific file probably means you
care about just what's in that file, not a general
lookup for "do we have this value anywhere at
all". If that is not the case, the caller can
always specify "--includes".
3. Writing files via "git config"; we want to treat
include.* variables as literal items to be copied (or
modified), and not expand them. So "git config
--unset-all foo.bar" would operate _only_ on
.git/config, not any of its included files (just as it
also does not operate on ~/.gitconfig).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-06 10:54:04 +01:00
|
|
|
ret = handle_path_include(value, inc);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2010-08-23 21:16:00 +02:00
|
|
|
void git_config_push_parameter(const char *text)
|
|
|
|
{
|
|
|
|
struct strbuf env = STRBUF_INIT;
|
|
|
|
const char *old = getenv(CONFIG_DATA_ENVIRONMENT);
|
|
|
|
if (old) {
|
|
|
|
strbuf_addstr(&env, old);
|
|
|
|
strbuf_addch(&env, ' ');
|
|
|
|
}
|
|
|
|
sq_quote_buf(&env, text);
|
|
|
|
setenv(CONFIG_DATA_ENVIRONMENT, env.buf, 1);
|
|
|
|
strbuf_release(&env);
|
|
|
|
}
|
|
|
|
|
2011-06-09 17:56:42 +02:00
|
|
|
int git_config_parse_parameter(const char *text,
|
|
|
|
config_fn_t fn, void *data)
|
2010-03-26 23:53:57 +01:00
|
|
|
{
|
2014-08-05 00:40:19 +02:00
|
|
|
const char *value;
|
2010-03-26 23:56:01 +01:00
|
|
|
struct strbuf **pair;
|
2014-08-05 00:40:19 +02:00
|
|
|
|
2011-06-09 17:55:09 +02:00
|
|
|
pair = strbuf_split_str(text, '=', 2);
|
2011-06-09 17:52:43 +02:00
|
|
|
if (!pair[0])
|
|
|
|
return error("bogus config parameter: %s", text);
|
2014-08-05 00:40:19 +02:00
|
|
|
|
|
|
|
if (pair[0]->len && pair[0]->buf[pair[0]->len - 1] == '=') {
|
2010-03-26 23:56:01 +01:00
|
|
|
strbuf_setlen(pair[0], pair[0]->len - 1);
|
2014-08-05 00:40:19 +02:00
|
|
|
value = pair[1] ? pair[1]->buf : "";
|
|
|
|
} else {
|
|
|
|
value = NULL;
|
|
|
|
}
|
|
|
|
|
2010-03-26 23:56:01 +01:00
|
|
|
strbuf_trim(pair[0]);
|
|
|
|
if (!pair[0]->len) {
|
|
|
|
strbuf_list_free(pair);
|
2011-05-25 00:49:55 +02:00
|
|
|
return error("bogus config parameter: %s", text);
|
2010-03-26 23:53:57 +01:00
|
|
|
}
|
2014-05-23 22:03:47 +02:00
|
|
|
strbuf_tolower(pair[0]);
|
2014-08-05 00:40:19 +02:00
|
|
|
if (fn(pair[0]->buf, value, data) < 0) {
|
2011-05-25 00:49:55 +02:00
|
|
|
strbuf_list_free(pair);
|
|
|
|
return -1;
|
2010-03-26 23:56:01 +01:00
|
|
|
}
|
|
|
|
strbuf_list_free(pair);
|
2010-03-26 23:53:57 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-05-25 00:49:55 +02:00
|
|
|
int git_config_from_parameters(config_fn_t fn, void *data)
|
|
|
|
{
|
2010-08-23 21:16:00 +02:00
|
|
|
const char *env = getenv(CONFIG_DATA_ENVIRONMENT);
|
|
|
|
char *envw;
|
|
|
|
const char **argv = NULL;
|
|
|
|
int nr = 0, alloc = 0;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (!env)
|
|
|
|
return 0;
|
|
|
|
/* sq_dequote will write over it */
|
|
|
|
envw = xstrdup(env);
|
|
|
|
|
|
|
|
if (sq_dequote_to_argv(envw, &argv, &nr, &alloc) < 0) {
|
|
|
|
free(envw);
|
|
|
|
return error("bogus format in " CONFIG_DATA_ENVIRONMENT);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < nr; i++) {
|
2011-05-25 00:49:55 +02:00
|
|
|
if (git_config_parse_parameter(argv[i], fn, data) < 0) {
|
2010-08-23 21:16:00 +02:00
|
|
|
free(argv);
|
|
|
|
free(envw);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
free(argv);
|
|
|
|
free(envw);
|
2011-05-25 00:49:55 +02:00
|
|
|
return nr > 0;
|
2010-08-23 21:16:00 +02:00
|
|
|
}
|
|
|
|
|
2005-10-11 01:31:08 +02:00
|
|
|
static int get_next_char(void)
|
|
|
|
{
|
2013-08-26 23:57:18 +02:00
|
|
|
int c = cf->do_fgetc(cf);
|
2005-10-11 01:31:08 +02:00
|
|
|
|
2013-05-11 15:19:29 +02:00
|
|
|
if (c == '\r') {
|
|
|
|
/* DOS like systems */
|
2013-08-26 23:57:18 +02:00
|
|
|
c = cf->do_fgetc(cf);
|
2013-05-11 15:19:29 +02:00
|
|
|
if (c != '\n') {
|
config: do not ungetc EOF
When we are parsing a config value, if we see a carriage
return, we fgetc the next character to see if it is a
line feed (in which case we silently drop the CR). If it
isn't, we then ungetc the character, and take the literal
CR.
But we never check whether we in fact got a character at
all. If the config file ends in CR, we will get EOF here,
and try to ungetc EOF. This works OK for a real stdio
stream. The ungetc returns an error, and the next fgetc will
then return EOF again.
However, our custom buffer-based stream is not so fortunate.
It happily rewinds the position of the stream by one
character, ignoring the fact that we fed it EOF. The next
fgetc call returns the final CR again, over and over, and we
end up in an infinite loop.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-02-05 07:53:28 +01:00
|
|
|
if (c != EOF)
|
|
|
|
cf->do_ungetc(c, cf);
|
2013-05-11 15:19:29 +02:00
|
|
|
c = '\r';
|
2005-10-11 01:31:08 +02:00
|
|
|
}
|
|
|
|
}
|
2013-05-11 15:19:29 +02:00
|
|
|
if (c == '\n')
|
|
|
|
cf->linenr++;
|
|
|
|
if (c == EOF) {
|
|
|
|
cf->eof = 1;
|
2014-08-07 13:59:13 +02:00
|
|
|
cf->linenr++;
|
2013-05-11 15:19:29 +02:00
|
|
|
c = '\n';
|
|
|
|
}
|
2005-10-11 01:31:08 +02:00
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *parse_value(void)
|
|
|
|
{
|
2011-04-10 22:54:18 +02:00
|
|
|
int quote = 0, comment = 0, space = 0;
|
2005-10-11 01:31:08 +02:00
|
|
|
|
config.c: Make git_config() work correctly when called recursively
On Cygwin, this fixes a test failure in t3301-notes.sh (test 98,
"git notes copy --for-rewrite (disabled)").
The test failure is caused by a recursive call to git_config() which
has the effect of skipping to the end-of-file while processing the
"notes.rewriteref" config variable. Thus, any config variables that
appear after "notes.rewriteref" are simply ignored by git_config().
Also, we note that the original FILE handle is leaked as a result
of the recursive call.
The recursive call to git_config() is due to the "schizophrenic stat"
functions on cygwin, where one of two different implementations of
the l/stat functions is selected lazily, depending on some config
variables.
In this case, the init_copy_notes_for_rewrite() function calls
git_config() with the notes_rewrite_config() callback function.
This callback, while processing the "notes.rewriteref" variable,
in turn calls string_list_add_refs_by_glob() to process the
associated ref value. This eventually leads to a call to the
get_ref_dir() function, which in turn calls stat(). On cygwin,
the stat() macro leads to an indirect call to cygwin_stat_stub()
which, via init_stat(), then calls git_config() in order to
determine which l/stat implementation to bind to.
In order to solve this problem, we modify git_config() so that the
global state variables used by the config reading code is packaged
up and managed on a local state stack.
Signed-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-06-16 22:24:51 +02:00
|
|
|
strbuf_reset(&cf->value);
|
2005-10-11 01:31:08 +02:00
|
|
|
for (;;) {
|
|
|
|
int c = get_next_char();
|
|
|
|
if (c == '\n') {
|
2012-03-09 22:57:54 +01:00
|
|
|
if (quote) {
|
|
|
|
cf->linenr--;
|
2005-10-11 01:31:08 +02:00
|
|
|
return NULL;
|
2012-03-09 22:57:54 +01:00
|
|
|
}
|
config.c: Make git_config() work correctly when called recursively
On Cygwin, this fixes a test failure in t3301-notes.sh (test 98,
"git notes copy --for-rewrite (disabled)").
The test failure is caused by a recursive call to git_config() which
has the effect of skipping to the end-of-file while processing the
"notes.rewriteref" config variable. Thus, any config variables that
appear after "notes.rewriteref" are simply ignored by git_config().
Also, we note that the original FILE handle is leaked as a result
of the recursive call.
The recursive call to git_config() is due to the "schizophrenic stat"
functions on cygwin, where one of two different implementations of
the l/stat functions is selected lazily, depending on some config
variables.
In this case, the init_copy_notes_for_rewrite() function calls
git_config() with the notes_rewrite_config() callback function.
This callback, while processing the "notes.rewriteref" variable,
in turn calls string_list_add_refs_by_glob() to process the
associated ref value. This eventually leads to a call to the
get_ref_dir() function, which in turn calls stat(). On cygwin,
the stat() macro leads to an indirect call to cygwin_stat_stub()
which, via init_stat(), then calls git_config() in order to
determine which l/stat implementation to bind to.
In order to solve this problem, we modify git_config() so that the
global state variables used by the config reading code is packaged
up and managed on a local state stack.
Signed-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-06-16 22:24:51 +02:00
|
|
|
return cf->value.buf;
|
2005-10-11 01:31:08 +02:00
|
|
|
}
|
|
|
|
if (comment)
|
|
|
|
continue;
|
|
|
|
if (isspace(c) && !quote) {
|
config.c: Make git_config() work correctly when called recursively
On Cygwin, this fixes a test failure in t3301-notes.sh (test 98,
"git notes copy --for-rewrite (disabled)").
The test failure is caused by a recursive call to git_config() which
has the effect of skipping to the end-of-file while processing the
"notes.rewriteref" config variable. Thus, any config variables that
appear after "notes.rewriteref" are simply ignored by git_config().
Also, we note that the original FILE handle is leaked as a result
of the recursive call.
The recursive call to git_config() is due to the "schizophrenic stat"
functions on cygwin, where one of two different implementations of
the l/stat functions is selected lazily, depending on some config
variables.
In this case, the init_copy_notes_for_rewrite() function calls
git_config() with the notes_rewrite_config() callback function.
This callback, while processing the "notes.rewriteref" variable,
in turn calls string_list_add_refs_by_glob() to process the
associated ref value. This eventually leads to a call to the
get_ref_dir() function, which in turn calls stat(). On cygwin,
the stat() macro leads to an indirect call to cygwin_stat_stub()
which, via init_stat(), then calls git_config() in order to
determine which l/stat implementation to bind to.
In order to solve this problem, we modify git_config() so that the
global state variables used by the config reading code is packaged
up and managed on a local state stack.
Signed-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-06-16 22:24:51 +02:00
|
|
|
if (cf->value.len)
|
2009-07-30 13:41:57 +02:00
|
|
|
space++;
|
2005-10-11 01:31:08 +02:00
|
|
|
continue;
|
|
|
|
}
|
2006-05-02 16:58:37 +02:00
|
|
|
if (!quote) {
|
|
|
|
if (c == ';' || c == '#') {
|
|
|
|
comment = 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2009-07-30 13:41:57 +02:00
|
|
|
for (; space; space--)
|
config.c: Make git_config() work correctly when called recursively
On Cygwin, this fixes a test failure in t3301-notes.sh (test 98,
"git notes copy --for-rewrite (disabled)").
The test failure is caused by a recursive call to git_config() which
has the effect of skipping to the end-of-file while processing the
"notes.rewriteref" config variable. Thus, any config variables that
appear after "notes.rewriteref" are simply ignored by git_config().
Also, we note that the original FILE handle is leaked as a result
of the recursive call.
The recursive call to git_config() is due to the "schizophrenic stat"
functions on cygwin, where one of two different implementations of
the l/stat functions is selected lazily, depending on some config
variables.
In this case, the init_copy_notes_for_rewrite() function calls
git_config() with the notes_rewrite_config() callback function.
This callback, while processing the "notes.rewriteref" variable,
in turn calls string_list_add_refs_by_glob() to process the
associated ref value. This eventually leads to a call to the
get_ref_dir() function, which in turn calls stat(). On cygwin,
the stat() macro leads to an indirect call to cygwin_stat_stub()
which, via init_stat(), then calls git_config() in order to
determine which l/stat implementation to bind to.
In order to solve this problem, we modify git_config() so that the
global state variables used by the config reading code is packaged
up and managed on a local state stack.
Signed-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-06-16 22:24:51 +02:00
|
|
|
strbuf_addch(&cf->value, ' ');
|
2005-10-11 01:31:08 +02:00
|
|
|
if (c == '\\') {
|
|
|
|
c = get_next_char();
|
|
|
|
switch (c) {
|
|
|
|
case '\n':
|
|
|
|
continue;
|
|
|
|
case 't':
|
|
|
|
c = '\t';
|
|
|
|
break;
|
|
|
|
case 'b':
|
|
|
|
c = '\b';
|
|
|
|
break;
|
|
|
|
case 'n':
|
|
|
|
c = '\n';
|
|
|
|
break;
|
2005-10-12 00:24:11 +02:00
|
|
|
/* Some characters escape as themselves */
|
|
|
|
case '\\': case '"':
|
|
|
|
break;
|
|
|
|
/* Reject unknown escape sequences */
|
|
|
|
default:
|
|
|
|
return NULL;
|
2005-10-11 01:31:08 +02:00
|
|
|
}
|
config.c: Make git_config() work correctly when called recursively
On Cygwin, this fixes a test failure in t3301-notes.sh (test 98,
"git notes copy --for-rewrite (disabled)").
The test failure is caused by a recursive call to git_config() which
has the effect of skipping to the end-of-file while processing the
"notes.rewriteref" config variable. Thus, any config variables that
appear after "notes.rewriteref" are simply ignored by git_config().
Also, we note that the original FILE handle is leaked as a result
of the recursive call.
The recursive call to git_config() is due to the "schizophrenic stat"
functions on cygwin, where one of two different implementations of
the l/stat functions is selected lazily, depending on some config
variables.
In this case, the init_copy_notes_for_rewrite() function calls
git_config() with the notes_rewrite_config() callback function.
This callback, while processing the "notes.rewriteref" variable,
in turn calls string_list_add_refs_by_glob() to process the
associated ref value. This eventually leads to a call to the
get_ref_dir() function, which in turn calls stat(). On cygwin,
the stat() macro leads to an indirect call to cygwin_stat_stub()
which, via init_stat(), then calls git_config() in order to
determine which l/stat implementation to bind to.
In order to solve this problem, we modify git_config() so that the
global state variables used by the config reading code is packaged
up and managed on a local state stack.
Signed-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-06-16 22:24:51 +02:00
|
|
|
strbuf_addch(&cf->value, c);
|
2005-10-11 01:31:08 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (c == '"') {
|
|
|
|
quote = 1-quote;
|
|
|
|
continue;
|
|
|
|
}
|
config.c: Make git_config() work correctly when called recursively
On Cygwin, this fixes a test failure in t3301-notes.sh (test 98,
"git notes copy --for-rewrite (disabled)").
The test failure is caused by a recursive call to git_config() which
has the effect of skipping to the end-of-file while processing the
"notes.rewriteref" config variable. Thus, any config variables that
appear after "notes.rewriteref" are simply ignored by git_config().
Also, we note that the original FILE handle is leaked as a result
of the recursive call.
The recursive call to git_config() is due to the "schizophrenic stat"
functions on cygwin, where one of two different implementations of
the l/stat functions is selected lazily, depending on some config
variables.
In this case, the init_copy_notes_for_rewrite() function calls
git_config() with the notes_rewrite_config() callback function.
This callback, while processing the "notes.rewriteref" variable,
in turn calls string_list_add_refs_by_glob() to process the
associated ref value. This eventually leads to a call to the
get_ref_dir() function, which in turn calls stat(). On cygwin,
the stat() macro leads to an indirect call to cygwin_stat_stub()
which, via init_stat(), then calls git_config() in order to
determine which l/stat implementation to bind to.
In order to solve this problem, we modify git_config() so that the
global state variables used by the config reading code is packaged
up and managed on a local state stack.
Signed-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-06-16 22:24:51 +02:00
|
|
|
strbuf_addch(&cf->value, c);
|
2005-10-11 01:31:08 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-10-30 17:25:36 +01:00
|
|
|
static inline int iskeychar(int c)
|
|
|
|
{
|
|
|
|
return isalnum(c) || c == '-';
|
|
|
|
}
|
|
|
|
|
2012-09-30 21:44:36 +02:00
|
|
|
static int get_value(config_fn_t fn, void *data, struct strbuf *name)
|
2005-10-11 01:31:08 +02:00
|
|
|
{
|
|
|
|
int c;
|
|
|
|
char *value;
|
2014-08-07 13:59:13 +02:00
|
|
|
int ret;
|
2005-10-11 01:31:08 +02:00
|
|
|
|
|
|
|
/* Get the full name */
|
|
|
|
for (;;) {
|
|
|
|
c = get_next_char();
|
config.c: Make git_config() work correctly when called recursively
On Cygwin, this fixes a test failure in t3301-notes.sh (test 98,
"git notes copy --for-rewrite (disabled)").
The test failure is caused by a recursive call to git_config() which
has the effect of skipping to the end-of-file while processing the
"notes.rewriteref" config variable. Thus, any config variables that
appear after "notes.rewriteref" are simply ignored by git_config().
Also, we note that the original FILE handle is leaked as a result
of the recursive call.
The recursive call to git_config() is due to the "schizophrenic stat"
functions on cygwin, where one of two different implementations of
the l/stat functions is selected lazily, depending on some config
variables.
In this case, the init_copy_notes_for_rewrite() function calls
git_config() with the notes_rewrite_config() callback function.
This callback, while processing the "notes.rewriteref" variable,
in turn calls string_list_add_refs_by_glob() to process the
associated ref value. This eventually leads to a call to the
get_ref_dir() function, which in turn calls stat(). On cygwin,
the stat() macro leads to an indirect call to cygwin_stat_stub()
which, via init_stat(), then calls git_config() in order to
determine which l/stat implementation to bind to.
In order to solve this problem, we modify git_config() so that the
global state variables used by the config reading code is packaged
up and managed on a local state stack.
Signed-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-06-16 22:24:51 +02:00
|
|
|
if (cf->eof)
|
2005-10-11 01:31:08 +02:00
|
|
|
break;
|
2006-10-30 17:25:36 +01:00
|
|
|
if (!iskeychar(c))
|
2005-10-11 01:31:08 +02:00
|
|
|
break;
|
2012-09-30 21:44:36 +02:00
|
|
|
strbuf_addch(name, tolower(c));
|
2005-10-11 01:31:08 +02:00
|
|
|
}
|
2012-09-30 21:44:36 +02:00
|
|
|
|
2005-10-11 01:31:08 +02:00
|
|
|
while (c == ' ' || c == '\t')
|
|
|
|
c = get_next_char();
|
|
|
|
|
|
|
|
value = NULL;
|
|
|
|
if (c != '\n') {
|
|
|
|
if (c != '=')
|
|
|
|
return -1;
|
|
|
|
value = parse_value();
|
|
|
|
if (!value)
|
|
|
|
return -1;
|
|
|
|
}
|
2014-08-07 13:59:13 +02:00
|
|
|
/*
|
|
|
|
* We already consumed the \n, but we need linenr to point to
|
|
|
|
* the line we just parsed during the call to fn to get
|
|
|
|
* accurate line number in error messages.
|
|
|
|
*/
|
|
|
|
cf->linenr--;
|
|
|
|
ret = fn(name->buf, value, data);
|
|
|
|
cf->linenr++;
|
|
|
|
return ret;
|
2005-10-11 01:31:08 +02:00
|
|
|
}
|
|
|
|
|
2012-09-30 21:44:36 +02:00
|
|
|
static int get_extended_base_var(struct strbuf *name, int c)
|
2006-05-09 21:24:02 +02:00
|
|
|
{
|
|
|
|
do {
|
|
|
|
if (c == '\n')
|
2012-03-09 22:57:54 +01:00
|
|
|
goto error_incomplete_line;
|
2006-05-09 21:24:02 +02:00
|
|
|
c = get_next_char();
|
|
|
|
} while (isspace(c));
|
|
|
|
|
|
|
|
/* We require the format to be '[base "extension"]' */
|
|
|
|
if (c != '"')
|
|
|
|
return -1;
|
2012-09-30 21:44:36 +02:00
|
|
|
strbuf_addch(name, '.');
|
2006-05-09 21:24:02 +02:00
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
int c = get_next_char();
|
|
|
|
if (c == '\n')
|
2012-03-09 22:57:54 +01:00
|
|
|
goto error_incomplete_line;
|
2006-05-09 21:24:02 +02:00
|
|
|
if (c == '"')
|
|
|
|
break;
|
|
|
|
if (c == '\\') {
|
|
|
|
c = get_next_char();
|
|
|
|
if (c == '\n')
|
2012-03-09 22:57:54 +01:00
|
|
|
goto error_incomplete_line;
|
2006-05-09 21:24:02 +02:00
|
|
|
}
|
2012-09-30 21:44:36 +02:00
|
|
|
strbuf_addch(name, c);
|
2006-05-09 21:24:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Final ']' */
|
|
|
|
if (get_next_char() != ']')
|
|
|
|
return -1;
|
2012-09-30 21:44:36 +02:00
|
|
|
return 0;
|
2012-03-09 22:57:54 +01:00
|
|
|
error_incomplete_line:
|
|
|
|
cf->linenr--;
|
|
|
|
return -1;
|
2006-05-09 21:24:02 +02:00
|
|
|
}
|
|
|
|
|
2012-09-30 21:44:36 +02:00
|
|
|
static int get_base_var(struct strbuf *name)
|
2005-10-11 01:31:08 +02:00
|
|
|
{
|
|
|
|
for (;;) {
|
|
|
|
int c = get_next_char();
|
config.c: Make git_config() work correctly when called recursively
On Cygwin, this fixes a test failure in t3301-notes.sh (test 98,
"git notes copy --for-rewrite (disabled)").
The test failure is caused by a recursive call to git_config() which
has the effect of skipping to the end-of-file while processing the
"notes.rewriteref" config variable. Thus, any config variables that
appear after "notes.rewriteref" are simply ignored by git_config().
Also, we note that the original FILE handle is leaked as a result
of the recursive call.
The recursive call to git_config() is due to the "schizophrenic stat"
functions on cygwin, where one of two different implementations of
the l/stat functions is selected lazily, depending on some config
variables.
In this case, the init_copy_notes_for_rewrite() function calls
git_config() with the notes_rewrite_config() callback function.
This callback, while processing the "notes.rewriteref" variable,
in turn calls string_list_add_refs_by_glob() to process the
associated ref value. This eventually leads to a call to the
get_ref_dir() function, which in turn calls stat(). On cygwin,
the stat() macro leads to an indirect call to cygwin_stat_stub()
which, via init_stat(), then calls git_config() in order to
determine which l/stat implementation to bind to.
In order to solve this problem, we modify git_config() so that the
global state variables used by the config reading code is packaged
up and managed on a local state stack.
Signed-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-06-16 22:24:51 +02:00
|
|
|
if (cf->eof)
|
2005-10-11 01:31:08 +02:00
|
|
|
return -1;
|
|
|
|
if (c == ']')
|
2012-09-30 21:44:36 +02:00
|
|
|
return 0;
|
2006-05-09 21:24:02 +02:00
|
|
|
if (isspace(c))
|
2012-09-30 21:44:36 +02:00
|
|
|
return get_extended_base_var(name, c);
|
2006-10-30 17:25:36 +01:00
|
|
|
if (!iskeychar(c) && c != '.')
|
2005-10-11 01:31:08 +02:00
|
|
|
return -1;
|
2012-09-30 21:44:36 +02:00
|
|
|
strbuf_addch(name, tolower(c));
|
2005-10-11 01:31:08 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-12 00:44:39 +02:00
|
|
|
static int git_parse_source(config_fn_t fn, void *data)
|
2005-10-11 01:31:08 +02:00
|
|
|
{
|
|
|
|
int comment = 0;
|
|
|
|
int baselen = 0;
|
2012-09-30 21:44:36 +02:00
|
|
|
struct strbuf *var = &cf->var;
|
2005-10-11 01:31:08 +02:00
|
|
|
|
2008-10-01 22:13:02 +02:00
|
|
|
/* U+FEFF Byte Order Mark in UTF8 */
|
|
|
|
static const unsigned char *utf8_bom = (unsigned char *) "\xef\xbb\xbf";
|
|
|
|
const unsigned char *bomptr = utf8_bom;
|
|
|
|
|
2005-10-11 01:31:08 +02:00
|
|
|
for (;;) {
|
|
|
|
int c = get_next_char();
|
2008-10-01 22:13:02 +02:00
|
|
|
if (bomptr && *bomptr) {
|
|
|
|
/* We are at the file beginning; skip UTF8-encoded BOM
|
|
|
|
* if present. Sane editors won't put this in on their
|
|
|
|
* own, but e.g. Windows Notepad will do it happily. */
|
|
|
|
if ((unsigned char) c == *bomptr) {
|
|
|
|
bomptr++;
|
|
|
|
continue;
|
|
|
|
} else {
|
|
|
|
/* Do not tolerate partial BOM. */
|
|
|
|
if (bomptr != utf8_bom)
|
|
|
|
break;
|
|
|
|
/* No BOM at file beginning. Cool. */
|
|
|
|
bomptr = NULL;
|
|
|
|
}
|
|
|
|
}
|
2005-10-11 01:31:08 +02:00
|
|
|
if (c == '\n') {
|
config.c: Make git_config() work correctly when called recursively
On Cygwin, this fixes a test failure in t3301-notes.sh (test 98,
"git notes copy --for-rewrite (disabled)").
The test failure is caused by a recursive call to git_config() which
has the effect of skipping to the end-of-file while processing the
"notes.rewriteref" config variable. Thus, any config variables that
appear after "notes.rewriteref" are simply ignored by git_config().
Also, we note that the original FILE handle is leaked as a result
of the recursive call.
The recursive call to git_config() is due to the "schizophrenic stat"
functions on cygwin, where one of two different implementations of
the l/stat functions is selected lazily, depending on some config
variables.
In this case, the init_copy_notes_for_rewrite() function calls
git_config() with the notes_rewrite_config() callback function.
This callback, while processing the "notes.rewriteref" variable,
in turn calls string_list_add_refs_by_glob() to process the
associated ref value. This eventually leads to a call to the
get_ref_dir() function, which in turn calls stat(). On cygwin,
the stat() macro leads to an indirect call to cygwin_stat_stub()
which, via init_stat(), then calls git_config() in order to
determine which l/stat implementation to bind to.
In order to solve this problem, we modify git_config() so that the
global state variables used by the config reading code is packaged
up and managed on a local state stack.
Signed-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-06-16 22:24:51 +02:00
|
|
|
if (cf->eof)
|
2005-10-11 01:31:08 +02:00
|
|
|
return 0;
|
|
|
|
comment = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (comment || isspace(c))
|
|
|
|
continue;
|
|
|
|
if (c == '#' || c == ';') {
|
|
|
|
comment = 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (c == '[') {
|
2012-09-30 21:44:36 +02:00
|
|
|
/* Reset prior to determining a new stem */
|
|
|
|
strbuf_reset(var);
|
|
|
|
if (get_base_var(var) < 0 || var->len < 1)
|
2005-10-11 01:31:08 +02:00
|
|
|
break;
|
2012-09-30 21:44:36 +02:00
|
|
|
strbuf_addch(var, '.');
|
|
|
|
baselen = var->len;
|
2005-10-11 01:31:08 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!isalpha(c))
|
|
|
|
break;
|
2012-09-30 21:44:36 +02:00
|
|
|
/*
|
|
|
|
* Truncate the var name back to the section header
|
|
|
|
* stem prior to grabbing the suffix part of the name
|
|
|
|
* and the value.
|
|
|
|
*/
|
|
|
|
strbuf_setlen(var, baselen);
|
|
|
|
strbuf_addch(var, tolower(c));
|
|
|
|
if (get_value(fn, data, var) < 0)
|
2005-10-11 01:31:08 +02:00
|
|
|
break;
|
|
|
|
}
|
2013-07-12 00:48:30 +02:00
|
|
|
if (cf->die_on_error)
|
2014-08-07 13:59:12 +02:00
|
|
|
die(_("bad config file line %d in %s"), cf->linenr, cf->name);
|
2013-07-12 00:48:30 +02:00
|
|
|
else
|
2014-08-07 13:59:12 +02:00
|
|
|
return error(_("bad config file line %d in %s"), cf->linenr, cf->name);
|
2005-10-11 01:31:08 +02:00
|
|
|
}
|
|
|
|
|
Support sizes >=2G in various config options accepting 'g' sizes.
The config options core.packedGitWindowSize, core.packedGitLimit,
core.deltaBaseCacheLimit, core.bigFileThreshold, pack.windowMemory and
pack.packSizeLimit all claim to support suffixes up to and including
'g'. This implies that they should accept sizes >=2G on 64-bit
systems: certainly, specifying a size of 3g should not silently be
translated to zero or transformed into a large negative value due to
integer overflow. However, due to use of git_config_int() rather than
git_config_ulong(), that is exactly what happens:
% git config core.bigFileThreshold 2g
% git gc --aggressive # with extra debugging code to print out
# core.bigfilethreshold after parsing
bigfilethreshold: -2147483648
[...]
This is probably irrelevant for core.deltaBaseCacheLimit, but is
problematic for the other values. (It is particularly problematic for
core.packedGitLimit, which can't even be set to its default value in
the config file due to this bug.)
This fixes things for 32-bit platforms as well. They get the usual bad
config error if an overlarge value is specified, e.g.:
fatal: bad config value for 'core.bigfilethreshold' in /home/nix/.gitconfig
This is detected in all cases, even if the 32-bit platform has no size
larger than 'long'. For signed integral configuration values, we also
detect the case where the value is too large for the signed type but
not the unsigned type.
Signed-off-by: Nick Alcock <nix@esperi.org.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-11-02 16:46:23 +01:00
|
|
|
static int parse_unit_factor(const char *end, uintmax_t *val)
|
2007-07-12 15:32:26 +02:00
|
|
|
{
|
|
|
|
if (!*end)
|
|
|
|
return 1;
|
2007-12-25 08:18:05 +01:00
|
|
|
else if (!strcasecmp(end, "k")) {
|
|
|
|
*val *= 1024;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
else if (!strcasecmp(end, "m")) {
|
|
|
|
*val *= 1024 * 1024;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
else if (!strcasecmp(end, "g")) {
|
|
|
|
*val *= 1024 * 1024 * 1024;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
2007-07-12 15:32:26 +02:00
|
|
|
}
|
|
|
|
|
2013-09-08 10:29:27 +02:00
|
|
|
static int git_parse_signed(const char *value, intmax_t *ret, intmax_t max)
|
2007-07-12 15:32:26 +02:00
|
|
|
{
|
|
|
|
if (value && *value) {
|
|
|
|
char *end;
|
Support sizes >=2G in various config options accepting 'g' sizes.
The config options core.packedGitWindowSize, core.packedGitLimit,
core.deltaBaseCacheLimit, core.bigFileThreshold, pack.windowMemory and
pack.packSizeLimit all claim to support suffixes up to and including
'g'. This implies that they should accept sizes >=2G on 64-bit
systems: certainly, specifying a size of 3g should not silently be
translated to zero or transformed into a large negative value due to
integer overflow. However, due to use of git_config_int() rather than
git_config_ulong(), that is exactly what happens:
% git config core.bigFileThreshold 2g
% git gc --aggressive # with extra debugging code to print out
# core.bigfilethreshold after parsing
bigfilethreshold: -2147483648
[...]
This is probably irrelevant for core.deltaBaseCacheLimit, but is
problematic for the other values. (It is particularly problematic for
core.packedGitLimit, which can't even be set to its default value in
the config file due to this bug.)
This fixes things for 32-bit platforms as well. They get the usual bad
config error if an overlarge value is specified, e.g.:
fatal: bad config value for 'core.bigfilethreshold' in /home/nix/.gitconfig
This is detected in all cases, even if the 32-bit platform has no size
larger than 'long'. For signed integral configuration values, we also
detect the case where the value is too large for the signed type but
not the unsigned type.
Signed-off-by: Nick Alcock <nix@esperi.org.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-11-02 16:46:23 +01:00
|
|
|
intmax_t val;
|
|
|
|
uintmax_t uval;
|
|
|
|
uintmax_t factor = 1;
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
val = strtoimax(value, &end, 0);
|
|
|
|
if (errno == ERANGE)
|
|
|
|
return 0;
|
2013-09-08 10:36:42 +02:00
|
|
|
if (!parse_unit_factor(end, &factor)) {
|
|
|
|
errno = EINVAL;
|
2007-12-25 08:18:05 +01:00
|
|
|
return 0;
|
2013-09-08 10:36:42 +02:00
|
|
|
}
|
2014-11-15 14:27:21 +01:00
|
|
|
uval = labs(val);
|
Support sizes >=2G in various config options accepting 'g' sizes.
The config options core.packedGitWindowSize, core.packedGitLimit,
core.deltaBaseCacheLimit, core.bigFileThreshold, pack.windowMemory and
pack.packSizeLimit all claim to support suffixes up to and including
'g'. This implies that they should accept sizes >=2G on 64-bit
systems: certainly, specifying a size of 3g should not silently be
translated to zero or transformed into a large negative value due to
integer overflow. However, due to use of git_config_int() rather than
git_config_ulong(), that is exactly what happens:
% git config core.bigFileThreshold 2g
% git gc --aggressive # with extra debugging code to print out
# core.bigfilethreshold after parsing
bigfilethreshold: -2147483648
[...]
This is probably irrelevant for core.deltaBaseCacheLimit, but is
problematic for the other values. (It is particularly problematic for
core.packedGitLimit, which can't even be set to its default value in
the config file due to this bug.)
This fixes things for 32-bit platforms as well. They get the usual bad
config error if an overlarge value is specified, e.g.:
fatal: bad config value for 'core.bigfilethreshold' in /home/nix/.gitconfig
This is detected in all cases, even if the 32-bit platform has no size
larger than 'long'. For signed integral configuration values, we also
detect the case where the value is too large for the signed type but
not the unsigned type.
Signed-off-by: Nick Alcock <nix@esperi.org.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-11-02 16:46:23 +01:00
|
|
|
uval *= factor;
|
2014-11-15 14:27:21 +01:00
|
|
|
if (uval > max || labs(val) > uval) {
|
2013-09-08 10:36:42 +02:00
|
|
|
errno = ERANGE;
|
Support sizes >=2G in various config options accepting 'g' sizes.
The config options core.packedGitWindowSize, core.packedGitLimit,
core.deltaBaseCacheLimit, core.bigFileThreshold, pack.windowMemory and
pack.packSizeLimit all claim to support suffixes up to and including
'g'. This implies that they should accept sizes >=2G on 64-bit
systems: certainly, specifying a size of 3g should not silently be
translated to zero or transformed into a large negative value due to
integer overflow. However, due to use of git_config_int() rather than
git_config_ulong(), that is exactly what happens:
% git config core.bigFileThreshold 2g
% git gc --aggressive # with extra debugging code to print out
# core.bigfilethreshold after parsing
bigfilethreshold: -2147483648
[...]
This is probably irrelevant for core.deltaBaseCacheLimit, but is
problematic for the other values. (It is particularly problematic for
core.packedGitLimit, which can't even be set to its default value in
the config file due to this bug.)
This fixes things for 32-bit platforms as well. They get the usual bad
config error if an overlarge value is specified, e.g.:
fatal: bad config value for 'core.bigfilethreshold' in /home/nix/.gitconfig
This is detected in all cases, even if the 32-bit platform has no size
larger than 'long'. For signed integral configuration values, we also
detect the case where the value is too large for the signed type but
not the unsigned type.
Signed-off-by: Nick Alcock <nix@esperi.org.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-11-02 16:46:23 +01:00
|
|
|
return 0;
|
2013-09-08 10:36:42 +02:00
|
|
|
}
|
Support sizes >=2G in various config options accepting 'g' sizes.
The config options core.packedGitWindowSize, core.packedGitLimit,
core.deltaBaseCacheLimit, core.bigFileThreshold, pack.windowMemory and
pack.packSizeLimit all claim to support suffixes up to and including
'g'. This implies that they should accept sizes >=2G on 64-bit
systems: certainly, specifying a size of 3g should not silently be
translated to zero or transformed into a large negative value due to
integer overflow. However, due to use of git_config_int() rather than
git_config_ulong(), that is exactly what happens:
% git config core.bigFileThreshold 2g
% git gc --aggressive # with extra debugging code to print out
# core.bigfilethreshold after parsing
bigfilethreshold: -2147483648
[...]
This is probably irrelevant for core.deltaBaseCacheLimit, but is
problematic for the other values. (It is particularly problematic for
core.packedGitLimit, which can't even be set to its default value in
the config file due to this bug.)
This fixes things for 32-bit platforms as well. They get the usual bad
config error if an overlarge value is specified, e.g.:
fatal: bad config value for 'core.bigfilethreshold' in /home/nix/.gitconfig
This is detected in all cases, even if the 32-bit platform has no size
larger than 'long'. For signed integral configuration values, we also
detect the case where the value is too large for the signed type but
not the unsigned type.
Signed-off-by: Nick Alcock <nix@esperi.org.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-11-02 16:46:23 +01:00
|
|
|
val *= factor;
|
|
|
|
*ret = val;
|
2007-07-12 15:32:26 +02:00
|
|
|
return 1;
|
|
|
|
}
|
2013-09-08 10:36:42 +02:00
|
|
|
errno = EINVAL;
|
2007-07-12 15:32:26 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-10-06 22:48:29 +02:00
|
|
|
static int git_parse_unsigned(const char *value, uintmax_t *ret, uintmax_t max)
|
2005-10-11 01:31:08 +02:00
|
|
|
{
|
|
|
|
if (value && *value) {
|
|
|
|
char *end;
|
Support sizes >=2G in various config options accepting 'g' sizes.
The config options core.packedGitWindowSize, core.packedGitLimit,
core.deltaBaseCacheLimit, core.bigFileThreshold, pack.windowMemory and
pack.packSizeLimit all claim to support suffixes up to and including
'g'. This implies that they should accept sizes >=2G on 64-bit
systems: certainly, specifying a size of 3g should not silently be
translated to zero or transformed into a large negative value due to
integer overflow. However, due to use of git_config_int() rather than
git_config_ulong(), that is exactly what happens:
% git config core.bigFileThreshold 2g
% git gc --aggressive # with extra debugging code to print out
# core.bigfilethreshold after parsing
bigfilethreshold: -2147483648
[...]
This is probably irrelevant for core.deltaBaseCacheLimit, but is
problematic for the other values. (It is particularly problematic for
core.packedGitLimit, which can't even be set to its default value in
the config file due to this bug.)
This fixes things for 32-bit platforms as well. They get the usual bad
config error if an overlarge value is specified, e.g.:
fatal: bad config value for 'core.bigfilethreshold' in /home/nix/.gitconfig
This is detected in all cases, even if the 32-bit platform has no size
larger than 'long'. For signed integral configuration values, we also
detect the case where the value is too large for the signed type but
not the unsigned type.
Signed-off-by: Nick Alcock <nix@esperi.org.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-11-02 16:46:23 +01:00
|
|
|
uintmax_t val;
|
|
|
|
uintmax_t oldval;
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
val = strtoumax(value, &end, 0);
|
|
|
|
if (errno == ERANGE)
|
|
|
|
return 0;
|
|
|
|
oldval = val;
|
2013-09-08 10:36:42 +02:00
|
|
|
if (!parse_unit_factor(end, &val)) {
|
|
|
|
errno = EINVAL;
|
2007-12-25 08:18:05 +01:00
|
|
|
return 0;
|
2013-09-08 10:36:42 +02:00
|
|
|
}
|
|
|
|
if (val > max || oldval > val) {
|
|
|
|
errno = ERANGE;
|
Support sizes >=2G in various config options accepting 'g' sizes.
The config options core.packedGitWindowSize, core.packedGitLimit,
core.deltaBaseCacheLimit, core.bigFileThreshold, pack.windowMemory and
pack.packSizeLimit all claim to support suffixes up to and including
'g'. This implies that they should accept sizes >=2G on 64-bit
systems: certainly, specifying a size of 3g should not silently be
translated to zero or transformed into a large negative value due to
integer overflow. However, due to use of git_config_int() rather than
git_config_ulong(), that is exactly what happens:
% git config core.bigFileThreshold 2g
% git gc --aggressive # with extra debugging code to print out
# core.bigfilethreshold after parsing
bigfilethreshold: -2147483648
[...]
This is probably irrelevant for core.deltaBaseCacheLimit, but is
problematic for the other values. (It is particularly problematic for
core.packedGitLimit, which can't even be set to its default value in
the config file due to this bug.)
This fixes things for 32-bit platforms as well. They get the usual bad
config error if an overlarge value is specified, e.g.:
fatal: bad config value for 'core.bigfilethreshold' in /home/nix/.gitconfig
This is detected in all cases, even if the 32-bit platform has no size
larger than 'long'. For signed integral configuration values, we also
detect the case where the value is too large for the signed type but
not the unsigned type.
Signed-off-by: Nick Alcock <nix@esperi.org.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-11-02 16:46:23 +01:00
|
|
|
return 0;
|
2013-09-08 10:36:42 +02:00
|
|
|
}
|
2007-12-25 08:18:05 +01:00
|
|
|
*ret = val;
|
2007-07-12 15:32:26 +02:00
|
|
|
return 1;
|
2005-10-11 01:31:08 +02:00
|
|
|
}
|
2013-09-08 10:36:42 +02:00
|
|
|
errno = EINVAL;
|
2007-07-12 15:32:26 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-09-08 10:33:08 +02:00
|
|
|
static int git_parse_int(const char *value, int *ret)
|
2008-02-21 01:00:32 +01:00
|
|
|
{
|
2013-09-08 10:29:27 +02:00
|
|
|
intmax_t tmp;
|
2013-09-08 10:33:08 +02:00
|
|
|
if (!git_parse_signed(value, &tmp, maximum_signed_value_of_type(int)))
|
2013-09-08 10:29:27 +02:00
|
|
|
return 0;
|
|
|
|
*ret = tmp;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
git-config: always treat --int as 64-bit internally
When you run "git config --int", the maximum size of integer
you get depends on how git was compiled, and what it
considers to be an "int".
This is almost useful, because your scripts calling "git
config" will behave similarly to git internally. But relying
on this is dubious; you have to actually know how git treats
each value internally (e.g., int versus unsigned long),
which is not documented and is subject to change. And even
if you know it is "unsigned long", we do not have a
git-config option to match that behavior.
Furthermore, you may simply be asking git to store a value
on your behalf (e.g., configuration for a hook). In that
case, the relevant range check has nothing at all to do with
git, but rather with whatever scripting tools you are using
(and git has no way of knowing what the appropriate range is
there).
Not only is the range check useless, but it is actively
harmful, as there is no way at all for scripts to look
at config variables with large values. For instance, one
cannot reliably get the value of pack.packSizeLimit via
git-config. On an LP64 system, git happily uses a 64-bit
"unsigned long" internally to represent the value, but the
script cannot read any value over 2G.
Ideally, the "--int" option would simply represent an
arbitrarily large integer. For practical purposes, however,
a 64-bit integer is large enough, and is much easier to
implement (and if somebody overflows it, we will still
notice the problem, and not simply return garbage).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-09-08 10:40:02 +02:00
|
|
|
static int git_parse_int64(const char *value, int64_t *ret)
|
|
|
|
{
|
|
|
|
intmax_t tmp;
|
|
|
|
if (!git_parse_signed(value, &tmp, maximum_signed_value_of_type(int64_t)))
|
|
|
|
return 0;
|
|
|
|
*ret = tmp;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2013-09-08 10:29:27 +02:00
|
|
|
int git_parse_ulong(const char *value, unsigned long *ret)
|
|
|
|
{
|
|
|
|
uintmax_t tmp;
|
|
|
|
if (!git_parse_unsigned(value, &tmp, maximum_unsigned_value_of_type(long)))
|
|
|
|
return 0;
|
|
|
|
*ret = tmp;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2014-04-16 18:51:47 +02:00
|
|
|
NORETURN
|
2013-09-08 10:38:22 +02:00
|
|
|
static void die_bad_number(const char *name, const char *value)
|
2008-02-21 01:00:32 +01:00
|
|
|
{
|
2013-09-08 10:38:22 +02:00
|
|
|
const char *reason = errno == ERANGE ?
|
|
|
|
"out of range" :
|
|
|
|
"invalid unit";
|
|
|
|
if (!value)
|
|
|
|
value = "";
|
|
|
|
|
config.c: Make git_config() work correctly when called recursively
On Cygwin, this fixes a test failure in t3301-notes.sh (test 98,
"git notes copy --for-rewrite (disabled)").
The test failure is caused by a recursive call to git_config() which
has the effect of skipping to the end-of-file while processing the
"notes.rewriteref" config variable. Thus, any config variables that
appear after "notes.rewriteref" are simply ignored by git_config().
Also, we note that the original FILE handle is leaked as a result
of the recursive call.
The recursive call to git_config() is due to the "schizophrenic stat"
functions on cygwin, where one of two different implementations of
the l/stat functions is selected lazily, depending on some config
variables.
In this case, the init_copy_notes_for_rewrite() function calls
git_config() with the notes_rewrite_config() callback function.
This callback, while processing the "notes.rewriteref" variable,
in turn calls string_list_add_refs_by_glob() to process the
associated ref value. This eventually leads to a call to the
get_ref_dir() function, which in turn calls stat(). On cygwin,
the stat() macro leads to an indirect call to cygwin_stat_stub()
which, via init_stat(), then calls git_config() in order to
determine which l/stat implementation to bind to.
In order to solve this problem, we modify git_config() so that the
global state variables used by the config reading code is packaged
up and managed on a local state stack.
Signed-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-06-16 22:24:51 +02:00
|
|
|
if (cf && cf->name)
|
2014-08-07 13:59:12 +02:00
|
|
|
die(_("bad numeric config value '%s' for '%s' in %s: %s"),
|
2013-09-08 10:38:22 +02:00
|
|
|
value, name, cf->name, reason);
|
2014-08-07 13:59:12 +02:00
|
|
|
die(_("bad numeric config value '%s' for '%s': %s"), value, name, reason);
|
2008-02-21 01:00:32 +01:00
|
|
|
}
|
|
|
|
|
2007-07-12 15:32:26 +02:00
|
|
|
int git_config_int(const char *name, const char *value)
|
|
|
|
{
|
2013-09-08 10:33:08 +02:00
|
|
|
int ret;
|
|
|
|
if (!git_parse_int(value, &ret))
|
2013-09-08 10:38:22 +02:00
|
|
|
die_bad_number(name, value);
|
2007-07-12 15:32:26 +02:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
git-config: always treat --int as 64-bit internally
When you run "git config --int", the maximum size of integer
you get depends on how git was compiled, and what it
considers to be an "int".
This is almost useful, because your scripts calling "git
config" will behave similarly to git internally. But relying
on this is dubious; you have to actually know how git treats
each value internally (e.g., int versus unsigned long),
which is not documented and is subject to change. And even
if you know it is "unsigned long", we do not have a
git-config option to match that behavior.
Furthermore, you may simply be asking git to store a value
on your behalf (e.g., configuration for a hook). In that
case, the relevant range check has nothing at all to do with
git, but rather with whatever scripting tools you are using
(and git has no way of knowing what the appropriate range is
there).
Not only is the range check useless, but it is actively
harmful, as there is no way at all for scripts to look
at config variables with large values. For instance, one
cannot reliably get the value of pack.packSizeLimit via
git-config. On an LP64 system, git happily uses a 64-bit
"unsigned long" internally to represent the value, but the
script cannot read any value over 2G.
Ideally, the "--int" option would simply represent an
arbitrarily large integer. For practical purposes, however,
a 64-bit integer is large enough, and is much easier to
implement (and if somebody overflows it, we will still
notice the problem, and not simply return garbage).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-09-08 10:40:02 +02:00
|
|
|
int64_t git_config_int64(const char *name, const char *value)
|
|
|
|
{
|
|
|
|
int64_t ret;
|
|
|
|
if (!git_parse_int64(value, &ret))
|
|
|
|
die_bad_number(name, value);
|
2007-07-12 15:32:26 +02:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned long git_config_ulong(const char *name, const char *value)
|
|
|
|
{
|
|
|
|
unsigned long ret;
|
|
|
|
if (!git_parse_ulong(value, &ret))
|
2013-09-08 10:38:22 +02:00
|
|
|
die_bad_number(name, value);
|
2007-07-12 15:32:26 +02:00
|
|
|
return ret;
|
2005-10-11 01:31:08 +02:00
|
|
|
}
|
|
|
|
|
2010-11-17 18:00:45 +01:00
|
|
|
static int git_config_maybe_bool_text(const char *name, const char *value)
|
2005-10-11 01:31:08 +02:00
|
|
|
{
|
|
|
|
if (!value)
|
|
|
|
return 1;
|
|
|
|
if (!*value)
|
|
|
|
return 0;
|
2010-02-17 08:59:46 +01:00
|
|
|
if (!strcasecmp(value, "true")
|
|
|
|
|| !strcasecmp(value, "yes")
|
|
|
|
|| !strcasecmp(value, "on"))
|
2005-10-11 01:31:08 +02:00
|
|
|
return 1;
|
2010-02-17 08:59:46 +01:00
|
|
|
if (!strcasecmp(value, "false")
|
|
|
|
|| !strcasecmp(value, "no")
|
|
|
|
|| !strcasecmp(value, "off"))
|
2005-10-11 01:31:08 +02:00
|
|
|
return 0;
|
2010-02-17 08:59:46 +01:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2010-11-17 18:00:45 +01:00
|
|
|
int git_config_maybe_bool(const char *name, const char *value)
|
|
|
|
{
|
2013-09-08 10:33:08 +02:00
|
|
|
int v = git_config_maybe_bool_text(name, value);
|
2010-11-17 18:00:45 +01:00
|
|
|
if (0 <= v)
|
|
|
|
return v;
|
2013-09-08 10:33:08 +02:00
|
|
|
if (git_parse_int(value, &v))
|
2010-12-19 04:36:41 +01:00
|
|
|
return !!v;
|
2010-11-17 18:00:45 +01:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2010-02-17 08:59:46 +01:00
|
|
|
int git_config_bool_or_int(const char *name, const char *value, int *is_bool)
|
|
|
|
{
|
2010-11-17 18:00:45 +01:00
|
|
|
int v = git_config_maybe_bool_text(name, value);
|
2010-02-17 08:59:46 +01:00
|
|
|
if (0 <= v) {
|
|
|
|
*is_bool = 1;
|
|
|
|
return v;
|
|
|
|
}
|
2008-04-13 03:33:31 +02:00
|
|
|
*is_bool = 0;
|
2008-04-13 21:11:11 +02:00
|
|
|
return git_config_int(name, value);
|
2005-10-11 01:31:08 +02:00
|
|
|
}
|
|
|
|
|
2008-04-13 03:33:31 +02:00
|
|
|
int git_config_bool(const char *name, const char *value)
|
|
|
|
{
|
|
|
|
int discard;
|
2008-04-13 21:11:11 +02:00
|
|
|
return !!git_config_bool_or_int(name, value, &discard);
|
2008-04-13 03:33:31 +02:00
|
|
|
}
|
|
|
|
|
2008-02-16 06:00:24 +01:00
|
|
|
int git_config_string(const char **dest, const char *var, const char *value)
|
|
|
|
{
|
|
|
|
if (!value)
|
|
|
|
return config_error_nonbool(var);
|
|
|
|
*dest = xstrdup(value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-11-17 18:24:25 +01:00
|
|
|
int git_config_pathname(const char **dest, const char *var, const char *value)
|
|
|
|
{
|
|
|
|
if (!value)
|
|
|
|
return config_error_nonbool(var);
|
|
|
|
*dest = expand_user_path(value);
|
|
|
|
if (!*dest)
|
2014-08-07 13:59:12 +02:00
|
|
|
die(_("failed to expand user dir in: '%s'"), value);
|
2009-11-17 18:24:25 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-06-18 23:37:18 +02:00
|
|
|
static int git_default_core_config(const char *var, const char *value)
|
2005-10-11 01:31:08 +02:00
|
|
|
{
|
|
|
|
/* This needs a better name */
|
|
|
|
if (!strcmp(var, "core.filemode")) {
|
|
|
|
trust_executable_bit = git_config_bool(var, value);
|
|
|
|
return 0;
|
|
|
|
}
|
2008-07-28 08:31:28 +02:00
|
|
|
if (!strcmp(var, "core.trustctime")) {
|
|
|
|
trust_ctime = git_config_bool(var, value);
|
|
|
|
return 0;
|
|
|
|
}
|
2013-05-07 07:32:58 +02:00
|
|
|
if (!strcmp(var, "core.checkstat")) {
|
2013-01-22 08:49:22 +01:00
|
|
|
if (!strcasecmp(value, "default"))
|
|
|
|
check_stat = 1;
|
|
|
|
else if (!strcasecmp(value, "minimal"))
|
|
|
|
check_stat = 0;
|
|
|
|
}
|
2005-10-11 01:31:08 +02:00
|
|
|
|
2007-06-25 00:11:24 +02:00
|
|
|
if (!strcmp(var, "core.quotepath")) {
|
|
|
|
quote_path_fully = git_config_bool(var, value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-03-02 22:11:30 +01:00
|
|
|
if (!strcmp(var, "core.symlinks")) {
|
|
|
|
has_symlinks = git_config_bool(var, value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-03-22 00:52:46 +01:00
|
|
|
if (!strcmp(var, "core.ignorecase")) {
|
|
|
|
ignore_case = git_config_bool(var, value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-10-06 20:22:24 +02:00
|
|
|
if (!strcmp(var, "core.attributesfile"))
|
|
|
|
return git_config_pathname(&git_attributes_file, var, value);
|
|
|
|
|
2007-01-07 11:00:28 +01:00
|
|
|
if (!strcmp(var, "core.bare")) {
|
|
|
|
is_bare_repository_cfg = git_config_bool(var, value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-02-09 06:15:24 +01:00
|
|
|
if (!strcmp(var, "core.ignorestat")) {
|
|
|
|
assume_unchanged = git_config_bool(var, value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-05-02 09:40:24 +02:00
|
|
|
if (!strcmp(var, "core.prefersymlinkrefs")) {
|
|
|
|
prefer_symlink_refs = git_config_bool(var, value);
|
2005-11-15 19:24:19 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-05-17 11:55:40 +02:00
|
|
|
if (!strcmp(var, "core.logallrefupdates")) {
|
|
|
|
log_all_ref_updates = git_config_bool(var, value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-03-21 03:45:47 +01:00
|
|
|
if (!strcmp(var, "core.warnambiguousrefs")) {
|
|
|
|
warn_ambiguous_refs = git_config_bool(var, value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-03-21 06:26:24 +01:00
|
|
|
if (!strcmp(var, "core.abbrev")) {
|
2010-10-28 20:28:04 +02:00
|
|
|
int abbrev = git_config_int(var, value);
|
|
|
|
if (abbrev < minimum_abbrev || abbrev > 40)
|
|
|
|
return -1;
|
|
|
|
default_abbrev = abbrev;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
Custom compression levels for objects and packs
Add config variables pack.compression and core.loosecompression ,
and switch --compression=level to pack-objects.
Loose objects will be compressed using core.loosecompression if set,
else core.compression if set, else Z_BEST_SPEED.
Packed objects will be compressed using --compression=level if seen,
else pack.compression if set, else core.compression if set,
else Z_DEFAULT_COMPRESSION. This is the "pack compression level".
Loose objects added to a pack undeltified will be recompressed
to the pack compression level if it is unequal to the current
loose compression level by the preceding rules, or if the loose
object was written while core.legacyheaders = true. Newly
deltified loose objects are always compressed to the current
pack compression level.
Previously packed objects added to a pack are recompressed
to the current pack compression level exactly when their
deltification status changes, since the previous pack data
cannot be reused.
In either case, the --no-reuse-object switch from the first
patch below will always force recompression to the current pack
compression level, instead of assuming the pack compression level
hasn't changed and pack data can be reused when possible.
This applies on top of the following patches from Nicolas Pitre:
[PATCH] allow for undeltified objects not to be reused
[PATCH] make "repack -f" imply "pack-objects --no-reuse-object"
Signed-off-by: Dana L. How <danahow@gmail.com>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-05-09 22:56:50 +02:00
|
|
|
if (!strcmp(var, "core.loosecompression")) {
|
2006-07-03 22:11:47 +02:00
|
|
|
int level = git_config_int(var, value);
|
|
|
|
if (level == -1)
|
|
|
|
level = Z_DEFAULT_COMPRESSION;
|
|
|
|
else if (level < 0 || level > Z_BEST_COMPRESSION)
|
2014-08-07 13:59:12 +02:00
|
|
|
die(_("bad zlib compression level %d"), level);
|
2006-07-03 22:11:47 +02:00
|
|
|
zlib_compression_level = level;
|
Custom compression levels for objects and packs
Add config variables pack.compression and core.loosecompression ,
and switch --compression=level to pack-objects.
Loose objects will be compressed using core.loosecompression if set,
else core.compression if set, else Z_BEST_SPEED.
Packed objects will be compressed using --compression=level if seen,
else pack.compression if set, else core.compression if set,
else Z_DEFAULT_COMPRESSION. This is the "pack compression level".
Loose objects added to a pack undeltified will be recompressed
to the pack compression level if it is unequal to the current
loose compression level by the preceding rules, or if the loose
object was written while core.legacyheaders = true. Newly
deltified loose objects are always compressed to the current
pack compression level.
Previously packed objects added to a pack are recompressed
to the current pack compression level exactly when their
deltification status changes, since the previous pack data
cannot be reused.
In either case, the --no-reuse-object switch from the first
patch below will always force recompression to the current pack
compression level, instead of assuming the pack compression level
hasn't changed and pack data can be reused when possible.
This applies on top of the following patches from Nicolas Pitre:
[PATCH] allow for undeltified objects not to be reused
[PATCH] make "repack -f" imply "pack-objects --no-reuse-object"
Signed-off-by: Dana L. How <danahow@gmail.com>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-05-09 22:56:50 +02:00
|
|
|
zlib_compression_seen = 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp(var, "core.compression")) {
|
|
|
|
int level = git_config_int(var, value);
|
|
|
|
if (level == -1)
|
|
|
|
level = Z_DEFAULT_COMPRESSION;
|
|
|
|
else if (level < 0 || level > Z_BEST_COMPRESSION)
|
2014-08-07 13:59:12 +02:00
|
|
|
die(_("bad zlib compression level %d"), level);
|
Custom compression levels for objects and packs
Add config variables pack.compression and core.loosecompression ,
and switch --compression=level to pack-objects.
Loose objects will be compressed using core.loosecompression if set,
else core.compression if set, else Z_BEST_SPEED.
Packed objects will be compressed using --compression=level if seen,
else pack.compression if set, else core.compression if set,
else Z_DEFAULT_COMPRESSION. This is the "pack compression level".
Loose objects added to a pack undeltified will be recompressed
to the pack compression level if it is unequal to the current
loose compression level by the preceding rules, or if the loose
object was written while core.legacyheaders = true. Newly
deltified loose objects are always compressed to the current
pack compression level.
Previously packed objects added to a pack are recompressed
to the current pack compression level exactly when their
deltification status changes, since the previous pack data
cannot be reused.
In either case, the --no-reuse-object switch from the first
patch below will always force recompression to the current pack
compression level, instead of assuming the pack compression level
hasn't changed and pack data can be reused when possible.
This applies on top of the following patches from Nicolas Pitre:
[PATCH] allow for undeltified objects not to be reused
[PATCH] make "repack -f" imply "pack-objects --no-reuse-object"
Signed-off-by: Dana L. How <danahow@gmail.com>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-05-09 22:56:50 +02:00
|
|
|
core_compression_level = level;
|
|
|
|
core_compression_seen = 1;
|
|
|
|
if (!zlib_compression_seen)
|
|
|
|
zlib_compression_level = level;
|
2006-07-03 22:11:47 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-12-23 08:34:28 +01:00
|
|
|
if (!strcmp(var, "core.packedgitwindowsize")) {
|
2007-02-14 22:20:41 +01:00
|
|
|
int pgsz_x2 = getpagesize() * 2;
|
Support sizes >=2G in various config options accepting 'g' sizes.
The config options core.packedGitWindowSize, core.packedGitLimit,
core.deltaBaseCacheLimit, core.bigFileThreshold, pack.windowMemory and
pack.packSizeLimit all claim to support suffixes up to and including
'g'. This implies that they should accept sizes >=2G on 64-bit
systems: certainly, specifying a size of 3g should not silently be
translated to zero or transformed into a large negative value due to
integer overflow. However, due to use of git_config_int() rather than
git_config_ulong(), that is exactly what happens:
% git config core.bigFileThreshold 2g
% git gc --aggressive # with extra debugging code to print out
# core.bigfilethreshold after parsing
bigfilethreshold: -2147483648
[...]
This is probably irrelevant for core.deltaBaseCacheLimit, but is
problematic for the other values. (It is particularly problematic for
core.packedGitLimit, which can't even be set to its default value in
the config file due to this bug.)
This fixes things for 32-bit platforms as well. They get the usual bad
config error if an overlarge value is specified, e.g.:
fatal: bad config value for 'core.bigfilethreshold' in /home/nix/.gitconfig
This is detected in all cases, even if the 32-bit platform has no size
larger than 'long'. For signed integral configuration values, we also
detect the case where the value is too large for the signed type but
not the unsigned type.
Signed-off-by: Nick Alcock <nix@esperi.org.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-11-02 16:46:23 +01:00
|
|
|
packed_git_window_size = git_config_ulong(var, value);
|
2007-02-14 22:20:41 +01:00
|
|
|
|
|
|
|
/* This value must be multiple of (pagesize * 2) */
|
|
|
|
packed_git_window_size /= pgsz_x2;
|
|
|
|
if (packed_git_window_size < 1)
|
|
|
|
packed_git_window_size = 1;
|
|
|
|
packed_git_window_size *= pgsz_x2;
|
2006-12-23 08:34:28 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-04-05 19:44:11 +02:00
|
|
|
if (!strcmp(var, "core.bigfilethreshold")) {
|
Support sizes >=2G in various config options accepting 'g' sizes.
The config options core.packedGitWindowSize, core.packedGitLimit,
core.deltaBaseCacheLimit, core.bigFileThreshold, pack.windowMemory and
pack.packSizeLimit all claim to support suffixes up to and including
'g'. This implies that they should accept sizes >=2G on 64-bit
systems: certainly, specifying a size of 3g should not silently be
translated to zero or transformed into a large negative value due to
integer overflow. However, due to use of git_config_int() rather than
git_config_ulong(), that is exactly what happens:
% git config core.bigFileThreshold 2g
% git gc --aggressive # with extra debugging code to print out
# core.bigfilethreshold after parsing
bigfilethreshold: -2147483648
[...]
This is probably irrelevant for core.deltaBaseCacheLimit, but is
problematic for the other values. (It is particularly problematic for
core.packedGitLimit, which can't even be set to its default value in
the config file due to this bug.)
This fixes things for 32-bit platforms as well. They get the usual bad
config error if an overlarge value is specified, e.g.:
fatal: bad config value for 'core.bigfilethreshold' in /home/nix/.gitconfig
This is detected in all cases, even if the 32-bit platform has no size
larger than 'long'. For signed integral configuration values, we also
detect the case where the value is too large for the signed type but
not the unsigned type.
Signed-off-by: Nick Alcock <nix@esperi.org.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-11-02 16:46:23 +01:00
|
|
|
big_file_threshold = git_config_ulong(var, value);
|
2011-04-05 19:44:11 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-12-23 08:33:35 +01:00
|
|
|
if (!strcmp(var, "core.packedgitlimit")) {
|
Support sizes >=2G in various config options accepting 'g' sizes.
The config options core.packedGitWindowSize, core.packedGitLimit,
core.deltaBaseCacheLimit, core.bigFileThreshold, pack.windowMemory and
pack.packSizeLimit all claim to support suffixes up to and including
'g'. This implies that they should accept sizes >=2G on 64-bit
systems: certainly, specifying a size of 3g should not silently be
translated to zero or transformed into a large negative value due to
integer overflow. However, due to use of git_config_int() rather than
git_config_ulong(), that is exactly what happens:
% git config core.bigFileThreshold 2g
% git gc --aggressive # with extra debugging code to print out
# core.bigfilethreshold after parsing
bigfilethreshold: -2147483648
[...]
This is probably irrelevant for core.deltaBaseCacheLimit, but is
problematic for the other values. (It is particularly problematic for
core.packedGitLimit, which can't even be set to its default value in
the config file due to this bug.)
This fixes things for 32-bit platforms as well. They get the usual bad
config error if an overlarge value is specified, e.g.:
fatal: bad config value for 'core.bigfilethreshold' in /home/nix/.gitconfig
This is detected in all cases, even if the 32-bit platform has no size
larger than 'long'. For signed integral configuration values, we also
detect the case where the value is too large for the signed type but
not the unsigned type.
Signed-off-by: Nick Alcock <nix@esperi.org.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-11-02 16:46:23 +01:00
|
|
|
packed_git_limit = git_config_ulong(var, value);
|
2006-12-23 08:33:35 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-03-19 06:14:37 +01:00
|
|
|
if (!strcmp(var, "core.deltabasecachelimit")) {
|
Support sizes >=2G in various config options accepting 'g' sizes.
The config options core.packedGitWindowSize, core.packedGitLimit,
core.deltaBaseCacheLimit, core.bigFileThreshold, pack.windowMemory and
pack.packSizeLimit all claim to support suffixes up to and including
'g'. This implies that they should accept sizes >=2G on 64-bit
systems: certainly, specifying a size of 3g should not silently be
translated to zero or transformed into a large negative value due to
integer overflow. However, due to use of git_config_int() rather than
git_config_ulong(), that is exactly what happens:
% git config core.bigFileThreshold 2g
% git gc --aggressive # with extra debugging code to print out
# core.bigfilethreshold after parsing
bigfilethreshold: -2147483648
[...]
This is probably irrelevant for core.deltaBaseCacheLimit, but is
problematic for the other values. (It is particularly problematic for
core.packedGitLimit, which can't even be set to its default value in
the config file due to this bug.)
This fixes things for 32-bit platforms as well. They get the usual bad
config error if an overlarge value is specified, e.g.:
fatal: bad config value for 'core.bigfilethreshold' in /home/nix/.gitconfig
This is detected in all cases, even if the 32-bit platform has no size
larger than 'long'. For signed integral configuration values, we also
detect the case where the value is too large for the signed type but
not the unsigned type.
Signed-off-by: Nick Alcock <nix@esperi.org.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-11-02 16:46:23 +01:00
|
|
|
delta_base_cache_limit = git_config_ulong(var, value);
|
2007-03-19 06:14:37 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-13 20:07:23 +01:00
|
|
|
if (!strcmp(var, "core.autocrlf")) {
|
2007-02-14 03:16:12 +01:00
|
|
|
if (value && !strcasecmp(value, "input")) {
|
2011-05-09 21:52:12 +02:00
|
|
|
if (core_eol == EOL_CRLF)
|
2010-06-04 21:29:08 +02:00
|
|
|
return error("core.autocrlf=input conflicts with core.eol=crlf");
|
2010-05-19 22:43:10 +02:00
|
|
|
auto_crlf = AUTO_CRLF_INPUT;
|
2007-02-14 03:16:12 +01:00
|
|
|
return 0;
|
|
|
|
}
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-13 20:07:23 +01:00
|
|
|
auto_crlf = git_config_bool(var, value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
safecrlf: Add mechanism to warn about irreversible crlf conversions
CRLF conversion bears a slight chance of corrupting data.
autocrlf=true will convert CRLF to LF during commit and LF to
CRLF during checkout. A file that contains a mixture of LF and
CRLF before the commit cannot be recreated by git. For text
files this is the right thing to do: it corrects line endings
such that we have only LF line endings in the repository.
But for binary files that are accidentally classified as text the
conversion can corrupt data.
If you recognize such corruption early you can easily fix it by
setting the conversion type explicitly in .gitattributes. Right
after committing you still have the original file in your work
tree and this file is not yet corrupted. You can explicitly tell
git that this file is binary and git will handle the file
appropriately.
Unfortunately, the desired effect of cleaning up text files with
mixed line endings and the undesired effect of corrupting binary
files cannot be distinguished. In both cases CRLFs are removed
in an irreversible way. For text files this is the right thing
to do because CRLFs are line endings, while for binary files
converting CRLFs corrupts data.
This patch adds a mechanism that can either warn the user about
an irreversible conversion or can even refuse to convert. The
mechanism is controlled by the variable core.safecrlf, with the
following values:
- false: disable safecrlf mechanism
- warn: warn about irreversible conversions
- true: refuse irreversible conversions
The default is to warn. Users are only affected by this default
if core.autocrlf is set. But the current default of git is to
leave core.autocrlf unset, so users will not see warnings unless
they deliberately chose to activate the autocrlf mechanism.
The safecrlf mechanism's details depend on the git command. The
general principles when safecrlf is active (not false) are:
- we warn/error out if files in the work tree can modified in an
irreversible way without giving the user a chance to backup the
original file.
- for read-only operations that do not modify files in the work tree
we do not not print annoying warnings.
There are exceptions. Even though...
- "git add" itself does not touch the files in the work tree, the
next checkout would, so the safety triggers;
- "git apply" to update a text file with a patch does touch the files
in the work tree, but the operation is about text files and CRLF
conversion is about fixing the line ending inconsistencies, so the
safety does not trigger;
- "git diff" itself does not touch the files in the work tree, it is
often run to inspect the changes you intend to next "git add". To
catch potential problems early, safety triggers.
The concept of a safety check was originally proposed in a similar
way by Linus Torvalds. Thanks to Dimitry Potapov for insisting
on getting the naked LF/autocrlf=true case right.
Signed-off-by: Steffen Prohaska <prohaska@zib.de>
2008-02-06 12:25:58 +01:00
|
|
|
if (!strcmp(var, "core.safecrlf")) {
|
|
|
|
if (value && !strcasecmp(value, "warn")) {
|
|
|
|
safe_crlf = SAFE_CRLF_WARN;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
safe_crlf = git_config_bool(var, value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-06-04 21:29:08 +02:00
|
|
|
if (!strcmp(var, "core.eol")) {
|
|
|
|
if (value && !strcasecmp(value, "lf"))
|
2011-05-09 21:52:12 +02:00
|
|
|
core_eol = EOL_LF;
|
2010-06-04 21:29:08 +02:00
|
|
|
else if (value && !strcasecmp(value, "crlf"))
|
2011-05-09 21:52:12 +02:00
|
|
|
core_eol = EOL_CRLF;
|
2010-06-04 21:29:08 +02:00
|
|
|
else if (value && !strcasecmp(value, "native"))
|
2011-05-09 21:52:12 +02:00
|
|
|
core_eol = EOL_NATIVE;
|
2010-06-04 21:29:08 +02:00
|
|
|
else
|
2011-05-09 21:52:12 +02:00
|
|
|
core_eol = EOL_UNSET;
|
|
|
|
if (core_eol == EOL_CRLF && auto_crlf == AUTO_CRLF_INPUT)
|
2010-06-04 21:29:08 +02:00
|
|
|
return error("core.autocrlf=input conflicts with core.eol=crlf");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-10-09 12:21:57 +02:00
|
|
|
if (!strcmp(var, "core.notesref")) {
|
|
|
|
notes_ref_name = xstrdup(value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-06-18 23:37:18 +02:00
|
|
|
if (!strcmp(var, "core.pager"))
|
|
|
|
return git_config_string(&pager_program, var, value);
|
|
|
|
|
|
|
|
if (!strcmp(var, "core.editor"))
|
|
|
|
return git_config_string(&editor_program, var, value);
|
|
|
|
|
2013-01-16 20:18:48 +01:00
|
|
|
if (!strcmp(var, "core.commentchar")) {
|
2014-07-24 06:42:39 +02:00
|
|
|
if (!value)
|
|
|
|
return config_error_nonbool(var);
|
2014-07-28 20:30:41 +02:00
|
|
|
else if (!strcasecmp(value, "auto"))
|
2014-05-17 03:52:23 +02:00
|
|
|
auto_comment_line_char = 1;
|
2014-07-28 20:30:41 +02:00
|
|
|
else if (value[0] && !value[1]) {
|
2014-07-24 06:42:39 +02:00
|
|
|
comment_line_char = value[0];
|
2014-05-17 03:52:23 +02:00
|
|
|
auto_comment_line_char = 0;
|
2014-05-17 03:52:22 +02:00
|
|
|
} else
|
|
|
|
return error("core.commentChar should only be one character");
|
|
|
|
return 0;
|
2013-01-16 20:18:48 +01:00
|
|
|
}
|
|
|
|
|
2010-08-30 15:38:38 +02:00
|
|
|
if (!strcmp(var, "core.askpass"))
|
|
|
|
return git_config_string(&askpass_program, var, value);
|
|
|
|
|
2008-06-18 23:37:18 +02:00
|
|
|
if (!strcmp(var, "core.excludesfile"))
|
2009-11-17 18:24:25 +01:00
|
|
|
return git_config_pathname(&excludes_file, var, value);
|
2008-06-18 23:37:18 +02:00
|
|
|
|
|
|
|
if (!strcmp(var, "core.whitespace")) {
|
|
|
|
if (!value)
|
|
|
|
return config_error_nonbool(var);
|
|
|
|
whitespace_rule_cfg = parse_whitespace_rule(value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-06-19 00:18:44 +02:00
|
|
|
if (!strcmp(var, "core.fsyncobjectfiles")) {
|
|
|
|
fsync_object_files = git_config_bool(var, value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-11-14 01:36:30 +01:00
|
|
|
if (!strcmp(var, "core.preloadindex")) {
|
|
|
|
core_preload_index = git_config_bool(var, value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-04-28 00:32:25 +02:00
|
|
|
if (!strcmp(var, "core.createobject")) {
|
|
|
|
if (!strcmp(value, "rename"))
|
|
|
|
object_creation_mode = OBJECT_CREATION_USES_RENAMES;
|
|
|
|
else if (!strcmp(value, "link"))
|
|
|
|
object_creation_mode = OBJECT_CREATION_USES_HARDLINKS;
|
|
|
|
else
|
2014-08-07 13:59:12 +02:00
|
|
|
die(_("invalid mode for object creation: %s"), value);
|
2009-04-25 11:57:14 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-08-20 15:47:08 +02:00
|
|
|
if (!strcmp(var, "core.sparsecheckout")) {
|
|
|
|
core_apply_sparse_checkout = git_config_bool(var, value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
git on Mac OS and precomposed unicode
Mac OS X mangles file names containing unicode on file systems HFS+,
VFAT or SAMBA. When a file using unicode code points outside ASCII
is created on a HFS+ drive, the file name is converted into
decomposed unicode and written to disk. No conversion is done if
the file name is already decomposed unicode.
Calling open("\xc3\x84", ...) with a precomposed "Ä" yields the same
result as open("\x41\xcc\x88",...) with a decomposed "Ä".
As a consequence, readdir() returns the file names in decomposed
unicode, even if the user expects precomposed unicode. Unlike on
HFS+, Mac OS X stores files on a VFAT drive (e.g. an USB drive) in
precomposed unicode, but readdir() still returns file names in
decomposed unicode. When a git repository is stored on a network
share using SAMBA, file names are send over the wire and written to
disk on the remote system in precomposed unicode, but Mac OS X
readdir() returns decomposed unicode to be compatible with its
behaviour on HFS+ and VFAT.
The unicode decomposition causes many problems:
- The names "git add" and other commands get from the end user may
often be precomposed form (the decomposed form is not easily input
from the keyboard), but when the commands read from the filesystem
to see what it is going to update the index with already is on the
filesystem, readdir() will give decomposed form, which is different.
- Similarly "git log", "git mv" and all other commands that need to
compare pathnames found on the command line (often but not always
precomposed form; a command line input resulting from globbing may
be in decomposed) with pathnames found in the tree objects (should
be precomposed form to be compatible with other systems and for
consistency in general).
- The same for names stored in the index, which should be
precomposed, that may need to be compared with the names read from
readdir().
NFS mounted from Linux is fully transparent and does not suffer from
the above.
As Mac OS X treats precomposed and decomposed file names as equal,
we can
- wrap readdir() on Mac OS X to return the precomposed form, and
- normalize decomposed form given from the command line also to the
precomposed form,
to ensure that all pathnames used in Git are always in the
precomposed form. This behaviour can be requested by setting
"core.precomposedunicode" configuration variable to true.
The code in compat/precomposed_utf8.c implements basically 4 new
functions: precomposed_utf8_opendir(), precomposed_utf8_readdir(),
precomposed_utf8_closedir() and precompose_argv(). The first three
are to wrap opendir(3), readdir(3), and closedir(3) functions.
The argv[] conversion allows to use the TAB filename completion done
by the shell on command line. It tolerates other tools which use
readdir() to feed decomposed file names into git.
When creating a new git repository with "git init" or "git clone",
"core.precomposedunicode" will be set "false".
The user needs to activate this feature manually. She typically
sets core.precomposedunicode to "true" on HFS and VFAT, or file
systems mounted via SAMBA.
Helped-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Torsten Bögershausen <tboegi@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-07-08 15:50:25 +02:00
|
|
|
if (!strcmp(var, "core.precomposeunicode")) {
|
|
|
|
precomposed_unicode = git_config_bool(var, value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-12-16 00:15:20 +01:00
|
|
|
if (!strcmp(var, "core.protecthfs")) {
|
|
|
|
protect_hfs = git_config_bool(var, value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-12-16 23:46:59 +01:00
|
|
|
if (!strcmp(var, "core.protectntfs")) {
|
|
|
|
protect_ntfs = git_config_bool(var, value);
|
|
|
|
return 0;
|
git on Mac OS and precomposed unicode
Mac OS X mangles file names containing unicode on file systems HFS+,
VFAT or SAMBA. When a file using unicode code points outside ASCII
is created on a HFS+ drive, the file name is converted into
decomposed unicode and written to disk. No conversion is done if
the file name is already decomposed unicode.
Calling open("\xc3\x84", ...) with a precomposed "Ä" yields the same
result as open("\x41\xcc\x88",...) with a decomposed "Ä".
As a consequence, readdir() returns the file names in decomposed
unicode, even if the user expects precomposed unicode. Unlike on
HFS+, Mac OS X stores files on a VFAT drive (e.g. an USB drive) in
precomposed unicode, but readdir() still returns file names in
decomposed unicode. When a git repository is stored on a network
share using SAMBA, file names are send over the wire and written to
disk on the remote system in precomposed unicode, but Mac OS X
readdir() returns decomposed unicode to be compatible with its
behaviour on HFS+ and VFAT.
The unicode decomposition causes many problems:
- The names "git add" and other commands get from the end user may
often be precomposed form (the decomposed form is not easily input
from the keyboard), but when the commands read from the filesystem
to see what it is going to update the index with already is on the
filesystem, readdir() will give decomposed form, which is different.
- Similarly "git log", "git mv" and all other commands that need to
compare pathnames found on the command line (often but not always
precomposed form; a command line input resulting from globbing may
be in decomposed) with pathnames found in the tree objects (should
be precomposed form to be compatible with other systems and for
consistency in general).
- The same for names stored in the index, which should be
precomposed, that may need to be compared with the names read from
readdir().
NFS mounted from Linux is fully transparent and does not suffer from
the above.
As Mac OS X treats precomposed and decomposed file names as equal,
we can
- wrap readdir() on Mac OS X to return the precomposed form, and
- normalize decomposed form given from the command line also to the
precomposed form,
to ensure that all pathnames used in Git are always in the
precomposed form. This behaviour can be requested by setting
"core.precomposedunicode" configuration variable to true.
The code in compat/precomposed_utf8.c implements basically 4 new
functions: precomposed_utf8_opendir(), precomposed_utf8_readdir(),
precomposed_utf8_closedir() and precompose_argv(). The first three
are to wrap opendir(3), readdir(3), and closedir(3) functions.
The argv[] conversion allows to use the TAB filename completion done
by the shell on command line. It tolerates other tools which use
readdir() to feed decomposed file names into git.
When creating a new git repository with "git init" or "git clone",
"core.precomposedunicode" will be set "false".
The user needs to activate this feature manually. She typically
sets core.precomposedunicode to "true" on HFS and VFAT, or file
systems mounted via SAMBA.
Helped-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Torsten Bögershausen <tboegi@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-07-08 15:50:25 +02:00
|
|
|
}
|
|
|
|
|
2008-06-18 23:37:18 +02:00
|
|
|
/* Add other config variables here and to Documentation/config.txt. */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-06-19 00:00:11 +02:00
|
|
|
static int git_default_i18n_config(const char *var, const char *value)
|
2008-06-18 23:40:35 +02:00
|
|
|
{
|
2008-02-16 06:00:24 +01:00
|
|
|
if (!strcmp(var, "i18n.commitencoding"))
|
|
|
|
return git_config_string(&git_commit_encoding, var, value);
|
2006-12-28 01:41:33 +01:00
|
|
|
|
2008-02-16 06:00:24 +01:00
|
|
|
if (!strcmp(var, "i18n.logoutputencoding"))
|
|
|
|
return git_config_string(&git_log_output_encoding, var, value);
|
2006-12-28 01:41:33 +01:00
|
|
|
|
2008-06-19 00:00:11 +02:00
|
|
|
/* Add other config variables here and to Documentation/config.txt. */
|
|
|
|
return 0;
|
|
|
|
}
|
core.excludesfile clean-up
There are inconsistencies in the way commands currently handle
the core.excludesfile configuration variable. The problem is
the variable is too new to be noticed by anything other than
git-add and git-status.
* git-ls-files does not notice any of the "ignore" files by
default, as it predates the standardized set of ignore files.
The calling scripts established the convention to use
.git/info/exclude, .gitignore, and later core.excludesfile.
* git-add and git-status know about it because they call
add_excludes_from_file() directly with their own notion of
which standard set of ignore files to use. This is just a
stupid duplication of code that need to be updated every time
the definition of the standard set of ignore files is
changed.
* git-read-tree takes --exclude-per-directory=<gitignore>,
not because the flexibility was needed. Again, this was
because the option predates the standardization of the ignore
files.
* git-merge-recursive uses hardcoded per-directory .gitignore
and nothing else. git-clean (scripted version) does not
honor core.* because its call to underlying ls-files does not
know about it. git-clean in C (parked in 'pu') doesn't either.
We probably could change git-ls-files to use the standard set
when no excludes are specified on the command line and ignore
processing was asked, or something like that, but that will be a
change in semantics and might break people's scripts in a subtle
way. I am somewhat reluctant to make such a change.
On the other hand, I think it makes perfect sense to fix
git-read-tree, git-merge-recursive and git-clean to follow the
same rule as other commands. I do not think of a valid use case
to give an exclude-per-directory that is nonstandard to
read-tree command, outside a "negative" test in the t1004 test
script.
This patch is the first step to untangle this mess.
The next step would be to teach read-tree, merge-recursive and
clean (in C) to use setup_standard_excludes().
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-11-14 09:05:00 +01:00
|
|
|
|
2008-06-19 00:00:11 +02:00
|
|
|
static int git_default_branch_config(const char *var, const char *value)
|
|
|
|
{
|
2008-02-19 17:24:37 +01:00
|
|
|
if (!strcmp(var, "branch.autosetupmerge")) {
|
|
|
|
if (value && !strcasecmp(value, "always")) {
|
|
|
|
git_branch_track = BRANCH_TRACK_ALWAYS;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
git_branch_track = git_config_bool(var, value);
|
|
|
|
return 0;
|
|
|
|
}
|
2008-05-11 00:36:29 +02:00
|
|
|
if (!strcmp(var, "branch.autosetuprebase")) {
|
|
|
|
if (!value)
|
|
|
|
return config_error_nonbool(var);
|
|
|
|
else if (!strcmp(value, "never"))
|
|
|
|
autorebase = AUTOREBASE_NEVER;
|
|
|
|
else if (!strcmp(value, "local"))
|
|
|
|
autorebase = AUTOREBASE_LOCAL;
|
|
|
|
else if (!strcmp(value, "remote"))
|
|
|
|
autorebase = AUTOREBASE_REMOTE;
|
|
|
|
else if (!strcmp(value, "always"))
|
|
|
|
autorebase = AUTOREBASE_ALWAYS;
|
|
|
|
else
|
|
|
|
return error("Malformed value for %s", var);
|
|
|
|
return 0;
|
|
|
|
}
|
2007-11-02 08:24:27 +01:00
|
|
|
|
2006-04-25 00:59:33 +02:00
|
|
|
/* Add other config variables here and to Documentation/config.txt. */
|
2005-10-11 01:31:08 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-03-16 16:42:51 +01:00
|
|
|
static int git_default_push_config(const char *var, const char *value)
|
|
|
|
{
|
|
|
|
if (!strcmp(var, "push.default")) {
|
|
|
|
if (!value)
|
|
|
|
return config_error_nonbool(var);
|
|
|
|
else if (!strcmp(value, "nothing"))
|
|
|
|
push_default = PUSH_DEFAULT_NOTHING;
|
|
|
|
else if (!strcmp(value, "matching"))
|
|
|
|
push_default = PUSH_DEFAULT_MATCHING;
|
2012-04-24 09:50:03 +02:00
|
|
|
else if (!strcmp(value, "simple"))
|
|
|
|
push_default = PUSH_DEFAULT_SIMPLE;
|
2011-02-16 01:54:24 +01:00
|
|
|
else if (!strcmp(value, "upstream"))
|
|
|
|
push_default = PUSH_DEFAULT_UPSTREAM;
|
|
|
|
else if (!strcmp(value, "tracking")) /* deprecated */
|
|
|
|
push_default = PUSH_DEFAULT_UPSTREAM;
|
2009-03-16 16:42:51 +01:00
|
|
|
else if (!strcmp(value, "current"))
|
|
|
|
push_default = PUSH_DEFAULT_CURRENT;
|
|
|
|
else {
|
|
|
|
error("Malformed value for %s: %s", var, value);
|
2012-04-24 09:50:03 +02:00
|
|
|
return error("Must be one of nothing, matching, simple, "
|
|
|
|
"upstream or current.");
|
2009-03-16 16:42:51 +01:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add other config variables here and to Documentation/config.txt. */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-02-08 15:34:27 +01:00
|
|
|
static int git_default_mailmap_config(const char *var, const char *value)
|
|
|
|
{
|
|
|
|
if (!strcmp(var, "mailmap.file"))
|
2014-05-27 10:45:58 +02:00
|
|
|
return git_config_pathname(&git_mailmap_file, var, value);
|
2012-12-12 12:04:04 +01:00
|
|
|
if (!strcmp(var, "mailmap.blob"))
|
|
|
|
return git_config_string(&git_mailmap_blob, var, value);
|
2009-02-08 15:34:27 +01:00
|
|
|
|
|
|
|
/* Add other config variables here and to Documentation/config.txt. */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-06-19 00:00:11 +02:00
|
|
|
int git_default_config(const char *var, const char *value, void *dummy)
|
|
|
|
{
|
2013-11-30 21:55:40 +01:00
|
|
|
if (starts_with(var, "core."))
|
2008-06-19 00:00:11 +02:00
|
|
|
return git_default_core_config(var, value);
|
|
|
|
|
2013-11-30 21:55:40 +01:00
|
|
|
if (starts_with(var, "user."))
|
2012-05-22 01:09:54 +02:00
|
|
|
return git_ident_config(var, value, dummy);
|
2008-06-19 00:00:11 +02:00
|
|
|
|
2013-11-30 21:55:40 +01:00
|
|
|
if (starts_with(var, "i18n."))
|
2008-06-19 00:00:11 +02:00
|
|
|
return git_default_i18n_config(var, value);
|
|
|
|
|
2013-11-30 21:55:40 +01:00
|
|
|
if (starts_with(var, "branch."))
|
2008-06-19 00:00:11 +02:00
|
|
|
return git_default_branch_config(var, value);
|
|
|
|
|
2013-11-30 21:55:40 +01:00
|
|
|
if (starts_with(var, "push."))
|
2009-03-16 16:42:51 +01:00
|
|
|
return git_default_push_config(var, value);
|
|
|
|
|
2013-11-30 21:55:40 +01:00
|
|
|
if (starts_with(var, "mailmap."))
|
2009-02-08 15:34:27 +01:00
|
|
|
return git_default_mailmap_config(var, value);
|
|
|
|
|
2013-11-30 21:55:40 +01:00
|
|
|
if (starts_with(var, "advice."))
|
2009-09-09 13:38:58 +02:00
|
|
|
return git_default_advice_config(var, value);
|
|
|
|
|
2008-06-19 00:00:11 +02:00
|
|
|
if (!strcmp(var, "pager.color") || !strcmp(var, "color.pager")) {
|
|
|
|
pager_use_color = git_config_bool(var,value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-10-28 23:48:40 +02:00
|
|
|
if (!strcmp(var, "pack.packsizelimit")) {
|
|
|
|
pack_size_limit_cfg = git_config_ulong(var, value);
|
|
|
|
return 0;
|
|
|
|
}
|
2008-06-19 00:00:11 +02:00
|
|
|
/* Add other config variables here and to Documentation/config.txt. */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-05-11 15:18:52 +02:00
|
|
|
/*
|
2013-07-12 00:48:30 +02:00
|
|
|
* All source specific fields in the union, die_on_error, name and the callbacks
|
2013-07-12 00:44:39 +02:00
|
|
|
* fgetc, ungetc, ftell of top need to be initialized before calling
|
2013-05-11 15:18:52 +02:00
|
|
|
* this function.
|
|
|
|
*/
|
2013-07-12 00:44:39 +02:00
|
|
|
static int do_config_from(struct config_source *top, config_fn_t fn, void *data)
|
2013-05-11 15:18:52 +02:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
/* push config-file parsing state stack */
|
|
|
|
top->prev = cf;
|
|
|
|
top->linenr = 1;
|
|
|
|
top->eof = 0;
|
|
|
|
strbuf_init(&top->value, 1024);
|
|
|
|
strbuf_init(&top->var, 1024);
|
|
|
|
cf = top;
|
|
|
|
|
2013-07-12 00:44:39 +02:00
|
|
|
ret = git_parse_source(fn, data);
|
2013-05-11 15:18:52 +02:00
|
|
|
|
|
|
|
/* pop config-file parsing state stack */
|
|
|
|
strbuf_release(&top->value);
|
|
|
|
strbuf_release(&top->var);
|
|
|
|
cf = top->prev;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-02-18 23:58:55 +01:00
|
|
|
static int do_config_from_file(config_fn_t fn,
|
|
|
|
const char *name, const char *path, FILE *f, void *data)
|
2005-10-11 01:31:08 +02:00
|
|
|
{
|
2014-02-18 23:58:55 +01:00
|
|
|
struct config_source top;
|
2005-10-11 01:31:08 +02:00
|
|
|
|
2014-02-18 23:58:55 +01:00
|
|
|
top.u.file = f;
|
|
|
|
top.name = name;
|
|
|
|
top.path = path;
|
|
|
|
top.die_on_error = 1;
|
|
|
|
top.do_fgetc = config_file_fgetc;
|
|
|
|
top.do_ungetc = config_file_ungetc;
|
|
|
|
top.do_ftell = config_file_ftell;
|
config.c: Make git_config() work correctly when called recursively
On Cygwin, this fixes a test failure in t3301-notes.sh (test 98,
"git notes copy --for-rewrite (disabled)").
The test failure is caused by a recursive call to git_config() which
has the effect of skipping to the end-of-file while processing the
"notes.rewriteref" config variable. Thus, any config variables that
appear after "notes.rewriteref" are simply ignored by git_config().
Also, we note that the original FILE handle is leaked as a result
of the recursive call.
The recursive call to git_config() is due to the "schizophrenic stat"
functions on cygwin, where one of two different implementations of
the l/stat functions is selected lazily, depending on some config
variables.
In this case, the init_copy_notes_for_rewrite() function calls
git_config() with the notes_rewrite_config() callback function.
This callback, while processing the "notes.rewriteref" variable,
in turn calls string_list_add_refs_by_glob() to process the
associated ref value. This eventually leads to a call to the
get_ref_dir() function, which in turn calls stat(). On cygwin,
the stat() macro leads to an indirect call to cygwin_stat_stub()
which, via init_stat(), then calls git_config() in order to
determine which l/stat implementation to bind to.
In order to solve this problem, we modify git_config() so that the
global state variables used by the config reading code is packaged
up and managed on a local state stack.
Signed-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-06-16 22:24:51 +02:00
|
|
|
|
2014-02-18 23:58:55 +01:00
|
|
|
return do_config_from(&top, fn, data);
|
|
|
|
}
|
config.c: Make git_config() work correctly when called recursively
On Cygwin, this fixes a test failure in t3301-notes.sh (test 98,
"git notes copy --for-rewrite (disabled)").
The test failure is caused by a recursive call to git_config() which
has the effect of skipping to the end-of-file while processing the
"notes.rewriteref" config variable. Thus, any config variables that
appear after "notes.rewriteref" are simply ignored by git_config().
Also, we note that the original FILE handle is leaked as a result
of the recursive call.
The recursive call to git_config() is due to the "schizophrenic stat"
functions on cygwin, where one of two different implementations of
the l/stat functions is selected lazily, depending on some config
variables.
In this case, the init_copy_notes_for_rewrite() function calls
git_config() with the notes_rewrite_config() callback function.
This callback, while processing the "notes.rewriteref" variable,
in turn calls string_list_add_refs_by_glob() to process the
associated ref value. This eventually leads to a call to the
get_ref_dir() function, which in turn calls stat(). On cygwin,
the stat() macro leads to an indirect call to cygwin_stat_stub()
which, via init_stat(), then calls git_config() in order to
determine which l/stat implementation to bind to.
In order to solve this problem, we modify git_config() so that the
global state variables used by the config reading code is packaged
up and managed on a local state stack.
Signed-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-06-16 22:24:51 +02:00
|
|
|
|
2014-02-18 23:58:55 +01:00
|
|
|
static int git_config_from_stdin(config_fn_t fn, void *data)
|
|
|
|
{
|
|
|
|
return do_config_from_file(fn, "<stdin>", NULL, stdin, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
int git_config_from_file(config_fn_t fn, const char *filename, void *data)
|
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
FILE *f;
|
config.c: Make git_config() work correctly when called recursively
On Cygwin, this fixes a test failure in t3301-notes.sh (test 98,
"git notes copy --for-rewrite (disabled)").
The test failure is caused by a recursive call to git_config() which
has the effect of skipping to the end-of-file while processing the
"notes.rewriteref" config variable. Thus, any config variables that
appear after "notes.rewriteref" are simply ignored by git_config().
Also, we note that the original FILE handle is leaked as a result
of the recursive call.
The recursive call to git_config() is due to the "schizophrenic stat"
functions on cygwin, where one of two different implementations of
the l/stat functions is selected lazily, depending on some config
variables.
In this case, the init_copy_notes_for_rewrite() function calls
git_config() with the notes_rewrite_config() callback function.
This callback, while processing the "notes.rewriteref" variable,
in turn calls string_list_add_refs_by_glob() to process the
associated ref value. This eventually leads to a call to the
get_ref_dir() function, which in turn calls stat(). On cygwin,
the stat() macro leads to an indirect call to cygwin_stat_stub()
which, via init_stat(), then calls git_config() in order to
determine which l/stat implementation to bind to.
In order to solve this problem, we modify git_config() so that the
global state variables used by the config reading code is packaged
up and managed on a local state stack.
Signed-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-06-16 22:24:51 +02:00
|
|
|
|
2014-02-18 23:58:55 +01:00
|
|
|
f = fopen(filename, "r");
|
|
|
|
if (f) {
|
|
|
|
ret = do_config_from_file(fn, filename, filename, f, data);
|
2005-10-11 01:31:08 +02:00
|
|
|
fclose(f);
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
2005-11-17 22:32:36 +01:00
|
|
|
|
2013-07-12 00:46:47 +02:00
|
|
|
int git_config_from_buf(config_fn_t fn, const char *name, const char *buf,
|
|
|
|
size_t len, void *data)
|
|
|
|
{
|
|
|
|
struct config_source top;
|
|
|
|
|
|
|
|
top.u.buf.buf = buf;
|
|
|
|
top.u.buf.len = len;
|
|
|
|
top.u.buf.pos = 0;
|
|
|
|
top.name = name;
|
2014-02-18 23:58:52 +01:00
|
|
|
top.path = NULL;
|
2013-07-12 00:48:30 +02:00
|
|
|
top.die_on_error = 0;
|
2013-08-26 23:57:18 +02:00
|
|
|
top.do_fgetc = config_buf_fgetc;
|
|
|
|
top.do_ungetc = config_buf_ungetc;
|
|
|
|
top.do_ftell = config_buf_ftell;
|
2013-07-12 00:46:47 +02:00
|
|
|
|
|
|
|
return do_config_from(&top, fn, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int git_config_from_blob_sha1(config_fn_t fn,
|
|
|
|
const char *name,
|
|
|
|
const unsigned char *sha1,
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
enum object_type type;
|
|
|
|
char *buf;
|
|
|
|
unsigned long size;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
buf = read_sha1_file(sha1, &type, &size);
|
|
|
|
if (!buf)
|
|
|
|
return error("unable to load config blob object '%s'", name);
|
|
|
|
if (type != OBJ_BLOB) {
|
|
|
|
free(buf);
|
|
|
|
return error("reference '%s' does not point to a blob", name);
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = git_config_from_buf(fn, name, buf, size, data);
|
|
|
|
free(buf);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int git_config_from_blob_ref(config_fn_t fn,
|
|
|
|
const char *name,
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
unsigned char sha1[20];
|
|
|
|
|
|
|
|
if (get_sha1(name, sha1) < 0)
|
|
|
|
return error("unable to resolve config blob '%s'", name);
|
|
|
|
return git_config_from_blob_sha1(fn, name, sha1, data);
|
|
|
|
}
|
|
|
|
|
2007-11-13 21:05:05 +01:00
|
|
|
const char *git_etc_gitconfig(void)
|
|
|
|
{
|
2007-11-13 21:05:06 +01:00
|
|
|
static const char *system_wide;
|
2008-07-13 22:31:18 +02:00
|
|
|
if (!system_wide)
|
|
|
|
system_wide = system_path(ETC_GITCONFIG);
|
2007-11-13 21:05:06 +01:00
|
|
|
return system_wide;
|
2007-11-13 21:05:05 +01:00
|
|
|
}
|
|
|
|
|
2014-08-26 17:23:21 +02:00
|
|
|
/*
|
|
|
|
* Parse environment variable 'k' as a boolean (in various
|
|
|
|
* possible spellings); if missing, use the default value 'def'.
|
|
|
|
*/
|
2010-03-17 20:55:51 +01:00
|
|
|
int git_env_bool(const char *k, int def)
|
2008-02-06 11:11:18 +01:00
|
|
|
{
|
|
|
|
const char *v = getenv(k);
|
|
|
|
return v ? git_config_bool(k, v) : def;
|
|
|
|
}
|
|
|
|
|
2014-08-26 17:23:21 +02:00
|
|
|
/*
|
|
|
|
* Parse environment variable 'k' as ulong with possibly a unit
|
|
|
|
* suffix; if missing, use the default value 'val'.
|
|
|
|
*/
|
|
|
|
unsigned long git_env_ulong(const char *k, unsigned long val)
|
|
|
|
{
|
|
|
|
const char *v = getenv(k);
|
|
|
|
if (v && !git_parse_ulong(v, &val))
|
|
|
|
die("failed to parse %s", k);
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
2008-02-06 11:11:18 +01:00
|
|
|
int git_config_system(void)
|
|
|
|
{
|
|
|
|
return !git_env_bool("GIT_CONFIG_NOSYSTEM", 0);
|
|
|
|
}
|
|
|
|
|
2010-11-26 16:32:33 +01:00
|
|
|
int git_config_early(config_fn_t fn, void *data, const char *repo_config)
|
2005-11-26 01:03:56 +01:00
|
|
|
{
|
2009-02-21 01:48:55 +01:00
|
|
|
int ret = 0, found = 0;
|
2012-06-22 11:03:23 +02:00
|
|
|
char *xdg_config = NULL;
|
|
|
|
char *user_config = NULL;
|
|
|
|
|
|
|
|
home_config_paths(&user_config, &xdg_config, "config");
|
Read configuration also from $HOME/.gitconfig
This patch is based on Pasky's, with three notable differences:
- I did not yet update the documentation
- I named it .gitconfig, not .gitrc
- git-repo-config does not barf when a unique key is overridden locally
The last means that if you have something like
[alias]
l = log --stat -M
in ~/.gitconfig, and
[alias]
l = log --stat -M next..
in $GIT_DIR/config, then
git-repo-config alias.l
returns only one value, namely the value from $GIT_DIR/config.
If you set the environment variable GIT_CONFIG, $HOME/.gitconfig is not
read, and neither $GIT_DIR/config, but $GIT_CONFIG instead.
If you set GIT_CONFIG_LOCAL instead, it is interpreted instead of
$GIT_DIR/config, but $HOME/.gitconfig is still read.
Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-06-20 01:48:03 +02:00
|
|
|
|
config: allow inaccessible configuration under $HOME
The changes v1.7.12.1~2^2~4 (config: warn on inaccessible files,
2012-08-21) and v1.8.1.1~22^2~2 (config: treat user and xdg config
permission problems as errors, 2012-10-13) were intended to prevent
important configuration (think "[transfer] fsckobjects") from being
ignored when the configuration is unintentionally unreadable (for
example with EIO on a flaky filesystem, or with ENOMEM due to a DoS
attack). Usually ~/.gitconfig and ~/.config/git are readable by the
current user, and if they aren't then it would be easy to fix those
permissions, so the damage from adding this check should have been
minimal.
Unfortunately the access() check often trips when git is being run as
a server. A daemon (such as inetd or git-daemon) starts as "root",
creates a listening socket, and then drops privileges, meaning that
when git commands are invoked they cannot access $HOME and die with
fatal: unable to access '/root/.config/git/config': Permission denied
Any patch to fix this would have one of three problems:
1. We annoy sysadmins who need to take an extra step to handle HOME
when dropping privileges (the current behavior, or any other
proposal that they have to opt into).
2. We annoy sysadmins who want to set HOME when dropping privileges,
either by making what they want to do impossible, or making them
set an extra variable or option to accomplish what used to work
(e.g., a patch to git-daemon to set HOME when --user is passed).
3. We loosen the check, so some cases which might be noteworthy are
not caught.
This patch is of type (3).
Treat user and xdg configuration that are inaccessible due to
permissions (EACCES) as though no user configuration was provided at
all.
An alternative method would be to check if $HOME is readable, but that
would not help in cases where the user who dropped privileges had a
globally readable HOME with only .config or .gitconfig being private.
This does not change the behavior when /etc/gitconfig or .git/config
is unreadable (since those are more serious configuration errors),
nor when ~/.gitconfig or ~/.config/git is unreadable due to problems
other than permissions.
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Improved-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-04-12 23:03:18 +02:00
|
|
|
if (git_config_system() && !access_or_die(git_etc_gitconfig(), R_OK, 0)) {
|
2008-06-30 09:37:47 +02:00
|
|
|
ret += git_config_from_file(fn, git_etc_gitconfig(),
|
|
|
|
data);
|
2009-02-21 01:48:55 +01:00
|
|
|
found += 1;
|
|
|
|
}
|
Read configuration also from $HOME/.gitconfig
This patch is based on Pasky's, with three notable differences:
- I did not yet update the documentation
- I named it .gitconfig, not .gitrc
- git-repo-config does not barf when a unique key is overridden locally
The last means that if you have something like
[alias]
l = log --stat -M
in ~/.gitconfig, and
[alias]
l = log --stat -M next..
in $GIT_DIR/config, then
git-repo-config alias.l
returns only one value, namely the value from $GIT_DIR/config.
If you set the environment variable GIT_CONFIG, $HOME/.gitconfig is not
read, and neither $GIT_DIR/config, but $GIT_CONFIG instead.
If you set GIT_CONFIG_LOCAL instead, it is interpreted instead of
$GIT_DIR/config, but $HOME/.gitconfig is still read.
Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-06-20 01:48:03 +02:00
|
|
|
|
config: allow inaccessible configuration under $HOME
The changes v1.7.12.1~2^2~4 (config: warn on inaccessible files,
2012-08-21) and v1.8.1.1~22^2~2 (config: treat user and xdg config
permission problems as errors, 2012-10-13) were intended to prevent
important configuration (think "[transfer] fsckobjects") from being
ignored when the configuration is unintentionally unreadable (for
example with EIO on a flaky filesystem, or with ENOMEM due to a DoS
attack). Usually ~/.gitconfig and ~/.config/git are readable by the
current user, and if they aren't then it would be easy to fix those
permissions, so the damage from adding this check should have been
minimal.
Unfortunately the access() check often trips when git is being run as
a server. A daemon (such as inetd or git-daemon) starts as "root",
creates a listening socket, and then drops privileges, meaning that
when git commands are invoked they cannot access $HOME and die with
fatal: unable to access '/root/.config/git/config': Permission denied
Any patch to fix this would have one of three problems:
1. We annoy sysadmins who need to take an extra step to handle HOME
when dropping privileges (the current behavior, or any other
proposal that they have to opt into).
2. We annoy sysadmins who want to set HOME when dropping privileges,
either by making what they want to do impossible, or making them
set an extra variable or option to accomplish what used to work
(e.g., a patch to git-daemon to set HOME when --user is passed).
3. We loosen the check, so some cases which might be noteworthy are
not caught.
This patch is of type (3).
Treat user and xdg configuration that are inaccessible due to
permissions (EACCES) as though no user configuration was provided at
all.
An alternative method would be to check if $HOME is readable, but that
would not help in cases where the user who dropped privileges had a
globally readable HOME with only .config or .gitconfig being private.
This does not change the behavior when /etc/gitconfig or .git/config
is unreadable (since those are more serious configuration errors),
nor when ~/.gitconfig or ~/.config/git is unreadable due to problems
other than permissions.
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Improved-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-04-12 23:03:18 +02:00
|
|
|
if (xdg_config && !access_or_die(xdg_config, R_OK, ACCESS_EACCES_OK)) {
|
2012-06-22 11:03:23 +02:00
|
|
|
ret += git_config_from_file(fn, xdg_config, data);
|
|
|
|
found += 1;
|
|
|
|
}
|
|
|
|
|
config: allow inaccessible configuration under $HOME
The changes v1.7.12.1~2^2~4 (config: warn on inaccessible files,
2012-08-21) and v1.8.1.1~22^2~2 (config: treat user and xdg config
permission problems as errors, 2012-10-13) were intended to prevent
important configuration (think "[transfer] fsckobjects") from being
ignored when the configuration is unintentionally unreadable (for
example with EIO on a flaky filesystem, or with ENOMEM due to a DoS
attack). Usually ~/.gitconfig and ~/.config/git are readable by the
current user, and if they aren't then it would be easy to fix those
permissions, so the damage from adding this check should have been
minimal.
Unfortunately the access() check often trips when git is being run as
a server. A daemon (such as inetd or git-daemon) starts as "root",
creates a listening socket, and then drops privileges, meaning that
when git commands are invoked they cannot access $HOME and die with
fatal: unable to access '/root/.config/git/config': Permission denied
Any patch to fix this would have one of three problems:
1. We annoy sysadmins who need to take an extra step to handle HOME
when dropping privileges (the current behavior, or any other
proposal that they have to opt into).
2. We annoy sysadmins who want to set HOME when dropping privileges,
either by making what they want to do impossible, or making them
set an extra variable or option to accomplish what used to work
(e.g., a patch to git-daemon to set HOME when --user is passed).
3. We loosen the check, so some cases which might be noteworthy are
not caught.
This patch is of type (3).
Treat user and xdg configuration that are inaccessible due to
permissions (EACCES) as though no user configuration was provided at
all.
An alternative method would be to check if $HOME is readable, but that
would not help in cases where the user who dropped privileges had a
globally readable HOME with only .config or .gitconfig being private.
This does not change the behavior when /etc/gitconfig or .git/config
is unreadable (since those are more serious configuration errors),
nor when ~/.gitconfig or ~/.config/git is unreadable due to problems
other than permissions.
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Improved-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-04-12 23:03:18 +02:00
|
|
|
if (user_config && !access_or_die(user_config, R_OK, ACCESS_EACCES_OK)) {
|
2012-06-22 11:03:23 +02:00
|
|
|
ret += git_config_from_file(fn, user_config, data);
|
|
|
|
found += 1;
|
Read configuration also from $HOME/.gitconfig
This patch is based on Pasky's, with three notable differences:
- I did not yet update the documentation
- I named it .gitconfig, not .gitrc
- git-repo-config does not barf when a unique key is overridden locally
The last means that if you have something like
[alias]
l = log --stat -M
in ~/.gitconfig, and
[alias]
l = log --stat -M next..
in $GIT_DIR/config, then
git-repo-config alias.l
returns only one value, namely the value from $GIT_DIR/config.
If you set the environment variable GIT_CONFIG, $HOME/.gitconfig is not
read, and neither $GIT_DIR/config, but $GIT_CONFIG instead.
If you set GIT_CONFIG_LOCAL instead, it is interpreted instead of
$GIT_DIR/config, but $HOME/.gitconfig is still read.
Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-06-20 01:48:03 +02:00
|
|
|
}
|
|
|
|
|
config: allow inaccessible configuration under $HOME
The changes v1.7.12.1~2^2~4 (config: warn on inaccessible files,
2012-08-21) and v1.8.1.1~22^2~2 (config: treat user and xdg config
permission problems as errors, 2012-10-13) were intended to prevent
important configuration (think "[transfer] fsckobjects") from being
ignored when the configuration is unintentionally unreadable (for
example with EIO on a flaky filesystem, or with ENOMEM due to a DoS
attack). Usually ~/.gitconfig and ~/.config/git are readable by the
current user, and if they aren't then it would be easy to fix those
permissions, so the damage from adding this check should have been
minimal.
Unfortunately the access() check often trips when git is being run as
a server. A daemon (such as inetd or git-daemon) starts as "root",
creates a listening socket, and then drops privileges, meaning that
when git commands are invoked they cannot access $HOME and die with
fatal: unable to access '/root/.config/git/config': Permission denied
Any patch to fix this would have one of three problems:
1. We annoy sysadmins who need to take an extra step to handle HOME
when dropping privileges (the current behavior, or any other
proposal that they have to opt into).
2. We annoy sysadmins who want to set HOME when dropping privileges,
either by making what they want to do impossible, or making them
set an extra variable or option to accomplish what used to work
(e.g., a patch to git-daemon to set HOME when --user is passed).
3. We loosen the check, so some cases which might be noteworthy are
not caught.
This patch is of type (3).
Treat user and xdg configuration that are inaccessible due to
permissions (EACCES) as though no user configuration was provided at
all.
An alternative method would be to check if $HOME is readable, but that
would not help in cases where the user who dropped privileges had a
globally readable HOME with only .config or .gitconfig being private.
This does not change the behavior when /etc/gitconfig or .git/config
is unreadable (since those are more serious configuration errors),
nor when ~/.gitconfig or ~/.config/git is unreadable due to problems
other than permissions.
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Improved-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-04-12 23:03:18 +02:00
|
|
|
if (repo_config && !access_or_die(repo_config, R_OK, 0)) {
|
2009-02-21 01:48:55 +01:00
|
|
|
ret += git_config_from_file(fn, repo_config, data);
|
|
|
|
found += 1;
|
|
|
|
}
|
2010-03-26 23:53:57 +01:00
|
|
|
|
2011-05-25 00:49:45 +02:00
|
|
|
switch (git_config_from_parameters(fn, data)) {
|
|
|
|
case -1: /* error */
|
2014-08-07 13:59:12 +02:00
|
|
|
die(_("unable to parse command-line config"));
|
2011-05-25 00:49:45 +02:00
|
|
|
break;
|
|
|
|
case 0: /* found nothing */
|
|
|
|
break;
|
|
|
|
default: /* found at least one item */
|
|
|
|
found++;
|
|
|
|
break;
|
|
|
|
}
|
2010-03-26 23:53:57 +01:00
|
|
|
|
2012-06-22 11:03:23 +02:00
|
|
|
free(xdg_config);
|
|
|
|
free(user_config);
|
2010-10-21 16:45:44 +02:00
|
|
|
return ret == 0 ? found : ret;
|
2005-11-26 01:03:56 +01:00
|
|
|
}
|
|
|
|
|
config: provide a version of git_config with more options
Callers may want to provide a specific version of a file in which to look
for config. Right now this can be done by setting the magic global
config_exclusive_filename variable. By providing a version of git_config
that takes a filename, we can take a step towards making this magic global
go away.
Furthermore, by providing a more "advanced" interface, we now have a a
natural place to add new options for callers like git-config, which care
about tweaking the specifics of config lookup, without disturbing the
large number of "simple" users (i.e., every other part of git).
The astute reader of this patch may notice that the logic for handling
config_exclusive_filename was taken out of git_config_early, but added
into git_config. This means that git_config_early will no longer respect
config_exclusive_filename. That's OK, because the only other caller of
git_config_early is check_repository_format_gently, but the only function
which sets config_exclusive_filename is cmd_config, which does not call
check_repository_format_gently (and if it did, it would have been a bug,
anyway, as we would be checking the repository format in the wrong file).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-16 09:05:56 +01:00
|
|
|
int git_config_with_options(config_fn_t fn, void *data,
|
2014-02-18 23:58:54 +01:00
|
|
|
struct git_config_source *config_source,
|
2013-07-12 00:46:47 +02:00
|
|
|
int respect_includes)
|
2010-11-26 16:32:33 +01:00
|
|
|
{
|
|
|
|
char *repo_config = NULL;
|
|
|
|
int ret;
|
config: add include directive
It can be useful to split your ~/.gitconfig across multiple
files. For example, you might have a "main" file which is
used on many machines, but a small set of per-machine
tweaks. Or you may want to make some of your config public
(e.g., clever aliases) while keeping other data back (e.g.,
your name or other identifying information). Or you may want
to include a number of config options in some subset of your
repos without copying and pasting (e.g., you want to
reference them from the .git/config of participating repos).
This patch introduces an include directive for config files.
It looks like:
[include]
path = /path/to/file
This is syntactically backwards-compatible with existing git
config parsers (i.e., they will see it as another config
entry and ignore it unless you are looking up include.path).
The implementation provides a "git_config_include" callback
which wraps regular config callbacks. Callers can pass it to
git_config_from_file, and it will transparently follow any
include directives, passing all of the discovered options to
the real callback.
Include directives are turned on automatically for "regular"
git config parsing. This includes calls to git_config, as
well as calls to the "git config" program that do not
specify a single file (e.g., using "-f", "--global", etc).
They are not turned on in other cases, including:
1. Parsing of other config-like files, like .gitmodules.
There isn't a real need, and I'd rather be conservative
and avoid unnecessary incompatibility or confusion.
2. Reading single files via "git config". This is for two
reasons:
a. backwards compatibility with scripts looking at
config-like files.
b. inspection of a specific file probably means you
care about just what's in that file, not a general
lookup for "do we have this value anywhere at
all". If that is not the case, the caller can
always specify "--includes".
3. Writing files via "git config"; we want to treat
include.* variables as literal items to be copied (or
modified), and not expand them. So "git config
--unset-all foo.bar" would operate _only_ on
.git/config, not any of its included files (just as it
also does not operate on ~/.gitconfig).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-06 10:54:04 +01:00
|
|
|
struct config_include_data inc = CONFIG_INCLUDE_INIT;
|
|
|
|
|
|
|
|
if (respect_includes) {
|
|
|
|
inc.fn = fn;
|
|
|
|
inc.data = data;
|
|
|
|
fn = git_config_include;
|
|
|
|
data = &inc;
|
|
|
|
}
|
2010-11-26 16:32:33 +01:00
|
|
|
|
config: provide a version of git_config with more options
Callers may want to provide a specific version of a file in which to look
for config. Right now this can be done by setting the magic global
config_exclusive_filename variable. By providing a version of git_config
that takes a filename, we can take a step towards making this magic global
go away.
Furthermore, by providing a more "advanced" interface, we now have a a
natural place to add new options for callers like git-config, which care
about tweaking the specifics of config lookup, without disturbing the
large number of "simple" users (i.e., every other part of git).
The astute reader of this patch may notice that the logic for handling
config_exclusive_filename was taken out of git_config_early, but added
into git_config. This means that git_config_early will no longer respect
config_exclusive_filename. That's OK, because the only other caller of
git_config_early is check_repository_format_gently, but the only function
which sets config_exclusive_filename is cmd_config, which does not call
check_repository_format_gently (and if it did, it would have been a bug,
anyway, as we would be checking the repository format in the wrong file).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-16 09:05:56 +01:00
|
|
|
/*
|
|
|
|
* If we have a specific filename, use it. Otherwise, follow the
|
|
|
|
* regular lookup sequence.
|
|
|
|
*/
|
2014-02-18 23:58:55 +01:00
|
|
|
if (config_source && config_source->use_stdin)
|
|
|
|
return git_config_from_stdin(fn, data);
|
|
|
|
else if (config_source && config_source->file)
|
2014-02-18 23:58:54 +01:00
|
|
|
return git_config_from_file(fn, config_source->file, data);
|
|
|
|
else if (config_source && config_source->blob)
|
|
|
|
return git_config_from_blob_ref(fn, config_source->blob, data);
|
config: provide a version of git_config with more options
Callers may want to provide a specific version of a file in which to look
for config. Right now this can be done by setting the magic global
config_exclusive_filename variable. By providing a version of git_config
that takes a filename, we can take a step towards making this magic global
go away.
Furthermore, by providing a more "advanced" interface, we now have a a
natural place to add new options for callers like git-config, which care
about tweaking the specifics of config lookup, without disturbing the
large number of "simple" users (i.e., every other part of git).
The astute reader of this patch may notice that the logic for handling
config_exclusive_filename was taken out of git_config_early, but added
into git_config. This means that git_config_early will no longer respect
config_exclusive_filename. That's OK, because the only other caller of
git_config_early is check_repository_format_gently, but the only function
which sets config_exclusive_filename is cmd_config, which does not call
check_repository_format_gently (and if it did, it would have been a bug,
anyway, as we would be checking the repository format in the wrong file).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-16 09:05:56 +01:00
|
|
|
|
2010-11-26 16:32:33 +01:00
|
|
|
repo_config = git_pathdup("config");
|
|
|
|
ret = git_config_early(fn, data, repo_config);
|
|
|
|
if (repo_config)
|
|
|
|
free(repo_config);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-08-07 13:59:17 +02:00
|
|
|
static void git_config_raw(config_fn_t fn, void *data)
|
config: provide a version of git_config with more options
Callers may want to provide a specific version of a file in which to look
for config. Right now this can be done by setting the magic global
config_exclusive_filename variable. By providing a version of git_config
that takes a filename, we can take a step towards making this magic global
go away.
Furthermore, by providing a more "advanced" interface, we now have a a
natural place to add new options for callers like git-config, which care
about tweaking the specifics of config lookup, without disturbing the
large number of "simple" users (i.e., every other part of git).
The astute reader of this patch may notice that the logic for handling
config_exclusive_filename was taken out of git_config_early, but added
into git_config. This means that git_config_early will no longer respect
config_exclusive_filename. That's OK, because the only other caller of
git_config_early is check_repository_format_gently, but the only function
which sets config_exclusive_filename is cmd_config, which does not call
check_repository_format_gently (and if it did, it would have been a bug,
anyway, as we would be checking the repository format in the wrong file).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-16 09:05:56 +01:00
|
|
|
{
|
2014-08-07 13:59:15 +02:00
|
|
|
if (git_config_with_options(fn, data, NULL, 1) < 0)
|
|
|
|
/*
|
|
|
|
* git_config_with_options() normally returns only
|
|
|
|
* positive values, as most errors are fatal, and
|
|
|
|
* non-fatal potential errors are guarded by "if"
|
|
|
|
* statements that are entered only when no error is
|
|
|
|
* possible.
|
|
|
|
*
|
|
|
|
* If we ever encounter a non-fatal error, it means
|
|
|
|
* something went really wrong and we should stop
|
|
|
|
* immediately.
|
|
|
|
*/
|
|
|
|
die(_("unknown error occured while reading the configuration files"));
|
config: provide a version of git_config with more options
Callers may want to provide a specific version of a file in which to look
for config. Right now this can be done by setting the magic global
config_exclusive_filename variable. By providing a version of git_config
that takes a filename, we can take a step towards making this magic global
go away.
Furthermore, by providing a more "advanced" interface, we now have a a
natural place to add new options for callers like git-config, which care
about tweaking the specifics of config lookup, without disturbing the
large number of "simple" users (i.e., every other part of git).
The astute reader of this patch may notice that the logic for handling
config_exclusive_filename was taken out of git_config_early, but added
into git_config. This means that git_config_early will no longer respect
config_exclusive_filename. That's OK, because the only other caller of
git_config_early is check_repository_format_gently, but the only function
which sets config_exclusive_filename is cmd_config, which does not call
check_repository_format_gently (and if it did, it would have been a bug,
anyway, as we would be checking the repository format in the wrong file).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-16 09:05:56 +01:00
|
|
|
}
|
|
|
|
|
2014-08-07 13:59:17 +02:00
|
|
|
static void configset_iter(struct config_set *cs, config_fn_t fn, void *data)
|
config: provide a version of git_config with more options
Callers may want to provide a specific version of a file in which to look
for config. Right now this can be done by setting the magic global
config_exclusive_filename variable. By providing a version of git_config
that takes a filename, we can take a step towards making this magic global
go away.
Furthermore, by providing a more "advanced" interface, we now have a a
natural place to add new options for callers like git-config, which care
about tweaking the specifics of config lookup, without disturbing the
large number of "simple" users (i.e., every other part of git).
The astute reader of this patch may notice that the logic for handling
config_exclusive_filename was taken out of git_config_early, but added
into git_config. This means that git_config_early will no longer respect
config_exclusive_filename. That's OK, because the only other caller of
git_config_early is check_repository_format_gently, but the only function
which sets config_exclusive_filename is cmd_config, which does not call
check_repository_format_gently (and if it did, it would have been a bug,
anyway, as we would be checking the repository format in the wrong file).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-16 09:05:56 +01:00
|
|
|
{
|
2014-08-07 13:59:17 +02:00
|
|
|
int i, value_index;
|
|
|
|
struct string_list *values;
|
|
|
|
struct config_set_element *entry;
|
|
|
|
struct configset_list *list = &cs->list;
|
|
|
|
struct key_value_info *kv_info;
|
|
|
|
|
|
|
|
for (i = 0; i < list->nr; i++) {
|
|
|
|
entry = list->items[i].e;
|
|
|
|
value_index = list->items[i].value_index;
|
|
|
|
values = &entry->value_list;
|
|
|
|
if (fn(entry->key, values->items[value_index].string, data) < 0) {
|
|
|
|
kv_info = values->items[value_index].util;
|
|
|
|
git_die_config_linenr(entry->key, kv_info->filename, kv_info->linenr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void git_config_check_init(void);
|
|
|
|
|
|
|
|
void git_config(config_fn_t fn, void *data)
|
|
|
|
{
|
|
|
|
git_config_check_init();
|
|
|
|
configset_iter(&the_config_set, fn, data);
|
config: provide a version of git_config with more options
Callers may want to provide a specific version of a file in which to look
for config. Right now this can be done by setting the magic global
config_exclusive_filename variable. By providing a version of git_config
that takes a filename, we can take a step towards making this magic global
go away.
Furthermore, by providing a more "advanced" interface, we now have a a
natural place to add new options for callers like git-config, which care
about tweaking the specifics of config lookup, without disturbing the
large number of "simple" users (i.e., every other part of git).
The astute reader of this patch may notice that the logic for handling
config_exclusive_filename was taken out of git_config_early, but added
into git_config. This means that git_config_early will no longer respect
config_exclusive_filename. That's OK, because the only other caller of
git_config_early is check_repository_format_gently, but the only function
which sets config_exclusive_filename is cmd_config, which does not call
check_repository_format_gently (and if it did, it would have been a bug,
anyway, as we would be checking the repository format in the wrong file).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-16 09:05:56 +01:00
|
|
|
}
|
|
|
|
|
2014-07-28 12:10:38 +02:00
|
|
|
static struct config_set_element *configset_find_element(struct config_set *cs, const char *key)
|
|
|
|
{
|
|
|
|
struct config_set_element k;
|
|
|
|
struct config_set_element *found_entry;
|
|
|
|
char *normalized_key;
|
|
|
|
int ret;
|
|
|
|
/*
|
|
|
|
* `key` may come from the user, so normalize it before using it
|
|
|
|
* for querying entries from the hashmap.
|
|
|
|
*/
|
|
|
|
ret = git_config_parse_key(key, &normalized_key, NULL);
|
|
|
|
|
|
|
|
if (ret)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
hashmap_entry_init(&k, strhash(normalized_key));
|
|
|
|
k.key = normalized_key;
|
|
|
|
found_entry = hashmap_get(&cs->config_hash, &k, NULL);
|
|
|
|
free(normalized_key);
|
|
|
|
return found_entry;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int configset_add_value(struct config_set *cs, const char *key, const char *value)
|
|
|
|
{
|
|
|
|
struct config_set_element *e;
|
2014-08-07 13:59:14 +02:00
|
|
|
struct string_list_item *si;
|
2014-08-07 13:59:17 +02:00
|
|
|
struct configset_list_item *l_item;
|
2014-08-07 13:59:14 +02:00
|
|
|
struct key_value_info *kv_info = xmalloc(sizeof(*kv_info));
|
|
|
|
|
2014-07-28 12:10:38 +02:00
|
|
|
e = configset_find_element(cs, key);
|
|
|
|
/*
|
|
|
|
* Since the keys are being fed by git_config*() callback mechanism, they
|
|
|
|
* are already normalized. So simply add them without any further munging.
|
|
|
|
*/
|
|
|
|
if (!e) {
|
|
|
|
e = xmalloc(sizeof(*e));
|
|
|
|
hashmap_entry_init(e, strhash(key));
|
|
|
|
e->key = xstrdup(key);
|
|
|
|
string_list_init(&e->value_list, 1);
|
|
|
|
hashmap_add(&cs->config_hash, e);
|
|
|
|
}
|
2015-01-13 02:59:09 +01:00
|
|
|
si = string_list_append_nodup(&e->value_list, xstrdup_or_null(value));
|
2014-08-07 13:59:17 +02:00
|
|
|
|
|
|
|
ALLOC_GROW(cs->list.items, cs->list.nr + 1, cs->list.alloc);
|
|
|
|
l_item = &cs->list.items[cs->list.nr++];
|
|
|
|
l_item->e = e;
|
|
|
|
l_item->value_index = e->value_list.nr - 1;
|
|
|
|
|
2014-08-07 13:59:14 +02:00
|
|
|
if (cf) {
|
|
|
|
kv_info->filename = strintern(cf->name);
|
|
|
|
kv_info->linenr = cf->linenr;
|
|
|
|
} else {
|
|
|
|
/* for values read from `git_config_from_parameters()` */
|
|
|
|
kv_info->filename = NULL;
|
|
|
|
kv_info->linenr = -1;
|
|
|
|
}
|
|
|
|
si->util = kv_info;
|
2014-07-28 12:10:38 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int config_set_element_cmp(const struct config_set_element *e1,
|
|
|
|
const struct config_set_element *e2, const void *unused)
|
|
|
|
{
|
|
|
|
return strcmp(e1->key, e2->key);
|
|
|
|
}
|
|
|
|
|
|
|
|
void git_configset_init(struct config_set *cs)
|
|
|
|
{
|
|
|
|
hashmap_init(&cs->config_hash, (hashmap_cmp_fn)config_set_element_cmp, 0);
|
|
|
|
cs->hash_initialized = 1;
|
2014-08-07 13:59:17 +02:00
|
|
|
cs->list.nr = 0;
|
|
|
|
cs->list.alloc = 0;
|
|
|
|
cs->list.items = NULL;
|
2014-07-28 12:10:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void git_configset_clear(struct config_set *cs)
|
|
|
|
{
|
|
|
|
struct config_set_element *entry;
|
|
|
|
struct hashmap_iter iter;
|
|
|
|
if (!cs->hash_initialized)
|
|
|
|
return;
|
|
|
|
|
|
|
|
hashmap_iter_init(&cs->config_hash, &iter);
|
|
|
|
while ((entry = hashmap_iter_next(&iter))) {
|
|
|
|
free(entry->key);
|
2014-08-07 13:59:14 +02:00
|
|
|
string_list_clear(&entry->value_list, 1);
|
2014-07-28 12:10:38 +02:00
|
|
|
}
|
|
|
|
hashmap_free(&cs->config_hash, 1);
|
|
|
|
cs->hash_initialized = 0;
|
2014-08-07 13:59:17 +02:00
|
|
|
free(cs->list.items);
|
|
|
|
cs->list.nr = 0;
|
|
|
|
cs->list.alloc = 0;
|
|
|
|
cs->list.items = NULL;
|
2014-07-28 12:10:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static int config_set_callback(const char *key, const char *value, void *cb)
|
|
|
|
{
|
|
|
|
struct config_set *cs = cb;
|
|
|
|
configset_add_value(cs, key, value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int git_configset_add_file(struct config_set *cs, const char *filename)
|
|
|
|
{
|
|
|
|
return git_config_from_file(config_set_callback, filename, cs);
|
|
|
|
}
|
|
|
|
|
|
|
|
int git_configset_get_value(struct config_set *cs, const char *key, const char **value)
|
|
|
|
{
|
|
|
|
const struct string_list *values = NULL;
|
|
|
|
/*
|
|
|
|
* Follows "last one wins" semantic, i.e., if there are multiple matches for the
|
|
|
|
* queried key in the files of the configset, the value returned will be the last
|
|
|
|
* value in the value list for that key.
|
|
|
|
*/
|
|
|
|
values = git_configset_get_value_multi(cs, key);
|
|
|
|
|
|
|
|
if (!values)
|
|
|
|
return 1;
|
|
|
|
assert(values->nr > 0);
|
|
|
|
*value = values->items[values->nr - 1].string;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
const struct string_list *git_configset_get_value_multi(struct config_set *cs, const char *key)
|
|
|
|
{
|
|
|
|
struct config_set_element *e = configset_find_element(cs, key);
|
|
|
|
return e ? &e->value_list : NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
int git_configset_get_string_const(struct config_set *cs, const char *key, const char **dest)
|
|
|
|
{
|
|
|
|
const char *value;
|
|
|
|
if (!git_configset_get_value(cs, key, &value))
|
|
|
|
return git_config_string(dest, key, value);
|
|
|
|
else
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int git_configset_get_string(struct config_set *cs, const char *key, char **dest)
|
|
|
|
{
|
|
|
|
return git_configset_get_string_const(cs, key, (const char **)dest);
|
|
|
|
}
|
|
|
|
|
|
|
|
int git_configset_get_int(struct config_set *cs, const char *key, int *dest)
|
|
|
|
{
|
|
|
|
const char *value;
|
|
|
|
if (!git_configset_get_value(cs, key, &value)) {
|
|
|
|
*dest = git_config_int(key, value);
|
|
|
|
return 0;
|
|
|
|
} else
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int git_configset_get_ulong(struct config_set *cs, const char *key, unsigned long *dest)
|
|
|
|
{
|
|
|
|
const char *value;
|
|
|
|
if (!git_configset_get_value(cs, key, &value)) {
|
|
|
|
*dest = git_config_ulong(key, value);
|
|
|
|
return 0;
|
|
|
|
} else
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int git_configset_get_bool(struct config_set *cs, const char *key, int *dest)
|
|
|
|
{
|
|
|
|
const char *value;
|
|
|
|
if (!git_configset_get_value(cs, key, &value)) {
|
|
|
|
*dest = git_config_bool(key, value);
|
|
|
|
return 0;
|
|
|
|
} else
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int git_configset_get_bool_or_int(struct config_set *cs, const char *key,
|
|
|
|
int *is_bool, int *dest)
|
|
|
|
{
|
|
|
|
const char *value;
|
|
|
|
if (!git_configset_get_value(cs, key, &value)) {
|
|
|
|
*dest = git_config_bool_or_int(key, value, is_bool);
|
|
|
|
return 0;
|
|
|
|
} else
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int git_configset_get_maybe_bool(struct config_set *cs, const char *key, int *dest)
|
|
|
|
{
|
|
|
|
const char *value;
|
|
|
|
if (!git_configset_get_value(cs, key, &value)) {
|
|
|
|
*dest = git_config_maybe_bool(key, value);
|
|
|
|
if (*dest == -1)
|
|
|
|
return -1;
|
|
|
|
return 0;
|
|
|
|
} else
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int git_configset_get_pathname(struct config_set *cs, const char *key, const char **dest)
|
|
|
|
{
|
|
|
|
const char *value;
|
|
|
|
if (!git_configset_get_value(cs, key, &value))
|
|
|
|
return git_config_pathname(dest, key, value);
|
|
|
|
else
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void git_config_check_init(void)
|
|
|
|
{
|
|
|
|
if (the_config_set.hash_initialized)
|
|
|
|
return;
|
|
|
|
git_configset_init(&the_config_set);
|
2014-08-07 13:59:17 +02:00
|
|
|
git_config_raw(config_set_callback, &the_config_set);
|
2014-07-28 12:10:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void git_config_clear(void)
|
|
|
|
{
|
|
|
|
if (!the_config_set.hash_initialized)
|
|
|
|
return;
|
|
|
|
git_configset_clear(&the_config_set);
|
|
|
|
}
|
|
|
|
|
|
|
|
int git_config_get_value(const char *key, const char **value)
|
|
|
|
{
|
|
|
|
git_config_check_init();
|
|
|
|
return git_configset_get_value(&the_config_set, key, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
const struct string_list *git_config_get_value_multi(const char *key)
|
|
|
|
{
|
|
|
|
git_config_check_init();
|
|
|
|
return git_configset_get_value_multi(&the_config_set, key);
|
|
|
|
}
|
|
|
|
|
|
|
|
int git_config_get_string_const(const char *key, const char **dest)
|
|
|
|
{
|
2014-08-07 13:59:16 +02:00
|
|
|
int ret;
|
2014-07-28 12:10:38 +02:00
|
|
|
git_config_check_init();
|
2014-08-07 13:59:16 +02:00
|
|
|
ret = git_configset_get_string_const(&the_config_set, key, dest);
|
|
|
|
if (ret < 0)
|
|
|
|
git_die_config(key, NULL);
|
|
|
|
return ret;
|
2014-07-28 12:10:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int git_config_get_string(const char *key, char **dest)
|
|
|
|
{
|
|
|
|
git_config_check_init();
|
|
|
|
return git_config_get_string_const(key, (const char **)dest);
|
|
|
|
}
|
|
|
|
|
|
|
|
int git_config_get_int(const char *key, int *dest)
|
|
|
|
{
|
|
|
|
git_config_check_init();
|
|
|
|
return git_configset_get_int(&the_config_set, key, dest);
|
|
|
|
}
|
|
|
|
|
|
|
|
int git_config_get_ulong(const char *key, unsigned long *dest)
|
|
|
|
{
|
|
|
|
git_config_check_init();
|
|
|
|
return git_configset_get_ulong(&the_config_set, key, dest);
|
|
|
|
}
|
|
|
|
|
|
|
|
int git_config_get_bool(const char *key, int *dest)
|
|
|
|
{
|
|
|
|
git_config_check_init();
|
|
|
|
return git_configset_get_bool(&the_config_set, key, dest);
|
|
|
|
}
|
|
|
|
|
|
|
|
int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest)
|
|
|
|
{
|
|
|
|
git_config_check_init();
|
|
|
|
return git_configset_get_bool_or_int(&the_config_set, key, is_bool, dest);
|
|
|
|
}
|
|
|
|
|
|
|
|
int git_config_get_maybe_bool(const char *key, int *dest)
|
|
|
|
{
|
|
|
|
git_config_check_init();
|
|
|
|
return git_configset_get_maybe_bool(&the_config_set, key, dest);
|
|
|
|
}
|
|
|
|
|
|
|
|
int git_config_get_pathname(const char *key, const char **dest)
|
|
|
|
{
|
2014-08-07 13:59:16 +02:00
|
|
|
int ret;
|
2014-07-28 12:10:38 +02:00
|
|
|
git_config_check_init();
|
2014-08-07 13:59:16 +02:00
|
|
|
ret = git_configset_get_pathname(&the_config_set, key, dest);
|
|
|
|
if (ret < 0)
|
|
|
|
git_die_config(key, NULL);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
NORETURN
|
|
|
|
void git_die_config_linenr(const char *key, const char *filename, int linenr)
|
|
|
|
{
|
|
|
|
if (!filename)
|
|
|
|
die(_("unable to parse '%s' from command-line config"), key);
|
|
|
|
else
|
|
|
|
die(_("bad config variable '%s' in file '%s' at line %d"),
|
|
|
|
key, filename, linenr);
|
|
|
|
}
|
|
|
|
|
|
|
|
NORETURN __attribute__((format(printf, 2, 3)))
|
|
|
|
void git_die_config(const char *key, const char *err, ...)
|
|
|
|
{
|
|
|
|
const struct string_list *values;
|
|
|
|
struct key_value_info *kv_info;
|
|
|
|
|
|
|
|
if (err) {
|
|
|
|
va_list params;
|
|
|
|
va_start(params, err);
|
|
|
|
vreportf("error: ", err, params);
|
|
|
|
va_end(params);
|
|
|
|
}
|
|
|
|
values = git_config_get_value_multi(key);
|
|
|
|
kv_info = values->items[values->nr - 1].util;
|
|
|
|
git_die_config_linenr(key, kv_info->filename, kv_info->linenr);
|
2014-07-28 12:10:38 +02:00
|
|
|
}
|
|
|
|
|
2005-11-17 22:32:36 +01:00
|
|
|
/*
|
|
|
|
* Find all the stuff for git_config_set() below.
|
|
|
|
*/
|
2005-11-20 06:52:22 +01:00
|
|
|
|
2005-11-17 22:32:36 +01:00
|
|
|
static struct {
|
|
|
|
int baselen;
|
2009-05-01 11:06:36 +02:00
|
|
|
char *key;
|
2005-11-20 13:24:18 +01:00
|
|
|
int do_not_match;
|
2009-05-01 11:06:36 +02:00
|
|
|
regex_t *value_regex;
|
2005-11-20 06:52:22 +01:00
|
|
|
int multi_replace;
|
2013-11-13 11:19:00 +01:00
|
|
|
size_t *offset;
|
|
|
|
unsigned int offset_alloc;
|
2005-11-17 22:32:36 +01:00
|
|
|
enum { START, SECTION_SEEN, SECTION_END_SEEN, KEY_SEEN } state;
|
|
|
|
int seen;
|
|
|
|
} store;
|
|
|
|
|
2009-05-01 11:06:36 +02:00
|
|
|
static int matches(const char *key, const char *value)
|
2005-11-20 13:24:18 +01:00
|
|
|
{
|
2014-08-19 08:20:00 +02:00
|
|
|
if (strcmp(key, store.key))
|
|
|
|
return 0; /* not ours */
|
|
|
|
if (!store.value_regex)
|
|
|
|
return 1; /* always matches */
|
|
|
|
if (store.value_regex == CONFIG_REGEX_NONE)
|
|
|
|
return 0; /* never matches */
|
|
|
|
|
|
|
|
return store.do_not_match ^
|
|
|
|
(value && !regexec(store.value_regex, value, 0, NULL, 0));
|
2005-11-20 13:24:18 +01:00
|
|
|
}
|
|
|
|
|
2009-05-01 11:06:36 +02:00
|
|
|
static int store_aux(const char *key, const char *value, void *cb)
|
2005-11-17 22:32:36 +01:00
|
|
|
{
|
2007-05-13 06:49:33 +02:00
|
|
|
const char *ep;
|
|
|
|
size_t section_len;
|
|
|
|
|
2005-11-17 22:32:36 +01:00
|
|
|
switch (store.state) {
|
|
|
|
case KEY_SEEN:
|
2005-11-20 13:24:18 +01:00
|
|
|
if (matches(key, value)) {
|
2005-11-20 06:52:22 +01:00
|
|
|
if (store.seen == 1 && store.multi_replace == 0) {
|
2014-08-07 13:59:12 +02:00
|
|
|
warning(_("%s has multiple values"), key);
|
2005-11-17 22:32:36 +01:00
|
|
|
}
|
2005-11-20 06:52:22 +01:00
|
|
|
|
2013-11-13 11:19:00 +01:00
|
|
|
ALLOC_GROW(store.offset, store.seen + 1,
|
|
|
|
store.offset_alloc);
|
|
|
|
|
2013-08-26 23:57:18 +02:00
|
|
|
store.offset[store.seen] = cf->do_ftell(cf);
|
2005-11-17 22:32:36 +01:00
|
|
|
store.seen++;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SECTION_SEEN:
|
2007-05-13 06:49:33 +02:00
|
|
|
/*
|
|
|
|
* What we are looking for is in store.key (both
|
|
|
|
* section and var), and its section part is baselen
|
|
|
|
* long. We found key (again, both section and var).
|
|
|
|
* We would want to know if this key is in the same
|
|
|
|
* section as what we are looking for. We already
|
|
|
|
* know we are in the same section as what should
|
|
|
|
* hold store.key.
|
|
|
|
*/
|
|
|
|
ep = strrchr(key, '.');
|
|
|
|
section_len = ep - key;
|
|
|
|
|
|
|
|
if ((section_len != store.baselen) ||
|
|
|
|
memcmp(key, store.key, section_len+1)) {
|
2005-11-17 22:32:36 +01:00
|
|
|
store.state = SECTION_END_SEEN;
|
|
|
|
break;
|
2007-05-13 06:49:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Do not increment matches: this is no match, but we
|
|
|
|
* just made sure we are in the desired section.
|
|
|
|
*/
|
2013-11-13 11:19:00 +01:00
|
|
|
ALLOC_GROW(store.offset, store.seen + 1,
|
|
|
|
store.offset_alloc);
|
2013-08-26 23:57:18 +02:00
|
|
|
store.offset[store.seen] = cf->do_ftell(cf);
|
2005-11-17 22:32:36 +01:00
|
|
|
/* fallthru */
|
|
|
|
case SECTION_END_SEEN:
|
|
|
|
case START:
|
2005-11-20 13:24:18 +01:00
|
|
|
if (matches(key, value)) {
|
2013-11-13 11:19:00 +01:00
|
|
|
ALLOC_GROW(store.offset, store.seen + 1,
|
|
|
|
store.offset_alloc);
|
2013-08-26 23:57:18 +02:00
|
|
|
store.offset[store.seen] = cf->do_ftell(cf);
|
2005-11-17 22:32:36 +01:00
|
|
|
store.state = KEY_SEEN;
|
|
|
|
store.seen++;
|
2006-05-09 21:24:02 +02:00
|
|
|
} else {
|
|
|
|
if (strrchr(key, '.') - key == store.baselen &&
|
2006-05-06 20:14:02 +02:00
|
|
|
!strncmp(key, store.key, store.baselen)) {
|
2006-05-05 15:49:15 +02:00
|
|
|
store.state = SECTION_SEEN;
|
2013-11-13 11:19:00 +01:00
|
|
|
ALLOC_GROW(store.offset,
|
|
|
|
store.seen + 1,
|
|
|
|
store.offset_alloc);
|
2013-08-26 23:57:18 +02:00
|
|
|
store.offset[store.seen] = cf->do_ftell(cf);
|
2006-05-09 21:24:02 +02:00
|
|
|
}
|
2006-05-06 20:14:02 +02:00
|
|
|
}
|
2005-11-17 22:32:36 +01:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-05-12 23:41:04 +02:00
|
|
|
static int write_error(const char *filename)
|
2007-01-08 16:58:38 +01:00
|
|
|
{
|
2008-05-12 23:41:04 +02:00
|
|
|
error("failed to write new configuration file %s", filename);
|
2007-01-08 16:58:38 +01:00
|
|
|
|
|
|
|
/* Same error code as "failed to rename". */
|
|
|
|
return 4;
|
|
|
|
}
|
|
|
|
|
2009-05-01 11:06:36 +02:00
|
|
|
static int store_write_section(int fd, const char *key)
|
2005-11-17 22:32:36 +01:00
|
|
|
{
|
2007-12-14 21:59:58 +01:00
|
|
|
const char *dot;
|
|
|
|
int i, success;
|
2008-10-09 21:12:12 +02:00
|
|
|
struct strbuf sb = STRBUF_INIT;
|
2006-05-09 21:24:02 +02:00
|
|
|
|
2007-12-14 21:59:58 +01:00
|
|
|
dot = memchr(key, '.', store.baselen);
|
2006-05-09 21:24:02 +02:00
|
|
|
if (dot) {
|
2007-12-14 21:59:58 +01:00
|
|
|
strbuf_addf(&sb, "[%.*s \"", (int)(dot - key), key);
|
|
|
|
for (i = dot - key + 1; i < store.baselen; i++) {
|
2008-05-04 07:37:52 +02:00
|
|
|
if (key[i] == '"' || key[i] == '\\')
|
2007-12-14 21:59:58 +01:00
|
|
|
strbuf_addch(&sb, '\\');
|
|
|
|
strbuf_addch(&sb, key[i]);
|
2006-05-09 21:24:02 +02:00
|
|
|
}
|
2007-12-14 21:59:58 +01:00
|
|
|
strbuf_addstr(&sb, "\"]\n");
|
|
|
|
} else {
|
|
|
|
strbuf_addf(&sb, "[%.*s]\n", store.baselen, key);
|
2006-05-09 21:24:02 +02:00
|
|
|
}
|
|
|
|
|
2007-12-14 21:59:58 +01:00
|
|
|
success = write_in_full(fd, sb.buf, sb.len) == sb.len;
|
|
|
|
strbuf_release(&sb);
|
2007-01-08 16:58:38 +01:00
|
|
|
|
2007-12-14 21:59:58 +01:00
|
|
|
return success;
|
2005-11-17 22:32:36 +01:00
|
|
|
}
|
|
|
|
|
2009-05-01 11:06:36 +02:00
|
|
|
static int store_write_pair(int fd, const char *key, const char *value)
|
2005-11-17 22:32:36 +01:00
|
|
|
{
|
2007-12-14 21:59:58 +01:00
|
|
|
int i, success;
|
|
|
|
int length = strlen(key + store.baselen + 1);
|
|
|
|
const char *quote = "";
|
2008-10-09 21:12:12 +02:00
|
|
|
struct strbuf sb = STRBUF_INIT;
|
2007-01-09 06:27:41 +01:00
|
|
|
|
2007-12-08 16:48:05 +01:00
|
|
|
/*
|
|
|
|
* Check to see if the value needs to be surrounded with a dq pair.
|
|
|
|
* Note that problematic characters are always backslash-quoted; this
|
|
|
|
* check is about not losing leading or trailing SP and strings that
|
|
|
|
* follow beginning-of-comment characters (i.e. ';' and '#') by the
|
|
|
|
* configuration parser.
|
|
|
|
*/
|
2007-01-09 06:27:41 +01:00
|
|
|
if (value[0] == ' ')
|
2007-12-14 21:59:58 +01:00
|
|
|
quote = "\"";
|
2007-01-09 06:27:41 +01:00
|
|
|
for (i = 0; value[i]; i++)
|
|
|
|
if (value[i] == ';' || value[i] == '#')
|
2007-12-14 21:59:58 +01:00
|
|
|
quote = "\"";
|
|
|
|
if (i && value[i - 1] == ' ')
|
|
|
|
quote = "\"";
|
|
|
|
|
|
|
|
strbuf_addf(&sb, "\t%.*s = %s",
|
|
|
|
length, key + store.baselen + 1, quote);
|
2005-11-17 22:32:36 +01:00
|
|
|
|
|
|
|
for (i = 0; value[i]; i++)
|
|
|
|
switch (value[i]) {
|
2007-01-08 16:58:38 +01:00
|
|
|
case '\n':
|
2007-12-14 21:59:58 +01:00
|
|
|
strbuf_addstr(&sb, "\\n");
|
2007-01-08 16:58:38 +01:00
|
|
|
break;
|
|
|
|
case '\t':
|
2007-12-14 21:59:58 +01:00
|
|
|
strbuf_addstr(&sb, "\\t");
|
2007-01-08 16:58:38 +01:00
|
|
|
break;
|
|
|
|
case '"':
|
|
|
|
case '\\':
|
2007-12-14 21:59:58 +01:00
|
|
|
strbuf_addch(&sb, '\\');
|
2007-01-08 16:58:38 +01:00
|
|
|
default:
|
2007-12-14 21:59:58 +01:00
|
|
|
strbuf_addch(&sb, value[i]);
|
2007-01-08 16:58:38 +01:00
|
|
|
break;
|
|
|
|
}
|
2007-12-14 21:59:58 +01:00
|
|
|
strbuf_addf(&sb, "%s\n", quote);
|
|
|
|
|
|
|
|
success = write_in_full(fd, sb.buf, sb.len) == sb.len;
|
|
|
|
strbuf_release(&sb);
|
|
|
|
|
|
|
|
return success;
|
2005-11-17 22:32:36 +01:00
|
|
|
}
|
|
|
|
|
2009-05-01 11:06:36 +02:00
|
|
|
static ssize_t find_beginning_of_line(const char *contents, size_t size,
|
|
|
|
size_t offset_, int *found_bracket)
|
2005-11-20 06:52:22 +01:00
|
|
|
{
|
2007-03-07 02:44:37 +01:00
|
|
|
size_t equal_offset = size, bracket_offset = size;
|
|
|
|
ssize_t offset;
|
2005-11-20 06:52:22 +01:00
|
|
|
|
2008-02-11 01:23:03 +01:00
|
|
|
contline:
|
2007-06-07 09:04:01 +02:00
|
|
|
for (offset = offset_-2; offset > 0
|
2005-11-20 06:52:22 +01:00
|
|
|
&& contents[offset] != '\n'; offset--)
|
|
|
|
switch (contents[offset]) {
|
|
|
|
case '=': equal_offset = offset; break;
|
|
|
|
case ']': bracket_offset = offset; break;
|
|
|
|
}
|
2008-02-11 01:23:03 +01:00
|
|
|
if (offset > 0 && contents[offset-1] == '\\') {
|
|
|
|
offset_ = offset;
|
|
|
|
goto contline;
|
|
|
|
}
|
2005-11-20 06:52:22 +01:00
|
|
|
if (bracket_offset < equal_offset) {
|
|
|
|
*found_bracket = 1;
|
|
|
|
offset = bracket_offset+1;
|
|
|
|
} else
|
|
|
|
offset++;
|
|
|
|
|
|
|
|
return offset;
|
|
|
|
}
|
|
|
|
|
2011-08-04 12:39:00 +02:00
|
|
|
int git_config_set_in_file(const char *config_filename,
|
|
|
|
const char *key, const char *value)
|
|
|
|
{
|
|
|
|
return git_config_set_multivar_in_file(config_filename, key, value, NULL, 0);
|
|
|
|
}
|
|
|
|
|
2009-05-01 11:06:36 +02:00
|
|
|
int git_config_set(const char *key, const char *value)
|
2005-11-17 22:32:36 +01:00
|
|
|
{
|
2005-11-20 06:52:22 +01:00
|
|
|
return git_config_set_multivar(key, value, NULL, 0);
|
2005-11-17 22:32:36 +01:00
|
|
|
}
|
|
|
|
|
2011-01-30 20:40:41 +01:00
|
|
|
/*
|
|
|
|
* Auxiliary function to sanity-check and split the key into the section
|
|
|
|
* identifier and variable name.
|
|
|
|
*
|
|
|
|
* Returns 0 on success, -1 when there is an invalid character in the key and
|
|
|
|
* -2 if there is no section name in the key.
|
|
|
|
*
|
|
|
|
* store_key - pointer to char* which will hold a copy of the key with
|
|
|
|
* lowercase section and variable name
|
|
|
|
* baselen - pointer to int which will hold the length of the
|
|
|
|
* section + subsection part, can be NULL
|
|
|
|
*/
|
|
|
|
int git_config_parse_key(const char *key, char **store_key, int *baselen_)
|
|
|
|
{
|
|
|
|
int i, dot, baselen;
|
|
|
|
const char *last_dot = strrchr(key, '.');
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Since "key" actually contains the section name and the real
|
|
|
|
* key name separated by a dot, we have to know where the dot is.
|
|
|
|
*/
|
|
|
|
|
2011-02-01 08:13:47 +01:00
|
|
|
if (last_dot == NULL || last_dot == key) {
|
2011-01-30 20:40:41 +01:00
|
|
|
error("key does not contain a section: %s", key);
|
2011-05-17 17:38:52 +02:00
|
|
|
return -CONFIG_NO_SECTION_OR_NAME;
|
2011-01-30 20:40:41 +01:00
|
|
|
}
|
|
|
|
|
2011-02-01 08:13:47 +01:00
|
|
|
if (!last_dot[1]) {
|
|
|
|
error("key does not contain variable name: %s", key);
|
2011-05-17 17:38:52 +02:00
|
|
|
return -CONFIG_NO_SECTION_OR_NAME;
|
2011-02-01 08:13:47 +01:00
|
|
|
}
|
|
|
|
|
2011-01-30 20:40:41 +01:00
|
|
|
baselen = last_dot - key;
|
|
|
|
if (baselen_)
|
|
|
|
*baselen_ = baselen;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Validate the key and while at it, lower case it for matching.
|
|
|
|
*/
|
|
|
|
*store_key = xmalloc(strlen(key) + 1);
|
|
|
|
|
|
|
|
dot = 0;
|
|
|
|
for (i = 0; key[i]; i++) {
|
|
|
|
unsigned char c = key[i];
|
|
|
|
if (c == '.')
|
|
|
|
dot = 1;
|
|
|
|
/* Leave the extended basename untouched.. */
|
|
|
|
if (!dot || i > baselen) {
|
|
|
|
if (!iskeychar(c) ||
|
|
|
|
(i == baselen + 1 && !isalpha(c))) {
|
|
|
|
error("invalid key: %s", key);
|
|
|
|
goto out_free_ret_1;
|
|
|
|
}
|
|
|
|
c = tolower(c);
|
|
|
|
} else if (c == '\n') {
|
|
|
|
error("invalid key (newline): %s", key);
|
|
|
|
goto out_free_ret_1;
|
|
|
|
}
|
|
|
|
(*store_key)[i] = c;
|
|
|
|
}
|
|
|
|
(*store_key)[i] = 0;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
out_free_ret_1:
|
|
|
|
free(*store_key);
|
2012-10-23 21:40:06 +02:00
|
|
|
*store_key = NULL;
|
2011-05-17 17:38:52 +02:00
|
|
|
return -CONFIG_INVALID_KEY;
|
2011-01-30 20:40:41 +01:00
|
|
|
}
|
|
|
|
|
2005-11-17 22:32:36 +01:00
|
|
|
/*
|
|
|
|
* If value==NULL, unset in (remove from) config,
|
|
|
|
* if value_regex!=NULL, disregard key/value pairs where value does not match.
|
2014-08-19 08:20:00 +02:00
|
|
|
* if value_regex==CONFIG_REGEX_NONE, do not match any existing values
|
|
|
|
* (only add a new one)
|
2005-11-20 06:52:22 +01:00
|
|
|
* if multi_replace==0, nothing, or only one matching key/value is replaced,
|
|
|
|
* else all matching key/values (regardless how many) are removed,
|
|
|
|
* before the new pair is written.
|
2005-11-17 22:32:36 +01:00
|
|
|
*
|
|
|
|
* Returns 0 on success.
|
|
|
|
*
|
|
|
|
* This function does this:
|
|
|
|
*
|
|
|
|
* - it locks the config file by creating ".git/config.lock"
|
|
|
|
*
|
|
|
|
* - it then parses the config using store_aux() as validator to find
|
|
|
|
* the position on the key/value pair to replace. If it is to be unset,
|
|
|
|
* it must be found exactly once.
|
|
|
|
*
|
|
|
|
* - the config file is mmap()ed and the part before the match (if any) is
|
|
|
|
* written to the lock file, then the changed part and the rest.
|
|
|
|
*
|
|
|
|
* - the config file is removed and the lock file rename()d to it.
|
|
|
|
*
|
|
|
|
*/
|
2011-08-04 12:39:00 +02:00
|
|
|
int git_config_set_multivar_in_file(const char *config_filename,
|
|
|
|
const char *key, const char *value,
|
|
|
|
const char *value_regex, int multi_replace)
|
2005-11-17 22:32:36 +01:00
|
|
|
{
|
2006-05-08 06:27:30 +02:00
|
|
|
int fd = -1, in_fd;
|
2006-04-17 17:14:48 +02:00
|
|
|
int ret;
|
2007-07-26 18:55:28 +02:00
|
|
|
struct lock_file *lock = NULL;
|
2012-02-16 09:04:05 +01:00
|
|
|
char *filename_buf = NULL;
|
2005-11-20 06:52:22 +01:00
|
|
|
|
2011-01-30 20:40:41 +01:00
|
|
|
/* parse-key returns negative; flip the sign to feed exit(3) */
|
|
|
|
ret = 0 - git_config_parse_key(key, &store.key, &store.baselen);
|
|
|
|
if (ret)
|
2006-04-17 17:14:48 +02:00
|
|
|
goto out_free;
|
2005-11-20 21:22:19 +01:00
|
|
|
|
|
|
|
store.multi_replace = multi_replace;
|
2005-11-17 22:32:36 +01:00
|
|
|
|
2012-02-16 09:04:05 +01:00
|
|
|
if (!config_filename)
|
|
|
|
config_filename = filename_buf = git_pathdup("config");
|
2005-11-17 22:32:36 +01:00
|
|
|
|
|
|
|
/*
|
2007-07-26 18:55:28 +02:00
|
|
|
* The lock serves a purpose in addition to locking: the new
|
2005-11-17 22:32:36 +01:00
|
|
|
* contents of .git/config will be written into it.
|
|
|
|
*/
|
2014-05-26 17:33:46 +02:00
|
|
|
lock = xcalloc(1, sizeof(struct lock_file));
|
2007-07-26 18:55:28 +02:00
|
|
|
fd = hold_lock_file_for_update(lock, config_filename, 0);
|
|
|
|
if (fd < 0) {
|
2009-04-29 23:27:54 +02:00
|
|
|
error("could not lock config file %s: %s", config_filename, strerror(errno));
|
2005-11-17 22:32:36 +01:00
|
|
|
free(store.key);
|
2011-05-17 17:38:52 +02:00
|
|
|
ret = CONFIG_NO_LOCK;
|
2006-04-17 17:14:48 +02:00
|
|
|
goto out_free;
|
2005-11-17 22:32:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If .git/config does not exist yet, write a minimal version.
|
|
|
|
*/
|
2006-01-05 12:43:34 +01:00
|
|
|
in_fd = open(config_filename, O_RDONLY);
|
|
|
|
if ( in_fd < 0 ) {
|
2005-11-17 22:32:36 +01:00
|
|
|
free(store.key);
|
|
|
|
|
2006-01-05 12:43:34 +01:00
|
|
|
if ( ENOENT != errno ) {
|
|
|
|
error("opening %s: %s", config_filename,
|
|
|
|
strerror(errno));
|
2011-05-17 17:38:52 +02:00
|
|
|
ret = CONFIG_INVALID_FILE; /* same as "invalid config file" */
|
2006-04-17 17:14:48 +02:00
|
|
|
goto out_free;
|
2006-01-05 12:43:34 +01:00
|
|
|
}
|
2005-11-17 22:32:36 +01:00
|
|
|
/* if nothing to unset, error out */
|
|
|
|
if (value == NULL) {
|
2011-05-17 17:38:52 +02:00
|
|
|
ret = CONFIG_NOTHING_SET;
|
2006-04-17 17:14:48 +02:00
|
|
|
goto out_free;
|
2005-11-17 22:32:36 +01:00
|
|
|
}
|
|
|
|
|
2009-05-01 11:06:36 +02:00
|
|
|
store.key = (char *)key;
|
2007-01-08 16:58:38 +01:00
|
|
|
if (!store_write_section(fd, key) ||
|
2007-01-11 22:16:26 +01:00
|
|
|
!store_write_pair(fd, key, value))
|
|
|
|
goto write_err_out;
|
|
|
|
} else {
|
2006-01-05 12:43:34 +01:00
|
|
|
struct stat st;
|
2009-05-01 11:06:36 +02:00
|
|
|
char *contents;
|
2007-03-07 02:44:37 +01:00
|
|
|
size_t contents_sz, copy_begin, copy_end;
|
|
|
|
int i, new_line = 0;
|
2005-11-17 22:32:36 +01:00
|
|
|
|
|
|
|
if (value_regex == NULL)
|
|
|
|
store.value_regex = NULL;
|
2014-08-19 08:20:00 +02:00
|
|
|
else if (value_regex == CONFIG_REGEX_NONE)
|
|
|
|
store.value_regex = CONFIG_REGEX_NONE;
|
2005-11-17 22:32:36 +01:00
|
|
|
else {
|
2005-11-20 13:24:18 +01:00
|
|
|
if (value_regex[0] == '!') {
|
|
|
|
store.do_not_match = 1;
|
|
|
|
value_regex++;
|
|
|
|
} else
|
|
|
|
store.do_not_match = 0;
|
|
|
|
|
2006-09-01 00:32:39 +02:00
|
|
|
store.value_regex = (regex_t*)xmalloc(sizeof(regex_t));
|
2005-11-17 22:32:36 +01:00
|
|
|
if (regcomp(store.value_regex, value_regex,
|
|
|
|
REG_EXTENDED)) {
|
2008-05-12 23:41:04 +02:00
|
|
|
error("invalid pattern: %s", value_regex);
|
2005-11-17 22:32:36 +01:00
|
|
|
free(store.value_regex);
|
2011-05-17 17:38:52 +02:00
|
|
|
ret = CONFIG_INVALID_PATTERN;
|
2006-04-17 17:14:48 +02:00
|
|
|
goto out_free;
|
2005-11-17 22:32:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-13 11:19:00 +01:00
|
|
|
ALLOC_GROW(store.offset, 1, store.offset_alloc);
|
2005-11-20 06:52:22 +01:00
|
|
|
store.offset[0] = 0;
|
2005-11-17 22:32:36 +01:00
|
|
|
store.state = START;
|
|
|
|
store.seen = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* After this, store.offset will contain the *end* offset
|
|
|
|
* of the last match, or remain at 0 if no match was found.
|
|
|
|
* As a side effect, we make sure to transform only a valid
|
|
|
|
* existing config file.
|
|
|
|
*/
|
2008-05-14 19:46:53 +02:00
|
|
|
if (git_config_from_file(store_aux, config_filename, NULL)) {
|
2008-05-12 23:41:04 +02:00
|
|
|
error("invalid config file %s", config_filename);
|
2005-11-17 22:32:36 +01:00
|
|
|
free(store.key);
|
2014-08-19 08:20:00 +02:00
|
|
|
if (store.value_regex != NULL &&
|
|
|
|
store.value_regex != CONFIG_REGEX_NONE) {
|
2005-11-17 22:32:36 +01:00
|
|
|
regfree(store.value_regex);
|
|
|
|
free(store.value_regex);
|
|
|
|
}
|
2011-05-17 17:38:52 +02:00
|
|
|
ret = CONFIG_INVALID_FILE;
|
2006-04-17 17:14:48 +02:00
|
|
|
goto out_free;
|
2005-11-17 22:32:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
free(store.key);
|
2014-08-19 08:20:00 +02:00
|
|
|
if (store.value_regex != NULL &&
|
|
|
|
store.value_regex != CONFIG_REGEX_NONE) {
|
2005-11-17 22:32:36 +01:00
|
|
|
regfree(store.value_regex);
|
|
|
|
free(store.value_regex);
|
|
|
|
}
|
|
|
|
|
2005-11-20 06:52:22 +01:00
|
|
|
/* if nothing to unset, or too many matches, error out */
|
|
|
|
if ((store.seen == 0 && value == NULL) ||
|
|
|
|
(store.seen > 1 && multi_replace == 0)) {
|
2011-05-17 17:38:52 +02:00
|
|
|
ret = CONFIG_NOTHING_SET;
|
2006-04-17 17:14:48 +02:00
|
|
|
goto out_free;
|
2005-11-17 22:32:36 +01:00
|
|
|
}
|
|
|
|
|
2006-01-05 12:43:34 +01:00
|
|
|
fstat(in_fd, &st);
|
2007-03-07 02:44:37 +01:00
|
|
|
contents_sz = xsize_t(st.st_size);
|
|
|
|
contents = xmmap(NULL, contents_sz, PROT_READ,
|
2005-11-17 22:32:36 +01:00
|
|
|
MAP_PRIVATE, in_fd, 0);
|
|
|
|
close(in_fd);
|
|
|
|
|
2014-10-01 12:28:32 +02:00
|
|
|
if (chmod(lock->filename.buf, st.st_mode & 07777) < 0) {
|
2014-07-16 00:54:30 +02:00
|
|
|
error("chmod on %s failed: %s",
|
2014-10-01 12:28:32 +02:00
|
|
|
lock->filename.buf, strerror(errno));
|
2014-05-06 02:17:14 +02:00
|
|
|
ret = CONFIG_NO_WRITE;
|
|
|
|
goto out_free;
|
|
|
|
}
|
|
|
|
|
2005-11-20 06:52:22 +01:00
|
|
|
if (store.seen == 0)
|
|
|
|
store.seen = 1;
|
|
|
|
|
|
|
|
for (i = 0, copy_begin = 0; i < store.seen; i++) {
|
|
|
|
if (store.offset[i] == 0) {
|
2007-03-07 02:44:37 +01:00
|
|
|
store.offset[i] = copy_end = contents_sz;
|
2005-11-20 06:52:22 +01:00
|
|
|
} else if (store.state != KEY_SEEN) {
|
|
|
|
copy_end = store.offset[i];
|
2005-11-17 22:32:36 +01:00
|
|
|
} else
|
2005-11-20 06:52:22 +01:00
|
|
|
copy_end = find_beginning_of_line(
|
2007-03-07 02:44:37 +01:00
|
|
|
contents, contents_sz,
|
2005-11-20 06:52:22 +01:00
|
|
|
store.offset[i]-2, &new_line);
|
|
|
|
|
2008-01-01 07:17:34 +01:00
|
|
|
if (copy_end > 0 && contents[copy_end-1] != '\n')
|
|
|
|
new_line = 1;
|
|
|
|
|
2005-11-20 06:52:22 +01:00
|
|
|
/* write the first part of the config */
|
|
|
|
if (copy_end > copy_begin) {
|
2007-01-11 22:16:26 +01:00
|
|
|
if (write_in_full(fd, contents + copy_begin,
|
|
|
|
copy_end - copy_begin) <
|
|
|
|
copy_end - copy_begin)
|
|
|
|
goto write_err_out;
|
|
|
|
if (new_line &&
|
use write_str_in_full helper to avoid literal string lengths
In 2d14d65 (Use a clearer style to issue commands to remote helpers,
2009-09-03) I happened to notice two changes like this:
- write_in_full(helper->in, "list\n", 5);
+
+ strbuf_addstr(&buf, "list\n");
+ write_in_full(helper->in, buf.buf, buf.len);
+ strbuf_reset(&buf);
IMHO, it would be better to define a new function,
static inline ssize_t write_str_in_full(int fd, const char *str)
{
return write_in_full(fd, str, strlen(str));
}
and then use it like this:
- strbuf_addstr(&buf, "list\n");
- write_in_full(helper->in, buf.buf, buf.len);
- strbuf_reset(&buf);
+ write_str_in_full(helper->in, "list\n");
Thus not requiring the added allocation, and still avoiding
the maintenance risk of literal string lengths.
These days, compilers are good enough that strlen("literal")
imposes no run-time cost.
Transformed via this:
perl -pi -e \
's/write_in_full\((.*?), (".*?"), \d+\)/write_str_in_full($1, $2)/'\
$(git grep -l 'write_in_full.*"')
Signed-off-by: Jim Meyering <meyering@redhat.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2009-09-12 10:54:32 +02:00
|
|
|
write_str_in_full(fd, "\n") != 1)
|
2007-01-11 22:16:26 +01:00
|
|
|
goto write_err_out;
|
2005-11-20 06:52:22 +01:00
|
|
|
}
|
|
|
|
copy_begin = store.offset[i];
|
2005-11-17 22:32:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* write the pair (value == NULL means unset) */
|
|
|
|
if (value != NULL) {
|
2007-01-11 22:16:26 +01:00
|
|
|
if (store.state == START) {
|
|
|
|
if (!store_write_section(fd, key))
|
|
|
|
goto write_err_out;
|
2007-01-08 16:58:38 +01:00
|
|
|
}
|
2007-01-11 22:16:26 +01:00
|
|
|
if (!store_write_pair(fd, key, value))
|
|
|
|
goto write_err_out;
|
2005-11-17 22:32:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* write the rest of the config */
|
2007-03-07 02:44:37 +01:00
|
|
|
if (copy_begin < contents_sz)
|
2007-01-11 22:16:26 +01:00
|
|
|
if (write_in_full(fd, contents + copy_begin,
|
2007-03-07 02:44:37 +01:00
|
|
|
contents_sz - copy_begin) <
|
|
|
|
contents_sz - copy_begin)
|
2007-01-11 22:16:26 +01:00
|
|
|
goto write_err_out;
|
2005-11-17 22:32:36 +01:00
|
|
|
|
2007-03-07 02:44:37 +01:00
|
|
|
munmap(contents, contents_sz);
|
2005-11-17 22:32:36 +01:00
|
|
|
}
|
|
|
|
|
2008-01-16 20:12:46 +01:00
|
|
|
if (commit_lock_file(lock) < 0) {
|
2008-05-12 23:41:04 +02:00
|
|
|
error("could not commit config file %s", config_filename);
|
2011-05-17 17:38:52 +02:00
|
|
|
ret = CONFIG_NO_WRITE;
|
2014-10-01 12:28:26 +02:00
|
|
|
lock = NULL;
|
2006-04-17 17:14:48 +02:00
|
|
|
goto out_free;
|
2005-11-17 22:32:36 +01:00
|
|
|
}
|
|
|
|
|
2007-07-26 18:55:28 +02:00
|
|
|
/*
|
|
|
|
* lock is committed, so don't try to roll it back below.
|
|
|
|
* NOTE: Since lockfile.c keeps a linked list of all created
|
|
|
|
* lock_file structures, it isn't safe to free(lock). It's
|
|
|
|
* better to just leave it hanging around.
|
|
|
|
*/
|
|
|
|
lock = NULL;
|
2006-04-17 17:14:48 +02:00
|
|
|
ret = 0;
|
|
|
|
|
2014-07-28 12:10:38 +02:00
|
|
|
/* Invalidate the config cache */
|
|
|
|
git_config_clear();
|
|
|
|
|
2006-04-17 17:14:48 +02:00
|
|
|
out_free:
|
2007-07-26 18:55:28 +02:00
|
|
|
if (lock)
|
|
|
|
rollback_lock_file(lock);
|
2012-02-16 09:04:05 +01:00
|
|
|
free(filename_buf);
|
2006-04-17 17:14:48 +02:00
|
|
|
return ret;
|
2007-01-11 22:16:26 +01:00
|
|
|
|
|
|
|
write_err_out:
|
2014-10-01 12:28:32 +02:00
|
|
|
ret = write_error(lock->filename.buf);
|
2007-01-11 22:16:26 +01:00
|
|
|
goto out_free;
|
|
|
|
|
2005-11-17 22:32:36 +01:00
|
|
|
}
|
|
|
|
|
2011-08-04 12:39:00 +02:00
|
|
|
int git_config_set_multivar(const char *key, const char *value,
|
|
|
|
const char *value_regex, int multi_replace)
|
|
|
|
{
|
2012-02-16 09:09:32 +01:00
|
|
|
return git_config_set_multivar_in_file(NULL, key, value, value_regex,
|
2012-02-16 09:04:05 +01:00
|
|
|
multi_replace);
|
2011-08-04 12:39:00 +02:00
|
|
|
}
|
|
|
|
|
2007-03-02 21:53:33 +01:00
|
|
|
static int section_name_match (const char *buf, const char *name)
|
|
|
|
{
|
|
|
|
int i = 0, j = 0, dot = 0;
|
2009-07-24 23:21:43 +02:00
|
|
|
if (buf[i] != '[')
|
|
|
|
return 0;
|
|
|
|
for (i = 1; buf[i] && buf[i] != ']'; i++) {
|
2007-03-02 21:53:33 +01:00
|
|
|
if (!dot && isspace(buf[i])) {
|
|
|
|
dot = 1;
|
|
|
|
if (name[j++] != '.')
|
|
|
|
break;
|
|
|
|
for (i++; isspace(buf[i]); i++)
|
|
|
|
; /* do nothing */
|
|
|
|
if (buf[i] != '"')
|
|
|
|
break;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (buf[i] == '\\' && dot)
|
|
|
|
i++;
|
|
|
|
else if (buf[i] == '"' && dot) {
|
|
|
|
for (i++; isspace(buf[i]); i++)
|
|
|
|
; /* do_nothing */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (buf[i] != name[j++])
|
|
|
|
break;
|
|
|
|
}
|
2009-07-24 23:21:43 +02:00
|
|
|
if (buf[i] == ']' && name[j] == 0) {
|
|
|
|
/*
|
|
|
|
* We match, now just find the right length offset by
|
|
|
|
* gobbling up any whitespace after it, as well
|
|
|
|
*/
|
|
|
|
i++;
|
|
|
|
for (; buf[i] && isspace(buf[i]); i++)
|
|
|
|
; /* do nothing */
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
return 0;
|
2007-03-02 21:53:33 +01:00
|
|
|
}
|
|
|
|
|
2012-04-26 03:47:14 +02:00
|
|
|
static int section_name_is_ok(const char *name)
|
|
|
|
{
|
|
|
|
/* Empty section names are bogus. */
|
|
|
|
if (!*name)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Before a dot, we must be alphanumeric or dash. After the first dot,
|
|
|
|
* anything goes, so we can stop checking.
|
|
|
|
*/
|
|
|
|
for (; *name && *name != '.'; name++)
|
|
|
|
if (*name != '-' && !isalnum(*name))
|
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2007-03-02 21:53:33 +01:00
|
|
|
/* if new_name == NULL, the section is removed instead */
|
2012-02-16 09:04:25 +01:00
|
|
|
int git_config_rename_section_in_file(const char *config_filename,
|
|
|
|
const char *old_name, const char *new_name)
|
2006-12-16 15:14:14 +01:00
|
|
|
{
|
2007-03-02 21:53:33 +01:00
|
|
|
int ret = 0, remove = 0;
|
2012-02-16 09:04:25 +01:00
|
|
|
char *filename_buf = NULL;
|
2012-04-26 03:47:14 +02:00
|
|
|
struct lock_file *lock;
|
2006-12-16 15:14:14 +01:00
|
|
|
int out_fd;
|
|
|
|
char buf[1024];
|
config.c: Make git_config() work correctly when called recursively
On Cygwin, this fixes a test failure in t3301-notes.sh (test 98,
"git notes copy --for-rewrite (disabled)").
The test failure is caused by a recursive call to git_config() which
has the effect of skipping to the end-of-file while processing the
"notes.rewriteref" config variable. Thus, any config variables that
appear after "notes.rewriteref" are simply ignored by git_config().
Also, we note that the original FILE handle is leaked as a result
of the recursive call.
The recursive call to git_config() is due to the "schizophrenic stat"
functions on cygwin, where one of two different implementations of
the l/stat functions is selected lazily, depending on some config
variables.
In this case, the init_copy_notes_for_rewrite() function calls
git_config() with the notes_rewrite_config() callback function.
This callback, while processing the "notes.rewriteref" variable,
in turn calls string_list_add_refs_by_glob() to process the
associated ref value. This eventually leads to a call to the
get_ref_dir() function, which in turn calls stat(). On cygwin,
the stat() macro leads to an indirect call to cygwin_stat_stub()
which, via init_stat(), then calls git_config() in order to
determine which l/stat implementation to bind to.
In order to solve this problem, we modify git_config() so that the
global state variables used by the config reading code is packaged
up and managed on a local state stack.
Signed-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-06-16 22:24:51 +02:00
|
|
|
FILE *config_file;
|
2014-05-06 02:17:14 +02:00
|
|
|
struct stat st;
|
2006-12-16 15:14:14 +01:00
|
|
|
|
2012-04-26 03:47:14 +02:00
|
|
|
if (new_name && !section_name_is_ok(new_name)) {
|
|
|
|
ret = error("invalid section name: %s", new_name);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2012-02-16 09:04:25 +01:00
|
|
|
if (!config_filename)
|
|
|
|
config_filename = filename_buf = git_pathdup("config");
|
|
|
|
|
2014-05-26 17:33:46 +02:00
|
|
|
lock = xcalloc(1, sizeof(struct lock_file));
|
2006-12-16 15:14:14 +01:00
|
|
|
out_fd = hold_lock_file_for_update(lock, config_filename, 0);
|
2006-12-20 06:55:27 +01:00
|
|
|
if (out_fd < 0) {
|
2008-05-12 23:41:04 +02:00
|
|
|
ret = error("could not lock config file %s", config_filename);
|
2006-12-20 06:55:27 +01:00
|
|
|
goto out;
|
|
|
|
}
|
2006-12-16 15:14:14 +01:00
|
|
|
|
2006-12-20 06:55:27 +01:00
|
|
|
if (!(config_file = fopen(config_filename, "rb"))) {
|
2007-04-05 16:20:55 +02:00
|
|
|
/* no config file means nothing to rename, no error */
|
|
|
|
goto unlock_and_out;
|
2006-12-20 06:55:27 +01:00
|
|
|
}
|
2006-12-16 15:14:14 +01:00
|
|
|
|
2014-05-06 02:17:14 +02:00
|
|
|
fstat(fileno(config_file), &st);
|
|
|
|
|
2014-10-01 12:28:32 +02:00
|
|
|
if (chmod(lock->filename.buf, st.st_mode & 07777) < 0) {
|
2014-07-16 00:54:30 +02:00
|
|
|
ret = error("chmod on %s failed: %s",
|
2014-10-01 12:28:32 +02:00
|
|
|
lock->filename.buf, strerror(errno));
|
2014-05-06 02:17:14 +02:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2006-12-16 15:14:14 +01:00
|
|
|
while (fgets(buf, sizeof(buf), config_file)) {
|
|
|
|
int i;
|
2007-01-08 16:58:38 +01:00
|
|
|
int length;
|
2009-07-24 23:21:44 +02:00
|
|
|
char *output = buf;
|
2006-12-16 15:14:14 +01:00
|
|
|
for (i = 0; buf[i] && isspace(buf[i]); i++)
|
|
|
|
; /* do nothing */
|
|
|
|
if (buf[i] == '[') {
|
|
|
|
/* it's a section */
|
2009-07-24 23:21:43 +02:00
|
|
|
int offset = section_name_match(&buf[i], old_name);
|
|
|
|
if (offset > 0) {
|
2007-03-02 21:53:33 +01:00
|
|
|
ret++;
|
|
|
|
if (new_name == NULL) {
|
|
|
|
remove = 1;
|
2006-12-16 15:14:14 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
store.baselen = strlen(new_name);
|
2007-01-08 16:58:38 +01:00
|
|
|
if (!store_write_section(out_fd, new_name)) {
|
2014-10-01 12:28:32 +02:00
|
|
|
ret = write_error(lock->filename.buf);
|
2007-01-08 16:58:38 +01:00
|
|
|
goto out;
|
|
|
|
}
|
2009-07-24 23:21:44 +02:00
|
|
|
/*
|
|
|
|
* We wrote out the new section, with
|
|
|
|
* a newline, now skip the old
|
|
|
|
* section's length
|
|
|
|
*/
|
|
|
|
output += offset + i;
|
|
|
|
if (strlen(output) > 0) {
|
|
|
|
/*
|
|
|
|
* More content means there's
|
|
|
|
* a declaration to put on the
|
|
|
|
* next line; indent with a
|
|
|
|
* tab
|
|
|
|
*/
|
|
|
|
output -= 1;
|
|
|
|
output[0] = '\t';
|
|
|
|
}
|
2006-12-16 15:14:14 +01:00
|
|
|
}
|
2007-03-02 21:53:33 +01:00
|
|
|
remove = 0;
|
2006-12-16 15:14:14 +01:00
|
|
|
}
|
2007-03-02 21:53:33 +01:00
|
|
|
if (remove)
|
|
|
|
continue;
|
2009-07-24 23:21:44 +02:00
|
|
|
length = strlen(output);
|
|
|
|
if (write_in_full(out_fd, output, length) != length) {
|
2014-10-01 12:28:32 +02:00
|
|
|
ret = write_error(lock->filename.buf);
|
2007-01-08 16:58:38 +01:00
|
|
|
goto out;
|
|
|
|
}
|
2006-12-16 15:14:14 +01:00
|
|
|
}
|
2006-12-20 06:55:27 +01:00
|
|
|
fclose(config_file);
|
2011-07-16 23:55:52 +02:00
|
|
|
unlock_and_out:
|
2008-01-16 20:12:46 +01:00
|
|
|
if (commit_lock_file(lock) < 0)
|
2008-05-12 23:41:04 +02:00
|
|
|
ret = error("could not commit config file %s", config_filename);
|
2011-07-16 23:55:52 +02:00
|
|
|
out:
|
2012-02-16 09:04:25 +01:00
|
|
|
free(filename_buf);
|
2006-12-16 15:14:14 +01:00
|
|
|
return ret;
|
|
|
|
}
|
2008-02-11 19:41:18 +01:00
|
|
|
|
2012-02-16 09:04:25 +01:00
|
|
|
int git_config_rename_section(const char *old_name, const char *new_name)
|
|
|
|
{
|
2012-02-16 09:09:32 +01:00
|
|
|
return git_config_rename_section_in_file(NULL, old_name, new_name);
|
2012-02-16 09:04:25 +01:00
|
|
|
}
|
|
|
|
|
2008-02-11 19:41:18 +01:00
|
|
|
/*
|
|
|
|
* Call this to report error for your variable that should not
|
|
|
|
* get a boolean value (i.e. "[my] var" means "true").
|
|
|
|
*/
|
2012-12-15 18:42:10 +01:00
|
|
|
#undef config_error_nonbool
|
2008-02-11 19:41:18 +01:00
|
|
|
int config_error_nonbool(const char *var)
|
|
|
|
{
|
|
|
|
return error("Missing value for '%s'", var);
|
|
|
|
}
|
2013-01-23 07:23:05 +01:00
|
|
|
|
|
|
|
int parse_config_key(const char *var,
|
|
|
|
const char *section,
|
|
|
|
const char **subsection, int *subsection_len,
|
|
|
|
const char **key)
|
|
|
|
{
|
|
|
|
int section_len = strlen(section);
|
|
|
|
const char *dot;
|
|
|
|
|
|
|
|
/* Does it start with "section." ? */
|
2013-11-30 21:55:40 +01:00
|
|
|
if (!starts_with(var, section) || var[section_len] != '.')
|
2013-01-23 07:23:05 +01:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Find the key; we don't know yet if we have a subsection, but we must
|
|
|
|
* parse backwards from the end, since the subsection may have dots in
|
|
|
|
* it, too.
|
|
|
|
*/
|
|
|
|
dot = strrchr(var, '.');
|
|
|
|
*key = dot + 1;
|
|
|
|
|
|
|
|
/* Did we have a subsection at all? */
|
|
|
|
if (dot == var + section_len) {
|
|
|
|
*subsection = NULL;
|
|
|
|
*subsection_len = 0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
*subsection = var + section_len + 1;
|
|
|
|
*subsection_len = dot - *subsection;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|