Commit ccb26ccd3c82dc54e1d795a57b4cf901f6ebc1a8

Stefan Sperling 2018-11-05T16:16:35

avoid a call to mktime() in commit graph's add_node()

diff --git a/got/got.c b/got/got.c
index d390e0e..0c2e16f 100644
--- a/got/got.c
+++ b/got/got.c
@@ -318,25 +318,16 @@ print_commit(struct got_commit_object *commit, struct got_object_id *id,
 	const struct got_error *err = NULL;
 	char *id_str, *datestr, *logmsg0, *logmsg, *line;
 	char datebuf[26];
-	time_t author_time, committer_time;
 
 	err = got_object_id_str(&id_str, id);
 	if (err)
 		return err;
 
-	author_time = mktime(&commit->tm_author);
-	committer_time = mktime(&commit->tm_committer);
-#if 0
-	/* This would express the date in committer's timezone. */
-	author_time += commit->tm_author.tm_gmtoff;
-	committer_time += commit->tm_committer.tm_gmtoff;
-#endif
-
 	printf("-----------------------------------------------\n");
 	printf("commit %s\n", id_str);
 	free(id_str);
 	printf("from: %s\n", commit->author);
-	datestr = get_datestr(&committer_time, datebuf);
+	datestr = get_datestr(&commit->committer_time, datebuf);
 	printf("date: %s UTC\n", datestr);
 	if (strcmp(commit->author, commit->committer) != 0)
 		printf("via: %s\n", commit->committer);
diff --git a/include/got_object.h b/include/got_object.h
index 43f6b03..6a7f144 100644
--- a/include/got_object.h
+++ b/include/got_object.h
@@ -49,9 +49,11 @@ struct got_commit_object {
 	unsigned int nparents;
 	struct got_object_id_queue parent_ids;
 	char *author;
-	struct tm tm_author;	/* UTC */
+	time_t author_time;	/* UTC */
+	time_t author_gmtoff;
 	char *committer;
-	struct tm tm_committer;	/* UTC */
+	time_t committer_time;	/* UTC */
+	time_t committer_gmtoff;
 	char *logmsg;
 
 	int refcnt; /* for internal use only */
diff --git a/lib/commit_graph.c b/lib/commit_graph.c
index d0e80bc..ea37d8d 100644
--- a/lib/commit_graph.c
+++ b/lib/commit_graph.c
@@ -429,7 +429,7 @@ add_node(struct got_commit_graph_node **new_node,
 		}
 	}
 
-	node->commit_timestamp = mktime(&commit->tm_committer);
+	node->commit_timestamp = commit->committer_time;
 	if (node->commit_timestamp == -1) {
 		free_node(node);
 		return got_error_from_errno();
diff --git a/lib/diff.c b/lib/diff.c
index 66dfd03..23f25d0 100644
--- a/lib/diff.c
+++ b/lib/diff.c
@@ -594,7 +594,6 @@ got_diff_objects_as_commits(struct got_object *obj1, struct got_object *obj2,
 	struct got_object *tree_obj1  = NULL, *tree_obj2 = NULL;
 	char *id_str;
 	char datebuf[26];
-	time_t time;
 
 	if (obj2 == NULL)
 		return got_error(GOT_ERR_NO_OBJ);
@@ -627,9 +626,8 @@ got_diff_objects_as_commits(struct got_object *obj1, struct got_object *obj2,
 		err = got_error_from_errno();
 		goto done;
 	}
-	time = mktime(&commit2->tm_committer);
 	if (fprintf(outfile, "date: %s UTC\n",
-	    get_datestr(&time, datebuf)) < 0) {
+	    get_datestr(&commit2->committer_time, datebuf)) < 0) {
 		err = got_error_from_errno();
 		goto done;
 	}
diff --git a/lib/got_lib_privsep.h b/lib/got_lib_privsep.h
index b39f11f..091c052 100644
--- a/lib/got_lib_privsep.h
+++ b/lib/got_lib_privsep.h
@@ -124,9 +124,11 @@ struct got_imsg_object {
 struct got_imsg_commit_object {
 	uint8_t tree_id[SHA1_DIGEST_LENGTH];
 	size_t author_len;
-	struct tm tm_author;
+	time_t author_time;
+	time_t author_gmtoff;
 	size_t committer_len;
-	struct tm tm_committer;
+	time_t committer_time;
+	time_t committer_gmtoff;
 	size_t logmsg_len;
 	int nparents;
 
diff --git a/lib/object_parse.c b/lib/object_parse.c
index 07d5265..a36f34a 100644
--- a/lib/object_parse.c
+++ b/lib/object_parse.c
@@ -187,13 +187,11 @@ parse_gmtoff(time_t *gmtoff, const char *tzstr)
 }
 
 static const struct got_error *
-parse_commit_time(struct tm *tm, char *committer)
+parse_commit_time(time_t *time, time_t *gmtoff, char *committer)
 {
 	const struct got_error *err = NULL;
 	const char *errstr;
 	char *space, *tzstr;
-	time_t gmtoff;
-	time_t time;
 
 	/* Parse and strip off trailing timezone indicator string. */
 	space = strrchr(committer, ' ');
@@ -202,7 +200,7 @@ parse_commit_time(struct tm *tm, char *committer)
 	tzstr = strdup(space + 1);
 	if (tzstr == NULL)
 		return got_error_from_errno();
-	err = parse_gmtoff(&gmtoff, tzstr);
+	err = parse_gmtoff(gmtoff, tzstr);
 	free(tzstr);
 	if (err)
 		return err;
@@ -214,16 +212,12 @@ parse_commit_time(struct tm *tm, char *committer)
 		return got_error(GOT_ERR_BAD_OBJ_DATA);
 
 	/* Timestamp parsed here is expressed in comitter's local time. */
-	time = strtonum(space + 1, 0, INT64_MAX, &errstr);
+	*time = strtonum(space + 1, 0, INT64_MAX, &errstr);
 	if (errstr)
 		return got_error(GOT_ERR_BAD_OBJ_DATA);
 
 	/* Express the time stamp in UTC. */
-	memset(tm, 0, sizeof(*tm));
-	time -= gmtoff;
-	if (localtime_r(&time, tm) == NULL)
-		return got_error_from_errno();
-	tm->tm_gmtoff = gmtoff;
+	*time -= *gmtoff;
 
 	/* Strip off parsed time information, leaving just author and email. */
 	*space = '\0';
@@ -320,7 +314,8 @@ got_object_parse_commit(struct got_commit_object **commit, char *buf, size_t len
 		}
 		*p = '\0';
 		slen = strlen(s);
-		err = parse_commit_time(&(*commit)->tm_author, s);
+		err = parse_commit_time(&(*commit)->author_time,
+		    &(*commit)->author_gmtoff, s);
 		if (err)
 			goto done;
 		(*commit)->author = strdup(s);
@@ -350,7 +345,8 @@ got_object_parse_commit(struct got_commit_object **commit, char *buf, size_t len
 		}
 		*p = '\0';
 		slen = strlen(s);
-		err = parse_commit_time(&(*commit)->tm_committer, s);
+		err = parse_commit_time(&(*commit)->committer_time,
+		    &(*commit)->committer_gmtoff, s);
 		if (err)
 			goto done;
 		(*commit)->committer = strdup(s);
diff --git a/lib/privsep.c b/lib/privsep.c
index 2429a94..9f128d5 100644
--- a/lib/privsep.c
+++ b/lib/privsep.c
@@ -414,11 +414,11 @@ got_privsep_send_commit(struct imsgbuf *ibuf, struct got_commit_object *commit)
 
 	memcpy(icommit.tree_id, commit->tree_id->sha1, sizeof(icommit.tree_id));
 	icommit.author_len = strlen(commit->author);
-	memcpy(&icommit.tm_author, &commit->tm_author,
-	    sizeof(icommit.tm_author));
+	icommit.author_time = commit->author_time;
+	icommit.author_gmtoff = commit->author_gmtoff;
 	icommit.committer_len = strlen(commit->committer);
-	memcpy(&icommit.tm_committer, &commit->tm_committer,
-	    sizeof(icommit.tm_committer));
+	icommit.committer_time = commit->committer_time;
+	icommit.committer_gmtoff = commit->committer_gmtoff;
 	icommit.logmsg_len = logmsg_len;
 	icommit.nparents = commit->nparents;
 
@@ -512,10 +512,10 @@ got_privsep_recv_commit(struct got_commit_object **commit, struct imsgbuf *ibuf)
 
 		memcpy((*commit)->tree_id->sha1, icommit.tree_id,
 		    SHA1_DIGEST_LENGTH);
-		memcpy(&(*commit)->tm_author, &icommit.tm_author,
-		    sizeof((*commit)->tm_author));
-		memcpy(&(*commit)->tm_committer, &icommit.tm_committer,
-		    sizeof((*commit)->tm_committer));
+		(*commit)->author_time = icommit.author_time;
+		(*commit)->author_gmtoff = icommit.author_gmtoff;
+		(*commit)->committer_time = icommit.committer_time;
+		(*commit)->committer_gmtoff = icommit.committer_gmtoff;
 
 		if (icommit.author_len == 0) {
 			(*commit)->author = strdup("");
diff --git a/tog/tog.c b/tog/tog.c
index fed6db7..659b2d4 100644
--- a/tog/tog.c
+++ b/tog/tog.c
@@ -874,9 +874,12 @@ draw_commit(struct tog_view *view, struct got_commit_object *commit,
 	static const size_t date_display_cols = 9;
 	static const size_t author_display_cols = 16;
 	const int avail = view->ncols;
+	struct tm tm;
 
-	if (strftime(datebuf, sizeof(datebuf), "%g/%m/%d ",
-	    &commit->tm_committer) >= sizeof(datebuf))
+	if (localtime_r(&commit->committer_time, &tm) == NULL)
+		return got_error_from_errno();
+	if (strftime(datebuf, sizeof(datebuf), "%g/%m/%d ", &tm)
+	    >= sizeof(datebuf))
 		return got_error(GOT_ERR_NO_SPACE);
 
 	if (avail < date_display_cols)