gitfo_exists: replace call to stat() with access()
[libgit2.git] / src / fileops.c
blob581dc350d5e699a9428caaf6a59fca78709f4bbe
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 (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 off_t len;
73 unsigned char *buff;
75 assert(obj && path && *path);
77 if ((fd = gitfo_open(path, O_RDONLY)) < 0)
78 return GIT_ERROR;
80 if (((len = gitfo_size(fd)) < 0)
81 || ((buff = git__malloc(len + 1)) == NULL)) {
82 gitfo_close(fd);
83 return GIT_ERROR;
86 if (gitfo_read(fd, buff, len) < 0) {
87 gitfo_close(fd);
88 free(buff);
89 return GIT_ERROR;
91 buff[len] = '\0';
93 gitfo_close(fd);
95 obj->data = buff;
96 obj->len = len;
98 return GIT_SUCCESS;
101 void gitfo_free_buf(gitfo_buf *obj)
103 assert(obj);
104 free(obj->data);
105 obj->data = NULL;
108 int gitfo_map_ro(git_map *out, git_file fd, off_t begin, size_t len)
110 if (git__mmap(out, len, GIT_PROT_READ, GIT_MAP_SHARED, fd, begin) < 0)
111 return git_os_error();
112 return GIT_SUCCESS;
115 void gitfo_free_map(git_map *out)
117 git__munmap(out);
120 /* cached diskio */
121 struct gitfo_cache {
122 git_file fd;
123 unsigned int cache_size, pos;
124 unsigned char *cache;
127 gitfo_cache *gitfo_enable_caching(git_file fd, size_t cache_size)
129 gitfo_cache *ioc;
131 ioc = git__malloc(sizeof(*ioc));
132 if (!ioc)
133 return NULL;
135 ioc->pos = 0;
136 ioc->cache_size = cache_size;
137 ioc->cache = git__malloc(cache_size);
138 if (!ioc->cache) {
139 free(ioc);
140 return NULL;
143 return ioc;
146 GIT_INLINE(void) gitfo_add_to_cache(gitfo_cache *ioc, void *buf, size_t len)
148 memcpy(ioc->cache + ioc->pos, buf, len);
149 ioc->pos += len;
152 int gitfo_flush_cached(gitfo_cache *ioc)
154 int result = GIT_SUCCESS;
156 if (ioc->pos) {
157 result = gitfo_write(ioc->fd, ioc->cache, ioc->pos);
158 ioc->pos = 0;
161 return result;
164 int gitfo_write_cached(gitfo_cache *ioc, void *buff, size_t len)
166 unsigned char *buf = buff;
168 for (;;) {
169 size_t space_left = ioc->cache_size - ioc->pos;
170 /* cache if it's small */
171 if (space_left > len) {
172 gitfo_add_to_cache(ioc, buf, len);
173 return GIT_SUCCESS;
176 /* flush the cache if it doesn't fit */
177 if (ioc->pos) {
178 int rc;
179 gitfo_add_to_cache(ioc, buf, space_left);
180 rc = gitfo_flush_cached(ioc);
181 if (rc < 0)
182 return rc;
184 len -= space_left;
185 buf += space_left;
188 /* write too-large chunks immediately */
189 if (len > ioc->cache_size)
190 return gitfo_write(ioc->fd, buf, len);
192 return GIT_SUCCESS;
195 int gitfo_close_cached(gitfo_cache *ioc)
197 git_file fd;
199 if (gitfo_flush_cached(ioc) < 0)
200 return GIT_ERROR;
202 fd = ioc->fd;
203 free(ioc->cache);
204 free(ioc);
206 return gitfo_close(fd);
209 int gitfo_dirent(
210 char *path,
211 size_t path_sz,
212 int (*fn)(void *, char *),
213 void *arg)
215 size_t wd_len = strlen(path);
216 DIR *dir;
217 struct dirent *de;
219 if (!wd_len || path_sz < wd_len + 2)
220 return GIT_ERROR;
222 while (path[wd_len - 1] == '/')
223 wd_len--;
224 path[wd_len++] = '/';
225 path[wd_len] = '\0';
227 dir = opendir(path);
228 if (!dir)
229 return git_os_error();
231 while ((de = readdir(dir)) != NULL) {
232 size_t de_len;
233 int result;
235 /* always skip '.' and '..' */
236 if (de->d_name[0] == '.') {
237 if (de->d_name[1] == '\0')
238 continue;
239 if (de->d_name[1] == '.' && de->d_name[2] == '\0')
240 continue;
243 de_len = strlen(de->d_name);
244 if (path_sz < wd_len + de_len + 1) {
245 closedir(dir);
246 return GIT_ERROR;
249 strcpy(path + wd_len, de->d_name);
250 result = fn(arg, path);
251 if (result < 0) {
252 closedir(dir);
253 return result;
255 if (result > 0) {
256 closedir(dir);
257 return result;
261 closedir(dir);
262 return GIT_SUCCESS;