]> git.proxmox.com Git - libgit2.git/blame - src/fileops.c
Wrap malloc and friends and report out of memory as GIT_ENOMEM
[libgit2.git] / src / fileops.c
CommitLineData
5ee2fe77 1#include "common.h"
ec250c6e
AE
2#include "fileops.h"
3
4int 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
24int 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
44off_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
52int 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
84void 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 */
92struct gitfo_cache {
93 git_file fd;
94 unsigned int cache_size, pos;
95 void *cache;
96};
97
98gitfo_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 117GIT_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
123int 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
135int 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
164int 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 */
182int 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}