]>
Commit | Line | Data |
---|---|---|
8bc9a0c7 LT |
1 | /* |
2 | * GIT - The information manager from hell | |
3 | * | |
4 | * Copyright (C) Linus Torvalds, 2005 | |
5 | */ | |
e83c5163 LT |
6 | #include "cache.h" |
7 | ||
e83c5163 LT |
8 | static int index_fd(const char *path, int namelen, struct cache_entry *ce, int fd, struct stat *st) |
9 | { | |
10 | z_stream stream; | |
11 | int max_out_bytes = namelen + st->st_size + 200; | |
12 | void *out = malloc(max_out_bytes); | |
13 | void *metadata = malloc(namelen + 200); | |
14 | void *in = mmap(NULL, st->st_size, PROT_READ, MAP_PRIVATE, fd, 0); | |
15 | SHA_CTX c; | |
16 | ||
17 | close(fd); | |
18 | if (!out || (int)(long)in == -1) | |
19 | return -1; | |
20 | ||
21 | memset(&stream, 0, sizeof(stream)); | |
22 | deflateInit(&stream, Z_BEST_COMPRESSION); | |
23 | ||
24 | /* | |
25 | * ASCII size + nul byte | |
26 | */ | |
27 | stream.next_in = metadata; | |
28 | stream.avail_in = 1+sprintf(metadata, "blob %lu", (unsigned long) st->st_size); | |
29 | stream.next_out = out; | |
30 | stream.avail_out = max_out_bytes; | |
31 | while (deflate(&stream, 0) == Z_OK) | |
32 | /* nothing */; | |
33 | ||
34 | /* | |
35 | * File content | |
36 | */ | |
37 | stream.next_in = in; | |
38 | stream.avail_in = st->st_size; | |
39 | while (deflate(&stream, Z_FINISH) == Z_OK) | |
40 | /*nothing */; | |
41 | ||
42 | deflateEnd(&stream); | |
43 | ||
44 | SHA1_Init(&c); | |
45 | SHA1_Update(&c, out, stream.total_out); | |
46 | SHA1_Final(ce->sha1, &c); | |
47 | ||
48 | return write_sha1_buffer(ce->sha1, out, stream.total_out); | |
49 | } | |
50 | ||
51 | static int add_file_to_cache(char *path) | |
52 | { | |
53 | int size, namelen; | |
54 | struct cache_entry *ce; | |
55 | struct stat st; | |
56 | int fd; | |
57 | ||
58 | fd = open(path, O_RDONLY); | |
59 | if (fd < 0) { | |
60 | if (errno == ENOENT) | |
61 | return remove_file_from_cache(path); | |
62 | return -1; | |
63 | } | |
64 | if (fstat(fd, &st) < 0) { | |
65 | close(fd); | |
66 | return -1; | |
67 | } | |
68 | namelen = strlen(path); | |
69 | size = cache_entry_size(namelen); | |
70 | ce = malloc(size); | |
71 | memset(ce, 0, size); | |
72 | memcpy(ce->name, path, namelen); | |
73 | ce->ctime.sec = st.st_ctime; | |
74 | ce->ctime.nsec = st.st_ctim.tv_nsec; | |
75 | ce->mtime.sec = st.st_mtime; | |
76 | ce->mtime.nsec = st.st_mtim.tv_nsec; | |
77 | ce->st_dev = st.st_dev; | |
78 | ce->st_ino = st.st_ino; | |
79 | ce->st_mode = st.st_mode; | |
80 | ce->st_uid = st.st_uid; | |
81 | ce->st_gid = st.st_gid; | |
82 | ce->st_size = st.st_size; | |
83 | ce->namelen = namelen; | |
84 | ||
85 | if (index_fd(path, namelen, ce, fd, &st) < 0) | |
86 | return -1; | |
87 | ||
88 | return add_cache_entry(ce); | |
89 | } | |
90 | ||
e83c5163 LT |
91 | /* |
92 | * We fundamentally don't like some paths: we don't want | |
93 | * dot or dot-dot anywhere, and in fact, we don't even want | |
94 | * any other dot-files (.dircache or anything else). They | |
95 | * are hidden, for chist sake. | |
96 | * | |
97 | * Also, we don't want double slashes or slashes at the | |
98 | * end that can make pathnames ambiguous. | |
99 | */ | |
100 | static int verify_path(char *path) | |
101 | { | |
102 | char c; | |
103 | ||
104 | goto inside; | |
105 | for (;;) { | |
106 | if (!c) | |
107 | return 1; | |
108 | if (c == '/') { | |
109 | inside: | |
110 | c = *path++; | |
111 | if (c != '/' && c != '.' && c != '\0') | |
112 | continue; | |
113 | return 0; | |
114 | } | |
115 | c = *path++; | |
116 | } | |
117 | } | |
118 | ||
119 | int main(int argc, char **argv) | |
120 | { | |
121 | int i, newfd, entries; | |
122 | ||
123 | entries = read_cache(); | |
124 | if (entries < 0) { | |
125 | perror("cache corrupted"); | |
126 | return -1; | |
127 | } | |
128 | ||
129 | newfd = open(".dircache/index.lock", O_RDWR | O_CREAT | O_EXCL, 0600); | |
130 | if (newfd < 0) { | |
131 | perror("unable to create new cachefile"); | |
132 | return -1; | |
133 | } | |
134 | for (i = 1 ; i < argc; i++) { | |
135 | char *path = argv[i]; | |
136 | if (!verify_path(path)) { | |
137 | fprintf(stderr, "Ignoring path %s\n", argv[i]); | |
138 | continue; | |
139 | } | |
140 | if (add_file_to_cache(path)) { | |
141 | fprintf(stderr, "Unable to add %s to database\n", path); | |
142 | goto out; | |
143 | } | |
144 | } | |
145 | if (!write_cache(newfd, active_cache, active_nr) && !rename(".dircache/index.lock", ".dircache/index")) | |
146 | return 0; | |
147 | out: | |
148 | unlink(".dircache/index.lock"); | |
19b2860c | 149 | return 0; |
e83c5163 | 150 | } |