git 源码解析(二)update-catch

update-catch.c 作用类似于以后的 git add f1 f2 ...

1. 从.dircache/index文件中读取所有的已存储的文件对应的catch_entry信息到内存列表中

2. 对于新文件:

    I. 将文件内容压缩

    II. 对压缩数据取SHA1值作为文件名

    III. 将压缩数据写入到文件

    IV. 添加新catch_entry到内存列表

3. 对于更新文件:

    I. 将文件内容压缩

    II. 对压缩数据取SHA1值作为文件名

    III. 将压缩数据写入到文件

    IV. 更新catch_entry到内存列表

4. 对于删除文件:

    I. 从内存列表中删除catch_entry

5. 将内存列表信息写入到.dircache/index.lock文件,重命名为.dircache/index

 

首先介绍几个关键的数据结构和宏定义

cache_entry: 用于保存每个源数据文件信息

cache_header: 用于保存索引信息

cache_entry_size:

ce_size:

struct cache_time {
	unsigned int sec;
	unsigned int nsec;
};

struct cache_entry {
	struct cache_time ctime;
	struct cache_time mtime;
	unsigned int st_dev;
	unsigned int st_ino;
	unsigned int st_mode;
	unsigned int st_uid;
	unsigned int st_gid;
	unsigned int st_size;
	unsigned char sha1[20];
	unsigned short namelen;
	unsigned char name[0];
};

#define CACHE_SIGNATURE 0x44495243
struct cache_header {
	unsigned int signature;
	unsigned int version;
	unsigned int entries;
	unsigned char sha1[20];
};

#define cache_entry_size(len) ((offsetof(struct cache_entry,name) + (len) + 8) & ~7)
#define ce_size(ce) cache_entry_size((ce)->namelen)
int main(int argc, char **argv)
{
    entries = read_cache(); // 从.dircache/index文件读取已保存的catch_entry信息,载入到内存
        fd = open(".dircache/index", O_RDONLY);
        fstat(fd, &st);
        size = st.st_size;
        map = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); // 映射文件内容到内存
        hdr = map;
        verify_hdr(hdr, size); // 校验cache_header中字段signature/version/sha1
            // 首先校验cache_header中signature字段和version字段
            // 然后取文件中cache_header前三个字段和所有cache_entry数据的hash值
            // 最后将此hash值与cache_header中sha1字段校验
            SHA1_Update(&c, hdr, offsetof(struct cache_header, sha1));
            SHA1_Update(&c, hdr+1, size - sizeof(*hdr));
            memcmp(sha1, hdr->sha1, 20);
        active_nr = hdr->entries; // 将.dircache/index中保存的cache_entry个数读入内存
        active_alloc = alloc_nr(active_nr);
        active_cache = calloc(active_alloc, sizeof(struct cache_entry *));
        offset = sizeof(*hdr);
        for (i = 0; i < hdr->entries; i++) // 将每个cache_entry地址值读入指针数组
            struct cache_entry *ce = map + offset;
            offset = offset + ce_size(ce);
            active_cache[i] = ce;
        return active_nr;
    newfd = open(".dircache/index.lock", O_RDWR | O_CREAT | O_EXCL, 0600);
    for (i = 1 ; i < argc; i++)
        char *path = argv[i];
        // 处理每一个源数据文件,创建并写入压缩数据到对应的sha1文件
        // 然后将catch_entry信息插入到catch_entry列表中
        add_file_to_cache(path)
            fd = open(path, O_RDONLY);
            if (errno == ENOENT)
                // 如果源文件的修改是被删除,则从cache_entry列表中删除
                return remove_file_from_cache(path);
                    // 根据文件路径名查找在cache_entry列表中的索引位置
                    // cache_entry列表按照路径名升序排列,通过二分法查找
                    int pos = cache_name_pos(path, strlen(path));
                    active_nr--;
                    // 将cache_entry列表中从待删除到最后的所有catch_entry向前移动一个位置
                    memmove(active_cache + pos, active_cache + pos + 1,
                               (active_nr - pos - 1) * sizeof(struct cache_entry *));
            fstat(fd, &st);
            namelen = strlen(path);
            size = cache_entry_size(namelen); // 分配catch_entry空间,填充除sha1外其它字段
            ce = malloc(size);
            ce->ctime.sec = st.st_ctime;
            ce->ctime.nsec = st.st_ctim.tv_nsec;
            ce->mtime.sec = st.st_mtime;
            ce->mtime.nsec = st.st_mtim.tv_nsec;
            ce->st_dev = st.st_dev;
            ce->st_ino = st.st_ino;
            ce->st_mode = st.st_mode;
            ce->st_uid = st.st_uid;
            ce->st_gid = st.st_gid;
            ce->st_size = st.st_size;
            ce->namelen = namelen;
            memcpy(ce->name, path, namelen);
            // 填充catch_entry中sha1字段,然后创建并将压缩数据写入sha1文件
            index_fd(path, namelen, ce, fd, &st);
                void *in = mmap(NULL, st->st_size, PROT_READ, MAP_PRIVATE, fd, 0);
                stream.next_in = metadata;
                // 将字符串 "blob %lu/0" 压缩
                stream.avail_in = 1+sprintf(metadata, "blob %lu", st_size); 
                stream.next_out = out;
                stream.avail_out = max_out_bytes;
                stream.next_in = in;  // 将源数据文件内容压缩
                stream.avail_in = st->st_size;
                SHA1_Init(&c);
                SHA1_Update(&c, out, stream.total_out);
                SHA1_Final(ce->sha1, &c); // 将两部分压缩内容取hash值,填充sha1字段
                // 创建并将压缩数据写入sha1文件
                write_sha1_buffer(ce->sha1, out, stream.total_out);
                    // 根据hash值生成.dircache/objects/xx/xx...(38位)文件名
                    char *filename = sha1_file_name(sha1);
                    fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
                    write(fd, buf, size);
                    close(fd);
            add_cache_entry(ce); // 将新建catch_entry加入到列表中
                // 二分法查找catch_entry将要插入的位置
                pos = cache_name_pos(ce->name, ce->namelen);
                if (pos < 0) // 如果源文件对应的catch_entry已存在,则用新的catch_entry替换
                    active_cache[-pos-1] = ce;
                    return;
                active_nr++; // catch_entry有效个数+1
                // 将catch_entry列表中从待插入位置到最后的数据全部后移一个位置
                memmove(active_cache + pos + 1, active_cache + pos,
                           (active_nr - pos - 1) * sizeof(ce));
                active_cache[pos] = ce; // 将新catch_entry插入到列表中
    // 将catch_entry列表信息写入到.dircache/index.lock文件
    write_cache(newfd, active_cache, active_nr);
        hdr.signature = CACHE_SIGNATURE;  //0x44495243
        hdr.version = 1;
        hdr.entries = active_nr; // 填充cache_header前三个字段
        SHA1_Init(&c);
        // cache_header前三个字段取hash值
        SHA1_Update(&c, &hdr, offsetof(struct cache_header, sha1));
        for (i = 0; i < entries; i++) // catch_entry列表中所有catch_entry数据取hash值
            struct cache_entry *ce = cache[i];
            int size = ce_size(ce);
            SHA1_Update(&c, ce, size);
        SHA1_Final(hdr.sha1, &c); // 将两部分数据的hash值填充到cache_header的sha1字段
        write(newfd, &hdr, sizeof(hdr)); // 将cache_header数据写入文件
        for (i = 0; i < active_nr; i++) // 将所有cache_entry信息写入文件
            struct cache_entry *ce = cache[i];
            int size = ce_size(ce);
            write(newfd, ce, size);
    rename(".dircache/index.lock", ".dircache/index") // 重命名文件为.dircache/index
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值