]>
Commit | Line | Data |
---|---|---|
5ee2fe77 | 1 | #include "common.h" |
ec250c6e AE |
2 | #include "fileops.h" |
3 | ||
4 | int gitfo_read(git_file fd, void *buf, size_t cnt) | |
5 | { | |
6 | char *b = buf; | |
7 | while (cnt) { | |
8 | ssize_t r = read(fd, b, cnt); | |
9 | if (r < 0) { | |
10 | if (errno == EINTR || errno == EAGAIN) | |
11 | continue; | |
12 | return -1; | |
13 | } | |
14 | if (!r) { | |
15 | errno = EPIPE; | |
16 | return -1; | |
17 | } | |
18 | cnt -= r; | |
19 | b += r; | |
20 | } | |
21 | return GIT_SUCCESS; | |
22 | } | |
23 | ||
24 | int gitfo_write(git_file fd, void *buf, size_t cnt) | |
25 | { | |
26 | char *b = buf; | |
27 | while (cnt) { | |
28 | ssize_t r = write(fd, b, cnt); | |
29 | if (r < 0) { | |
30 | if (errno == EINTR || errno == EAGAIN) | |
31 | continue; | |
32 | return -1; | |
33 | } | |
34 | if (!r) { | |
35 | errno = EPIPE; | |
36 | return -1; | |
37 | } | |
38 | cnt -= r; | |
39 | b += r; | |
40 | } | |
41 | return GIT_SUCCESS; | |
42 | } | |
43 | ||
44 | off_t gitfo_size(git_file fd) | |
45 | { | |
46 | gitfo_statbuf sb; | |
47 | if (fstat(fd, &sb)) | |
48 | return -1; | |
49 | return sb.st_size; | |
50 | } | |
4188d28f | 51 | |
75d58430 RJ |
52 | int gitfo_read_file(gitfo_buf *obj, const char *path) |
53 | { | |
54 | git_file fd; | |
55 | off_t len; | |
42fd40db | 56 | unsigned char *buff; |
75d58430 RJ |
57 | |
58 | assert(obj && path && *path); | |
59 | ||
60 | if ((fd = gitfo_open(path, O_RDONLY)) < 0) | |
64a47c01 | 61 | return GIT_ERROR; |
75d58430 | 62 | |
64a47c01 SP |
63 | if (((len = gitfo_size(fd)) < 0) |
64 | || ((buff = git__malloc(len + 1)) == NULL)) { | |
75d58430 | 65 | gitfo_close(fd); |
64a47c01 | 66 | return GIT_ERROR; |
75d58430 RJ |
67 | } |
68 | ||
69 | if (gitfo_read(fd, buff, len) < 0) { | |
70 | gitfo_close(fd); | |
71 | free(buff); | |
64a47c01 | 72 | return GIT_ERROR; |
75d58430 | 73 | } |
42fd40db | 74 | buff[len] = '\0'; |
75d58430 RJ |
75 | |
76 | gitfo_close(fd); | |
77 | ||
78 | obj->data = buff; | |
79 | obj->len = len; | |
80 | ||
81 | return GIT_SUCCESS; | |
82 | } | |
83 | ||
84 | void gitfo_free_buf(gitfo_buf *obj) | |
85 | { | |
86 | assert(obj); | |
87 | free(obj->data); | |
88 | obj->data = NULL; | |
89 | } | |
90 | ||
4188d28f AE |
91 | /* cached diskio */ |
92 | struct gitfo_cache { | |
93 | git_file fd; | |
94 | unsigned int cache_size, pos; | |
95 | void *cache; | |
96 | }; | |
97 | ||
98 | gitfo_cache *gitfo_enable_caching(git_file fd, size_t cache_size) | |
99 | { | |
100 | gitfo_cache *ioc; | |
101 | ||
64a47c01 | 102 | ioc = git__malloc(sizeof(*ioc)); |
4188d28f AE |
103 | if (!ioc) |
104 | return NULL; | |
105 | ||
106 | ioc->pos = 0; | |
107 | ioc->cache_size = cache_size; | |
64a47c01 | 108 | ioc->cache = git__malloc(cache_size); |
4188d28f AE |
109 | if (!ioc->cache) { |
110 | free(ioc); | |
111 | return NULL; | |
112 | } | |
113 | ||
114 | return ioc; | |
115 | } | |
116 | ||
213e720c | 117 | GIT_INLINE(void) gitfo_add_to_cache(gitfo_cache *ioc, void *buf, size_t len) |
4188d28f AE |
118 | { |
119 | memcpy(ioc->cache + ioc->pos, buf, len); | |
120 | ioc->pos += len; | |
121 | } | |
122 | ||
123 | int gitfo_flush_cached(gitfo_cache *ioc) | |
124 | { | |
125 | int result = GIT_SUCCESS; | |
126 | ||
127 | if (ioc->pos) { | |
128 | result = gitfo_write(ioc->fd, ioc->cache, ioc->pos); | |
129 | ioc->pos = 0; | |
130 | } | |
131 | ||
132 | return result; | |
133 | } | |
134 | ||
135 | int gitfo_write_cached(gitfo_cache *ioc, void *buf, size_t len) | |
136 | { | |
137 | for (;;) { | |
138 | size_t space_left = ioc->cache_size - ioc->pos; | |
139 | /* cache if it's small */ | |
140 | if (space_left > len) { | |
141 | gitfo_add_to_cache(ioc, buf, len); | |
142 | return GIT_SUCCESS; | |
143 | } | |
144 | ||
145 | /* flush the cache if it doesn't fit */ | |
146 | if (ioc->pos) { | |
147 | int rc; | |
148 | gitfo_add_to_cache(ioc, buf, space_left); | |
149 | rc = gitfo_flush_cached(ioc); | |
150 | if (rc < 0) | |
151 | return rc; | |
152 | ||
153 | len -= space_left; | |
154 | buf += space_left; | |
155 | } | |
156 | ||
157 | /* write too-large chunks immediately */ | |
158 | if (len > ioc->cache_size) | |
159 | return gitfo_write(ioc->fd, buf, len); | |
160 | } | |
161 | return GIT_SUCCESS; | |
162 | } | |
163 | ||
164 | int gitfo_close_cached(gitfo_cache *ioc) | |
165 | { | |
166 | git_file fd; | |
167 | ||
168 | if (gitfo_flush_cached(ioc) < 0) | |
169 | return -1; | |
170 | ||
171 | fd = ioc->fd; | |
172 | free(ioc->cache); | |
173 | free(ioc); | |
174 | ||
175 | return gitfo_close(fd); | |
176 | } | |
ea790f33 AE |
177 | |
178 | /** | |
179 | * Walk a directory and run 'fn' for each encountered entry | |
180 | * (except '.' and '..'). | |
181 | */ | |
182 | int git_foreach_dirent(const char *wd, int (*fn)(void *, const char *), void *arg) | |
183 | { | |
5ee2fe77 | 184 | char path[GIT_PATH_MAX]; |
ea790f33 AE |
185 | size_t wd_len; |
186 | DIR *dir; | |
187 | struct dirent *de; | |
188 | ||
189 | if (!wd) | |
190 | return GIT_ERROR; | |
191 | ||
192 | wd_len = strlen(wd); | |
193 | if (!wd_len || sizeof(path) < wd_len + 2) | |
194 | return GIT_ERROR; | |
195 | ||
196 | strcpy(path, wd); | |
197 | while (path[wd_len - 1] == '/') | |
198 | wd_len--; | |
199 | path[wd_len++] = '/'; | |
200 | path[wd_len] = '\0'; | |
201 | ||
202 | dir = opendir(wd); | |
203 | if (!dir) | |
204 | return GIT_ERROR; | |
205 | ||
206 | while ((de = readdir(dir))) { | |
207 | size_t de_len; | |
208 | int result; | |
209 | ||
210 | /* always skip '.' and '..' */ | |
211 | if (de->d_name[0] == '.') { | |
212 | if (de->d_name[1] == '\0') | |
213 | continue; | |
214 | if (de->d_name[1] == '.' && de->d_name[2] == '\0') | |
215 | continue; | |
216 | } | |
217 | ||
218 | de_len = strlen(de->d_name); | |
219 | if (sizeof(path) < wd_len + de_len + 1) { | |
220 | closedir(dir); | |
221 | return GIT_ERROR; | |
222 | } | |
223 | ||
224 | strcpy(path + wd_len, de->d_name); | |
225 | result = fn(arg, path); | |
226 | if (result < 0) { | |
227 | closedir(dir); | |
228 | return result; | |
229 | } | |
230 | if (result > 0) { | |
231 | closedir(dir); | |
232 | return result; | |
233 | } | |
234 | } | |
235 | ||
236 | closedir(dir); | |
237 | return GIT_SUCCESS; | |
238 | } |