From: Junio C Hamano Date: Tue, 29 May 2012 20:09:13 +0000 (-0700) Subject: Merge branch 'jk/ident-gecos-strbuf' X-Git-Tag: v1.7.11-rc1~15 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/261ec7d02ae25ba1f5532645fa6fd790515bfa70?hp=-c Merge branch 'jk/ident-gecos-strbuf' Fixes quite a lot of brokenness when ident information needs to be taken from the system and cleans up the code. By Jeff King * jk/ident-gecos-strbuf: (22 commits) format-patch: do not use bogus email addresses in message ids ident: reject bogus email addresses with IDENT_STRICT ident: rename IDENT_ERROR_ON_NO_NAME to IDENT_STRICT format-patch: use GIT_COMMITTER_EMAIL in message ids ident: let callers omit name with fmt_indent ident: refactor NO_DATE flag in fmt_ident ident: reword empty ident error message format-patch: refactor get_patch_filename ident: trim whitespace from default name/email ident: use a dynamic strbuf in fmt_ident ident: use full dns names to generate email addresses ident: report passwd errors with a more friendly message drop length limitations on gecos-derived names and emails ident: don't write fallback username into git_default_name fmt_ident: drop IDENT_WARN_ON_NO_NAME code format-patch: use default email for generating message ids ident: trim trailing newline from /etc/mailname move git_default_* variables to ident.c move identity config parsing to ident.c fmt-merge-msg: don't use static buffer in record_person ... --- 261ec7d02ae25ba1f5532645fa6fd790515bfa70 diff --combined builtin/fmt-merge-msg.c index d42015d867,4ee6a88d75..bf93b043b7 --- a/builtin/fmt-merge-msg.c +++ b/builtin/fmt-merge-msg.c @@@ -230,7 -230,7 +230,7 @@@ static void add_branch_desc(struct strb static void record_person(int which, struct string_list *people, struct commit *commit) { - char name_buf[MAX_GITNAME], *name, *name_end; + char *name_buf, *name, *name_end; struct string_list_item *elem; const char *field = (which == 'a') ? "\nauthor " : "\ncommitter "; @@@ -243,10 -243,9 +243,9 @@@ name_end--; while (isspace(*name_end) && name <= name_end) name_end--; - if (name_end < name || name + MAX_GITNAME <= name_end) + if (name_end < name) return; - memcpy(name_buf, name, name_end - name + 1); - name_buf[name_end - name + 1] = '\0'; + name_buf = xmemdupz(name, name_end - name + 1); elem = string_list_lookup(people, name_buf); if (!elem) { @@@ -254,6 -253,7 +253,7 @@@ elem->util = (void *)0; } elem->util = (void*)(util_as_integral(elem) + 1); + free(name_buf); } static int cmp_string_list_util_as_integral(const void *a_, const void *b_) @@@ -462,10 -462,7 +462,10 @@@ static void fmt_tag_signature(struct st strbuf_add(tagbuf, tag_body, buf + len - tag_body); } strbuf_complete_line(tagbuf); - strbuf_add_lines(tagbuf, "# ", sig->buf, sig->len); + if (sig->len) { + strbuf_addch(tagbuf, '\n'); + strbuf_add_lines(tagbuf, "# ", sig->buf, sig->len); + } } static void fmt_merge_msg_sigs(struct strbuf *out) @@@ -630,7 -627,8 +630,7 @@@ int fmt_merge_msg(struct strbuf *in, st rev.ignore_merges = 1; rev.limited = 1; - if (suffixcmp(out->buf, "\n")) - strbuf_addch(out, '\n'); + strbuf_complete_line(out); for (i = 0; i < origins.nr; i++) shortlog(origins.items[i].string, diff --combined cache.h index cc5048c202,f89f22db70..06413e1584 --- a/cache.h +++ b/cache.h @@@ -887,15 -887,19 +887,19 @@@ unsigned long approxidate_careful(cons unsigned long approxidate_relative(const char *date, const struct timeval *now); enum date_mode parse_date_format(const char *format); - #define IDENT_WARN_ON_NO_NAME 1 - #define IDENT_ERROR_ON_NO_NAME 2 - #define IDENT_NO_DATE 4 + #define IDENT_STRICT 1 + #define IDENT_NO_DATE 2 + #define IDENT_NO_NAME 4 extern const char *git_author_info(int); extern const char *git_committer_info(int); extern const char *fmt_ident(const char *name, const char *email, const char *date_str, int); extern const char *fmt_name(const char *name, const char *email); + extern const char *ident_default_name(void); + extern const char *ident_default_email(void); + extern const char *ident_default_date(void); extern const char *git_editor(void); extern const char *git_pager(int stdout_is_tty); + extern int git_ident_config(const char *, const char *, void *); struct ident_split { const char *name_begin; @@@ -947,7 -951,6 +951,7 @@@ extern struct alternate_object_databas char base[FLEX_ARRAY]; /* more */ } *alt_odb_list; extern void prepare_alt_odb(void); +extern void read_info_alternates(const char * relative_base, int depth); extern void add_to_alternates_file(const char *reference); typedef int alt_odb_fn(struct alternate_object_database *, void *); extern void foreach_alt_odb(alt_odb_fn, void*); @@@ -1139,9 -1142,6 +1143,6 @@@ struct config_include_data #define CONFIG_INCLUDE_INIT { 0 } extern int git_config_include(const char *name, const char *value, void *data); - #define MAX_GITNAME (1000) - extern char git_default_email[MAX_GITNAME]; - extern char git_default_name[MAX_GITNAME]; #define IDENT_NAME_GIVEN 01 #define IDENT_MAIL_GIVEN 02 #define IDENT_ALL_GIVEN (IDENT_NAME_GIVEN|IDENT_MAIL_GIVEN) diff --combined ident.c index 5df094d175,98852c7cc9..443c0751bd --- a/ident.c +++ b/ident.c @@@ -7,7 -7,10 +7,10 @@@ */ #include "cache.h" + static struct strbuf git_default_name = STRBUF_INIT; + static struct strbuf git_default_email = STRBUF_INIT; static char git_default_date[50]; + int user_ident_explicitly_given; #ifdef NO_GECOS_IN_PWENT #define get_gecos(ignored) "&" @@@ -15,42 -18,27 +18,27 @@@ #define get_gecos(struct_passwd) ((struct_passwd)->pw_gecos) #endif - static void copy_gecos(const struct passwd *w, char *name, size_t sz) + static void copy_gecos(const struct passwd *w, struct strbuf *name) { - char *src, *dst; - size_t len, nlen; - - nlen = strlen(w->pw_name); + char *src; /* Traditionally GECOS field had office phone numbers etc, separated * with commas. Also & stands for capitalized form of the login name. */ - for (len = 0, dst = name, src = get_gecos(w); len < sz; src++) { + for (src = get_gecos(w); *src && *src != ','; src++) { int ch = *src; - if (ch != '&') { - *dst++ = ch; - if (ch == 0 || ch == ',') - break; - len++; - continue; - } - if (len + nlen < sz) { + if (ch != '&') + strbuf_addch(name, ch); + else { /* Sorry, Mr. McDonald... */ - *dst++ = toupper(*w->pw_name); - memcpy(dst, w->pw_name + 1, nlen - 1); - dst += nlen - 1; - len += nlen; + strbuf_addch(name, toupper(*w->pw_name)); + strbuf_addstr(name, w->pw_name + 1); } } - if (len < sz) - name[len] = 0; - else - die("Your parents must have hated you!"); - } - static int add_mailname_host(char *buf, size_t len) + static int add_mailname_host(struct strbuf *buf) { FILE *mailname; @@@ -61,7 -49,7 +49,7 @@@ strerror(errno)); return -1; } - if (!fgets(buf, len, mailname)) { + if (strbuf_getline(buf, mailname, '\n') == EOF) { if (ferror(mailname)) warning("cannot read /etc/mailname: %s", strerror(errno)); @@@ -73,94 -61,67 +61,67 @@@ return 0; } - static void add_domainname(char *buf, size_t len) + static void add_domainname(struct strbuf *out) { + char buf[1024]; struct hostent *he; - size_t namelen; - const char *domainname; - if (gethostname(buf, len)) { + if (gethostname(buf, sizeof(buf))) { warning("cannot get host name: %s", strerror(errno)); - strlcpy(buf, "(none)", len); + strbuf_addstr(out, "(none)"); return; } - namelen = strlen(buf); - if (memchr(buf, '.', namelen)) - return; - - he = gethostbyname(buf); - buf[namelen++] = '.'; - buf += namelen; - len -= namelen; - if (he && (domainname = strchr(he->h_name, '.'))) - strlcpy(buf, domainname + 1, len); + if (strchr(buf, '.')) + strbuf_addstr(out, buf); + else if ((he = gethostbyname(buf)) && strchr(he->h_name, '.')) + strbuf_addstr(out, he->h_name); else - strlcpy(buf, "(none)", len); + strbuf_addf(out, "%s.(none)", buf); } - static void copy_email(const struct passwd *pw) + static void copy_email(const struct passwd *pw, struct strbuf *email) { /* * Make up a fake email address * (name + '@' + hostname [+ '.' + domainname]) */ - size_t len = strlen(pw->pw_name); - if (len > sizeof(git_default_email)/2) - die("Your sysadmin must hate you!"); - memcpy(git_default_email, pw->pw_name, len); - git_default_email[len++] = '@'; - - if (!add_mailname_host(git_default_email + len, - sizeof(git_default_email) - len)) + strbuf_addstr(email, pw->pw_name); + strbuf_addch(email, '@'); + + if (!add_mailname_host(email)) return; /* read from "/etc/mailname" (Debian) */ - add_domainname(git_default_email + len, - sizeof(git_default_email) - len); + add_domainname(email); } - static void setup_ident(const char **name, const char **emailp) + const char *ident_default_name(void) { - struct passwd *pw = NULL; - - /* Get the name ("gecos") */ - if (!*name && !git_default_name[0]) { - pw = getpwuid(getuid()); - if (!pw) - die("You don't exist. Go away!"); - copy_gecos(pw, git_default_name, sizeof(git_default_name)); + if (!git_default_name.len) { + copy_gecos(xgetpwuid_self(), &git_default_name); + strbuf_trim(&git_default_name); } - if (!*name) - *name = git_default_name; + return git_default_name.buf; + } - if (!*emailp && !git_default_email[0]) { + const char *ident_default_email(void) + { + if (!git_default_email.len) { const char *email = getenv("EMAIL"); if (email && email[0]) { - strlcpy(git_default_email, email, - sizeof(git_default_email)); + strbuf_addstr(&git_default_email, email); user_ident_explicitly_given |= IDENT_MAIL_GIVEN; - } else { - if (!pw) - pw = getpwuid(getuid()); - if (!pw) - die("You don't exist. Go away!"); - copy_email(pw); - } + } else + copy_email(xgetpwuid_self(), &git_default_email); + strbuf_trim(&git_default_email); } - if (!*emailp) - *emailp = git_default_email; - - /* And set the default date */ - if (!git_default_date[0]) - datestamp(git_default_date, sizeof(git_default_date)); + return git_default_email.buf; } - static int add_raw(char *buf, size_t size, int offset, const char *str) + const char *ident_default_date(void) { - size_t len = strlen(str); - if (offset + len > size) - return size; - memcpy(buf + offset, str, len); - return offset + len; + if (!git_default_date[0]) + datestamp(git_default_date, sizeof(git_default_date)); + return git_default_date; } static int crud(unsigned char c) @@@ -181,7 -142,7 +142,7 @@@ * Copy over a string to the destination, but avoid special * characters ('\n', '<' and '>') and remove crud at the end */ - static int copy(char *buf, size_t size, int offset, const char *src) + static void strbuf_addstr_without_crud(struct strbuf *sb, const char *src) { size_t i, len; unsigned char c; @@@ -205,19 -166,19 +166,19 @@@ /* * Copy the rest to the buffer, but avoid the special * characters '\n' '<' and '>' that act as delimiters on - * an identification line + * an identification line. We can only remove crud, never add it, + * so 'len' is our maximum. */ + strbuf_grow(sb, len); for (i = 0; i < len; i++) { c = *src++; switch (c) { case '\n': case '<': case '>': continue; } - if (offset >= size) - return size; - buf[offset++] = c; + sb->buf[sb->len++] = c; } - return offset; + sb->buf[sb->len] = '\0'; } /* @@@ -244,7 -205,7 +205,7 @@@ int split_ident_line(struct ident_spli if (!split->mail_begin) return status; - for (cp = split->mail_begin - 2; line < cp; cp--) + for (cp = split->mail_begin - 2; line <= cp; cp--) if (!isspace(*cp)) { split->name_end = cp + 1; break; @@@ -304,57 -265,62 +265,62 @@@ static const char *env_hint const char *fmt_ident(const char *name, const char *email, const char *date_str, int flag) { - static char buffer[1000]; + static struct strbuf ident = STRBUF_INIT; char date[50]; - int i; - int error_on_no_name = (flag & IDENT_ERROR_ON_NO_NAME); - int warn_on_no_name = (flag & IDENT_WARN_ON_NO_NAME); - int name_addr_only = (flag & IDENT_NO_DATE); + int strict = (flag & IDENT_STRICT); + int want_date = !(flag & IDENT_NO_DATE); + int want_name = !(flag & IDENT_NO_NAME); - setup_ident(&name, &email); + if (want_name && !name) + name = ident_default_name(); + if (!email) + email = ident_default_email(); - if (!*name) { + if (want_name && !*name) { struct passwd *pw; - if ((warn_on_no_name || error_on_no_name) && - name == git_default_name && env_hint) { - fputs(env_hint, stderr); - env_hint = NULL; /* warn only once */ + if (strict) { + if (name == git_default_name.buf) + fputs(env_hint, stderr); + die("empty ident name (for <%s>) not allowed", email); } - if (error_on_no_name) - die("empty ident %s <%s> not allowed", name, email); - pw = getpwuid(getuid()); - if (!pw) - die("You don't exist. Go away!"); - strlcpy(git_default_name, pw->pw_name, - sizeof(git_default_name)); - name = git_default_name; + pw = xgetpwuid_self(); + name = pw->pw_name; + } + + if (strict && email == git_default_email.buf && + strstr(email, "(none)")) { + fputs(env_hint, stderr); + die("unable to auto-detect email address (got '%s')", email); } - strcpy(date, git_default_date); - if (!name_addr_only && date_str && date_str[0]) { - if (parse_date(date_str, date, sizeof(date)) < 0) - die("invalid date format: %s", date_str); + if (want_date) { + if (date_str && date_str[0]) { + if (parse_date(date_str, date, sizeof(date)) < 0) + die("invalid date format: %s", date_str); + } + else + strcpy(date, ident_default_date()); } - i = copy(buffer, sizeof(buffer), 0, name); - i = add_raw(buffer, sizeof(buffer), i, " <"); - i = copy(buffer, sizeof(buffer), i, email); - if (!name_addr_only) { - i = add_raw(buffer, sizeof(buffer), i, "> "); - i = copy(buffer, sizeof(buffer), i, date); - } else { - i = add_raw(buffer, sizeof(buffer), i, ">"); + strbuf_reset(&ident); + if (want_name) { + strbuf_addstr_without_crud(&ident, name); + strbuf_addstr(&ident, " <"); } - if (i >= sizeof(buffer)) - die("Impossibly long personal identifier"); - buffer[i] = 0; - return buffer; + strbuf_addstr_without_crud(&ident, email); + if (want_name) + strbuf_addch(&ident, '>'); + if (want_date) { + strbuf_addch(&ident, ' '); + strbuf_addstr_without_crud(&ident, date); + } + return ident.buf; } const char *fmt_name(const char *name, const char *email) { - return fmt_ident(name, email, NULL, IDENT_ERROR_ON_NO_NAME | IDENT_NO_DATE); + return fmt_ident(name, email, NULL, IDENT_STRICT | IDENT_NO_DATE); } const char *git_author_info(int flag) @@@ -385,3 -351,26 +351,26 @@@ int user_ident_sufficiently_given(void return (user_ident_explicitly_given == IDENT_ALL_GIVEN); #endif } + + int git_ident_config(const char *var, const char *value, void *data) + { + if (!strcmp(var, "user.name")) { + if (!value) + return config_error_nonbool(var); + strbuf_reset(&git_default_name); + strbuf_addstr(&git_default_name, value); + user_ident_explicitly_given |= IDENT_NAME_GIVEN; + return 0; + } + + if (!strcmp(var, "user.email")) { + if (!value) + return config_error_nonbool(var); + strbuf_reset(&git_default_email); + strbuf_addstr(&git_default_email, value); + user_ident_explicitly_given |= IDENT_MAIL_GIVEN; + return 0; + } + + return 0; + }