]>
Commit | Line | Data |
---|---|---|
5ee2fe77 | 1 | #include "common.h" |
ec250c6e AE |
2 | #include "fileops.h" |
3 | ||
7dd8a9f7 SP |
4 | int gitfo_open(const char *path, int flags) |
5 | { | |
7a6cf815 | 6 | int fd = open(path, flags | O_BINARY); |
7dd8a9f7 SP |
7 | return fd >= 0 ? fd : git_os_error(); |
8 | } | |
9 | ||
10 | int gitfo_creat(const char *path, int mode) | |
11 | { | |
7a6cf815 | 12 | int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, mode); |
7dd8a9f7 SP |
13 | return fd >= 0 ? fd : git_os_error(); |
14 | } | |
15 | ||
ec250c6e AE |
16 | int gitfo_read(git_file fd, void *buf, size_t cnt) |
17 | { | |
18 | char *b = buf; | |
19 | while (cnt) { | |
20 | ssize_t r = read(fd, b, cnt); | |
21 | if (r < 0) { | |
22 | if (errno == EINTR || errno == EAGAIN) | |
23 | continue; | |
7dd8a9f7 | 24 | return git_os_error(); |
ec250c6e AE |
25 | } |
26 | if (!r) { | |
27 | errno = EPIPE; | |
7dd8a9f7 | 28 | return git_os_error(); |
ec250c6e AE |
29 | } |
30 | cnt -= r; | |
31 | b += r; | |
32 | } | |
33 | return GIT_SUCCESS; | |
34 | } | |
35 | ||
36 | int gitfo_write(git_file fd, void *buf, size_t cnt) | |
37 | { | |
38 | char *b = buf; | |
39 | while (cnt) { | |
40 | ssize_t r = write(fd, b, cnt); | |
41 | if (r < 0) { | |
42 | if (errno == EINTR || errno == EAGAIN) | |
43 | continue; | |
7dd8a9f7 | 44 | return git_os_error(); |
ec250c6e AE |
45 | } |
46 | if (!r) { | |
47 | errno = EPIPE; | |
7dd8a9f7 | 48 | return git_os_error(); |
ec250c6e AE |
49 | } |
50 | cnt -= r; | |
51 | b += r; | |
52 | } | |
53 | return GIT_SUCCESS; | |
54 | } | |
55 | ||
6fd195d7 VM |
56 | int gitfo_isdir(const char *path) |
57 | { | |
58 | struct stat st; | |
43e380a8 VM |
59 | int len, stat_error; |
60 | ||
61 | if (!path) | |
62 | return GIT_ENOTFOUND; | |
63 | ||
64 | len = strlen(path); | |
65 | ||
66 | /* win32: stat path for folders cannot end in a slash */ | |
67 | if (path[len - 1] == '/') { | |
68 | char *path_fixed = NULL; | |
69 | path_fixed = git__strdup(path); | |
70 | path_fixed[len - 1] = 0; | |
71 | stat_error = gitfo_stat(path_fixed, &st); | |
72 | free(path_fixed); | |
73 | } else { | |
74 | stat_error = gitfo_stat(path, &st); | |
75 | } | |
76 | ||
1f080e2d VM |
77 | if (stat_error < GIT_SUCCESS) |
78 | return GIT_ENOTFOUND; | |
79 | ||
80 | if (!S_ISDIR(st.st_mode)) | |
81 | return GIT_ENOTFOUND; | |
82 | ||
83 | return GIT_SUCCESS; | |
6fd195d7 VM |
84 | } |
85 | ||
7350e633 SP |
86 | int gitfo_exists(const char *path) |
87 | { | |
4d503f88 | 88 | return access(path, F_OK); |
7350e633 SP |
89 | } |
90 | ||
ec250c6e AE |
91 | off_t gitfo_size(git_file fd) |
92 | { | |
7dd8a9f7 | 93 | struct stat sb; |
3cc60635 | 94 | if (gitfo_fstat(fd, &sb)) |
7dd8a9f7 | 95 | return git_os_error(); |
ec250c6e AE |
96 | return sb.st_size; |
97 | } | |
4188d28f | 98 | |
75d58430 RJ |
99 | int gitfo_read_file(gitfo_buf *obj, const char *path) |
100 | { | |
101 | git_file fd; | |
90d4d2f0 RJ |
102 | size_t len; |
103 | off_t size; | |
42fd40db | 104 | unsigned char *buff; |
75d58430 RJ |
105 | |
106 | assert(obj && path && *path); | |
107 | ||
108 | if ((fd = gitfo_open(path, O_RDONLY)) < 0) | |
64a47c01 | 109 | return GIT_ERROR; |
75d58430 | 110 | |
90d4d2f0 RJ |
111 | if (((size = gitfo_size(fd)) < 0) || !git__is_sizet(size+1)) { |
112 | gitfo_close(fd); | |
113 | return GIT_ERROR; | |
114 | } | |
115 | len = (size_t) size; | |
116 | ||
117 | if ((buff = git__malloc(len + 1)) == NULL) { | |
75d58430 | 118 | gitfo_close(fd); |
64a47c01 | 119 | return GIT_ERROR; |
75d58430 RJ |
120 | } |
121 | ||
122 | if (gitfo_read(fd, buff, len) < 0) { | |
123 | gitfo_close(fd); | |
124 | free(buff); | |
64a47c01 | 125 | return GIT_ERROR; |
75d58430 | 126 | } |
42fd40db | 127 | buff[len] = '\0'; |
75d58430 RJ |
128 | |
129 | gitfo_close(fd); | |
130 | ||
131 | obj->data = buff; | |
132 | obj->len = len; | |
133 | ||
134 | return GIT_SUCCESS; | |
135 | } | |
136 | ||
137 | void gitfo_free_buf(gitfo_buf *obj) | |
138 | { | |
139 | assert(obj); | |
140 | free(obj->data); | |
141 | obj->data = NULL; | |
142 | } | |
143 | ||
ca481fc4 RJ |
144 | int gitfo_move_file(char *from, char *to) |
145 | { | |
146 | if (!link(from, to)) { | |
147 | gitfo_unlink(from); | |
148 | return GIT_SUCCESS; | |
149 | } | |
150 | ||
151 | if (!rename(from, to)) | |
152 | return GIT_SUCCESS; | |
153 | ||
154 | return git_os_error(); | |
155 | } | |
156 | ||
79ca2edc | 157 | int gitfo_map_ro(git_map *out, git_file fd, off_t begin, size_t len) |
20e7f426 | 158 | { |
6f02c3ba | 159 | if (git__mmap(out, len, GIT_PROT_READ, GIT_MAP_SHARED, fd, begin) < GIT_SUCCESS) |
20e7f426 | 160 | return git_os_error(); |
20e7f426 SP |
161 | return GIT_SUCCESS; |
162 | } | |
163 | ||
79ca2edc | 164 | void gitfo_free_map(git_map *out) |
20e7f426 | 165 | { |
79ca2edc | 166 | git__munmap(out); |
20e7f426 SP |
167 | } |
168 | ||
4188d28f AE |
169 | /* cached diskio */ |
170 | struct gitfo_cache { | |
171 | git_file fd; | |
4c9a3973 | 172 | size_t cache_size, pos; |
fc3c3a20 | 173 | unsigned char *cache; |
4188d28f AE |
174 | }; |
175 | ||
176 | gitfo_cache *gitfo_enable_caching(git_file fd, size_t cache_size) | |
177 | { | |
178 | gitfo_cache *ioc; | |
179 | ||
64a47c01 | 180 | ioc = git__malloc(sizeof(*ioc)); |
4188d28f AE |
181 | if (!ioc) |
182 | return NULL; | |
183 | ||
803a6b4d | 184 | ioc->fd = fd; |
4188d28f AE |
185 | ioc->pos = 0; |
186 | ioc->cache_size = cache_size; | |
64a47c01 | 187 | ioc->cache = git__malloc(cache_size); |
4188d28f AE |
188 | if (!ioc->cache) { |
189 | free(ioc); | |
190 | return NULL; | |
191 | } | |
192 | ||
193 | return ioc; | |
194 | } | |
195 | ||
213e720c | 196 | GIT_INLINE(void) gitfo_add_to_cache(gitfo_cache *ioc, void *buf, size_t len) |
4188d28f AE |
197 | { |
198 | memcpy(ioc->cache + ioc->pos, buf, len); | |
199 | ioc->pos += len; | |
200 | } | |
201 | ||
202 | int gitfo_flush_cached(gitfo_cache *ioc) | |
203 | { | |
204 | int result = GIT_SUCCESS; | |
205 | ||
206 | if (ioc->pos) { | |
207 | result = gitfo_write(ioc->fd, ioc->cache, ioc->pos); | |
208 | ioc->pos = 0; | |
209 | } | |
210 | ||
211 | return result; | |
212 | } | |
213 | ||
fc3c3a20 | 214 | int gitfo_write_cached(gitfo_cache *ioc, void *buff, size_t len) |
4188d28f | 215 | { |
fc3c3a20 RJ |
216 | unsigned char *buf = buff; |
217 | ||
4188d28f AE |
218 | for (;;) { |
219 | size_t space_left = ioc->cache_size - ioc->pos; | |
220 | /* cache if it's small */ | |
221 | if (space_left > len) { | |
222 | gitfo_add_to_cache(ioc, buf, len); | |
223 | return GIT_SUCCESS; | |
224 | } | |
225 | ||
226 | /* flush the cache if it doesn't fit */ | |
227 | if (ioc->pos) { | |
228 | int rc; | |
229 | gitfo_add_to_cache(ioc, buf, space_left); | |
230 | rc = gitfo_flush_cached(ioc); | |
231 | if (rc < 0) | |
232 | return rc; | |
233 | ||
234 | len -= space_left; | |
235 | buf += space_left; | |
236 | } | |
237 | ||
238 | /* write too-large chunks immediately */ | |
239 | if (len > ioc->cache_size) | |
240 | return gitfo_write(ioc->fd, buf, len); | |
241 | } | |
4188d28f AE |
242 | } |
243 | ||
244 | int gitfo_close_cached(gitfo_cache *ioc) | |
245 | { | |
246 | git_file fd; | |
247 | ||
6f02c3ba | 248 | if (gitfo_flush_cached(ioc) < GIT_SUCCESS) |
7dd8a9f7 | 249 | return GIT_ERROR; |
4188d28f AE |
250 | |
251 | fd = ioc->fd; | |
252 | free(ioc->cache); | |
253 | free(ioc); | |
254 | ||
255 | return gitfo_close(fd); | |
256 | } | |
ea790f33 | 257 | |
5690f02e SP |
258 | int gitfo_dirent( |
259 | char *path, | |
260 | size_t path_sz, | |
261 | int (*fn)(void *, char *), | |
262 | void *arg) | |
ea790f33 | 263 | { |
5690f02e | 264 | size_t wd_len = strlen(path); |
ea790f33 AE |
265 | DIR *dir; |
266 | struct dirent *de; | |
267 | ||
5690f02e | 268 | if (!wd_len || path_sz < wd_len + 2) |
ea790f33 AE |
269 | return GIT_ERROR; |
270 | ||
ea790f33 AE |
271 | while (path[wd_len - 1] == '/') |
272 | wd_len--; | |
273 | path[wd_len++] = '/'; | |
274 | path[wd_len] = '\0'; | |
275 | ||
5690f02e | 276 | dir = opendir(path); |
ea790f33 | 277 | if (!dir) |
7dd8a9f7 | 278 | return git_os_error(); |
ea790f33 | 279 | |
a9984a4e | 280 | while ((de = readdir(dir)) != NULL) { |
ea790f33 AE |
281 | size_t de_len; |
282 | int result; | |
283 | ||
284 | /* always skip '.' and '..' */ | |
285 | if (de->d_name[0] == '.') { | |
286 | if (de->d_name[1] == '\0') | |
287 | continue; | |
288 | if (de->d_name[1] == '.' && de->d_name[2] == '\0') | |
289 | continue; | |
290 | } | |
291 | ||
292 | de_len = strlen(de->d_name); | |
5690f02e | 293 | if (path_sz < wd_len + de_len + 1) { |
ea790f33 AE |
294 | closedir(dir); |
295 | return GIT_ERROR; | |
296 | } | |
297 | ||
298 | strcpy(path + wd_len, de->d_name); | |
299 | result = fn(arg, path); | |
6f02c3ba | 300 | if (result < GIT_SUCCESS) { |
ea790f33 AE |
301 | closedir(dir); |
302 | return result; | |
303 | } | |
304 | if (result > 0) { | |
305 | closedir(dir); | |
306 | return result; | |
307 | } | |
308 | } | |
309 | ||
310 | closedir(dir); | |
311 | return GIT_SUCCESS; | |
312 | } | |
1a5204a7 | 313 | |
314 | int gitfo_mkdir_recurs(const char *path, int mode) | |
315 | { | |
f0b2bfe5 | 316 | int error; |
40c44d2f VM |
317 | char *pp, *sp; |
318 | char *path_copy = git__strdup(path); | |
f0b2bfe5 | 319 | |
40c44d2f VM |
320 | if (path_copy == NULL) |
321 | return GIT_ENOMEM; | |
f0b2bfe5 | 322 | |
40c44d2f VM |
323 | error = GIT_SUCCESS; |
324 | pp = path_copy; | |
325 | ||
326 | while (error == 0 && (sp = strchr(pp, '/')) != 0) { | |
327 | if (sp != pp && gitfo_isdir(path_copy) < GIT_SUCCESS) { | |
328 | *sp = 0; | |
329 | error = gitfo_mkdir(path_copy, mode); | |
330 | *sp = '/'; | |
331 | } | |
332 | ||
333 | pp = sp + 1; | |
334 | } | |
f0b2bfe5 | 335 | |
40c44d2f VM |
336 | if (*(pp - 1) != '/' && error == GIT_SUCCESS) |
337 | error = gitfo_mkdir(path, mode); | |
338 | ||
339 | free(path_copy); | |
340 | return error; | |
341 | ||
342 | } |