Merge branch 'jn/warn-on-inaccessible-loosen'
authorJunio C Hamano <gitster@pobox.com>
Mon, 7 Jan 2013 06:11:16 +0000 (22:11 -0800)
committerJunio C Hamano <gitster@pobox.com>
Mon, 7 Jan 2013 06:11:16 +0000 (22:11 -0800)
Deal with a situation where .config/git is a file and we notice
.config/git/config is not readable due to ENOTDIR, not ENOENT.

* jn/warn-on-inaccessible-loosen:
  config: exit on error accessing any config file
  doc: advertise GIT_CONFIG_NOSYSTEM
  config: treat user and xdg config permission problems as errors
  config, gitignore: failure to access with ENOTDIR is ok

1  2 
Documentation/git-config.txt
Documentation/git.txt
config.c
git-compat-util.h
wrapper.c

@@@ -54,16 -54,16 +54,16 @@@ configuration file by default, and opti
  '--file <filename>' can be used to tell the command to write to
  that location (you can say '--local' but that is the default).
  
 -This command will fail (with exit code ret) if:
 +This command will fail with non-zero status upon error.  Some exit
 +codes are:
  
  . The config file is invalid (ret=3),
  . can not write to the config file (ret=4),
  . no section or name was provided (ret=2),
  . the section or key is invalid (ret=1),
  . you try to unset an option which does not exist (ret=5),
 -. you try to unset/set an option for which multiple lines match (ret=5),
 -. you try to use an invalid regexp (ret=6), or
 -. you use '--global' option without $HOME being properly set (ret=128).
 +. you try to unset/set an option for which multiple lines match (ret=5), or
 +. you try to use an invalid regexp (ret=6).
  
  On success, the command returns the exit code 0.
  
@@@ -240,6 -240,10 +240,10 @@@ GIT_CONFIG:
        Using the "--global" option forces this to ~/.gitconfig. Using the
        "--system" option forces this to $(prefix)/etc/gitconfig.
  
+ GIT_CONFIG_NOSYSTEM::
+       Whether to skip reading settings from the system-wide
+       $(prefix)/etc/gitconfig file. See linkgit:git[1] for details.
  See also <<FILES>>.
  
  
@@@ -267,7 -271,7 +271,7 @@@ Given a .git/config like this
  
        ; Proxy settings
        [core]
 -              gitproxy="proxy-command" for kernel.org
 +              gitproxy=proxy-command for kernel.org
                gitproxy=default-proxy ; for all the rest
  
  you can set the filemode to true with
@@@ -342,7 -346,7 +346,7 @@@ To actually match only values with an e
  To add a new proxy, without altering any of the existing ones, use
  
  ------------
 -% git config core.gitproxy '"proxy-command" for example.com'
 +% git config --add core.gitproxy '"proxy-command" for example.com'
  ------------
  
  An example to use customized color from the configuration in your
diff --combined Documentation/git.txt
@@@ -22,17 -22,18 +22,17 @@@ unusually rich command set that provide
  and full access to internals.
  
  See linkgit:gittutorial[7] to get started, then see
 -link:everyday.html[Everyday Git] for a useful minimum set of commands, and
 -"man git-commandname" for documentation of each command.  CVS users may
 -also want to read linkgit:gitcvs-migration[7].  See
 -the link:user-manual.html[Git User's Manual] for a more in-depth
 -introduction.
 +link:everyday.html[Everyday Git] for a useful minimum set of
 +commands.  The link:user-manual.html[Git User's Manual] has a more
 +in-depth introduction.
  
 -The '<command>' is either a name of a Git command (see below) or an alias
 -as defined in the configuration file (see linkgit:git-config[1]).
 +After you mastered the basic concepts, you can come back to this
 +page to learn what commands git offers.  You can learn more about
 +individual git commands with "git help command".  linkgit:gitcli[7]
 +manual page gives you an overview of the command line command syntax.
  
 -Formatted and hyperlinked version of the latest git
 -documentation can be viewed at
 -`http://git-htmldocs.googlecode.com/git/git.html`.
 +Formatted and hyperlinked version of the latest git documentation
 +can be viewed at `http://git-htmldocs.googlecode.com/git/git.html`.
  
  ifdef::stalenotes[]
  [NOTE]
@@@ -43,33 -44,14 +43,33 @@@ unreleased) version of git, that is ava
  branch of the `git.git` repository.
  Documentation for older releases are available here:
  
 -* link:v1.7.12/git.html[documentation for release 1.7.12]
 +* link:v1.8.1/git.html[documentation for release 1.8.1]
  
  * release notes for
 +  link:RelNotes/1.8.1.txt[1.8.1].
 +
 +* link:v1.8.0.3/git.html[documentation for release 1.8.0.3]
 +
 +* release notes for
 +  link:RelNotes/1.8.0.3.txt[1.8.0.3],
 +  link:RelNotes/1.8.0.2.txt[1.8.0.2],
 +  link:RelNotes/1.8.0.1.txt[1.8.0.1],
 +  link:RelNotes/1.8.0.txt[1.8.0].
 +
 +* link:v1.7.12.4/git.html[documentation for release 1.7.12.4]
 +
 +* release notes for
 +  link:RelNotes/1.7.12.4.txt[1.7.12.4],
 +  link:RelNotes/1.7.12.3.txt[1.7.12.3],
 +  link:RelNotes/1.7.12.2.txt[1.7.12.2],
 +  link:RelNotes/1.7.12.1.txt[1.7.12.1],
    link:RelNotes/1.7.12.txt[1.7.12].
  
 -* link:v1.7.11.5/git.html[documentation for release 1.7.11.5]
 +* link:v1.7.11.7/git.html[documentation for release 1.7.11.7]
  
  * release notes for
 +  link:RelNotes/1.7.11.7.txt[1.7.11.7],
 +  link:RelNotes/1.7.11.6.txt[1.7.11.6],
    link:RelNotes/1.7.11.5.txt[1.7.11.5],
    link:RelNotes/1.7.11.4.txt[1.7.11.4],
    link:RelNotes/1.7.11.3.txt[1.7.11.3],
@@@ -428,11 -410,24 +428,11 @@@ help ...`
        Do not use replacement refs to replace git objects. See
        linkgit:git-replace[1] for more information.
  
 +--literal-pathspecs::
 +      Treat pathspecs literally, rather than as glob patterns. This is
 +      equivalent to setting the `GIT_LITERAL_PATHSPECS` environment
 +      variable to `1`.
  
 -FURTHER DOCUMENTATION
 ----------------------
 -
 -See the references above to get started using git.  The following is
 -probably more detail than necessary for a first-time user.
 -
 -The link:user-manual.html#git-concepts[git concepts chapter of the
 -user-manual] and linkgit:gitcore-tutorial[7] both provide
 -introductions to the underlying git architecture.
 -
 -See linkgit:gitworkflows[7] for an overview of recommended workflows.
 -
 -See also the link:howto-index.html[howto] documents for some useful
 -examples.
 -
 -The internals are documented in the
 -link:technical/api-index.html[GIT API documentation].
  
  GIT COMMANDS
  ------------
@@@ -661,7 -656,6 +661,7 @@@ git so take care if using Cogito etc
        If the 'GIT_DIR' environment variable is set then it
        specifies a path to use instead of the default `.git`
        for the base of the repository.
 +      The '--git-dir' command-line option also sets this value.
  
  'GIT_WORK_TREE'::
        Set the path to the working tree.  The value will not be
@@@ -777,6 -771,14 +777,14 @@@ for further details
        and read the password from its STDOUT. See also the 'core.askpass'
        option in linkgit:git-config[1].
  
+ 'GIT_CONFIG_NOSYSTEM'::
+       Whether to skip reading settings from the system-wide
+       `$(prefix)/etc/gitconfig` file.  This environment variable can
+       be used along with `$HOME` and `$XDG_CONFIG_HOME` to create a
+       predictable environment for a picky script, or you can set it
+       temporarily to avoid using a buggy `/etc/gitconfig` file while
+       waiting for someone with sufficient permissions to fix it.
  'GIT_FLUSH'::
        If this environment variable is set to "1", then commands such
        as 'git blame' (in incremental mode), 'git rev-list', 'git log',
        as a file path and will try to write the trace messages
        into it.
  
 +GIT_LITERAL_PATHSPECS::
 +      Setting this variable to `1` will cause git to treat all
 +      pathspecs literally, rather than as glob patterns. For example,
 +      running `GIT_LITERAL_PATHSPECS=1 git log -- '*.c'` will search
 +      for commits that touch the path `*.c`, not any paths that the
 +      glob `*.c` matches. You might want this if you are feeding
 +      literal paths to git (e.g., paths previously given to you by
 +      `git ls-tree`, `--raw` diff output, etc).
 +
 +
  Discussion[[Discussion]]
  ------------------------
  
@@@ -864,37 -856,12 +872,37 @@@ The index is also capable of storing mu
  for a given pathname.  These stages are used to hold the various
  unmerged version of a file when a merge is in progress.
  
 +FURTHER DOCUMENTATION
 +---------------------
 +
 +See the references in the "description" section to get started
 +using git.  The following is probably more detail than necessary
 +for a first-time user.
 +
 +The link:user-manual.html#git-concepts[git concepts chapter of the
 +user-manual] and linkgit:gitcore-tutorial[7] both provide
 +introductions to the underlying git architecture.
 +
 +See linkgit:gitworkflows[7] for an overview of recommended workflows.
 +
 +See also the link:howto-index.html[howto] documents for some useful
 +examples.
 +
 +The internals are documented in the
 +link:technical/api-index.html[GIT API documentation].
 +
 +Users migrating from CVS may also want to
 +read linkgit:gitcvs-migration[7].
 +
 +
  Authors
  -------
  Git was started by Linus Torvalds, and is currently maintained by Junio
  C Hamano. Numerous contributions have come from the git mailing list
 -<git@vger.kernel.org>. For a more complete list of contributors, see
 -http://git-scm.com/about. If you have a clone of git.git itself, the
 +<git@vger.kernel.org>.  http://www.ohloh.net/p/git/contributors/summary
 +gives you a more complete list of contributors.
 +
 +If you have a clone of git.git itself, the
  output of linkgit:git-shortlog[1] and linkgit:git-blame[1] can show you
  the authors for specific parts of the project.
  
diff --combined config.c
+++ b/config.c
@@@ -10,6 -10,8 +10,6 @@@
  #include "strbuf.h"
  #include "quote.h"
  
 -#define MAXNAME (256)
 -
  typedef struct config_file {
        struct config_file *prev;
        FILE *f;
@@@ -17,7 -19,7 +17,7 @@@
        int linenr;
        int eof;
        struct strbuf value;
 -      char var[MAXNAME];
 +      struct strbuf var;
  } config_file;
  
  static config_file *cf;
@@@ -58,7 -60,7 +58,7 @@@ static int handle_path_include(const ch
                path = buf.buf;
        }
  
-       if (!access_or_warn(path, R_OK)) {
+       if (!access_or_die(path, R_OK)) {
                if (++inc->depth > MAX_INCLUDE_DEPTH)
                        die(include_depth_advice, MAX_INCLUDE_DEPTH, path,
                            cf && cf->name ? cf->name : "the command line");
@@@ -258,7 -260,7 +258,7 @@@ static inline int iskeychar(int c
        return isalnum(c) || c == '-';
  }
  
 -static int get_value(config_fn_t fn, void *data, char *name, unsigned int len)
 +static int get_value(config_fn_t fn, void *data, struct strbuf *name)
  {
        int c;
        char *value;
                        break;
                if (!iskeychar(c))
                        break;
 -              name[len++] = tolower(c);
 -              if (len >= MAXNAME)
 -                      return -1;
 +              strbuf_addch(name, tolower(c));
        }
 -      name[len] = 0;
 +
        while (c == ' ' || c == '\t')
                c = get_next_char();
  
                if (!value)
                        return -1;
        }
 -      return fn(name, value, data);
 +      return fn(name->buf, value, data);
  }
  
 -static int get_extended_base_var(char *name, int baselen, int c)
 +static int get_extended_base_var(struct strbuf *name, int c)
  {
        do {
                if (c == '\n')
        /* We require the format to be '[base "extension"]' */
        if (c != '"')
                return -1;
 -      name[baselen++] = '.';
 +      strbuf_addch(name, '.');
  
        for (;;) {
                int c = get_next_char();
                        if (c == '\n')
                                goto error_incomplete_line;
                }
 -              name[baselen++] = c;
 -              if (baselen > MAXNAME / 2)
 -                      return -1;
 +              strbuf_addch(name, c);
        }
  
        /* Final ']' */
        if (get_next_char() != ']')
                return -1;
 -      return baselen;
 +      return 0;
  error_incomplete_line:
        cf->linenr--;
        return -1;
  }
  
 -static int get_base_var(char *name)
 +static int get_base_var(struct strbuf *name)
  {
 -      int baselen = 0;
 -
        for (;;) {
                int c = get_next_char();
                if (cf->eof)
                        return -1;
                if (c == ']')
 -                      return baselen;
 +                      return 0;
                if (isspace(c))
 -                      return get_extended_base_var(name, baselen, c);
 +                      return get_extended_base_var(name, c);
                if (!iskeychar(c) && c != '.')
                        return -1;
 -              if (baselen > MAXNAME / 2)
 -                      return -1;
 -              name[baselen++] = tolower(c);
 +              strbuf_addch(name, tolower(c));
        }
  }
  
@@@ -343,7 -353,7 +343,7 @@@ static int git_parse_file(config_fn_t f
  {
        int comment = 0;
        int baselen = 0;
 -      char *var = cf->var;
 +      struct strbuf *var = &cf->var;
  
        /* U+FEFF Byte Order Mark in UTF8 */
        static const unsigned char *utf8_bom = (unsigned char *) "\xef\xbb\xbf";
                        continue;
                }
                if (c == '[') {
 -                      baselen = get_base_var(var);
 -                      if (baselen <= 0)
 +                      /* Reset prior to determining a new stem */
 +                      strbuf_reset(var);
 +                      if (get_base_var(var) < 0 || var->len < 1)
                                break;
 -                      var[baselen++] = '.';
 -                      var[baselen] = 0;
 +                      strbuf_addch(var, '.');
 +                      baselen = var->len;
                        continue;
                }
                if (!isalpha(c))
                        break;
 -              var[baselen] = tolower(c);
 -              if (get_value(fn, data, var, baselen+1) < 0)
 +              /*
 +               * 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)
                        break;
        }
        die("bad config file line %d in %s", cf->linenr, cf->name);
@@@ -839,8 -842,6 +839,8 @@@ static int git_default_mailmap_config(c
  {
        if (!strcmp(var, "mailmap.file"))
                return git_config_string(&git_mailmap_file, var, value);
 +      if (!strcmp(var, "mailmap.blob"))
 +              return git_config_string(&git_mailmap_blob, var, value);
  
        /* Add other config variables here and to Documentation/config.txt. */
        return 0;
@@@ -898,14 -899,12 +898,14 @@@ int git_config_from_file(config_fn_t fn
                top.linenr = 1;
                top.eof = 0;
                strbuf_init(&top.value, 1024);
 +              strbuf_init(&top.var, 1024);
                cf = &top;
  
                ret = git_parse_file(fn, data);
  
                /* pop config-file parsing state stack */
                strbuf_release(&top.value);
 +              strbuf_release(&top.var);
                cf = top.prev;
  
                fclose(f);
@@@ -940,23 -939,23 +940,23 @@@ int git_config_early(config_fn_t fn, vo
  
        home_config_paths(&user_config, &xdg_config, "config");
  
-       if (git_config_system() && !access_or_warn(git_etc_gitconfig(), R_OK)) {
+       if (git_config_system() && !access_or_die(git_etc_gitconfig(), R_OK)) {
                ret += git_config_from_file(fn, git_etc_gitconfig(),
                                            data);
                found += 1;
        }
  
-       if (xdg_config && !access_or_warn(xdg_config, R_OK)) {
+       if (xdg_config && !access_or_die(xdg_config, R_OK)) {
                ret += git_config_from_file(fn, xdg_config, data);
                found += 1;
        }
  
-       if (user_config && !access_or_warn(user_config, R_OK)) {
+       if (user_config && !access_or_die(user_config, R_OK)) {
                ret += git_config_from_file(fn, user_config, data);
                found += 1;
        }
  
-       if (repo_config && !access_or_warn(repo_config, R_OK)) {
+       if (repo_config && !access_or_die(repo_config, R_OK)) {
                ret += git_config_from_file(fn, repo_config, data);
                found += 1;
        }
@@@ -1281,7 -1280,6 +1281,7 @@@ int git_config_parse_key(const char *ke
  
  out_free_ret_1:
        free(*store_key);
 +      *store_key = NULL;
        return -CONFIG_INVALID_KEY;
  }
  
@@@ -1662,7 -1660,6 +1662,7 @@@ int git_config_rename_section(const cha
   * Call this to report error for your variable that should not
   * get a boolean value (i.e. "[my] var" means "true").
   */
 +#undef config_error_nonbool
  int config_error_nonbool(const char *var)
  {
        return error("Missing value for '%s'", var);
diff --combined git-compat-util.h
@@@ -74,8 -74,7 +74,8 @@@
  # define _XOPEN_SOURCE 500
  # endif
  #elif !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__USLC__) && \
 -      !defined(_M_UNIX) && !defined(__sgi) && !defined(__DragonFly__)
 +      !defined(_M_UNIX) && !defined(__sgi) && !defined(__DragonFly__) && \
 +      !defined(__TANDEM) && !defined(__QNX__)
  #define _XOPEN_SOURCE 600 /* glibc2 and AIX 5.3L need 500, OpenBSD needs 600 for S_ISLNK() */
  #define _XOPEN_SOURCE_EXTENDED 1 /* AIX 5.3L needs this */
  #endif
  #include <stdlib.h>
  #include <stdarg.h>
  #include <string.h>
 +#ifdef HAVE_STRINGS_H
 +#include <strings.h> /* for strcasecmp() */
 +#endif
  #include <errno.h>
  #include <limits.h>
 +#ifdef NEEDS_SYS_PARAM_H
  #include <sys/param.h>
 +#endif
  #include <sys/types.h>
  #include <dirent.h>
  #include <sys/time.h>
  #else
  #include <stdint.h>
  #endif
 +#ifdef NO_INTPTR_T
 +/*
 + * On I16LP32, ILP32 and LP64 "long" is the save bet, however
 + * on LLP86, IL33LLP64 and P64 it needs to be "long long",
 + * while on IP16 and IP16L32 it is "int" (resp. "short")
 + * Size needs to match (or exceed) 'sizeof(void *)'.
 + * We can't take "long long" here as not everybody has it.
 + */
 +typedef long intptr_t;
 +typedef unsigned long uintptr_t;
 +#endif
  #if defined(__CYGWIN__)
  #undef _XOPEN_SOURCE
  #include <grp.h>
  #define probe_utf8_pathname_composition(a,b)
  #endif
  
 +#ifdef MKDIR_WO_TRAILING_SLASH
 +#define mkdir(a,b) compat_mkdir_wo_trailing_slash((a),(b))
 +extern int compat_mkdir_wo_trailing_slash(const char*, mode_t);
 +#endif
 +
 +#ifdef NO_STRUCT_ITIMERVAL
 +struct itimerval {
 +      struct timeval it_interval;
 +      struct timeval it_value;
 +}
 +#endif
 +
 +#ifdef NO_SETITIMER
 +#define setitimer(which,value,ovalue)
 +#endif
 +
  #ifndef NO_LIBGEN_H
  #include <libgen.h>
  #else
@@@ -290,17 -257,6 +290,17 @@@ extern NORETURN void die_errno(const ch
  extern int error(const char *err, ...) __attribute__((format (printf, 1, 2)));
  extern void warning(const char *err, ...) __attribute__((format (printf, 1, 2)));
  
 +/*
 + * Let callers be aware of the constant return value; this can help
 + * gcc with -Wuninitialized analysis. We have to restrict this trick to
 + * gcc, though, because of the variadic macro and the magic ## comma pasting
 + * behavior. But since we're only trying to help gcc, anyway, it's OK; other
 + * compilers will fall back to using the function as usual.
 + */
 +#ifdef __GNUC__
 +#define error(fmt, ...) (error((fmt), ##__VA_ARGS__), -1)
 +#endif
 +
  extern void set_die_routine(NORETURN_PTR void (*routine)(const char *err, va_list params));
  extern void set_error_routine(void (*routine)(const char *err, va_list params));
  
@@@ -424,10 -380,6 +424,10 @@@ void *gitmemmem(const void *haystack, s
                  const void *needle, size_t needlelen);
  #endif
  
 +#ifdef NO_GETPAGESIZE
 +#define getpagesize() sysconf(_SC_PAGESIZE)
 +#endif
 +
  #ifdef FREAD_READS_DIRECTORIES
  #ifdef fopen
  #undef fopen
@@@ -523,7 -475,6 +523,7 @@@ extern const char tolower_trans_tbl[256
  #undef isdigit
  #undef isalpha
  #undef isalnum
 +#undef isprint
  #undef islower
  #undef isupper
  #undef tolower
@@@ -541,7 -492,6 +541,7 @@@ extern unsigned char sane_ctype[256]
  #define isdigit(x) sane_istest(x,GIT_DIGIT)
  #define isalpha(x) sane_istest(x,GIT_ALPHA)
  #define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT)
 +#define isprint(x) ((x) >= 0x20 && (x) <= 0x7e)
  #define islower(x) sane_iscase(x, 1)
  #define isupper(x) sane_iscase(x, 0)
  #define is_glob_special(x) sane_istest(x,GIT_GLOB_SPECIAL)
@@@ -654,8 -604,12 +654,12 @@@ int rmdir_or_warn(const char *path)
   */
  int remove_or_warn(unsigned int mode, const char *path);
  
- /* Call access(2), but warn for any error besides ENOENT. */
+ /*
+  * Call access(2), but warn for any error except "missing file"
+  * (ENOENT or ENOTDIR).
+  */
  int access_or_warn(const char *path, int mode);
+ int access_or_die(const char *path, int mode);
  
  /* Warn on an inaccessible file that ought to be accessible */
  void warn_on_inaccessible(const char *path);
diff --combined wrapper.c
+++ b/wrapper.c
@@@ -229,7 -229,7 +229,7 @@@ int xmkstemp(char *template
                int saved_errno = errno;
                const char *nonrelative_template;
  
 -              if (!template[0])
 +              if (strlen(template) != strlen(origtemplate))
                        template = origtemplate;
  
                nonrelative_template = absolute_path(template);
@@@ -411,11 -411,19 +411,19 @@@ void warn_on_inaccessible(const char *p
  int access_or_warn(const char *path, int mode)
  {
        int ret = access(path, mode);
-       if (ret && errno != ENOENT)
+       if (ret && errno != ENOENT && errno != ENOTDIR)
                warn_on_inaccessible(path);
        return ret;
  }
  
+ int access_or_die(const char *path, int mode)
+ {
+       int ret = access(path, mode);
+       if (ret && errno != ENOENT && errno != ENOTDIR)
+               die_errno(_("unable to access '%s'"), path);
+       return ret;
+ }
  struct passwd *xgetpwuid_self(void)
  {
        struct passwd *pw;