This patch adds a command git-id for use on
the command line to see what git will set your id too,
and for use in scripts (git-tag-script) so they can get your git id.
The common code for computing the git-id is moved to ident.c
Fix parse_date to not mind being passed a constant date
to parse.
The code to compute the identifier has been restructured
to at least make a reasonable stab at error handling. The
original version had so many unchecked return values it was
just scary to think about.
Eric
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -47,7 +47,7 @@ PROG= git-update-cache git-diff-files
git-diff-stages git-rev-parse git-patch-id git-pack-objects \
git-unpack-objects git-verify-pack git-receive-pack git-send-pack \
git-prune-packed git-fetch-pack git-upload-pack git-clone-pack \
- git-show-index
+ git-show-index git-id
all: $(PROG)
@@ -57,7 +57,7 @@ install: $(PROG) $(SCRIPTS)
LIB_OBJS=read-cache.o sha1_file.o usage.o object.o commit.o tree.o blob.o \
tag.o date.o index.o diff-delta.o patch-delta.o entry.o path.o \
- epoch.o refs.o csum-file.o pack-check.o pkt-line.o connect.o
+ epoch.o refs.o csum-file.o pack-check.o pkt-line.o connect.o ident.o
LIB_FILE=libgit.a
LIB_H=cache.h object.h blob.h tree.h commit.h tag.h delta.h epoch.h
csum-file.h \
pack.h pkt-line.h refs.h
diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -208,9 +208,14 @@ extern void *read_object_with_reference(
unsigned char *sha1_ret);
const char *show_date(unsigned long time, int timezone);
-void parse_date(char *date, char *buf, int bufsize);
+void parse_date(const char *date, char *buf, int bufsize);
void datestamp(char *buf, int bufsize);
+int git_ident(char *buf, size_t bufsize,
+ const char *env_name, const char *env_email, const char *env_date);
+int git_committer_ident(char *buf, size_t bufsize);
+int git_author_ident(char *buf, size_t bufsize);
+
static inline void *xmalloc(size_t size)
{
void *ret = malloc(size);
diff --git a/commit-tree.c b/commit-tree.c
--- a/commit-tree.c
+++ b/commit-tree.c
@@ -5,9 +5,10 @@
*/
#include "cache.h"
-#include <pwd.h>
#include <time.h>
#include <ctype.h>
+#include <string.h>
+#include <errno.h>
#define BLOCKING (1ul << 14)
@@ -45,39 +46,6 @@ static void add_buffer(char **bufp, unsi
memcpy(buf + size, one_line, len);
}
-static void remove_special(char *p)
-{
- char c;
- char *dst = p, *src = p;
-
- for (;;) {
- c = *src;
- src++;
- switch(c) {
- case '\n': case '<': case '>':
- continue;
- }
- *dst++ = c;
- if (!c)
- break;
- }
-
- /*
- * Go back, and remove crud from the end: some people
- * have commas etc in their gecos field
- */
- dst--;
- while (--dst >= p) {
- unsigned char c = *dst;
- switch (c) {
- case ',': case ';': case '.':
- *dst = 0;
- continue;
- }
- break;
- }
-}
-
static void check_valid(unsigned char *sha1, const char *expect)
{
void *buf;
@@ -114,16 +82,13 @@ static int new_parent(int idx)
int main(int argc, char **argv)
{
- int i, len;
+ int i;
int parents = 0;
unsigned char tree_sha1[20];
unsigned char commit_sha1[20];
- char *gecos, *realgecos, *commitgecos;
- char *email, *commitemail, realemail[1000];
- char date[50], realdate[50];
- char *audate, *cmdate;
+ char committer[1000];
+ char author[1000];
char comment[1000];
- struct passwd *pw;
char *buffer;
unsigned int size;
@@ -142,35 +107,12 @@ int main(int argc, char **argv)
}
if (!parents)
fprintf(stderr, "Committing initial tree %s\n", argv[1]);
- pw = getpwuid(getuid());
- if (!pw)
- die("You don't exist. Go away!");
- realgecos = pw->pw_gecos;
- len = strlen(pw->pw_name);
- memcpy(realemail, pw->pw_name, len);
- realemail[len] = '@';
- gethostname(realemail+len+1, sizeof(realemail)-len-1);
- if (!strchr(realemail+len+1, '.')) {
- strcat(realemail, ".");
- getdomainname(realemail+strlen(realemail),
sizeof(realemail)-strlen(realemail)-1);
+ if (git_author_ident(author, sizeof(author)) < 0) {
+ die("Bad author! %s", strerror(errno));
+ }
+ if (git_committer_ident(committer, sizeof(committer)) < 0) {
+ die("Bad Committer! %s", strerror(errno));
}
-
- datestamp(realdate, sizeof(realdate));
- strcpy(date, realdate);
-
- commitgecos = gitenv("GIT_COMMITTER_NAME") ? : realgecos;
- commitemail = gitenv("GIT_COMMITTER_EMAIL") ? : realemail;
- gecos = gitenv("GIT_AUTHOR_NAME") ? : realgecos;
- email = gitenv("GIT_AUTHOR_EMAIL") ? : realemail;
- audate = gitenv("GIT_AUTHOR_DATE");
- if (audate)
- parse_date(audate, date, sizeof(date));
- cmdate = gitenv("GIT_COMMITTER_DATE");
- if (cmdate)
- parse_date(cmdate, realdate, sizeof(realdate));
-
- remove_special(gecos); remove_special(realgecos);
remove_special(commitgecos);
- remove_special(email); remove_special(realemail);
remove_special(commitemail);
init_buffer(&buffer, &size);
add_buffer(&buffer, &size, "tree %s\n", sha1_to_hex(tree_sha1));
@@ -184,8 +126,8 @@ int main(int argc, char **argv)
add_buffer(&buffer, &size, "parent %s\n",
sha1_to_hex(parent_sha1[i]));
/* Person/date information */
- add_buffer(&buffer, &size, "author %s <%s> %s\n", gecos, email, date);
- add_buffer(&buffer, &size, "committer %s <%s> %s\n\n", commitgecos,
commitemail, realdate);
+ add_buffer(&buffer, &size, "author %s <%s> %s\n", author);
+ add_buffer(&buffer, &size, "committer %s <%s> %s\n\n", committer);
/* And add the comment */
while (fgets(comment, sizeof(comment), stdin) != NULL)
diff --git a/date.c b/date.c
--- a/date.c
+++ b/date.c
@@ -224,7 +224,7 @@ static int is_date(int year, int month,
return 0;
}
-static int match_multi_number(unsigned long num, char c, char *date, char
*end, struct tm *tm)
+static int match_multi_number(unsigned long num, char c, const char *date,
char *end, struct tm *tm)
{
long num2, num3;
@@ -270,7 +270,7 @@ static int match_multi_number(unsigned l
/*
* We've seen a digit. Time? Year? Date?
*/
-static int match_digit(char *date, struct tm *tm, int *offset, int *tm_gmt)
+static int match_digit(const char *date, struct tm *tm, int *offset, int
*tm_gmt)
{
int n;
char *end;
@@ -361,7 +361,7 @@ static int match_digit(char *date, struc
return n;
}
-static int match_tz(char *date, int *offp)
+static int match_tz(const char *date, int *offp)
{
char *end;
int offset = strtoul(date+1, &end, 10);
@@ -388,7 +388,7 @@ static int match_tz(char *date, int *off
/* Gr. strptime is crap for this; it doesn't have a way to require RFC2822
(i.e. English) day/month names, and it doesn't work correctly with %z. */
-void parse_date(char *date, char *result, int maxlen)
+void parse_date(const char *date, char *result, int maxlen)
{
struct tm tm;
int offset, sign, tm_gmt;
diff --git a/git-tag-script b/git-tag-script
--- a/git-tag-script
+++ b/git-tag-script
@@ -7,6 +7,7 @@ name="$1"
object=${2:-$(cat "$GIT_DIR"/HEAD)}
type=$(git-cat-file -t $object) || exit 1
+tagger=$(git-id) || exit 1
( echo "#"
echo "# Write a tag message"
@@ -17,8 +18,9 @@ grep -v '^#' < .editmsg | git-stripspace
[ -s .tagmsg ] || exit
-( echo -e "object $object\ntype $type\ntag $name\n"; cat .tagmsg ) > .tmp-tag
+( echo -e "object $object\ntype $type\ntag $name\ntagger $tagger\n"; cat
.tagmsg ) > .tmp-tag
rm -f .tmp-tag.asc .tagmsg
gpg -bsa .tmp-tag && cat .tmp-tag.asc >> .tmp-tag
+mkdir -p "$GIT_DIR/refs/tags"
git-mktag < .tmp-tag > "$GIT_DIR/refs/tags/$name"
#rm .tmp-tag .tmp-tag.sig
diff --git a/id.c b/id.c
new file mode 100644
--- /dev/null
+++ b/id.c
@@ -0,0 +1,36 @@
+#include "cache.h"
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+
+static char *id_usage = "git-id [--author | --committer]";
+
+int main(int argc, char **argv)
+{
+ char buf[1000];
+ int (*ident)(char *buf, size_t bufsize);
+ int i;
+
+ ident = git_committer_ident;
+ for(i = 1; i < argc; i++) {
+ char *arg = argv[i];
+ if (strcmp(arg, "--author") == 0) {
+ ident = git_author_ident;
+ }
+ else if (strcmp(arg, "--committer") == 0) {
+ ident = git_committer_ident;
+ }
+ else {
+ usage(id_usage);
+ }
+ }
+
+
+ if (ident(buf, sizeof(buf)) < 0) {
+ die("Cannot resolve ident: %s\n", strerror(errno));
+ }
+
+ printf("%s\n", buf);
+
+ return 0;
+}
diff --git a/ident.c b/ident.c
new file mode 100644
--- /dev/null
+++ b/ident.c
@@ -0,0 +1,144 @@
+/*
+ * GIT - The information manager from hell
+ *
+ * Copyright (C) Eric Biederman, 2005
+ */
+#include "cache.h"
+
+#include <pwd.h>
+#include <time.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+
+#define MAX_NAME 1000
+#define MAX_EMAIL 1000
+#define MAX_DATE 50
+static void remove_special(char *p)
+{
+ char c;
+ char *dst = p, *src = p;
+
+ for (;;) {
+ c = *src;
+ src++;
+ switch(c) {
+ case '\n': case '<': case '>':
+ continue;
+ }
+ *dst++ = c;
+ if (!c)
+ break;
+ }
+
+ /*
+ * Go back, and remove crud from the end: some people
+ * have commas etc in their gecos field
+ */
+ dst--;
+ while (--dst >= p) {
+ unsigned char c = *dst;
+ switch (c) {
+ case ',': case ';': case '.':
+ *dst = 0;
+ continue;
+ }
+ break;
+ }
+}
+
+int git_ident(char *buf, size_t bufsize,
+ const char *env_name, const char *env_email, const char *env_date)
+{
+ int len;
+ char name[MAX_NAME];
+ char email[MAX_EMAIL];
+ char date[MAX_DATE];
+ struct passwd *pw;
+ int count;
+
+ /* Lookup the user in the password file */
+ pw = getpwuid(getuid());
+ if (!pw)
+ return -1;
+
+ /* Get the users full name */
+ strncpy(name, pw->pw_gecos, sizeof(name));
+ name[sizeof(name) - 1] = '\0';
+
+ /* Get the email address with error handling */
+ len = strlen(pw->pw_name);
+ if (len >= (sizeof(email) - 2)) {
+ /* Bad user name length */
+ errno = ENOMEM;
+ return -1;
+ }
+ memcpy(email, pw->pw_name, len);
+ email[len] = '@';
+ email[len + 1] = '\0';
+
+ if (gethostname(email+len+1, sizeof(email)-len-1) < 0) {
+ return -1;
+ }
+ email[sizeof(email) - 1] = '\0';
+ len = strlen(email);
+ if (!strchr(email+len+1, '.')) {
+ if (len >= (sizeof(email) - 1)) {
+ errno = ENOMEM;
+ return -1;
+ }
+ email[len] = '.';
+ if (getdomainname(email+len+1, sizeof(email) - len - 1) < 0) {
+ return -1;
+ }
+ }
+ /* Get the date */
+ datestamp(date, sizeof(date));
+
+ if (env_name) {
+ strncpy(name, env_name, sizeof(name));
+ name[sizeof(name) - 1] = '\0';
+ }
+ if (env_email) {
+ strncpy(email, env_email, sizeof(email));
+ email[sizeof(email) - 1] = '\0';
+ }
+ if (env_date) {
+ parse_date(env_date, date, sizeof(date));
+ }
+ remove_special(name);
+ remove_special(email);
+ count = snprintf(buf, bufsize, "%s <%s> %s", name, email, date);
+ if (count > bufsize) {
+ errno = ENOMEM;
+ return -1;
+ }
+ if (count < 0) {
+ return -1;
+ }
+ return 0;
+}
+
+int git_committer_ident(char *buf, size_t bufsize)
+{
+ const char *name;
+ const char *email;
+ const char *date;
+ name = gitenv("GIT_COMMITTER_NAME");
+ email = gitenv("GIT_COMMITTER_EMAIL");
+ date = gitenv("GIT_COMMITTER_DATE");
+ return git_ident(buf, bufsize, name, email, date);
+}
+
+int git_author_ident(char *buf, size_t bufsize)
+{
+ const char *name;
+ const char *email;
+ const char *date;
+ name = gitenv("GIT_AUTHOR_NAME");
+ email = gitenv("GIT_AUTHOR_EMAIL");
+ date = gitenv("GIT_AUTHOR_DATE");
+ return git_ident(buf, bufsize, name, email, date);
+}
+
diff --git a/mktag.c b/mktag.c
--- a/mktag.c
+++ b/mktag.c
@@ -42,7 +42,7 @@ static int verify_tag(char *buffer, unsi
int typelen;
char type[20];
unsigned char sha1[20];
- const char *object, *type_line, *tag_line;
+ const char *object, *type_line, *tag_line, *tagger_line;
if (size < 64 || size > MAXSIZE-1)
return -1;
@@ -92,6 +92,12 @@ static int verify_tag(char *buffer, unsi
return -1;
}
+ /* Verify the tagger line */
+ tagger_line = tag_line;
+
+ if (memcmp(tagger_line, "tagger", 6) || (tagger_line[6] == '\n'))
+ return -1;
+
/* The actual stuff afterwards we don't care about.. */
return 0;
}
@@ -119,7 +125,7 @@ int main(int argc, char **argv)
size += ret;
}
- // Verify it for some basic sanity: it needs to start with "object
<sha1>\ntype "
+ // Verify it for some basic sanity: it needs to start with "object
<sha1>\ntype\ntagger "
if (verify_tag(buffer, size) < 0)
die("invalid tag signature file");
-
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at http://vger.kernel.org/majordomo-info.html