Commit 97affdf2 by Russell Belfer

Merge pull request #1815 from libgit2/ntk/topic/stream_write/check_before_overwriting

Ask the odbbackend if the object exists before overwriting it
parents 366bd2f4 4047950f
...@@ -92,6 +92,10 @@ struct git_odb_stream { ...@@ -92,6 +92,10 @@ struct git_odb_stream {
/** /**
* Store the contents of the stream as an object with the id * Store the contents of the stream as an object with the id
* specified in `oid`. * specified in `oid`.
*
* This method will *not* be invoked by libgit2 if the object pointed at
* by `oid` already exists in any backend. Libgit2 will however take care
* of properly disposing the stream through a call to `free()`.
*/ */
int (*finalize_write)(git_odb_stream *stream, const git_oid *oid); int (*finalize_write)(git_odb_stream *stream, const git_oid *oid);
......
...@@ -900,6 +900,10 @@ int git_odb_stream_write(git_odb_stream *stream, const char *buffer, size_t len) ...@@ -900,6 +900,10 @@ int git_odb_stream_write(git_odb_stream *stream, const char *buffer, size_t len)
int git_odb_stream_finalize_write(git_oid *out, git_odb_stream *stream) int git_odb_stream_finalize_write(git_oid *out, git_odb_stream *stream)
{ {
git_hash_final(out, stream->hash_ctx); git_hash_final(out, stream->hash_ctx);
if (git_odb_exists(stream->backend->odb, out))
return 0;
return stream->finalize_write(stream, out); return stream->finalize_write(stream, out);
} }
......
...@@ -781,13 +781,6 @@ static int loose_backend__stream_fwrite(git_odb_stream *_stream, const git_oid * ...@@ -781,13 +781,6 @@ static int loose_backend__stream_fwrite(git_odb_stream *_stream, const git_oid *
if (object_file_name(&final_path, backend, oid) < 0 || if (object_file_name(&final_path, backend, oid) < 0 ||
object_mkdir(&final_path, backend) < 0) object_mkdir(&final_path, backend) < 0)
error = -1; error = -1;
/*
* Don't try to add an existing object to the repository. This
* is what git does and allows us to sidestep the fact that
* we're not allowed to overwrite a read-only file on Windows.
*/
else if (git_path_exists(final_path.ptr) == true)
git_filebuf_cleanup(&stream->fbuf);
else else
error = git_filebuf_commit_at( error = git_filebuf_commit_at(
&stream->fbuf, final_path.ptr, GIT_OBJECT_FILE_MODE); &stream->fbuf, final_path.ptr, GIT_OBJECT_FILE_MODE);
......
...@@ -41,14 +41,46 @@ void test_object_blob_fromchunks__can_create_a_blob_from_a_in_memory_chunk_provi ...@@ -41,14 +41,46 @@ void test_object_blob_fromchunks__can_create_a_blob_from_a_in_memory_chunk_provi
cl_git_pass(git_oid_fromstr(&expected_oid, "321cbdf08803c744082332332838df6bd160f8f9")); cl_git_pass(git_oid_fromstr(&expected_oid, "321cbdf08803c744082332332838df6bd160f8f9"));
cl_git_fail(git_object_lookup(&blob, repo, &expected_oid, GIT_OBJ_ANY)); cl_git_fail_with(
git_object_lookup(&blob, repo, &expected_oid, GIT_OBJ_ANY),
GIT_ENOTFOUND);
cl_git_pass(git_blob_create_fromchunks(&oid, repo, NULL, text_chunked_source_cb, &howmany)); cl_git_pass(git_blob_create_fromchunks(&oid, repo, NULL, text_chunked_source_cb, &howmany));
cl_git_pass(git_object_lookup(&blob, repo, &expected_oid, GIT_OBJ_ANY)); cl_git_pass(git_object_lookup(&blob, repo, &expected_oid, GIT_OBJ_ANY));
cl_assert(git_oid_cmp(&expected_oid, git_object_id(blob)) == 0);
git_object_free(blob); git_object_free(blob);
} }
void test_object_blob_fromchunks__doesnot_overwrite_an_already_existing_object(void)
{
git_buf path = GIT_BUF_INIT;
git_buf content = GIT_BUF_INIT;
git_oid expected_oid, oid;
int howmany = 7;
cl_git_pass(git_oid_fromstr(&expected_oid, "321cbdf08803c744082332332838df6bd160f8f9"));
cl_git_pass(git_blob_create_fromchunks(&oid, repo, NULL, text_chunked_source_cb, &howmany));
/* Let's replace the content of the blob file storage with something else... */
cl_git_pass(git_buf_joinpath(&path, git_repository_path(repo), "objects/32/1cbdf08803c744082332332838df6bd160f8f9"));
cl_git_pass(p_unlink(git_buf_cstr(&path)));
cl_git_mkfile(git_buf_cstr(&path), "boom");
/* ...request a creation of the same blob... */
howmany = 7;
cl_git_pass(git_blob_create_fromchunks(&oid, repo, NULL, text_chunked_source_cb, &howmany));
/* ...and ensure the content of the faked blob file hasn't been altered */
cl_git_pass(git_futils_readbuffer(&content, git_buf_cstr(&path)));
cl_assert(!git__strcmp("boom", git_buf_cstr(&content)));
git_buf_free(&path);
git_buf_free(&content);
}
#define GITATTR "* text=auto\n" \ #define GITATTR "* text=auto\n" \
"*.txt text\n" \ "*.txt text\n" \
"*.data binary\n" "*.data binary\n"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment