summaryrefslogtreecommitdiff
path: root/src/checkout.c
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@microsoft.com>2015-01-22 16:11:36 -0600
committerEdward Thomson <ethomson@microsoft.com>2015-02-17 15:57:10 -0500
commite78f5c9f4282319cf8e1afc8631e6259e91653a6 (patch)
treecb1dac68dc96eb8554efb67104944c12d1b3eab7 /src/checkout.c
parent5555696f8a48d2319a7ca0918726711e6a81a924 (diff)
downloadlibgit2-e78f5c9f4282319cf8e1afc8631e6259e91653a6.tar.gz
checkout: stream the blob into the filters
Use the new streaming filter API during checkout.
Diffstat (limited to 'src/checkout.c')
-rw-r--r--src/checkout.c121
1 files changed, 82 insertions, 39 deletions
diff --git a/src/checkout.c b/src/checkout.c
index 880af3dff..623ac92a1 100644
--- a/src/checkout.c
+++ b/src/checkout.c
@@ -17,6 +17,7 @@
#include "git2/diff.h"
#include "git2/submodule.h"
#include "git2/sys/index.h"
+#include "git2/sys/filter.h"
#include "refs.h"
#include "repository.h"
@@ -1371,39 +1372,37 @@ static int mkpath2file(
return error;
}
-static int buffer_to_file(
- checkout_data *data,
- struct stat *st,
- git_buf *buf,
- const char *path,
- mode_t file_mode)
-{
- int error;
-
- if ((error = mkpath2file(data, path, data->opts.dir_mode)) < 0)
- return error;
+struct checkout_stream {
+ git_filter_stream base;
+ const char *path;
+ int fd;
+ int open;
+};
- if ((error = git_futils_writebuffer(
- buf, path, data->opts.file_open_flags, file_mode)) < 0)
- return error;
+static int checkout_stream_write(
+ git_filter_stream *s, const char *buffer, size_t len)
+{
+ struct checkout_stream *stream = (struct checkout_stream *)s;
+ int ret;
- if (st) {
- data->perfdata.stat_calls++;
+ if ((ret = p_write(stream->fd, buffer, len)) < 0)
+ giterr_set(GITERR_OS, "Could not write to '%s'", stream->path);
- if ((error = p_stat(path, st)) < 0) {
- giterr_set(GITERR_OS, "Error statting '%s'", path);
- return error;
- }
- }
+ return ret;
+}
- if (GIT_PERMS_IS_EXEC(file_mode)) {
- data->perfdata.chmod_calls++;
+static int checkout_stream_close(git_filter_stream *s)
+{
+ struct checkout_stream *stream = (struct checkout_stream *)s;
+ assert(stream && stream->open);
- if ((error = p_chmod(path, file_mode)) < 0)
- giterr_set(GITERR_OS, "Failed to set permissions on '%s'", path);
- }
+ stream->open = 0;
+ return 0;
+}
- return error;
+static void checkout_stream_free(git_filter_stream *s)
+{
+ GIT_UNUSED(s);
}
static int blob_content_to_file(
@@ -1411,36 +1410,80 @@ static int blob_content_to_file(
struct stat *st,
git_blob *blob,
const char *path,
- const char * hint_path,
+ const char *hint_path,
mode_t entry_filemode)
{
+ int flags = data->opts.file_open_flags;
mode_t file_mode = data->opts.file_mode ?
data->opts.file_mode : entry_filemode;
- git_buf out = GIT_BUF_INIT;
+ struct checkout_stream writer;
+ mode_t mode;
git_filter_list *fl = NULL;
+ int fd;
int error = 0;
if (hint_path == NULL)
hint_path = path;
- if (!data->opts.disable_filters)
- error = git_filter_list__load_with_attr_session(
+ if ((error = mkpath2file(data, path, data->opts.dir_mode)) < 0)
+ return error;
+
+ if (flags <= 0)
+ flags = O_CREAT | O_TRUNC | O_WRONLY;
+ if (!(mode = file_mode))
+ mode = GIT_FILEMODE_BLOB;
+
+ if ((fd = p_open(path, flags, mode)) < 0) {
+ giterr_set(GITERR_OS, "Could not open '%s' for writing", path);
+ return fd;
+ }
+
+ if (!data->opts.disable_filters &&
+ (error = git_filter_list__load_with_attr_session(
&fl, data->repo, &data->attr_session, blob, hint_path,
- GIT_FILTER_TO_WORKTREE, GIT_FILTER_OPT_DEFAULT);
+ GIT_FILTER_TO_WORKTREE, GIT_FILTER_OPT_DEFAULT)))
+ return error;
+
+ /* setup the writer */
+ memset(&writer, 0, sizeof(struct checkout_stream));
+ writer.base.write = checkout_stream_write;
+ writer.base.close = checkout_stream_close;
+ writer.base.free = checkout_stream_free;
+ writer.path = path;
+ writer.fd = fd;
+ writer.open = 1;
+
+ error = git_filter_list_stream_blob(fl, blob, (git_filter_stream *)&writer);
- if (!error)
- error = git_filter_list_apply_to_blob(&out, fl, blob);
+ assert(writer.open == 0);
git_filter_list_free(fl);
+ p_close(fd);
- if (!error) {
- error = buffer_to_file(data, st, &out, path, file_mode);
- st->st_mode = entry_filemode;
+ if (error < 0)
+ return error;
+
+ if (GIT_PERMS_IS_EXEC(mode)) {
+ data->perfdata.chmod_calls++;
+
+ if ((error = p_chmod(path, mode)) < 0) {
+ giterr_set(GITERR_OS, "Failed to set permissions on '%s'", path);
+ return error;
+ }
+ }
- git_buf_free(&out);
+ if (st) {
+ data->perfdata.stat_calls++;
+
+ if ((error = p_stat(path, st)) < 0) {
+ giterr_set(GITERR_OS, "Error statting '%s'", path);
+ return error;
+ }
+
+ st->st_mode = entry_filemode;
}
- return error;
+ return 0;
}
static int blob_content_to_link(