int main(int argc, char **argv)
{
unsigned char sha1[20];
if (argc != 3 || get_sha1_hex(argv[2], sha1))
usage("cat-file: cat-file [-t | tagname(blob/tree/commit)] <sha1>");
// get file type(blob/tree/commit), content size and content
buf = read_sha1_file(sha1, type, &size);
map = map_sha1_file(sha1, &mapsize);
char *filename = sha1_file_name(sha1);
int fd = open(filename, O_RDONLY);
fstat(fd, &st);
map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
*mapsize = st.st_size;
return map;
buf = unpack_sha1_file(map, mapsize, type, size);
char buffer[8192];
stream.next_in = map;
stream.avail_in = mapsize;
stream.next_out = buffer;
stream.avail_out = sizeof(buffer);
inflate(&stream, 0);
// buffer: "blob %lu\0xxx"
// buffer: "tree %lu\0%o %s\0sha1%o %s\0sha1...%o %s\0sha1"
// buffer: "commit %lu\0tree %s\nparent %s\n..parent %s\nauthor %s <%s> %s\ncommitter %s <%s> %s\n\n%s"
sscanf(buffer, "%10s %lu", type, size);
bytes = strlen(buffer) + 1;
buf = malloc(*size);
memcpy(buf, buffer + bytes, stream.total_out - bytes);
// buf: "xxx"
// buf: "%o %s\0sha1%o %s\0sha1...%o %s\0sha1"
// buf: "tree %s\nparent %s\n..parent %s\nauthor %s <%s> %s\ncommitter %s <%s> %s\n\n%s"
return buf;
while (size > 0)
long ret = write(1, buf, size); // why file handle is 1, stdout??
size -= ret;
buf += ret;
}
1. buf = read_sha1_file(sha1, type, &size); # 读取sha1文件类型,大小和内容数据
void * read_sha1_file(unsigned char *sha1, char *type, unsigned long *size)
{
z_stream stream;
char buffer[8192];
struct stat st;
int i, fd, ret, bytes;
void *map, *buf;
char *filename = sha1_file_name(sha1);
fd = open(filename, O_RDONLY);
if (fd < 0) {
perror(filename);
return NULL;
}
if (fstat(fd, &st) < 0) {
close(fd);
return NULL;
}
map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
close(fd);
if (-1 == (int)(long)map)
return NULL;
/* Get the data stream */
memset(&stream, 0, sizeof(stream));
stream.next_in = map;
stream.avail_in = st.st_size;
stream.next_out = buffer;
stream.avail_out = sizeof(buffer);
inflateInit(&stream);
ret = inflate(&stream, 0);
if (sscanf(buffer, "%10s %lu", type, size) != 2)
return NULL;
bytes = strlen(buffer) + 1;
buf = malloc(*size);
if (!buf)
return NULL;
memcpy(buf, buffer + bytes, stream.total_out - bytes);
bytes = stream.total_out - bytes;
if (bytes < *size && ret == Z_OK) {
stream.next_out = buf + bytes;
stream.avail_out = *size - bytes;
while (inflate(&stream, Z_FINISH) == Z_OK)
/* nothing */;
}
inflateEnd(&stream);
return buf;
}
1.1 char *filename = sha1_file_name(sha1); # 根据hash值生成.dircache/objects/xx/xx..xx(38位)
1.2 map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); # sha1文件内容映射到内存
1.3 将文件中读取的压缩数据解压,从解压数据中读取类型和大小,返回解压数据
2. fd = mkstemp(template); # 创建唯一的临时文件
3. write(fd, buf, size); # 将解压数据写入临时文件