From: Karthik Nayak <karthik.188@gmail.com>
To: git@vger.kernel.org
Cc: gitster@pobox.com, sunshine@sunshineco.com,
Karthik Nayak <karthik.188@gmail.com>
Subject: [PATCH v7 1/4] sha1_file.c: support reading from a loose object of unknown type
Date: Sun, 5 Apr 2015 23:58:25 +0530 [thread overview]
Message-ID: <1428258505-25223-1-git-send-email-karthik.188@gmail.com> (raw)
In-Reply-To: <1428126162-18987-1-git-send-email-karthik.188@gmail.com>
Update sha1_loose_object_info() to optionally allow it to read
from a loose object file of unknown/bogus type; as the function
usually returns the type of the object it read in the form of enum
for known types, add an optional "typename" field to receive the
name of the type in textual form and a flag to indicate the reading
of a loose object file of unknown/bogus type.
Add parse_sha1_header_extended() which acts as a wrapper around
parse_sha1_header() allowing more information to be obtained.
Add unpack_sha1_header_to_strbuf() to unpack sha1 headers of
unknown/corrupt objects which have a unknown sha1 header size to
a strbuf structure. This was written by Junio C Hamano but tested
by me.
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Eric Sunshine <sunshine@sunshineco.com>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
cache.h | 2 ++
sha1_file.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++++------------
2 files changed, 94 insertions(+), 22 deletions(-)
diff --git a/cache.h b/cache.h
index c47323e..ea6faf0 100644
--- a/cache.h
+++ b/cache.h
@@ -881,6 +881,7 @@ extern int is_ntfs_dotgit(const char *name);
/* object replacement */
#define LOOKUP_REPLACE_OBJECT 1
+#define LOOKUP_LITERALLY 2
extern void *read_sha1_file_extended(const unsigned char *sha1, enum object_type *type, unsigned long *size, unsigned flag);
static inline void *read_sha1_file(const unsigned char *sha1, enum object_type *type, unsigned long *size)
{
@@ -1349,6 +1350,7 @@ struct object_info {
unsigned long *sizep;
unsigned long *disk_sizep;
unsigned char *delta_base_sha1;
+ struct strbuf *typename;
/* Response */
enum {
diff --git a/sha1_file.c b/sha1_file.c
index 980ce6b..ac8fffc 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -1564,6 +1564,34 @@ int unpack_sha1_header(git_zstream *stream, unsigned char *map, unsigned long ma
return git_inflate(stream, 0);
}
+static int unpack_sha1_header_to_strbuf(git_zstream *stream, unsigned char *map,
+ unsigned long mapsize,
+ struct strbuf *header)
+{
+ unsigned char buffer[32], *cp;
+ unsigned long bufsiz = sizeof(buffer);
+ int status;
+
+ status = unpack_sha1_header(stream, map, mapsize, buffer, bufsiz);
+
+ if (status) {
+ strbuf_add(header, buffer, stream->next_out - buffer);
+ return status;
+ }
+
+ do {
+ status = git_inflate(stream, 0);
+ strbuf_add(header, buffer, stream->next_out - buffer);
+ for (cp = buffer; cp < stream->next_out; cp++)
+ if (!*cp)
+ /* Found the NUL at the end of the header */
+ return 0;
+ stream->next_out = buffer;
+ stream->avail_out = bufsiz;
+ } while (status != Z_STREAM_END);
+ return -1;
+}
+
static void *unpack_sha1_rest(git_zstream *stream, void *buffer, unsigned long size, const unsigned char *sha1)
{
int bytes = strlen(buffer) + 1;
@@ -1614,27 +1642,24 @@ static void *unpack_sha1_rest(git_zstream *stream, void *buffer, unsigned long s
* too permissive for what we want to check. So do an anal
* object header parse by hand.
*/
-int parse_sha1_header(const char *hdr, unsigned long *sizep)
+int parse_sha1_header_extended(const char *hdr, struct object_info *oi,
+ unsigned int flags)
{
- char type[10];
- int i;
+ struct strbuf typename = STRBUF_INIT;
unsigned long size;
+ int type;
/*
* The type can be at most ten bytes (including the
* terminating '\0' that we add), and is followed by
* a space.
*/
- i = 0;
for (;;) {
char c = *hdr++;
if (c == ' ')
break;
- type[i++] = c;
- if (i >= sizeof(type))
- return -1;
+ strbuf_addch(&typename, c);
}
- type[i] = 0;
/*
* The length must follow immediately, and be in canonical
@@ -1652,12 +1677,39 @@ int parse_sha1_header(const char *hdr, unsigned long *sizep)
size = size * 10 + c;
}
}
- *sizep = size;
+
+ type = type_from_string_gently(typename.buf, typename.len, 1);
+ if (oi->sizep)
+ *oi->sizep = size;
+ if (oi->typename)
+ strbuf_addbuf(oi->typename, &typename);
+ strbuf_release(&typename);
/*
+ * Set type to 0 if its an unknown object and
+ * we're obtaining the type using '--literally'
+ * option.
+ */
+ if ((flags & LOOKUP_LITERALLY) && (type == -1))
+ type = 0;
+ else if (type == -1)
+ die("invalid object type");
+ if (oi->typep)
+ *oi->typep = type;
+ /*
* The length must be followed by a zero byte
*/
- return *hdr ? -1 : type_from_string(type);
+ return *hdr ? -1 : type;
+}
+
+int parse_sha1_header(const char *hdr, unsigned long *sizep)
+{
+ struct object_info oi;
+
+ oi.sizep = sizep;
+ oi.typename = NULL;
+ oi.typep = NULL;
+ return parse_sha1_header_extended(hdr, &oi, LOOKUP_REPLACE_OBJECT);
}
static void *unpack_sha1_file(void *map, unsigned long mapsize, enum object_type *type, unsigned long *size, const unsigned char *sha1)
@@ -2522,13 +2574,15 @@ struct packed_git *find_sha1_pack(const unsigned char *sha1,
}
static int sha1_loose_object_info(const unsigned char *sha1,
- struct object_info *oi)
+ struct object_info *oi,
+ int flags)
{
- int status;
- unsigned long mapsize, size;
+ int status = 0;
+ unsigned long mapsize;
void *map;
git_zstream stream;
char hdr[32];
+ struct strbuf hdrbuf = STRBUF_INIT;
if (oi->delta_base_sha1)
hashclr(oi->delta_base_sha1);
@@ -2555,17 +2609,26 @@ static int sha1_loose_object_info(const unsigned char *sha1,
return -1;
if (oi->disk_sizep)
*oi->disk_sizep = mapsize;
- if (unpack_sha1_header(&stream, map, mapsize, hdr, sizeof(hdr)) < 0)
- status = error("unable to unpack %s header",
- sha1_to_hex(sha1));
- else if ((status = parse_sha1_header(hdr, &size)) < 0)
- status = error("unable to parse %s header", sha1_to_hex(sha1));
- else if (oi->sizep)
- *oi->sizep = size;
+ if ((flags & LOOKUP_LITERALLY)) {
+ if (unpack_sha1_header_to_strbuf(&stream, map, mapsize, &hdrbuf) < 0)
+ status = error("unable to unpack %s header with --literally",
+ sha1_to_hex(sha1));
+ else if ((status = parse_sha1_header_extended(hdrbuf.buf, oi, flags)) < 0)
+ status = error("unable to parse %s header with --literally",
+ sha1_to_hex(sha1));
+ } else {
+ if (unpack_sha1_header(&stream, map, mapsize, hdr, sizeof(hdr)) < 0)
+ status = error("unable to unpack %s header",
+ sha1_to_hex(sha1));
+ else if ((status = parse_sha1_header_extended(hdr, oi, flags)) < 0)
+ status = error("unable to parse %s header", sha1_to_hex(sha1));
+ }
git_inflate_end(&stream);
munmap(map, mapsize);
- if (oi->typep)
+ if (status && oi->typep)
*oi->typep = status;
+ if (hdrbuf.buf)
+ strbuf_release(&hdrbuf);
return 0;
}
@@ -2576,6 +2639,9 @@ int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi,
int rtype;
const unsigned char *real = lookup_replace_object_extended(sha1, flags);
+ if (oi->typename && !oi->typep)
+ die("object_info: cannot use typename without typep");
+
co = find_cached_object(real);
if (co) {
if (oi->typep)
@@ -2586,13 +2652,15 @@ int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi,
*(oi->disk_sizep) = 0;
if (oi->delta_base_sha1)
hashclr(oi->delta_base_sha1);
+ if (oi->typename)
+ strbuf_addstr(oi->typename, typename(co->type));
oi->whence = OI_CACHED;
return 0;
}
if (!find_pack_entry(real, &e)) {
/* Most likely it's a loose object. */
- if (!sha1_loose_object_info(real, oi)) {
+ if (!sha1_loose_object_info(real, oi, flags)) {
oi->whence = OI_LOOSE;
return 0;
}
@@ -2616,6 +2684,8 @@ int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi,
oi->u.packed.is_delta = (rtype == OBJ_REF_DELTA ||
rtype == OBJ_OFS_DELTA);
}
+ if (oi->typename)
+ strbuf_addstr(oi->typename, typename(*oi->typep));
return 0;
}
--
2.4.0.rc1.249.g9f2ee54
next prev parent reply other threads:[~2015-04-05 18:28 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-04-04 5:41 [PATCH v7 0/4] cat-file: teach cat-file a '--literally' option karthik nayak
2015-04-04 5:42 ` [PATCH v7 1/4] sha1_file.c: support reading from a loose object of unknown type Karthik Nayak
2015-04-04 19:34 ` Junio C Hamano
2015-04-04 19:53 ` karthik nayak
2015-04-05 7:46 ` Junio C Hamano
2015-04-05 7:52 ` karthik nayak
2015-04-05 19:57 ` Junio C Hamano
2015-04-07 10:34 ` karthik nayak
2015-04-05 18:28 ` Karthik Nayak [this message]
2015-04-07 20:46 ` Eric Sunshine
2015-04-04 5:44 ` [PATCH v7 2/4] cat-file: teach cat-file a '--literally' option Karthik Nayak
2015-04-07 20:49 ` Eric Sunshine
2015-04-04 5:44 ` [PATCH v7 3/4] cat-file: add documentation for " Karthik Nayak
2015-04-07 20:49 ` Eric Sunshine
2015-04-04 5:44 ` [PATCH v7 4/4] t1006: add tests for git cat-file --literally Karthik Nayak
2015-04-07 20:49 ` Eric Sunshine
2015-04-08 17:42 ` karthik nayak
2015-04-08 20:34 ` Eric Sunshine
2015-04-09 3:24 ` Karthik Nayak
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1428258505-25223-1-git-send-email-karthik.188@gmail.com \
--to=karthik.188@gmail.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=sunshine@sunshineco.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).