Fixed memory leaks in test suite
[libgit2.git] / src / fileops.c
blobf101cec32d82654159d264d177ed9ae0de42b6d7
1 #include "common.h"
2 #include "fileops.h"
4 int gitfo_open(const char *path, int flags)
6 int fd = open(path, flags | O_BINARY);
7 return fd >= 0 ? fd : git_os_error();
10 int gitfo_creat(const char *path, int mode)
12 int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, mode);
13 return fd >= 0 ? fd : git_os_error();
16 int gitfo_read(git_file fd, void *buf, size_t cnt)
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;
24 return git_os_error();
26 if (!r) {
27 errno = EPIPE;
28 return git_os_error();
30 cnt -= r;
31 b += r;
33 return GIT_SUCCESS;
36 int gitfo_write(git_file fd, void *buf, size_t cnt)
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;
44 return git_os_error();
46 if (!r) {
47 errno = EPIPE;
48 return git_os_error();
50 cnt -= r;
51 b += r;
53 return GIT_SUCCESS;
56 int gitfo_exists(const char *path)
58 return access(path, F_OK);
61 off_t gitfo_size(git_file fd)
63 struct stat sb;
64 if (gitfo_fstat(fd, &sb))
65 return git_os_error();
66 return sb.st_size;
69 int gitfo_read_file(gitfo_buf *obj, const char *path)
71 git_file fd;
72 size_t len;
73 off_t size;
74 unsigned char *buff;
76 assert(obj && path && *path);
78 if ((fd = gitfo_open(path, O_RDONLY)) < 0)
79 return GIT_ERROR;
81 if (((size = gitfo_size(fd)) < 0) || !git__is_sizet(size+1)) {
82 gitfo_close(fd);
83 return GIT_ERROR;
85 len = (size_t) size;
87 if ((buff = git__malloc(len + 1)) == NULL) {
88 gitfo_close(fd);
89 return GIT_ERROR;
92 if (gitfo_read(fd, buff, len) < 0) {
93 gitfo_close(fd);
94 free(buff);
95 return GIT_ERROR;
97 buff[len] = '\0';
99 gitfo_close(fd);
101 obj->data = buff;
102 obj->len = len;
104 return GIT_SUCCESS;
107 void gitfo_free_buf(gitfo_buf *obj)
109 assert(obj);
110 free(obj->data);
111 obj->data = NULL;
114 int gitfo_move_file(char *from, char *to)
116 if (!link(from, to)) {
117 gitfo_unlink(from);
118 return GIT_SUCCESS;
121 if (!rename(from, to))
122 return GIT_SUCCESS;
124 return git_os_error();
127 int gitfo_map_ro(git_map *out, git_file fd, off_t begin, size_t len)
129 if (git__mmap(out, len, GIT_PROT_READ, GIT_MAP_SHARED, fd, begin) < 0)
130 return git_os_error();
131 return GIT_SUCCESS;
134 void gitfo_free_map(git_map *out)
136 git__munmap(out);
139 /* cached diskio */
140 struct gitfo_cache {
141 git_file fd;
142 size_t cache_size, pos;
143 unsigned char *cache;
146 gitfo_cache *gitfo_enable_caching(git_file fd, size_t cache_size)
148 gitfo_cache *ioc;
150 ioc = git__malloc(sizeof(*ioc));
151 if (!ioc)
152 return NULL;
154 ioc->fd = fd;
155 ioc->pos = 0;
156 ioc->cache_size = cache_size;
157 ioc->cache = git__malloc(cache_size);
158 if (!ioc->cache) {
159 free(ioc);
160 return NULL;
163 return ioc;
166 GIT_INLINE(void) gitfo_add_to_cache(gitfo_cache *ioc, void *buf, size_t len)
168 memcpy(ioc->cache + ioc->pos, buf, len);
169 ioc->pos += len;
172 int gitfo_flush_cached(gitfo_cache *ioc)
174 int result = GIT_SUCCESS;
176 if (ioc->pos) {
177 result = gitfo_write(ioc->fd, ioc->cache, ioc->pos);
178 ioc->pos = 0;
181 return result;
184 int gitfo_write_cached(gitfo_cache *ioc, void *buff, size_t len)
186 unsigned char *buf = buff;
188 for (;;) {
189 size_t space_left = ioc->cache_size - ioc->pos;
190 /* cache if it's small */
191 if (space_left > len) {
192 gitfo_add_to_cache(ioc, buf, len);
193 return GIT_SUCCESS;
196 /* flush the cache if it doesn't fit */
197 if (ioc->pos) {
198 int rc;
199 gitfo_add_to_cache(ioc, buf, space_left);
200 rc = gitfo_flush_cached(ioc);
201 if (rc < 0)
202 return rc;
204 len -= space_left;
205 buf += space_left;
208 /* write too-large chunks immediately */
209 if (len > ioc->cache_size)
210 return gitfo_write(ioc->fd, buf, len);
214 int gitfo_close_cached(gitfo_cache *ioc)
216 git_file fd;
218 if (gitfo_flush_cached(ioc) < 0)
219 return GIT_ERROR;
221 fd = ioc->fd;
222 free(ioc->cache);
223 free(ioc);
225 return gitfo_close(fd);
228 int gitfo_dirent(
229 char *path,
230 size_t path_sz,
231 int (*fn)(void *, char *),
232 void *arg)
234 size_t wd_len = strlen(path);
235 DIR *dir;
236 struct dirent *de;
238 if (!wd_len || path_sz < wd_len + 2)
239 return GIT_ERROR;
241 while (path[wd_len - 1] == '/')
242 wd_len--;
243 path[wd_len++] = '/';
244 path[wd_len] = '\0';
246 dir = opendir(path);
247 if (!dir)
248 return git_os_error();
250 while ((de = readdir(dir)) != NULL) {
251 size_t de_len;
252 int result;
254 /* always skip '.' and '..' */
255 if (de->d_name[0] == '.') {
256 if (de->d_name[1] == '\0')
257 continue;
258 if (de->d_name[1] == '.' && de->d_name[2] == '\0')
259 continue;
262 de_len = strlen(de->d_name);
263 if (path_sz < wd_len + de_len + 1) {
264 closedir(dir);
265 return GIT_ERROR;
268 strcpy(path + wd_len, de->d_name);
269 result = fn(arg, path);
270 if (result < 0) {
271 closedir(dir);
272 return result;
274 if (result > 0) {
275 closedir(dir);
276 return result;
280 closedir(dir);
281 return GIT_SUCCESS;