git的write-tree
命令的执行入口main
(write-tree.c):
30 #define ORIG_OFFSET (40) /* Enough space to add the header of "tree <size>\0" */
31
32 int main(int argc, char **argv)
33 {
34 unsigned long size, offset, val;
35 int i, entries = read_cache();
36 char *buffer;
37
38 if (entries <= 0) {
39 fprintf(stderr, "No file-cache to create a tree of\n");
40 exit(1);
41 }
42
43 /* Guess at an initial size */
44 size = entries * 40 + 400;
45 buffer = malloc(size);
46 offset = ORIG_OFFSET;
47
48 for (i = 0; i < entries; i++) {
49 struct cache_entry *ce = active_cache[i];
50 if (check_valid_sha1(ce->sha1) < 0)
51 exit(1);
52 if (offset + ce->namelen + 60 > size) {
53 size = alloc_nr(offset + ce->namelen + 60);
54 buffer = realloc(buffer, size);
55 }
56 offset += sprintf(buffer + offset, "%o %s", ce->st_mode, ce->name);
57 buffer[offset++] = 0;
58 memcpy(buffer + offset, ce->sha1, 20);
59 offset += 20;
60 }
61
62 i = prepend_integer(buffer, offset - ORIG_OFFSET, ORIG_OFFSET);
63 i -= 5;
64 memcpy(buffer+i, "tree ", 5);
65
66 buffer += i;
67 offset -= i;
68
69 write_sha1_file(buffer, offset);
70 return 0;
71 }
git的write-tree命令把cache区域中当前信息保存下来, 相当于快照功能.Line35:41获取当前cache区域的信息,如果cache区域为空,视为错误,直接返回. Line43:46动态分配一个预估的内存空间buffer
,用来保存cache相关信息.Line48:60循环遍历active_cache
中元素,将元素相关信息写入分配的地址空间,对于每个cache_entry
对象,保存了文件模式,文件名和文件内容的sha1.Line50调用函数check_valid_sha1
校验cache_entry
对象对应的文件,该函数的实现为(write-tree.c):
8 static int check_valid_sha1(unsigned char *sha1)
9 {
10 char *filename = sha1_file_name(sha1);
11 int ret;
12
13 /* If we were anal, we'd check that the sha1 of the contents actually matches */
14 ret = access(filename, R_OK);
15 if (ret)
16 perror(filename);
17 return ret;
18 }
Line10调用函数sha1_file_name
获得该sha1对应的文件名.Line14通过系统调用access
来测试文件是否可读.严格来讲,应该读取文件内容,校验文件内容的sha1.
回到函数main
,Line52:55如果之前分配的动态内存空间不足,不能再容纳cache_entry
对象信息,则进行动态空间扩容.Line56:59将cache_entry
对象的文件模式,文件名以及文件内容的sha1写入buffer.注意动态内存buffer
头部预留了ORIG_OFFSET
字节用来存储元数据.元数据包括类型字符串(这里是tree
)和写入的cache信息大小.Line62调用函数prepend_integer
将cache信息大小写入buffer.该函数的实现为(write-tree.c):
20 static int prepend_integer(char *buffer, unsigned val, int i)
21 {
22 buffer[--i] = '\0';
23 do {
24 buffer[--i] = '0' + (val % 10);
25 val /= 10;
26 } while (val);
27 return i;
28 }
这个函数需要注意的两点是:val
值是以字符的形式写入buffer的,写入buffer时,是从后往前写入的.该函数返回buffer头部空闲字节的长度.
回到函数main
,Line63:64将buffer头部空闲字节长度减少5,用来写入类型字符串.同样是写在buffer预留空间的尾部.Line66:67将buffer指针指向有效数据的起始位置,同时更新有效数据的长度.Line69调用函数write_sha1_file
将cache快照信息写入文件对象.