diff options
-rw-r--r-- | src/fileops.c | 87 | ||||
-rw-r--r-- | src/fileops.h | 6 |
2 files changed, 93 insertions, 0 deletions
diff --git a/src/fileops.c b/src/fileops.c index 1ca0fbb08..62da145b9 100644 --- a/src/fileops.c +++ b/src/fileops.c @@ -47,3 +47,90 @@ off_t gitfo_size(git_file fd) return -1; return sb.st_size; } + +/* cached diskio */ +struct gitfo_cache { + git_file fd; + unsigned int cache_size, pos; + void *cache; +}; + +gitfo_cache *gitfo_enable_caching(git_file fd, size_t cache_size) +{ + gitfo_cache *ioc; + + ioc = malloc(sizeof(*ioc)); + if (!ioc) + return NULL; + + ioc->pos = 0; + ioc->cache_size = cache_size; + ioc->cache = malloc(cache_size); + if (!ioc->cache) { + free(ioc); + return NULL; + } + + return ioc; +} + +static inline void gitfo_add_to_cache(gitfo_cache *ioc, void *buf, size_t len) +{ + memcpy(ioc->cache + ioc->pos, buf, len); + ioc->pos += len; +} + +int gitfo_flush_cached(gitfo_cache *ioc) +{ + int result = GIT_SUCCESS; + + if (ioc->pos) { + result = gitfo_write(ioc->fd, ioc->cache, ioc->pos); + ioc->pos = 0; + } + + return result; +} + +int gitfo_write_cached(gitfo_cache *ioc, void *buf, size_t len) +{ + for (;;) { + size_t space_left = ioc->cache_size - ioc->pos; + /* cache if it's small */ + if (space_left > len) { + gitfo_add_to_cache(ioc, buf, len); + return GIT_SUCCESS; + } + + /* flush the cache if it doesn't fit */ + if (ioc->pos) { + int rc; + gitfo_add_to_cache(ioc, buf, space_left); + rc = gitfo_flush_cached(ioc); + if (rc < 0) + return rc; + + len -= space_left; + buf += space_left; + } + + /* write too-large chunks immediately */ + if (len > ioc->cache_size) + return gitfo_write(ioc->fd, buf, len); + } + return GIT_SUCCESS; +} + +int gitfo_close_cached(gitfo_cache *ioc) +{ + git_file fd; + + if (gitfo_flush_cached(ioc) < 0) + return -1; + + fd = ioc->fd; + free(ioc->cache); + free(ioc); + + return gitfo_close(fd); +} diff --git a/src/fileops.h b/src/fileops.h index 32d6b9111..56d0888fe 100644 --- a/src/fileops.h +++ b/src/fileops.h @@ -21,6 +21,7 @@ typedef int git_file; typedef struct stat gitfo_statbuf; +typedef struct gitfo_cache gitfo_cache; #define gitfo_open(path, flags) open(path, flags) #define gitfo_close(fd) close(fd) @@ -34,4 +35,9 @@ extern off_t gitfo_size(git_file fd); #define gitfo_stat(path, buf) stat(path, buf) #define gitfo_fsync(fd) fsync(fd) +extern gitfo_cache *gitfo_enable_caching(git_file fd, size_t cache_size); +extern int gitfo_write_cached(gitfo_cache *ioc, void *buf, size_t len); +extern int gitfo_flush_cached(gitfo_cache *ioc); +extern int gitfo_close_cached(gitfo_cache *ioc); + #endif /* INCLUDE_fileops_h__ */ |