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

Reply via email to