static int write_index(git_index *index, git_filebuf *file) { int error = GIT_SUCCESS; git_oid hash_final; struct index_header header; int is_extended; assert(index && file); is_extended = is_index_extended(index); header.signature = htonl(INDEX_HEADER_SIG); header.version = htonl(is_extended ? INDEX_VERSION_NUMBER_EXT : INDEX_VERSION_NUMBER); header.entry_count = htonl(index->entries.length); git_filebuf_write(file, &header, sizeof(struct index_header)); error = write_entries(index, file); if (error < GIT_SUCCESS) return git__rethrow(error, "Failed to write index"); /* TODO: write extensions (tree cache) */ /* get out the hash for all the contents we've appended to the file */ git_filebuf_hash(&hash_final, file); /* write it at the end of the file */ git_filebuf_write(file, hash_final.id, GIT_OID_RAWSZ); return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to write index"); }
int git_blob_create_fromchunks( git_oid *oid, git_repository *repo, const char *hintpath, int (*source_cb)(char *content, size_t max_length, void *payload), void *payload) { int error; char *content = NULL; git_filebuf file = GIT_FILEBUF_INIT; git_buf path = GIT_BUF_INIT; assert(oid && repo && source_cb); if ((error = git_buf_joinpath( &path, git_repository_path(repo), GIT_OBJECTS_DIR "streamed")) < 0) goto cleanup; content = git__malloc(BUFFER_SIZE); GITERR_CHECK_ALLOC(content); if ((error = git_filebuf_open( &file, git_buf_cstr(&path), GIT_FILEBUF_TEMPORARY, 0666)) < 0) goto cleanup; while (1) { int read_bytes = source_cb(content, BUFFER_SIZE, payload); if (!read_bytes) break; if (read_bytes > BUFFER_SIZE) { giterr_set(GITERR_OBJECT, "Invalid chunk size while creating blob"); error = GIT_EBUFS; } else if (read_bytes < 0) { error = giterr_set_after_callback(read_bytes); } else { error = git_filebuf_write(&file, content, read_bytes); } if (error < 0) goto cleanup; } if ((error = git_filebuf_flush(&file)) < 0) goto cleanup; error = git_blob__create_from_paths( oid, NULL, repo, file.path_lock, hintpath, 0, hintpath != NULL); cleanup: git_buf_free(&path); git_filebuf_cleanup(&file); git__free(content); return error; }
int git_filebuf_printf(git_filebuf *file, const char *format, ...) { va_list arglist; size_t space_left; int len, res; char *tmp_buffer; ENSURE_BUF_OK(file); space_left = file->buf_size - file->buf_pos; do { va_start(arglist, format); len = p_vsnprintf((char *)file->buffer + file->buf_pos, space_left, format, arglist); va_end(arglist); if (len < 0) { file->last_error = BUFERR_MEM; return -1; } if ((size_t)len + 1 <= space_left) { file->buf_pos += len; return 0; } if (flush_buffer(file) < 0) return -1; space_left = file->buf_size - file->buf_pos; } while ((size_t)len + 1 <= space_left); tmp_buffer = git__malloc(len + 1); if (!tmp_buffer) { file->last_error = BUFERR_MEM; return -1; } va_start(arglist, format); len = p_vsnprintf(tmp_buffer, len + 1, format, arglist); va_end(arglist); if (len < 0) { git__free(tmp_buffer); file->last_error = BUFERR_MEM; return -1; } res = git_filebuf_write(file, tmp_buffer, len); git__free(tmp_buffer); return res; }
int git_blob_create_fromchunks( git_oid *oid, git_repository *repo, const char *hintpath, int (*source_cb)(char *content, size_t max_length, void *payload), void *payload) { int error = -1, read_bytes; char *content = NULL; git_filebuf file = GIT_FILEBUF_INIT; git_buf path = GIT_BUF_INIT; if (git_buf_join_n( &path, '/', 3, git_repository_path(repo), GIT_OBJECTS_DIR, "streamed") < 0) goto cleanup; content = git__malloc(BUFFER_SIZE); GITERR_CHECK_ALLOC(content); if (git_filebuf_open(&file, git_buf_cstr(&path), GIT_FILEBUF_TEMPORARY) < 0) goto cleanup; while (1) { read_bytes = source_cb(content, BUFFER_SIZE, payload); assert(read_bytes <= BUFFER_SIZE); if (read_bytes <= 0) break; if (git_filebuf_write(&file, content, read_bytes) < 0) goto cleanup; } if (read_bytes < 0) goto cleanup; if (git_filebuf_flush(&file) < 0) goto cleanup; error = blob_create_internal(oid, repo, file.path_lock, hintpath, hintpath != NULL); cleanup: git_buf_free(&path); git_filebuf_cleanup(&file); git__free(content); return error; }
static int loose_backend__write(git_odb_backend *_backend, const git_oid *oid, const void *data, size_t len, git_otype type) { int error = 0; git_buf final_path = GIT_BUF_INIT; char header[MAX_HEADER_LEN]; size_t header_len; git_filebuf fbuf = GIT_FILEBUF_INIT; loose_backend *backend; backend = (loose_backend *)_backend; /* prepare the header for the file */ if ((error = git_odb__format_object_header(&header_len, header, sizeof(header), len, type)) < 0) goto cleanup; if (git_buf_joinpath(&final_path, backend->objects_dir, "tmp_object") < 0 || git_filebuf_open(&fbuf, final_path.ptr, filebuf_flags(backend), backend->object_file_mode) < 0) { error = -1; goto cleanup; } git_filebuf_write(&fbuf, header, header_len); git_filebuf_write(&fbuf, data, len); if (object_file_name(&final_path, backend, oid) < 0 || object_mkdir(&final_path, backend) < 0 || git_filebuf_commit_at(&fbuf, final_path.ptr) < 0) error = -1; cleanup: if (error < 0) git_filebuf_cleanup(&fbuf); git_buf_dispose(&final_path); return error; }
/* make sure git_filebuf_write writes large buffer correctly */ void test_core_filebuf__2(void) { git_filebuf file; char test[] = "test"; unsigned char buf[4096 * 4]; /* 2 * WRITE_BUFFER_SIZE */ memset(buf, 0xfe, sizeof(buf)); cl_git_pass(git_filebuf_open(&file, test, 0)); cl_git_pass(git_filebuf_write(&file, buf, sizeof(buf))); cl_git_pass(git_filebuf_commit(&file)); cl_must_pass(p_unlink(test)); }
/* make sure git_filebuf_write writes large buffer correctly */ void test_core_filebuf__2(void) { git_filebuf file = GIT_FILEBUF_INIT; char test[] = "test"; unsigned char buf[4096 * 4]; /* 2 * WRITE_BUFFER_SIZE */ memset(buf, 0xfe, sizeof(buf)); cl_git_pass(git_filebuf_open(&file, test, 0, 0666)); cl_git_pass(git_filebuf_write(&file, buf, sizeof(buf))); cl_git_pass(git_filebuf_commit(&file)); cl_assert_equal_file((char *)buf, sizeof(buf), test); cl_must_pass(p_unlink(test)); }
void test_index_tests__add(void) { git_index *index; git_filebuf file = GIT_FILEBUF_INIT; git_repository *repo; const git_index_entry *entry; git_oid id1; cl_set_cleanup(&cleanup_myrepo, NULL); /* Intialize a new repository */ cl_git_pass(git_repository_init(&repo, "./myrepo", 0)); /* Ensure we're the only guy in the room */ cl_git_pass(git_repository_index(&index, repo)); cl_assert(git_index_entrycount(index) == 0); /* Create a new file in the working directory */ cl_git_pass(git_futils_mkpath2file("myrepo/test.txt", 0777)); cl_git_pass(git_filebuf_open(&file, "myrepo/test.txt", 0, 0666)); cl_git_pass(git_filebuf_write(&file, "hey there\n", 10)); cl_git_pass(git_filebuf_commit(&file)); /* Store the expected hash of the file/blob * This has been generated by executing the following * $ echo "hey there" | git hash-object --stdin */ cl_git_pass(git_oid_fromstr(&id1, "a8233120f6ad708f843d861ce2b7228ec4e3dec6")); /* Add the new file to the index */ cl_git_pass(git_index_add_bypath(index, "test.txt")); /* Wow... it worked! */ cl_assert(git_index_entrycount(index) == 1); entry = git_index_get_byindex(index, 0); /* And the built-in hashing mechanism worked as expected */ cl_assert_equal_oid(&id1, &entry->id); /* Test access by path instead of index */ cl_assert((entry = git_index_get_bypath(index, "test.txt", 0)) != NULL); cl_assert_equal_oid(&id1, &entry->id); git_index_free(index); git_repository_free(repo); }
static int blob_writestream_write(git_writestream *_stream, const char *buffer, size_t len) { blob_writestream *stream = (blob_writestream *) _stream; return git_filebuf_write(&stream->fbuf, buffer, len); }
void test_index_tests__add_frombuffer_reset_entry(void) { git_index *index; git_repository *repo; git_index_entry entry; const git_index_entry *returned_entry; git_filebuf file = GIT_FILEBUF_INIT; git_oid id1; git_blob *blob; const char *old_content = "here\n"; const char *content = "hey there\n"; cl_set_cleanup(&cleanup_myrepo, NULL); /* Intialize a new repository */ cl_git_pass(git_repository_init(&repo, "./myrepo", 0)); cl_git_pass(git_repository_index(&index, repo)); cl_git_pass(git_futils_mkpath2file("myrepo/test.txt", 0777)); cl_git_pass(git_filebuf_open(&file, "myrepo/test.txt", 0, 0666)); cl_git_pass(git_filebuf_write(&file, old_content, strlen(old_content))); cl_git_pass(git_filebuf_commit(&file)); /* Store the expected hash of the file/blob * This has been generated by executing the following * $ echo "hey there" | git hash-object --stdin */ cl_git_pass(git_oid_fromstr(&id1, "a8233120f6ad708f843d861ce2b7228ec4e3dec6")); cl_git_pass(git_index_add_bypath(index, "test.txt")); /* Add the new file to the index */ memset(&entry, 0x0, sizeof(git_index_entry)); entry.mode = GIT_FILEMODE_BLOB; entry.path = "test.txt"; cl_git_pass(git_index_add_frombuffer(index, &entry, content, strlen(content))); /* Wow... it worked! */ cl_assert(git_index_entrycount(index) == 1); returned_entry = git_index_get_byindex(index, 0); /* And the built-in hashing mechanism worked as expected */ cl_assert_equal_oid(&id1, &returned_entry->id); /* And mode is the one asked */ cl_assert_equal_i(GIT_FILEMODE_BLOB, returned_entry->mode); /* Test access by path instead of index */ cl_assert((returned_entry = git_index_get_bypath(index, "test.txt", 0)) != NULL); cl_assert_equal_oid(&id1, &returned_entry->id); cl_assert_equal_i(0, returned_entry->dev); cl_assert_equal_i(0, returned_entry->ino); cl_assert_equal_i(0, returned_entry->uid); cl_assert_equal_i(0, returned_entry->uid); cl_assert_equal_i(10, returned_entry->file_size); /* Test the blob is in the repository */ cl_git_pass(git_blob_lookup(&blob, repo, &id1)); cl_assert_equal_s(content, git_blob_rawcontent(blob)); git_blob_free(blob); git_index_free(index); git_repository_free(repo); }
static int loose_backend__writestream_write(git_odb_stream *_stream, const char *data, size_t len) { loose_writestream *stream = (loose_writestream *)_stream; return git_filebuf_write(&stream->fbuf, data, len); }
/* Receiving data from a socket and storing it is pretty much the same for git and HTTP */ int git_fetch__download_pack( char **out, const char *buffered, size_t buffered_size, GIT_SOCKET fd, git_repository *repo) { git_filebuf file = GIT_FILEBUF_INIT; int error; char buff[1024]; git_buf path = GIT_BUF_INIT; static const char suff[] = "/objects/pack/pack-received"; gitno_buffer buf; gitno_buffer_setup(&buf, buff, sizeof(buff), fd); if (memcmp(buffered, "PACK", strlen("PACK"))) { return git__throw(GIT_ERROR, "The pack doesn't start with the signature"); } error = git_buf_joinpath(&path, repo->path_repository, suff); if (error < GIT_SUCCESS) goto cleanup; error = git_filebuf_open(&file, path.ptr, GIT_FILEBUF_TEMPORARY); if (error < GIT_SUCCESS) goto cleanup; /* Part of the packfile has been received, don't loose it */ error = git_filebuf_write(&file, buffered, buffered_size); if (error < GIT_SUCCESS) goto cleanup; while (1) { error = git_filebuf_write(&file, buf.data, buf.offset); if (error < GIT_SUCCESS) goto cleanup; gitno_consume_n(&buf, buf.offset); error = gitno_recv(&buf); if (error < GIT_SUCCESS) goto cleanup; if (error == 0) /* Orderly shutdown */ break; } *out = git__strdup(file.path_lock); if (*out == NULL) { error = GIT_ENOMEM; goto cleanup; } /* A bit dodgy, but we need to keep the pack at the temporary path */ error = git_filebuf_commit_at(&file, file.path_lock, GIT_PACK_FILE_MODE); cleanup: if (error < GIT_SUCCESS) git_filebuf_cleanup(&file); git_buf_free(&path); return error; }
int git_indexer_commit(git_indexer *idx, git_transfer_progress *stats) { git_mwindow *w = NULL; unsigned int i, long_offsets = 0, left; int error; struct git_pack_idx_header hdr; git_buf filename = GIT_BUF_INIT; struct entry *entry; git_oid trailer_hash, file_hash; git_hash_ctx ctx; git_filebuf index_file = {0}; void *packfile_trailer; if (git_hash_ctx_init(&ctx) < 0) return -1; /* Test for this before resolve_deltas(), as it plays with idx->off */ if (idx->off < idx->pack->mwf.size - 20) { giterr_set(GITERR_INDEXER, "Unexpected data at the end of the pack"); return -1; } packfile_trailer = git_mwindow_open(&idx->pack->mwf, &w, idx->pack->mwf.size - GIT_OID_RAWSZ, GIT_OID_RAWSZ, &left); if (packfile_trailer == NULL) { git_mwindow_close(&w); goto on_error; } /* Compare the packfile trailer as it was sent to us and what we calculated */ git_oid_fromraw(&file_hash, (unsigned char*) packfile_trailer); git_mwindow_close(&w); git_hash_final(&trailer_hash, &idx->trailer); if (git_oid_cmp(&file_hash, &trailer_hash)) { giterr_set(GITERR_INDEXER, "packfile trailer mismatch"); return -1; } /* Freeze the number of deltas */ stats->total_deltas = stats->total_objects - stats->indexed_objects; if ((error = resolve_deltas(idx, stats)) < 0) return error; if (stats->indexed_objects != stats->total_objects) { giterr_set(GITERR_INDEXER, "early EOF"); return -1; } if (stats->local_objects > 0) { if (update_header_and_rehash(idx, stats) < 0) return -1; git_hash_final(&trailer_hash, &idx->trailer); write_at(idx, &trailer_hash, idx->pack->mwf.size - GIT_OID_RAWSZ, GIT_OID_RAWSZ); } git_vector_sort(&idx->objects); git_buf_sets(&filename, idx->pack->pack_name); git_buf_shorten(&filename, strlen("pack")); git_buf_puts(&filename, "idx"); if (git_buf_oom(&filename)) return -1; if (git_filebuf_open(&index_file, filename.ptr, GIT_FILEBUF_HASH_CONTENTS, idx->mode) < 0) goto on_error; /* Write out the header */ hdr.idx_signature = htonl(PACK_IDX_SIGNATURE); hdr.idx_version = htonl(2); git_filebuf_write(&index_file, &hdr, sizeof(hdr)); /* Write out the fanout table */ for (i = 0; i < 256; ++i) { uint32_t n = htonl(idx->fanout[i]); git_filebuf_write(&index_file, &n, sizeof(n)); } /* Write out the object names (SHA-1 hashes) */ git_vector_foreach(&idx->objects, i, entry, struct entry*) { git_filebuf_write(&index_file, &entry->oid, sizeof(git_oid)); git_hash_update(&ctx, &entry->oid, GIT_OID_RAWSZ); } git_hash_final(&idx->hash, &ctx); /* Write out the CRC32 values */ git_vector_foreach(&idx->objects, i, entry, struct entry*) { git_filebuf_write(&index_file, &entry->crc, sizeof(uint32_t)); } /* Write out the offsets */ git_vector_foreach(&idx->objects, i, entry, struct entry*) { uint32_t n; if (entry->offset == UINT32_MAX) n = htonl(0x80000000 | long_offsets++); else n = htonl(entry->offset); git_filebuf_write(&index_file, &n, sizeof(uint32_t)); } /* Write out the long offsets */ git_vector_foreach(&idx->objects, i, entry, struct entry*) { uint32_t split[2]; if (entry->offset != UINT32_MAX) continue; split[0] = htonl(entry->offset_long >> 32); split[1] = htonl(entry->offset_long & 0xffffffff); git_filebuf_write(&index_file, &split, sizeof(uint32_t) * 2); } /* Write out the packfile trailer to the index */ if (git_filebuf_write(&index_file, &trailer_hash, GIT_OID_RAWSZ) < 0) goto on_error; /* Write out the hash of the idx */ if (git_filebuf_hash(&trailer_hash, &index_file) < 0) goto on_error; git_filebuf_write(&index_file, &trailer_hash, sizeof(git_oid)); /* Figure out what the final name should be */ if (index_path(&filename, idx, ".idx") < 0) goto on_error; /* Commit file */ if (git_filebuf_commit_at(&index_file, filename.ptr) < 0) goto on_error; git_mwindow_free_all(&idx->pack->mwf); /* We need to close the descriptor here so Windows doesn't choke on commit_at */ if (p_close(idx->pack->mwf.fd) < 0) { giterr_set(GITERR_OS, "failed to close packfile"); goto on_error; } idx->pack->mwf.fd = -1; if (index_path(&filename, idx, ".pack") < 0) goto on_error; /* And don't forget to rename the packfile to its new place. */ p_rename(idx->pack->pack_name, git_buf_cstr(&filename)); git_buf_free(&filename); git_hash_ctx_cleanup(&ctx); return 0; on_error: git_mwindow_free_all(&idx->pack->mwf); git_filebuf_cleanup(&index_file); git_buf_free(&filename); git_hash_ctx_cleanup(&ctx); return -1; }
BEGIN_TEST(config16, "add a variable in a new section") git_config *cfg; int i; git_filebuf buf; /* By freeing the config, we make sure we flush the values */ must_pass(git_config_open_ondisk(&cfg, CONFIG_BASE "/config10")); must_pass(git_config_set_int(cfg, "section.tmp", 5)); must_pass(git_config_get_int(cfg, "section.tmp", &i)); must_be_true(i == 5); must_pass(git_config_delete(cfg, "section.tmp")); git_config_free(cfg); /* As the section wasn't removed, owerwrite the file */ must_pass(git_filebuf_open(&buf, CONFIG_BASE "/config10", 0)); must_pass(git_filebuf_write(&buf, "[empty]\n", strlen("[empty]\n"))); must_pass(git_filebuf_commit(&buf)); END_TEST BEGIN_SUITE(config) ADD_TEST(config0); ADD_TEST(config1); ADD_TEST(config2); ADD_TEST(config3); ADD_TEST(config4); ADD_TEST(config5); ADD_TEST(config6); ADD_TEST(config7); ADD_TEST(config8); ADD_TEST(config9); ADD_TEST(config10);