]> git.proxmox.com Git - libgit2.git/blame - src/fileops.c
Fix issues in repository initialization
[libgit2.git] / src / fileops.c
CommitLineData
5ee2fe77 1#include "common.h"
ec250c6e
AE
2#include "fileops.h"
3
7dd8a9f7
SP
4int 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
10int 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
16int 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
36int 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
56int 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
86int gitfo_exists(const char *path)
87{
4d503f88 88 return access(path, F_OK);
7350e633
SP
89}
90
ec250c6e
AE
91off_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
99int 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
137void gitfo_free_buf(gitfo_buf *obj)
138{
139 assert(obj);
140 free(obj->data);
141 obj->data = NULL;
142}
143
ca481fc4
RJ
144int 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 157int 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 164void gitfo_free_map(git_map *out)
20e7f426 165{
79ca2edc 166 git__munmap(out);
20e7f426
SP
167}
168
4188d28f
AE
169/* cached diskio */
170struct gitfo_cache {
171 git_file fd;
4c9a3973 172 size_t cache_size, pos;
fc3c3a20 173 unsigned char *cache;
4188d28f
AE
174};
175
176gitfo_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 196GIT_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
202int 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 214int 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
244int 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
258int 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
314int 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}