Merge branch 'jc/hash-object' into maint

"hash-object --literally" introduced in v2.2 was not prepared to
take a really long object type name.

* jc/hash-object:
  write_sha1_file(): do not use a separate sha1[] array
  t1007: add hash-object --literally tests
  hash-object --literally: fix buffer overrun with extra-long object type
  git-hash-object.txt: document --literally option
This commit is contained in:
Junio C Hamano 2015-05-26 13:49:24 -07:00
commit 1e6c8babf8
5 changed files with 43 additions and 9 deletions

View File

@ -9,7 +9,7 @@ git-hash-object - Compute object ID and optionally creates a blob from a file
SYNOPSIS SYNOPSIS
-------- --------
[verse] [verse]
'git hash-object' [-t <type>] [-w] [--path=<file>|--no-filters] [--stdin] [--] <file>... 'git hash-object' [-t <type>] [-w] [--path=<file>|--no-filters] [--stdin [--literally]] [--] <file>...
'git hash-object' [-t <type>] [-w] --stdin-paths [--no-filters] < <list-of-paths> 'git hash-object' [-t <type>] [-w] --stdin-paths [--no-filters] < <list-of-paths>
DESCRIPTION DESCRIPTION
@ -51,7 +51,13 @@ OPTIONS
Hash the contents as is, ignoring any input filter that would Hash the contents as is, ignoring any input filter that would
have been chosen by the attributes mechanism, including the end-of-line have been chosen by the attributes mechanism, including the end-of-line
conversion. If the file is read from standard input then this conversion. If the file is read from standard input then this
is always implied, unless the --path option is given. is always implied, unless the `--path` option is given.
--literally::
Allow `--stdin` to hash any garbage into a loose object which might not
otherwise pass standard object parsing or git-fsck checks. Useful for
stress-testing Git itself or reproducing characteristics of corrupt or
bogus objects encountered in the wild.
GIT GIT
--- ---

View File

@ -22,10 +22,8 @@ static int hash_literally(unsigned char *sha1, int fd, const char *type, unsigne
if (strbuf_read(&buf, fd, 4096) < 0) if (strbuf_read(&buf, fd, 4096) < 0)
ret = -1; ret = -1;
else if (flags & HASH_WRITE_OBJECT)
ret = write_sha1_file(buf.buf, buf.len, type, sha1);
else else
ret = hash_sha1_file(buf.buf, buf.len, type, sha1); ret = hash_sha1_file_literally(buf.buf, buf.len, type, sha1, flags);
strbuf_release(&buf); strbuf_release(&buf);
return ret; return ret;
} }

View File

@ -874,6 +874,7 @@ static inline const unsigned char *lookup_replace_object_extended(const unsigned
extern int sha1_object_info(const unsigned char *, unsigned long *); extern int sha1_object_info(const unsigned char *, unsigned long *);
extern int hash_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *sha1); extern int hash_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *sha1);
extern int write_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *return_sha1); extern int write_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *return_sha1);
extern int hash_sha1_file_literally(const void *buf, unsigned long len, const char *type, unsigned char *sha1, unsigned flags);
extern int pretend_sha1_file(void *, unsigned long, enum object_type, unsigned char *); extern int pretend_sha1_file(void *, unsigned long, enum object_type, unsigned char *);
extern int force_object_loose(const unsigned char *sha1, time_t mtime); extern int force_object_loose(const unsigned char *sha1, time_t mtime);
extern int git_open_noatime(const char *name); extern int git_open_noatime(const char *name);

View File

@ -3009,9 +3009,8 @@ static int freshen_packed_object(const unsigned char *sha1)
return 1; return 1;
} }
int write_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *returnsha1) int write_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *sha1)
{ {
unsigned char sha1[20];
char hdr[32]; char hdr[32];
int hdrlen; int hdrlen;
@ -3019,13 +3018,32 @@ int write_sha1_file(const void *buf, unsigned long len, const char *type, unsign
* it out into .git/objects/??/?{38} file. * it out into .git/objects/??/?{38} file.
*/ */
write_sha1_file_prepare(buf, len, type, sha1, hdr, &hdrlen); write_sha1_file_prepare(buf, len, type, sha1, hdr, &hdrlen);
if (returnsha1)
hashcpy(returnsha1, sha1);
if (freshen_packed_object(sha1) || freshen_loose_object(sha1)) if (freshen_packed_object(sha1) || freshen_loose_object(sha1))
return 0; return 0;
return write_loose_object(sha1, hdr, hdrlen, buf, len, 0); return write_loose_object(sha1, hdr, hdrlen, buf, len, 0);
} }
int hash_sha1_file_literally(const void *buf, unsigned long len, const char *type,
unsigned char *sha1, unsigned flags)
{
char *header;
int hdrlen, status = 0;
/* type string, SP, %lu of the length plus NUL must fit this */
header = xmalloc(strlen(type) + 32);
write_sha1_file_prepare(buf, len, type, sha1, header, &hdrlen);
if (!(flags & HASH_WRITE_OBJECT))
goto cleanup;
if (freshen_packed_object(sha1) || freshen_loose_object(sha1))
goto cleanup;
status = write_loose_object(sha1, header, hdrlen, buf, len, 0);
cleanup:
free(header);
return status;
}
int force_object_loose(const unsigned char *sha1, time_t mtime) int force_object_loose(const unsigned char *sha1, time_t mtime)
{ {
void *buf; void *buf;

View File

@ -209,4 +209,15 @@ test_expect_success 'hash-object complains about truncated type name' '
test_must_fail git hash-object -t bl --stdin </dev/null test_must_fail git hash-object -t bl --stdin </dev/null
' '
test_expect_success '--literally' '
t=1234567890 &&
echo example | git hash-object -t $t --literally --stdin
'
test_expect_success '--literally with extra-long type' '
t=12345678901234567890123456789012345678901234567890 &&
t="$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t" &&
echo example | git hash-object -t $t --literally --stdin
'
test_done test_done