mirror of
				https://git.proxmox.com/git/libgit2
				synced 2025-10-31 00:16:35 +00:00 
			
		
		
		
	Merge pull request #3948 from libgit2/cmn/v24-updates
Backport fixes to v0.24
This commit is contained in:
		
						commit
						e9f10cdad1
					
				| @ -40,7 +40,7 @@ OPTION( USE_ICONV			"Link with and use iconv library" 		OFF ) | ||||
| OPTION( USE_SSH				"Link with libssh to enable SSH support" ON ) | ||||
| OPTION( USE_GSSAPI			"Link with libgssapi for SPNEGO auth"   OFF ) | ||||
| OPTION( VALGRIND			"Configure build for valgrind"			OFF ) | ||||
| OPTION( CURL			"User curl for HTTP if available" ON) | ||||
| OPTION( CURL			"Use curl for HTTP if available" ON) | ||||
| OPTION( DEBUG_POOL			"Enable debug pool allocator"			OFF ) | ||||
| 
 | ||||
| IF(DEBUG_POOL) | ||||
| @ -151,6 +151,10 @@ FUNCTION(TARGET_OS_LIBRARIES target) | ||||
| 		TARGET_LINK_LIBRARIES(${target} socket nsl) | ||||
| 		LIST(APPEND LIBGIT2_PC_LIBS "-lsocket" "-lnsl") | ||||
| 		SET(LIBGIT2_PC_LIBS ${LIBGIT2_PC_LIBS} PARENT_SCOPE) | ||||
| 	ELSEIF(CMAKE_SYSTEM_NAME MATCHES "Haiku") | ||||
| 		TARGET_LINK_LIBRARIES(${target} network) | ||||
| 		LIST(APPEND LIBGIT2_PC_LIBS "-lnetwork") | ||||
| 		SET(LIBGIT2_PC_LIBS ${LIBGIT2_PC_LIBS} PARENT_SCOPE) | ||||
| 	ENDIF() | ||||
| 	CHECK_LIBRARY_EXISTS(rt clock_gettime "time.h" NEED_LIBRT) | ||||
| 	IF(NEED_LIBRT) | ||||
| @ -161,6 +165,8 @@ FUNCTION(TARGET_OS_LIBRARIES target) | ||||
| 
 | ||||
| 	IF(THREADSAFE) | ||||
| 		TARGET_LINK_LIBRARIES(${target} ${CMAKE_THREAD_LIBS_INIT}) | ||||
| 		LIST(APPEND LIBGIT2_PC_LIBS ${CMAKE_THREAD_LIBS_INIT}) | ||||
| 		SET(LIBGIT2_PC_LIBS ${LIBGIT2_PC_LIBS} PARENT_SCOPE) | ||||
| 	ENDIF() | ||||
| ENDFUNCTION() | ||||
| 
 | ||||
| @ -280,6 +286,7 @@ ELSE () | ||||
| 	IF (CURL_FOUND) | ||||
| 		ADD_DEFINITIONS(-DGIT_CURL) | ||||
| 		INCLUDE_DIRECTORIES(${CURL_INCLUDE_DIRS}) | ||||
| 		LINK_DIRECTORIES(${CURL_LIBRARY_DIRS}) | ||||
| 		LINK_LIBRARIES(${CURL_LIBRARIES}) | ||||
| 		LIST(APPEND LIBGIT2_PC_LIBS ${CURL_LDFLAGS}) | ||||
| 	ENDIF() | ||||
| @ -467,19 +474,21 @@ ELSE () | ||||
| 		SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG") | ||||
| 	ENDIF () | ||||
| 
 | ||||
| 	IF (MINGW) # MinGW always does PIC and complains if we tell it to | ||||
| 	IF (MINGW OR MSYS) # MinGW and MSYS always do PIC and complain if we tell them to | ||||
| 		STRING(REGEX REPLACE "-fPIC" "" CMAKE_SHARED_LIBRARY_C_FLAGS "${CMAKE_SHARED_LIBRARY_C_FLAGS}") | ||||
| 		# MinGW >= 3.14 uses the C99-style stdio functions | ||||
| 		# automatically, but forks like mingw-w64 still want | ||||
| 		# us to define this in order to use them | ||||
| 		ADD_DEFINITIONS(-D__USE_MINGW_ANSI_STDIO=1) | ||||
| 
 | ||||
| 	ELSEIF (BUILD_SHARED_LIBS) | ||||
| 		ADD_C_FLAG_IF_SUPPORTED(-fvisibility=hidden) | ||||
| 
 | ||||
| 		SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") | ||||
| 	ENDIF () | ||||
| 
 | ||||
| 	IF (MINGW) | ||||
| 		# MinGW >= 3.14 uses the C99-style stdio functions | ||||
| 		# automatically, but forks like mingw-w64 still want | ||||
| 		# us to define this in order to use them | ||||
| 		ADD_DEFINITIONS(-D__USE_MINGW_ANSI_STDIO=1) | ||||
| 	ENDIF () | ||||
| 
 | ||||
| 	ADD_C_FLAG_IF_SUPPORTED(-Wdocumentation) | ||||
| 	ADD_C_FLAG_IF_SUPPORTED(-Wno-missing-field-initializers) | ||||
| 	ADD_C_FLAG_IF_SUPPORTED(-Wstrict-aliasing=2) | ||||
|  | ||||
							
								
								
									
										50
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										50
									
								
								README.md
									
									
									
									
									
								
							| @ -15,18 +15,30 @@ with any kind of software without having to release its source code. | ||||
| Additionally, the example code has been released to the public domain (see the | ||||
| [separate license](examples/COPYING) for more information). | ||||
| 
 | ||||
| * Website: [libgit2.github.com](http://libgit2.github.com) | ||||
| * StackOverflow Tag: [libgit2](http://stackoverflow.com/questions/tagged/libgit2) | ||||
| * Issues: [GitHub Issues](https://github.com/libgit2/libgit2/issues) (Right here!) | ||||
| * API documentation: <http://libgit2.github.com/libgit2/> | ||||
| * IRC: [#libgit2](irc://irc.freenode.net/libgit2) on irc.freenode.net. | ||||
| * Mailing list: The libgit2 mailing list was | ||||
|     traditionally hosted in Librelist but has been deprecated. We encourage you to | ||||
|     [use StackOverflow](http://stackoverflow.com/questions/tagged/libgit2) instead for any questions regarding | ||||
|     the library, or [open an issue](https://github.com/libgit2/libgit2/issues) | ||||
|     on GitHub for bug reports.  The mailing list archives are still available at | ||||
|     <http://librelist.com/browser/libgit2/>. | ||||
| Getting Help | ||||
| ============ | ||||
| 
 | ||||
| **Join us on Slack** | ||||
| 
 | ||||
| Visit [slack.libgit2.org](http://slack.libgit2.org/) to sign up, then join | ||||
| us in `#libgit2`.  If you prefer IRC, you can also point your client to our | ||||
| slack channel once you've registered. | ||||
| 
 | ||||
| **Getting Help** | ||||
| 
 | ||||
| If you have questions about the library, please be sure to check out the | ||||
| [API documentation](http://libgit2.github.com/libgit2/).  If you still have | ||||
| questions, reach out to us on Slack or post a question on  | ||||
| [StackOverflow](http://stackoverflow.com/questions/tagged/libgit2) (with the `libgit2` tag). | ||||
| 
 | ||||
| **Reporting Bugs** | ||||
| 
 | ||||
| Please open a [GitHub Issue](https://github.com/libgit2/libgit2/issues) and | ||||
| include as much information as possible.  If possible, provide sample code | ||||
| that illustrates the problem you're seeing.  If you're seeing a bug only | ||||
| on a specific repository, please provide a link to it if possible. | ||||
| 
 | ||||
| We ask that you not open a GitHub Issue for help, only for bug reports. | ||||
| 
 | ||||
| What It Can Do | ||||
| ============== | ||||
| @ -235,16 +247,22 @@ we can add it to the list. | ||||
| How Can I Contribute? | ||||
| ================================== | ||||
| 
 | ||||
| Check the [contribution guidelines](CONTRIBUTING.md) to understand our | ||||
| workflow, the libgit2 [coding conventions](CONVENTIONS.md), and our list of | ||||
| [good starting projects](PROJECTS.md). | ||||
| We welcome new contributors!  We have a number of issues marked as | ||||
| ["up for grabs"](https://github.com/libgit2/libgit2/issues?q=is%3Aissue+is%3Aopen+label%3A%22up+for+grabs%22) | ||||
| and | ||||
| ["easy fix"](https://github.com/libgit2/libgit2/issues?utf8=✓&q=is%3Aissue+is%3Aopen+label%3A%22easy+fix%22) | ||||
| that are good places to jump in and get started.  There's much more detailed | ||||
| information in our list of [outstanding projects](PROJECTS.md). | ||||
| 
 | ||||
| Please be sure to check the [contribution guidelines](CONTRIBUTING.md) to | ||||
| understand our workflow, and the libgit2 [coding conventions](CONVENTIONS.md). | ||||
| 
 | ||||
| License | ||||
| ================================== | ||||
| 
 | ||||
| `libgit2` is under GPL2 **with linking exception**. This means you can link to | ||||
| and use the library from any program, proprietary or open source; paid or | ||||
| gratis.  However, you cannot modify libgit2 and distribute it without | ||||
| supplying the source. | ||||
| gratis.  However, if you modify libgit2 itself, you must distribute the | ||||
| source to your modified version of libgit2. | ||||
| 
 | ||||
| See the [COPYING file](COPYING) for the full license text. | ||||
|  | ||||
| @ -66,6 +66,8 @@ Key | ||||
| - Bi       - ignored blob (WD only) | ||||
| - T1,T2,T3 - trees with different SHAs, | ||||
| - Ti       - ignored tree (WD only) | ||||
| - S1,S2    - submodules with different SHAs | ||||
| - Sd       - dirty submodule (WD only) | ||||
| - x        - nothing | ||||
| 
 | ||||
| Diff with 2 non-workdir iterators | ||||
| @ -162,6 +164,27 @@ Checkout From 3 Iterators (2 not workdir, 1 workdir) | ||||
| | 35+ |  T1 |     T2 |      x         | update locally deleted tree (SAFE+MISSING)                         | | ||||
| | 36* |  T1 |     T2 |  B1/Bi         | update to tree with typechanged tree->blob conflict (F-1)          | | ||||
| | 37  |  T1 |     T2 | T1/T2/T3       | update to existing tree (MAYBE SAFE)                               | | ||||
| | 38+ |   x |     S1 |      x         | add submodule (SAFE)                                               | | ||||
| | 39  |   x |     S1 |  S1/Sd         | independently added submodule (SUBMODULE)                          | | ||||
| | 40* |   x |     S1 |     B1         | add submodule with blob confilct (FORCEABLE)                       | | ||||
| | 41* |   x |     S1 |     T1         | add submodule with tree conflict (FORCEABLE)                       | | ||||
| | 42  |  S1 |      x |  S1/Sd         | deleted submodule (SUBMODULE)                                      | | ||||
| | 43  |  S1 |      x |      x         | independently deleted submodule (SUBMODULE)                        | | ||||
| | 44  |  S1 |      x |     B1         | independently deleted submodule with added blob (SAFE+MISSING)     | | ||||
| | 45  |  S1 |      x |     T1         | independently deleted submodule with added tree (SAFE+MISSING)     | | ||||
| | 46  |  S1 |     S1 |      x         | locally deleted submodule (SUBMODULE)                              | | ||||
| | 47+ |  S1 |     S2 |      x         | update locally deleted submodule (SAFE)                            | | ||||
| | 48  |  S1 |     S1 |     S2         | locally updated submodule commit (SUBMODULE)                       | | ||||
| | 49  |  S1 |     S2 |     S1         | updated submodule commit (SUBMODULE)                               | | ||||
| | 50+ |  S1 |     B1 |      x         | add blob with locally deleted submodule (SAFE+MISSING)             | | ||||
| | 51* |  S1 |     B1 |     S1         | typechange submodule->blob (SAFE)                                  | | ||||
| | 52* |  S1 |     B1 |     Sd         | typechange dirty submodule->blob (SAFE!?!?)                        | | ||||
| | 53+ |  S1 |     T1 |      x         | add tree with locally deleted submodule (SAFE+MISSING)             | | ||||
| | 54* |  S1 |     T1 |  S1/Sd         | typechange submodule->tree (MAYBE SAFE)                            | | ||||
| | 55+ |  B1 |     S1 |      x         | add submodule with locally deleted blob (SAFE+MISSING)             | | ||||
| | 56* |  B1 |     S1 |     B1         | typechange blob->submodule (SAFE)                                  | | ||||
| | 57+ |  T1 |     S1 |      x         | add submodule with locally deleted tree (SAFE+MISSING)             | | ||||
| | 58* |  T1 |     S1 |     T1         | typechange tree->submodule (SAFE)                                  | | ||||
| 
 | ||||
| 
 | ||||
| The number is followed by ' ' if no change is needed or '+' if the case | ||||
| @ -176,6 +199,8 @@ There are four tiers of safe cases: | ||||
|                   content, which is unknown at this point | ||||
| * FORCEABLE == conflict unless FORCE is given | ||||
| * DIRTY     == no conflict but change is not applied unless FORCE | ||||
| * SUBMODULE == no conflict and no change is applied unless a deleted | ||||
|                submodule dir is empty | ||||
| 
 | ||||
| Some slightly unusual circumstances: | ||||
| 
 | ||||
| @ -198,7 +223,9 @@ Some slightly unusual circumstances: | ||||
|     cases, if baseline == target, we don't touch the workdir (it is | ||||
|     either already right or is "dirty").  However, since this case also | ||||
|     implies that a ?/B1/x case will exist as well, it can be skipped. | ||||
| * 41 - It's not clear how core git distinguishes this case from 39 (mode?). | ||||
| * 52 - Core git makes destructive changes without any warning when the | ||||
|     submodule is dirty and the type changes to a blob. | ||||
| 
 | ||||
| Cases 3, 17, 24, 26, and 29 are all considered conflicts even though | ||||
| none of them will require making any updates to the working directory. | ||||
| 
 | ||||
|  | ||||
| @ -313,6 +313,13 @@ GIT_EXTERN(int) git_checkout_init_options( | ||||
|  * Updates files in the index and the working tree to match the content of | ||||
|  * the commit pointed at by HEAD. | ||||
|  * | ||||
|  * Note that this is _not_ the correct mechanism used to switch branches; | ||||
|  * do not change your `HEAD` and then call this method, that would leave | ||||
|  * you with checkout conflicts since your working directory would then | ||||
|  * appear to be dirty.  Instead, checkout the target of the branch and | ||||
|  * then update `HEAD` using `git_repository_set_head` to point to the | ||||
|  * branch you checked out. | ||||
|  * | ||||
|  * @param repo repository to check out (must be non-bare) | ||||
|  * @param opts specifies checkout options (may be NULL) | ||||
|  * @return 0 on success, GIT_EUNBORNBRANCH if HEAD points to a non | ||||
|  | ||||
| @ -96,7 +96,7 @@ GIT_INLINE(int) git_array__search( | ||||
| { | ||||
| 	size_t lim; | ||||
| 	unsigned char *part, *array = array_ptr, *base = array_ptr; | ||||
| 	int cmp; | ||||
| 	int cmp = -1; | ||||
| 
 | ||||
| 	for (lim = array_len; lim != 0; lim >>= 1) { | ||||
| 		part = base + (lim >> 1) * item_size; | ||||
|  | ||||
| @ -37,25 +37,27 @@ static void origin_decref(git_blame__origin *o) | ||||
| static int make_origin(git_blame__origin **out, git_commit *commit, const char *path) | ||||
| { | ||||
| 	git_blame__origin *o; | ||||
| 	git_object *blob; | ||||
| 	size_t path_len = strlen(path), alloc_len; | ||||
| 	int error = 0; | ||||
| 
 | ||||
| 	if ((error = git_object_lookup_bypath(&blob, (git_object*)commit, | ||||
| 			path, GIT_OBJ_BLOB)) < 0) | ||||
| 		return error; | ||||
| 
 | ||||
| 	GITERR_CHECK_ALLOC_ADD(&alloc_len, sizeof(*o), path_len); | ||||
| 	GITERR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, 1); | ||||
| 	o = git__calloc(1, alloc_len); | ||||
| 	GITERR_CHECK_ALLOC(o); | ||||
| 
 | ||||
| 	o->commit = commit; | ||||
| 	o->blob = (git_blob *) blob; | ||||
| 	o->refcnt = 1; | ||||
| 	strcpy(o->path, path); | ||||
| 
 | ||||
| 	if (!(error = git_object_lookup_bypath((git_object**)&o->blob, (git_object*)commit, | ||||
| 			path, GIT_OBJ_BLOB))) { | ||||
| 		*out = o; | ||||
| 	} else { | ||||
| 		origin_decref(o); | ||||
| 	} | ||||
| 	return error; | ||||
| 	*out = o; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /* Locate an existing origin or create a new one. */ | ||||
| @ -529,8 +531,16 @@ static int pass_blame(git_blame *blame, git_blame__origin *origin, uint32_t opt) | ||||
| 			goto finish; | ||||
| 		porigin = find_origin(blame, p, origin); | ||||
| 
 | ||||
| 		if (!porigin) | ||||
| 		if (!porigin) { | ||||
| 			/*
 | ||||
| 			 * We only have to decrement the parent's | ||||
| 			 * reference count when no porigin has | ||||
| 			 * been created, as otherwise the commit | ||||
| 			 * is assigned to the created object. | ||||
| 			 */ | ||||
| 			git_commit_free(p); | ||||
| 			continue; | ||||
| 		} | ||||
| 		if (porigin->blob && origin->blob && | ||||
| 		    !git_oid_cmp(git_blob_id(porigin->blob), git_blob_id(origin->blob))) { | ||||
| 			pass_whole_blame(blame, origin, porigin); | ||||
|  | ||||
| @ -464,7 +464,8 @@ static int checkout_action_with_wd( | ||||
| 			*action = CHECKOUT_ACTION_IF(SAFE, REMOVE, NONE); | ||||
| 		break; | ||||
| 	case GIT_DELTA_MODIFIED: /* case 16, 17, 18 (or 36 but not really) */ | ||||
| 		if (checkout_is_workdir_modified(data, &delta->old_file, &delta->new_file, wd)) | ||||
| 		if (wd->mode != GIT_FILEMODE_COMMIT && | ||||
| 			checkout_is_workdir_modified(data, &delta->old_file, &delta->new_file, wd)) | ||||
| 			*action = CHECKOUT_ACTION_IF(FORCE, UPDATE_BLOB, CONFLICT); | ||||
| 		else | ||||
| 			*action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE); | ||||
| @ -1342,9 +1343,11 @@ fail: | ||||
| 
 | ||||
| static bool should_remove_existing(checkout_data *data) | ||||
| { | ||||
| 	int ignorecase = 0; | ||||
| 	int ignorecase; | ||||
| 
 | ||||
| 	git_repository__cvar(&ignorecase, data->repo, GIT_CVAR_IGNORECASE); | ||||
| 	if (git_repository__cvar(&ignorecase, data->repo, GIT_CVAR_IGNORECASE) < 0) { | ||||
| 		ignorecase = 0; | ||||
| 	} | ||||
| 
 | ||||
| 	return (ignorecase && | ||||
| 		(data->strategy & GIT_CHECKOUT_DONT_REMOVE_EXISTING) == 0); | ||||
| @ -2405,8 +2408,13 @@ static int checkout_data_init( | ||||
| 
 | ||||
| 	if (!data->opts.baseline && !data->opts.baseline_index) { | ||||
| 		data->opts_free_baseline = true; | ||||
| 		error = 0; | ||||
| 
 | ||||
| 		error = checkout_lookup_head_tree(&data->opts.baseline, repo); | ||||
| 		/* if we don't have an index, this is an initial checkout and
 | ||||
| 		 * should be against an empty baseline | ||||
| 		 */ | ||||
| 		if (data->index->on_disk) | ||||
| 			error = checkout_lookup_head_tree(&data->opts.baseline, repo); | ||||
| 
 | ||||
| 		if (error == GIT_EUNBORNBRANCH) { | ||||
| 			error = 0; | ||||
| @ -2691,7 +2699,7 @@ int git_checkout_tree( | ||||
| 	if ((error = git_repository_index(&index, repo)) < 0) | ||||
| 		return error; | ||||
| 
 | ||||
| 	if ((opts->checkout_strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH)) { | ||||
| 	if (opts && (opts->checkout_strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH)) { | ||||
| 		iter_opts.pathlist.count = opts->paths.count; | ||||
| 		iter_opts.pathlist.strings = opts->paths.strings; | ||||
| 	} | ||||
|  | ||||
| @ -45,7 +45,7 @@ | ||||
| # include "win32/error.h" | ||||
| # include "win32/version.h" | ||||
| # ifdef GIT_THREADS | ||||
| #	include "win32/pthread.h" | ||||
| #	include "win32/thread.h" | ||||
| # endif | ||||
| # if defined(GIT_MSVC_CRTDBG) | ||||
| #   include "win32/w32_stack.h" | ||||
|  | ||||
| @ -49,6 +49,37 @@ int git__delta_read_header( | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| #define DELTA_HEADER_BUFFER_LEN 16 | ||||
| int git__delta_read_header_fromstream(size_t *base_sz, size_t *res_sz, git_packfile_stream *stream) | ||||
| { | ||||
| 	static const size_t buffer_len = DELTA_HEADER_BUFFER_LEN; | ||||
| 	unsigned char buffer[DELTA_HEADER_BUFFER_LEN]; | ||||
| 	const unsigned char *delta, *delta_end; | ||||
| 	size_t len; | ||||
| 	ssize_t read; | ||||
| 
 | ||||
| 	len = read = 0; | ||||
| 	while (len < buffer_len) { | ||||
| 		read = git_packfile_stream_read(stream, &buffer[len], buffer_len - len); | ||||
| 
 | ||||
| 		if (read == 0) | ||||
| 			break; | ||||
| 
 | ||||
| 		if (read == GIT_EBUFS) | ||||
| 			continue; | ||||
| 
 | ||||
| 		len += read; | ||||
| 	} | ||||
| 
 | ||||
| 	delta = buffer; | ||||
| 	delta_end = delta + len; | ||||
| 	if ((hdr_sz(base_sz, &delta, delta_end) < 0) || | ||||
| 	    (hdr_sz(res_sz, &delta, delta_end) < 0)) | ||||
| 		return -1; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int git__delta_apply( | ||||
| 	git_rawobj *out, | ||||
| 	const unsigned char *base, | ||||
| @ -90,13 +121,13 @@ int git__delta_apply( | ||||
| 			size_t off = 0, len = 0; | ||||
| 
 | ||||
| 			if (cmd & 0x01) off = *delta++; | ||||
| 			if (cmd & 0x02) off |= *delta++ << 8; | ||||
| 			if (cmd & 0x04) off |= *delta++ << 16; | ||||
| 			if (cmd & 0x08) off |= *delta++ << 24; | ||||
| 			if (cmd & 0x02) off |= *delta++ << 8UL; | ||||
| 			if (cmd & 0x04) off |= *delta++ << 16UL; | ||||
| 			if (cmd & 0x08) off |= *delta++ << 24UL; | ||||
| 
 | ||||
| 			if (cmd & 0x10) len = *delta++; | ||||
| 			if (cmd & 0x20) len |= *delta++ << 8; | ||||
| 			if (cmd & 0x40) len |= *delta++ << 16; | ||||
| 			if (cmd & 0x20) len |= *delta++ << 8UL; | ||||
| 			if (cmd & 0x40) len |= *delta++ << 16UL; | ||||
| 			if (!len)		len = 0x10000; | ||||
| 
 | ||||
| 			if (base_len < off + len || res_sz < len) | ||||
|  | ||||
| @ -8,6 +8,7 @@ | ||||
| #define INCLUDE_delta_apply_h__ | ||||
| 
 | ||||
| #include "odb.h" | ||||
| #include "pack.h" | ||||
| 
 | ||||
| /**
 | ||||
|  * Apply a git binary delta to recover the original content. | ||||
| @ -47,4 +48,15 @@ extern int git__delta_read_header( | ||||
| 	size_t *base_sz, | ||||
| 	size_t *res_sz); | ||||
| 
 | ||||
| /**
 | ||||
|  * Read the header of a git binary delta | ||||
|  * | ||||
|  * This variant reads just enough from the packfile stream to read the | ||||
|  * delta header. | ||||
|  */ | ||||
| extern int git__delta_read_header_fromstream( | ||||
| 	size_t *base_sz, | ||||
| 	size_t *res_sz, | ||||
| 	git_packfile_stream *stream); | ||||
| 
 | ||||
| #endif | ||||
|  | ||||
| @ -70,7 +70,7 @@ static int lock_file(git_filebuf *file, int flags, mode_t mode) | ||||
| 		git_file source; | ||||
| 		char buffer[FILEIO_BUFSIZE]; | ||||
| 		ssize_t read_bytes; | ||||
| 		int error; | ||||
| 		int error = 0; | ||||
| 
 | ||||
| 		source = p_open(file->path_original, O_RDONLY); | ||||
| 		if (source < 0) { | ||||
|  | ||||
							
								
								
									
										20
									
								
								src/global.c
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								src/global.c
									
									
									
									
									
								
							| @ -59,8 +59,9 @@ static int init_common(void) | ||||
| 	if ((ret = git_hash_global_init()) == 0 && | ||||
| 		(ret = git_sysdir_global_init()) == 0 && | ||||
| 		(ret = git_filter_global_init()) == 0 && | ||||
| 		(ret = git_transport_ssh_global_init()) == 0) | ||||
| 		ret = git_openssl_stream_global_init(); | ||||
| 		(ret = git_transport_ssh_global_init()) == 0 && | ||||
| 		(ret = git_openssl_stream_global_init()) == 0) | ||||
| 		ret = git_mwindow_global_init(); | ||||
| 
 | ||||
| 	GIT_MEMORY_BARRIER; | ||||
| 
 | ||||
| @ -85,11 +86,6 @@ static void shutdown_common(void) | ||||
| 
 | ||||
| 	git__free(git__user_agent); | ||||
| 	git__free(git__ssl_ciphers); | ||||
| 
 | ||||
| #if defined(GIT_MSVC_CRTDBG) | ||||
| 	git_win32__crtdbg_stacktrace_cleanup(); | ||||
| 	git_win32__stack_cleanup(); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
| @ -137,7 +133,7 @@ static int synchronized_threads_init(void) | ||||
| 
 | ||||
| 	_tls_index = TlsAlloc(); | ||||
| 
 | ||||
| 	win32_pthread_initialize(); | ||||
| 	git_threads_init(); | ||||
| 
 | ||||
| 	if (git_mutex_init(&git__mwindow_mutex)) | ||||
| 		return -1; | ||||
| @ -181,6 +177,11 @@ int git_libgit2_shutdown(void) | ||||
| 
 | ||||
| 		TlsFree(_tls_index); | ||||
| 		git_mutex_free(&git__mwindow_mutex); | ||||
| 
 | ||||
| #if defined(GIT_MSVC_CRTDBG) | ||||
| 		git_win32__crtdbg_stacktrace_cleanup(); | ||||
| 		git_win32__stack_cleanup(); | ||||
| #endif | ||||
| 	} | ||||
| 
 | ||||
| 	/* Exit the lock */ | ||||
| @ -226,6 +227,9 @@ void git__free_tls_data(void) | ||||
| 
 | ||||
| BOOL WINAPI DllMain(HINSTANCE hInstDll, DWORD fdwReason, LPVOID lpvReserved) | ||||
| { | ||||
| 	GIT_UNUSED(hInstDll); | ||||
| 	GIT_UNUSED(lpvReserved); | ||||
| 
 | ||||
| 	/* This is how Windows lets us know our thread is being shut down */ | ||||
| 	if (fdwReason == DLL_THREAD_DETACH) { | ||||
| 		git__free_tls_data(); | ||||
|  | ||||
							
								
								
									
										61
									
								
								src/ignore.c
									
									
									
									
									
								
							
							
						
						
									
										61
									
								
								src/ignore.c
									
									
									
									
									
								
							| @ -11,35 +11,64 @@ | ||||
| #define GIT_IGNORE_DEFAULT_RULES ".\n..\n.git\n" | ||||
| 
 | ||||
| /**
 | ||||
|  * A negative ignore pattern can match a positive one without | ||||
|  * wildcards if its pattern equals the tail of the positive | ||||
|  * pattern. Thus | ||||
|  * A negative ignore pattern can negate a positive one without | ||||
|  * wildcards if it is a basename only and equals the basename of | ||||
|  * the positive pattern. Thus | ||||
|  * | ||||
|  * foo/bar | ||||
|  * !bar | ||||
|  * | ||||
|  * would result in foo/bar being unignored again. | ||||
|  * would result in foo/bar being unignored again while | ||||
|  * | ||||
|  * moo/foo/bar | ||||
|  * !foo/bar | ||||
|  * | ||||
|  * would do nothing. The reverse also holds true: a positive | ||||
|  * basename pattern can be negated by unignoring the basename in | ||||
|  * subdirectories. Thus | ||||
|  * | ||||
|  * bar | ||||
|  * !foo/bar | ||||
|  * | ||||
|  * would result in foo/bar being unignored again. As with the | ||||
|  * first case, | ||||
|  * | ||||
|  * foo/bar | ||||
|  * !moo/foo/bar | ||||
|  * | ||||
|  * would do nothing, again. | ||||
|  */ | ||||
| static int does_negate_pattern(git_attr_fnmatch *rule, git_attr_fnmatch *neg) | ||||
| { | ||||
| 	git_attr_fnmatch *longer, *shorter; | ||||
| 	char *p; | ||||
| 
 | ||||
| 	if ((rule->flags & GIT_ATTR_FNMATCH_NEGATIVE) == 0 | ||||
| 		&& (neg->flags & GIT_ATTR_FNMATCH_NEGATIVE) != 0) { | ||||
| 		/*
 | ||||
| 		 * no chance of matching if rule is shorter than | ||||
| 		 * the negated one | ||||
| 		 */ | ||||
| 		if (rule->length < neg->length) | ||||
| 
 | ||||
| 		/* If lengths match we need to have an exact match */ | ||||
| 		if (rule->length == neg->length) { | ||||
| 			return strcmp(rule->pattern, neg->pattern) == 0; | ||||
| 		} else if (rule->length < neg->length) { | ||||
| 			shorter = rule; | ||||
| 			longer = neg; | ||||
| 		} else { | ||||
| 			shorter = neg; | ||||
| 			longer = rule; | ||||
| 		} | ||||
| 
 | ||||
| 		/* Otherwise, we need to check if the shorter
 | ||||
| 		 * rule is a basename only (that is, it contains | ||||
| 		 * no path separator) and, if so, if it | ||||
| 		 * matches the tail of the longer rule */ | ||||
| 		p = longer->pattern + longer->length - shorter->length; | ||||
| 
 | ||||
| 		if (p[-1] != '/') | ||||
| 			return false; | ||||
| 		if (memchr(shorter->pattern, '/', shorter->length) != NULL) | ||||
| 			return false; | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * shift pattern so its tail aligns with the | ||||
| 		 * negated pattern | ||||
| 		 */ | ||||
| 		p = rule->pattern + rule->length - neg->length; | ||||
| 		if (strcmp(p, neg->pattern) == 0) | ||||
| 			return true; | ||||
| 		return memcmp(p, shorter->pattern, shorter->length) == 0; | ||||
| 	} | ||||
| 
 | ||||
| 	return false; | ||||
|  | ||||
							
								
								
									
										21
									
								
								src/index.c
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								src/index.c
									
									
									
									
									
								
							| @ -505,10 +505,11 @@ static int index_remove_entry(git_index *index, size_t pos) | ||||
| 	int error = 0; | ||||
| 	git_index_entry *entry = git_vector_get(&index->entries, pos); | ||||
| 
 | ||||
| 	if (entry != NULL) | ||||
| 	if (entry != NULL) { | ||||
| 		git_tree_cache_invalidate_path(index->tree, entry->path); | ||||
| 		DELETE_IN_MAP(index, entry); | ||||
| 	} | ||||
| 
 | ||||
| 	DELETE_IN_MAP(index, entry); | ||||
| 	error = git_vector_remove(&index->entries, pos); | ||||
| 
 | ||||
| 	if (!error) { | ||||
| @ -2968,6 +2969,8 @@ int git_index_read_index( | ||||
| 			*remove_entry = NULL; | ||||
| 		int diff; | ||||
| 
 | ||||
| 		error = 0; | ||||
| 
 | ||||
| 		if (old_entry && new_entry) | ||||
| 			diff = git_index_entry_cmp(old_entry, new_entry); | ||||
| 		else if (!old_entry && new_entry) | ||||
| @ -2985,7 +2988,8 @@ int git_index_read_index( | ||||
| 			/* Path and stage are equal, if the OID is equal, keep it to
 | ||||
| 			 * keep the stat cache data. | ||||
| 			 */ | ||||
| 			if (git_oid_equal(&old_entry->id, &new_entry->id)) { | ||||
| 			if (git_oid_equal(&old_entry->id, &new_entry->id) && | ||||
| 				old_entry->mode == new_entry->mode) { | ||||
| 				add_entry = (git_index_entry *)old_entry; | ||||
| 			} else { | ||||
| 				dup_entry = (git_index_entry *)new_entry; | ||||
| @ -2996,8 +3000,17 @@ int git_index_read_index( | ||||
| 		if (dup_entry) { | ||||
| 			if ((error = index_entry_dup_nocache(&add_entry, index, dup_entry)) < 0) | ||||
| 				goto done; | ||||
| 
 | ||||
| 			index_entry_adjust_namemask(add_entry, | ||||
| 				((struct entry_internal *)add_entry)->pathlen); | ||||
| 		} | ||||
| 
 | ||||
| 		/* invalidate this path in the tree cache if this is new (to
 | ||||
| 		 * invalidate the parent trees) | ||||
| 		 */ | ||||
| 		if (dup_entry && !remove_entry && index->tree) | ||||
| 			git_tree_cache_invalidate_path(index->tree, dup_entry->path); | ||||
| 
 | ||||
| 		if (add_entry) { | ||||
| 			if ((error = git_vector_insert(&new_entries, add_entry)) == 0) | ||||
| 				INSERT_IN_MAP_EX(index, new_entries_map, add_entry, error); | ||||
| @ -3008,7 +3021,7 @@ int git_index_read_index( | ||||
| 
 | ||||
| 		if (error < 0) { | ||||
| 			giterr_set(GITERR_INDEX, "failed to insert entry"); | ||||
| 			return error; | ||||
| 			goto done; | ||||
| 		} | ||||
| 
 | ||||
| 		if (diff <= 0) { | ||||
|  | ||||
| @ -2730,6 +2730,7 @@ static int merge_check_workdir(size_t *conflicts, git_repository *repo, git_inde | ||||
| 	opts.flags |= GIT_DIFF_DISABLE_PATHSPEC_MATCH; | ||||
| 	opts.pathspec.count = merged_paths->length; | ||||
| 	opts.pathspec.strings = (char **)merged_paths->contents; | ||||
| 	opts.ignore_submodules = GIT_SUBMODULE_IGNORE_ALL; | ||||
| 
 | ||||
| 	if ((error = git_diff_index_to_workdir(&wd_diff_list, repo, NULL, &opts)) < 0) | ||||
| 		goto done; | ||||
|  | ||||
| @ -33,20 +33,7 @@ static git_mwindow_ctl mem_ctl; | ||||
| /* Global list of mwindow files, to open packs once across repos */ | ||||
| git_strmap *git__pack_cache = NULL; | ||||
| 
 | ||||
| /**
 | ||||
|  * Run under mwindow lock | ||||
|  */ | ||||
| int git_mwindow_files_init(void) | ||||
| { | ||||
| 	if (git__pack_cache) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	git__on_shutdown(git_mwindow_files_free); | ||||
| 
 | ||||
| 	return git_strmap_alloc(&git__pack_cache); | ||||
| } | ||||
| 
 | ||||
| void git_mwindow_files_free(void) | ||||
| static void git_mwindow_files_free(void) | ||||
| { | ||||
| 	git_strmap *tmp = git__pack_cache; | ||||
| 
 | ||||
| @ -54,6 +41,14 @@ void git_mwindow_files_free(void) | ||||
| 	git_strmap_free(tmp); | ||||
| } | ||||
| 
 | ||||
| int git_mwindow_global_init(void) | ||||
| { | ||||
| 	assert(!git__pack_cache); | ||||
| 
 | ||||
| 	git__on_shutdown(git_mwindow_files_free); | ||||
| 	return git_strmap_alloc(&git__pack_cache); | ||||
| } | ||||
| 
 | ||||
| int git_mwindow_get_pack(struct git_pack_file **out, const char *path) | ||||
| { | ||||
| 	int error; | ||||
| @ -69,12 +64,6 @@ int git_mwindow_get_pack(struct git_pack_file **out, const char *path) | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	if (git_mwindow_files_init() < 0) { | ||||
| 		git_mutex_unlock(&git__mwindow_mutex); | ||||
| 		git__free(packname); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	pos = git_strmap_lookup_index(git__pack_cache, packname); | ||||
| 	git__free(packname); | ||||
| 
 | ||||
|  | ||||
| @ -43,8 +43,7 @@ int git_mwindow_file_register(git_mwindow_file *mwf); | ||||
| void git_mwindow_file_deregister(git_mwindow_file *mwf); | ||||
| void git_mwindow_close(git_mwindow **w_cursor); | ||||
| 
 | ||||
| int git_mwindow_files_init(void); | ||||
| void git_mwindow_files_free(void); | ||||
| extern int git_mwindow_global_init(void); | ||||
| 
 | ||||
| struct git_pack_file; /* just declaration to avoid cyclical includes */ | ||||
| int git_mwindow_get_pack(struct git_pack_file **out, const char *path); | ||||
|  | ||||
							
								
								
									
										11
									
								
								src/odb.c
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								src/odb.c
									
									
									
									
									
								
							| @ -803,19 +803,12 @@ int git_odb__read_header_or_object( | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static git_oid empty_blob = {{ 0xe6, 0x9d, 0xe2, 0x9b, 0xb2, 0xd1, 0xd6, 0x43, 0x4b, 0x8b, | ||||
| 			       0x29, 0xae, 0x77, 0x5a, 0xd8, 0xc2, 0xe4, 0x8c, 0x53, 0x91 }}; | ||||
| static git_oid empty_tree = {{ 0x4b, 0x82, 0x5d, 0xc6, 0x42, 0xcb, 0x6e, 0xb9, 0xa0, 0x60, | ||||
| 			       0xe5, 0x4b, 0xf8, 0xd6, 0x92, 0x88, 0xfb, 0xee, 0x49, 0x04 }}; | ||||
| 
 | ||||
| static int hardcoded_objects(git_rawobj *raw, const git_oid *id) | ||||
| { | ||||
| 	if (!git_oid_cmp(id, &empty_blob)) { | ||||
| 		raw->type = GIT_OBJ_BLOB; | ||||
| 		raw->len = 0; | ||||
| 		raw->data = git__calloc(1, sizeof(uint8_t)); | ||||
| 		return 0; | ||||
| 	} else if (!git_oid_cmp(id, &empty_tree)) { | ||||
| 	if (!git_oid_cmp(id, &empty_tree)) { | ||||
| 		raw->type = GIT_OBJ_TREE; | ||||
| 		raw->len = 0; | ||||
| 		raw->data = git__calloc(1, sizeof(uint8_t)); | ||||
| @ -1229,7 +1222,7 @@ int git_odb__error_notfound( | ||||
| { | ||||
| 	if (oid != NULL) { | ||||
| 		char oid_str[GIT_OID_HEXSZ + 1]; | ||||
| 		git_oid_tostr(oid_str, oid_len, oid); | ||||
| 		git_oid_tostr(oid_str, oid_len+1, oid); | ||||
| 		giterr_set(GITERR_ODB, "Object not found - %s (%.*s)", | ||||
| 			message, oid_len, oid_str); | ||||
| 	} else | ||||
|  | ||||
| @ -91,7 +91,7 @@ static int object_mkdir(const git_buf *name, const loose_backend *be) | ||||
| 
 | ||||
| static size_t get_binary_object_header(obj_hdr *hdr, git_buf *obj) | ||||
| { | ||||
| 	unsigned char c; | ||||
| 	unsigned long c; | ||||
| 	unsigned char *data = (unsigned char *)obj->ptr; | ||||
| 	size_t shift, size, used = 0; | ||||
| 
 | ||||
|  | ||||
| @ -591,9 +591,6 @@ int git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir) | ||||
| 	struct pack_backend *backend = NULL; | ||||
| 	git_buf path = GIT_BUF_INIT; | ||||
| 
 | ||||
| 	if (git_mwindow_files_init() < 0) | ||||
| 		return -1; | ||||
| 
 | ||||
| 	if (pack_backend__alloc(&backend, 8) < 0) | ||||
| 		return -1; | ||||
| 
 | ||||
|  | ||||
| @ -522,8 +522,9 @@ ssize_t openssl_read(git_stream *stream, void *data, size_t len) | ||||
| 	openssl_stream *st = (openssl_stream *) stream; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	if ((ret = SSL_read(st->ssl, data, len)) <= 0) | ||||
| 		ssl_set_error(st->ssl, ret); | ||||
| 	if ((ret = SSL_read(st->ssl, data, len)) <= 0) { | ||||
| 		return ssl_set_error(st->ssl, ret); | ||||
| 	} | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| @ -1186,7 +1186,7 @@ static int ll_find_deltas(git_packbuilder *pb, git_pobject **list, | ||||
| 		git_mutex_init(&p[i].mutex); | ||||
| 		git_cond_init(&p[i].cond); | ||||
| 
 | ||||
| 		ret = git_thread_create(&p[i].thread, NULL, | ||||
| 		ret = git_thread_create(&p[i].thread, | ||||
| 					threaded_find_deltas, &p[i]); | ||||
| 		if (ret) { | ||||
| 			giterr_set(GITERR_THREAD, "unable to create thread"); | ||||
|  | ||||
							
								
								
									
										11
									
								
								src/pack.c
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								src/pack.c
									
									
									
									
									
								
							| @ -499,15 +499,14 @@ int git_packfile_resolve_header( | ||||
| 
 | ||||
| 	if (type == GIT_OBJ_OFS_DELTA || type == GIT_OBJ_REF_DELTA) { | ||||
| 		size_t base_size; | ||||
| 		git_rawobj delta; | ||||
| 		git_packfile_stream stream; | ||||
| 
 | ||||
| 		base_offset = get_delta_base(p, &w_curs, &curpos, type, offset); | ||||
| 		git_mwindow_close(&w_curs); | ||||
| 		error = packfile_unpack_compressed(&delta, p, &w_curs, &curpos, size, type); | ||||
| 		git_mwindow_close(&w_curs); | ||||
| 		if (error < 0) | ||||
| 		if ((error = git_packfile_stream_open(&stream, p, curpos)) < 0) | ||||
| 			return error; | ||||
| 		error = git__delta_read_header(delta.data, delta.len, &base_size, size_p); | ||||
| 		git__free(delta.data); | ||||
| 		error = git__delta_read_header_fromstream(&base_size, size_p, &stream); | ||||
| 		git_packfile_stream_free(&stream); | ||||
| 		if (error < 0) | ||||
| 			return error; | ||||
| 	} else | ||||
|  | ||||
| @ -53,8 +53,10 @@ int git_refspec__parse(git_refspec *refspec, const char *input, bool is_fetch) | ||||
| 
 | ||||
| 	if (rhs) { | ||||
| 		size_t rlen = strlen(++rhs); | ||||
| 		is_glob = (1 <= rlen && strchr(rhs, '*')); | ||||
| 		refspec->dst = git__strndup(rhs, rlen); | ||||
| 		if (rlen || !is_fetch) { | ||||
| 			is_glob = (1 <= rlen && strchr(rhs, '*')); | ||||
| 			refspec->dst = git__strndup(rhs, rlen); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	llen = (rhs ? (size_t)(rhs - lhs - 1) : strlen(lhs)); | ||||
|  | ||||
							
								
								
									
										20
									
								
								src/remote.c
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								src/remote.c
									
									
									
									
									
								
							| @ -1414,7 +1414,11 @@ static int update_tips_for_spec( | ||||
| 		/* In autotag mode, don't overwrite any locally-existing tags */ | ||||
| 		error = git_reference_create(&ref, remote->repo, refname.ptr, &head->oid, !autotag,  | ||||
| 				log_message); | ||||
| 		if (error < 0 && error != GIT_EEXISTS) | ||||
| 
 | ||||
| 		if (error == GIT_EEXISTS) | ||||
| 			continue; | ||||
| 
 | ||||
| 		if (error < 0) | ||||
| 			goto on_error; | ||||
| 
 | ||||
| 		git_reference_free(ref); | ||||
| @ -2224,15 +2228,21 @@ static int remove_branch_config_related_entries( | ||||
| 		if (git_buf_printf(&buf, "branch.%.*s.merge", (int)branch_len, branch) < 0) | ||||
| 			break; | ||||
| 
 | ||||
| 		if ((error = git_config_delete_entry(config, git_buf_cstr(&buf))) < 0) | ||||
| 			break; | ||||
| 		if ((error = git_config_delete_entry(config, git_buf_cstr(&buf))) < 0) { | ||||
| 			if (error != GIT_ENOTFOUND) | ||||
| 				break; | ||||
| 			giterr_clear(); | ||||
| 		} | ||||
| 
 | ||||
| 		git_buf_clear(&buf); | ||||
| 		if (git_buf_printf(&buf, "branch.%.*s.remote", (int)branch_len, branch) < 0) | ||||
| 			break; | ||||
| 
 | ||||
| 		if ((error = git_config_delete_entry(config, git_buf_cstr(&buf))) < 0) | ||||
| 			break; | ||||
| 		if ((error = git_config_delete_entry(config, git_buf_cstr(&buf))) < 0) { | ||||
| 			if (error != GIT_ENOTFOUND) | ||||
| 				break; | ||||
| 			giterr_clear(); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (error == GIT_ITEROVER) | ||||
|  | ||||
| @ -264,7 +264,7 @@ cleanup: | ||||
|  * the stack could remove directories name limits, but at the cost of doing | ||||
|  * repeated malloc/frees inside the loop below, so let's not do it now. | ||||
|  */ | ||||
| static int find_ceiling_dir_offset( | ||||
| static size_t find_ceiling_dir_offset( | ||||
| 	const char *path, | ||||
| 	const char *ceiling_directories) | ||||
| { | ||||
| @ -278,7 +278,7 @@ static int find_ceiling_dir_offset( | ||||
| 	min_len = (size_t)(git_path_root(path) + 1); | ||||
| 
 | ||||
| 	if (ceiling_directories == NULL || min_len == 0) | ||||
| 		return (int)min_len; | ||||
| 		return min_len; | ||||
| 
 | ||||
| 	for (sep = ceil = ceiling_directories; *sep; ceil = sep + 1) { | ||||
| 		for (sep = ceil; *sep && *sep != GIT_PATH_LIST_SEPARATOR; sep++); | ||||
| @ -305,7 +305,7 @@ static int find_ceiling_dir_offset( | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return (int)(max_len <= min_len ? min_len : max_len); | ||||
| 	return (max_len <= min_len ? min_len : max_len); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
| @ -359,21 +359,36 @@ static int find_repo( | ||||
| 	git_buf path = GIT_BUF_INIT; | ||||
| 	struct stat st; | ||||
| 	dev_t initial_device = 0; | ||||
| 	bool try_with_dot_git = ((flags & GIT_REPOSITORY_OPEN_BARE) != 0); | ||||
| 	int ceiling_offset; | ||||
| 	int min_iterations; | ||||
| 	bool in_dot_git; | ||||
| 	size_t ceiling_offset = 0; | ||||
| 
 | ||||
| 	git_buf_free(repo_path); | ||||
| 
 | ||||
| 	if ((error = git_path_prettify(&path, start_path, NULL)) < 0) | ||||
| 		return error; | ||||
| 
 | ||||
| 	ceiling_offset = find_ceiling_dir_offset(path.ptr, ceiling_dirs); | ||||
| 	/* in_dot_git toggles each loop:
 | ||||
| 	 * /a/b/c/.git, /a/b/c, /a/b/.git, /a/b, /a/.git, /a | ||||
| 	 * With GIT_REPOSITORY_OPEN_BARE, we assume we started with /a/b/c.git | ||||
| 	 * and don't append .git the first time through. | ||||
| 	 * min_iterations indicates the number of iterations left before going | ||||
| 	 * further counts as a search. */ | ||||
| 	if (flags & GIT_REPOSITORY_OPEN_BARE) { | ||||
| 		in_dot_git = true; | ||||
| 		min_iterations = 1; | ||||
| 	} else { | ||||
| 		in_dot_git = false; | ||||
| 		min_iterations = 2; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!try_with_dot_git && | ||||
| 		(error = git_buf_joinpath(&path, path.ptr, DOT_GIT)) < 0) | ||||
| 		return error; | ||||
| 	while (!error && (min_iterations || !(path.ptr[ceiling_offset] == 0 || | ||||
| 					      (flags & GIT_REPOSITORY_OPEN_NO_SEARCH)))) { | ||||
| 		if (!in_dot_git) | ||||
| 			if ((error = git_buf_joinpath(&path, path.ptr, DOT_GIT)) < 0) | ||||
| 				break; | ||||
| 		in_dot_git = !in_dot_git; | ||||
| 
 | ||||
| 	while (!error && !git_buf_len(repo_path)) { | ||||
| 		if (p_stat(path.ptr, &st) == 0) { | ||||
| 			/* check that we have not crossed device boundaries */ | ||||
| 			if (initial_device == 0) | ||||
| @ -414,17 +429,10 @@ static int find_repo( | ||||
| 			break; | ||||
| 		} | ||||
| 
 | ||||
| 		if (try_with_dot_git) { | ||||
| 			/* if we tried original dir with and without .git AND either hit
 | ||||
| 			 * directory ceiling or NO_SEARCH was requested, then be done. | ||||
| 			 */ | ||||
| 			if (path.ptr[ceiling_offset] == '\0' || | ||||
| 				(flags & GIT_REPOSITORY_OPEN_NO_SEARCH) != 0) | ||||
| 				break; | ||||
| 			/* otherwise look first for .git item */ | ||||
| 			error = git_buf_joinpath(&path, path.ptr, DOT_GIT); | ||||
| 		} | ||||
| 		try_with_dot_git = !try_with_dot_git; | ||||
| 		/* Once we've checked the directory (and .git if applicable),
 | ||||
| 		 * find the ceiling for a search. */ | ||||
| 		if (min_iterations && (--min_iterations == 0)) | ||||
| 			ceiling_offset = find_ceiling_dir_offset(path.ptr, ceiling_dirs); | ||||
| 	} | ||||
| 
 | ||||
| 	if (!error && parent_path && !(flags & GIT_REPOSITORY_OPEN_BARE)) { | ||||
|  | ||||
| @ -16,7 +16,7 @@ | ||||
| #include "socket_stream.h" | ||||
| #include "curl_stream.h" | ||||
| 
 | ||||
| int stransport_error(OSStatus ret) | ||||
| static int stransport_error(OSStatus ret) | ||||
| { | ||||
| 	CFStringRef message; | ||||
| 
 | ||||
| @ -33,6 +33,7 @@ int stransport_error(OSStatus ret) | ||||
| 	CFRelease(message); | ||||
| #else | ||||
|     giterr_set(GITERR_NET, "SecureTransport error: OSStatus %d", (unsigned int)ret); | ||||
|     GIT_UNUSED(message); | ||||
| #endif | ||||
| 
 | ||||
| 	return -1; | ||||
| @ -46,7 +47,7 @@ typedef struct { | ||||
| 	git_cert_x509 cert_info; | ||||
| } stransport_stream; | ||||
| 
 | ||||
| int stransport_connect(git_stream *stream) | ||||
| static int stransport_connect(git_stream *stream) | ||||
| { | ||||
| 	stransport_stream *st = (stransport_stream *) stream; | ||||
| 	int error; | ||||
| @ -66,6 +67,9 @@ int stransport_connect(git_stream *stream) | ||||
| 	if ((ret = SSLCopyPeerTrust(st->ctx, &trust)) != noErr) | ||||
| 		goto on_error; | ||||
| 
 | ||||
| 	if (!trust) | ||||
| 		return GIT_ECERTIFICATE; | ||||
| 
 | ||||
| 	if ((ret = SecTrustEvaluate(trust, &sec_res)) != noErr) | ||||
| 		goto on_error; | ||||
| 
 | ||||
| @ -89,7 +93,7 @@ on_error: | ||||
| 	return stransport_error(ret); | ||||
| } | ||||
| 
 | ||||
| int stransport_certificate(git_cert **out, git_stream *stream) | ||||
| static int stransport_certificate(git_cert **out, git_stream *stream) | ||||
| { | ||||
| 	stransport_stream *st = (stransport_stream *) stream; | ||||
| 	SecTrustRef trust = NULL; | ||||
| @ -116,7 +120,7 @@ int stransport_certificate(git_cert **out, git_stream *stream) | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int stransport_set_proxy(git_stream *stream, const char *proxy) | ||||
| static int stransport_set_proxy(git_stream *stream, const char *proxy) | ||||
| { | ||||
| 	stransport_stream *st = (stransport_stream *) stream; | ||||
| 
 | ||||
| @ -146,7 +150,7 @@ static OSStatus write_cb(SSLConnectionRef conn, const void *data, size_t *len) | ||||
| 	return noErr; | ||||
| } | ||||
| 
 | ||||
| ssize_t stransport_write(git_stream *stream, const char *data, size_t len, int flags) | ||||
| static ssize_t stransport_write(git_stream *stream, const char *data, size_t len, int flags) | ||||
| { | ||||
| 	stransport_stream *st = (stransport_stream *) stream; | ||||
| 	size_t data_len, processed; | ||||
| @ -195,7 +199,7 @@ static OSStatus read_cb(SSLConnectionRef conn, void *data, size_t *len) | ||||
| 	return error; | ||||
| } | ||||
| 
 | ||||
| ssize_t stransport_read(git_stream *stream, void *data, size_t len) | ||||
| static ssize_t stransport_read(git_stream *stream, void *data, size_t len) | ||||
| { | ||||
| 	stransport_stream *st = (stransport_stream *) stream; | ||||
| 	size_t processed; | ||||
| @ -207,7 +211,7 @@ ssize_t stransport_read(git_stream *stream, void *data, size_t len) | ||||
| 	return processed; | ||||
| } | ||||
| 
 | ||||
| int stransport_close(git_stream *stream) | ||||
| static int stransport_close(git_stream *stream) | ||||
| { | ||||
| 	stransport_stream *st = (stransport_stream *) stream; | ||||
| 	OSStatus ret; | ||||
| @ -219,7 +223,7 @@ int stransport_close(git_stream *stream) | ||||
| 	return git_stream_close(st->io); | ||||
| } | ||||
| 
 | ||||
| void stransport_free(git_stream *stream) | ||||
| static void stransport_free(git_stream *stream) | ||||
| { | ||||
| 	stransport_stream *st = (stransport_stream *) stream; | ||||
| 
 | ||||
| @ -255,6 +259,7 @@ int git_stransport_stream_new(git_stream **out, const char *host, const char *po | ||||
| 	st->ctx = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType); | ||||
| 	if (!st->ctx) { | ||||
| 		giterr_set(GITERR_NET, "failed to create SSL context"); | ||||
| 		git__free(st); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| @ -264,7 +269,8 @@ int git_stransport_stream_new(git_stream **out, const char *host, const char *po | ||||
| 	    (ret = SSLSetProtocolVersionMin(st->ctx, kTLSProtocol1)) != noErr || | ||||
| 	    (ret = SSLSetProtocolVersionMax(st->ctx, kTLSProtocol12)) != noErr || | ||||
| 	    (ret = SSLSetPeerDomainName(st->ctx, host, strlen(host))) != noErr) { | ||||
| 		git_stream_free((git_stream *)st); | ||||
| 		CFRelease(st->ctx); | ||||
| 		git__free(st); | ||||
| 		return stransport_error(ret); | ||||
| 	} | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										90
									
								
								src/sysdir.c
									
									
									
									
									
								
							
							
						
						
									
										90
									
								
								src/sysdir.c
									
									
									
									
									
								
							| @ -83,45 +83,43 @@ static int git_sysdir_guess_template_dirs(git_buf *out) | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| typedef int (*git_sysdir_guess_cb)(git_buf *out); | ||||
| 
 | ||||
| static git_buf git_sysdir__dirs[GIT_SYSDIR__MAX] = | ||||
| 	{ GIT_BUF_INIT, GIT_BUF_INIT, GIT_BUF_INIT, GIT_BUF_INIT, GIT_BUF_INIT }; | ||||
| 
 | ||||
| static git_sysdir_guess_cb git_sysdir__dir_guess[GIT_SYSDIR__MAX] = { | ||||
| 	git_sysdir_guess_system_dirs, | ||||
| 	git_sysdir_guess_global_dirs, | ||||
| 	git_sysdir_guess_xdg_dirs, | ||||
| 	git_sysdir_guess_programdata_dirs, | ||||
| 	git_sysdir_guess_template_dirs, | ||||
| struct git_sysdir__dir { | ||||
| 	git_buf buf; | ||||
| 	int (*guess)(git_buf *out); | ||||
| }; | ||||
| 
 | ||||
| static int git_sysdir__dirs_shutdown_set = 0; | ||||
| static struct git_sysdir__dir git_sysdir__dirs[] = { | ||||
| 	{ GIT_BUF_INIT, git_sysdir_guess_system_dirs }, | ||||
| 	{ GIT_BUF_INIT, git_sysdir_guess_global_dirs }, | ||||
| 	{ GIT_BUF_INIT, git_sysdir_guess_xdg_dirs }, | ||||
| 	{ GIT_BUF_INIT, git_sysdir_guess_programdata_dirs }, | ||||
| 	{ GIT_BUF_INIT, git_sysdir_guess_template_dirs }, | ||||
| }; | ||||
| 
 | ||||
| static void git_sysdir_global_shutdown(void) | ||||
| { | ||||
| 	size_t i; | ||||
| 
 | ||||
| 	for (i = 0; i < ARRAY_SIZE(git_sysdir__dirs); ++i) | ||||
| 		git_buf_free(&git_sysdir__dirs[i].buf); | ||||
| } | ||||
| 
 | ||||
| int git_sysdir_global_init(void) | ||||
| { | ||||
| 	git_sysdir_t i; | ||||
| 	const git_buf *path; | ||||
| 	size_t i; | ||||
| 	int error = 0; | ||||
| 
 | ||||
| 	for (i = 0; !error && i < GIT_SYSDIR__MAX; i++) | ||||
| 		error = git_sysdir_get(&path, i); | ||||
| 	for (i = 0; !error && i < ARRAY_SIZE(git_sysdir__dirs); i++) | ||||
| 		error = git_sysdir__dirs[i].guess(&git_sysdir__dirs[i].buf); | ||||
| 
 | ||||
| 	git__on_shutdown(git_sysdir_global_shutdown); | ||||
| 
 | ||||
| 	return error; | ||||
| } | ||||
| 
 | ||||
| void git_sysdir_global_shutdown(void) | ||||
| { | ||||
| 	int i; | ||||
| 	for (i = 0; i < GIT_SYSDIR__MAX; ++i) | ||||
| 		git_buf_free(&git_sysdir__dirs[i]); | ||||
| 
 | ||||
| 	git_sysdir__dirs_shutdown_set = 0; | ||||
| } | ||||
| 
 | ||||
| static int git_sysdir_check_selector(git_sysdir_t which) | ||||
| { | ||||
| 	if (which < GIT_SYSDIR__MAX) | ||||
| 	if (which < ARRAY_SIZE(git_sysdir__dirs)) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	giterr_set(GITERR_INVALID, "config directory selector out of range"); | ||||
| @ -137,18 +135,7 @@ int git_sysdir_get(const git_buf **out, git_sysdir_t which) | ||||
| 
 | ||||
| 	GITERR_CHECK_ERROR(git_sysdir_check_selector(which)); | ||||
| 
 | ||||
| 	if (!git_buf_len(&git_sysdir__dirs[which])) { | ||||
| 		/* prepare shutdown if we're going to need it */ | ||||
| 		if (!git_sysdir__dirs_shutdown_set) { | ||||
| 			git__on_shutdown(git_sysdir_global_shutdown); | ||||
| 			git_sysdir__dirs_shutdown_set = 1; | ||||
| 		} | ||||
| 
 | ||||
| 		GITERR_CHECK_ERROR( | ||||
| 			git_sysdir__dir_guess[which](&git_sysdir__dirs[which])); | ||||
| 	} | ||||
| 
 | ||||
| 	*out = &git_sysdir__dirs[which]; | ||||
| 	*out = &git_sysdir__dirs[which].buf; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| @ -183,31 +170,38 @@ int git_sysdir_set(git_sysdir_t which, const char *search_path) | ||||
| 	if (search_path != NULL) | ||||
| 		expand_path = strstr(search_path, PATH_MAGIC); | ||||
| 
 | ||||
| 	/* init with default if not yet done and needed (ignoring error) */ | ||||
| 	if ((!search_path || expand_path) && | ||||
| 		!git_buf_len(&git_sysdir__dirs[which])) | ||||
| 		git_sysdir__dir_guess[which](&git_sysdir__dirs[which]); | ||||
| 	/* reset the default if this path has been cleared */ | ||||
| 	if (!search_path || expand_path) | ||||
| 		git_sysdir__dirs[which].guess(&git_sysdir__dirs[which].buf); | ||||
| 
 | ||||
| 	/* if $PATH is not referenced, then just set the path */ | ||||
| 	if (!expand_path) | ||||
| 		return git_buf_sets(&git_sysdir__dirs[which], search_path); | ||||
| 	if (!expand_path) { | ||||
| 		if (search_path) | ||||
| 			git_buf_sets(&git_sysdir__dirs[which].buf, search_path); | ||||
| 
 | ||||
| 		goto done; | ||||
| 	} | ||||
| 
 | ||||
| 	/* otherwise set to join(before $PATH, old value, after $PATH) */ | ||||
| 	if (expand_path > search_path) | ||||
| 		git_buf_set(&merge, search_path, expand_path - search_path); | ||||
| 
 | ||||
| 	if (git_buf_len(&git_sysdir__dirs[which])) | ||||
| 	if (git_buf_len(&git_sysdir__dirs[which].buf)) | ||||
| 		git_buf_join(&merge, GIT_PATH_LIST_SEPARATOR, | ||||
| 			merge.ptr, git_sysdir__dirs[which].ptr); | ||||
| 			merge.ptr, git_sysdir__dirs[which].buf.ptr); | ||||
| 
 | ||||
| 	expand_path += strlen(PATH_MAGIC); | ||||
| 	if (*expand_path) | ||||
| 		git_buf_join(&merge, GIT_PATH_LIST_SEPARATOR, merge.ptr, expand_path); | ||||
| 
 | ||||
| 	git_buf_swap(&git_sysdir__dirs[which], &merge); | ||||
| 	git_buf_swap(&git_sysdir__dirs[which].buf, &merge); | ||||
| 	git_buf_free(&merge); | ||||
| 
 | ||||
| 	return git_buf_oom(&git_sysdir__dirs[which]) ? -1 : 0; | ||||
| done: | ||||
| 	if (git_buf_oom(&git_sysdir__dirs[which].buf)) | ||||
| 		return -1; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int git_sysdir_find_in_dirlist( | ||||
|  | ||||
| @ -103,9 +103,4 @@ extern int git_sysdir_get_str(char *out, size_t outlen, git_sysdir_t which); | ||||
|  */ | ||||
| extern int git_sysdir_set(git_sysdir_t which, const char *paths); | ||||
| 
 | ||||
| /**
 | ||||
|  * Free the configuration file search paths. | ||||
|  */ | ||||
| extern void git_sysdir_global_shutdown(void); | ||||
| 
 | ||||
| #endif /* INCLUDE_sysdir_h__ */ | ||||
|  | ||||
							
								
								
									
										10
									
								
								src/tag.c
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								src/tag.c
									
									
									
									
									
								
							| @ -137,8 +137,14 @@ static int tag_parse(git_tag *tag, const char *buffer, const char *buffer_end) | ||||
| 
 | ||||
| 	tag->message = NULL; | ||||
| 	if (buffer < buffer_end) { | ||||
| 		if( *buffer != '\n' ) | ||||
| 			return tag_error("No new line before message"); | ||||
| 		/* If we're not at the end of the header, search for it */ | ||||
| 		if( *buffer != '\n' ) { | ||||
| 			search = strstr(buffer, "\n\n"); | ||||
| 			if (search) | ||||
| 				buffer = search + 1; | ||||
| 			else | ||||
| 				return tag_error("tag contains no message"); | ||||
| 		} | ||||
| 
 | ||||
| 		text_len = buffer_end - ++buffer; | ||||
| 
 | ||||
|  | ||||
| @ -40,58 +40,12 @@ typedef git_atomic git_atomic_ssize; | ||||
| 
 | ||||
| #ifdef GIT_THREADS | ||||
| 
 | ||||
| #if !defined(GIT_WIN32) | ||||
| 
 | ||||
| typedef struct { | ||||
| 	pthread_t thread; | ||||
| } git_thread; | ||||
| 
 | ||||
| #define git_thread_create(git_thread_ptr, attr, start_routine, arg) \ | ||||
| 	pthread_create(&(git_thread_ptr)->thread, attr, start_routine, arg) | ||||
| #define git_thread_join(git_thread_ptr, status) \ | ||||
| 	pthread_join((git_thread_ptr)->thread, status) | ||||
| 
 | ||||
| #ifdef GIT_WIN32 | ||||
| #   include "win32/thread.h" | ||||
| #else | ||||
| #   include "unix/pthread.h" | ||||
| #endif | ||||
| 
 | ||||
| /* Pthreads Mutex */ | ||||
| #define git_mutex pthread_mutex_t | ||||
| #define git_mutex_init(a)	pthread_mutex_init(a, NULL) | ||||
| #define git_mutex_lock(a)	pthread_mutex_lock(a) | ||||
| #define git_mutex_unlock(a) pthread_mutex_unlock(a) | ||||
| #define git_mutex_free(a)	pthread_mutex_destroy(a) | ||||
| 
 | ||||
| /* Pthreads condition vars */ | ||||
| #define git_cond pthread_cond_t | ||||
| #define git_cond_init(c)	pthread_cond_init(c, NULL) | ||||
| #define git_cond_free(c) 	pthread_cond_destroy(c) | ||||
| #define git_cond_wait(c, l)	pthread_cond_wait(c, l) | ||||
| #define git_cond_signal(c)	pthread_cond_signal(c) | ||||
| #define git_cond_broadcast(c)	pthread_cond_broadcast(c) | ||||
| 
 | ||||
| /* Pthread (-ish) rwlock
 | ||||
|  * | ||||
|  * This differs from normal pthreads rwlocks in two ways: | ||||
|  * 1. Separate APIs for releasing read locks and write locks (as | ||||
|  *    opposed to the pure POSIX API which only has one unlock fn) | ||||
|  * 2. You should not use recursive read locks (i.e. grabbing a read | ||||
|  *    lock in a thread that already holds a read lock) because the | ||||
|  *    Windows implementation doesn't support it | ||||
|  */ | ||||
| #define git_rwlock pthread_rwlock_t | ||||
| #define git_rwlock_init(a)		pthread_rwlock_init(a, NULL) | ||||
| #define git_rwlock_rdlock(a)	pthread_rwlock_rdlock(a) | ||||
| #define git_rwlock_rdunlock(a)	pthread_rwlock_rdunlock(a) | ||||
| #define git_rwlock_wrlock(a)	pthread_rwlock_wrlock(a) | ||||
| #define git_rwlock_wrunlock(a)	pthread_rwlock_wrunlock(a) | ||||
| #define git_rwlock_free(a)		pthread_rwlock_destroy(a) | ||||
| #define GIT_RWLOCK_STATIC_INIT	PTHREAD_RWLOCK_INITIALIZER | ||||
| 
 | ||||
| #ifndef GIT_WIN32 | ||||
| #define pthread_rwlock_rdunlock pthread_rwlock_unlock | ||||
| #define pthread_rwlock_wrunlock pthread_rwlock_unlock | ||||
| #endif | ||||
| 
 | ||||
| 
 | ||||
| GIT_INLINE(void) git_atomic_set(git_atomic *a, int val) | ||||
| { | ||||
| #if defined(GIT_WIN32) | ||||
| @ -178,7 +132,7 @@ GIT_INLINE(int64_t) git_atomic64_add(git_atomic64 *a, int64_t addend) | ||||
| #else | ||||
| 
 | ||||
| #define git_thread unsigned int | ||||
| #define git_thread_create(thread, attr, start_routine, arg) 0 | ||||
| #define git_thread_create(thread, start_routine, arg) 0 | ||||
| #define git_thread_join(id, status) (void)0 | ||||
| 
 | ||||
| /* Pthreads Mutex */ | ||||
|  | ||||
| @ -114,7 +114,7 @@ static bool challenge_match(git_http_auth_scheme *scheme, void *data) | ||||
| 	size_t scheme_len; | ||||
| 
 | ||||
| 	scheme_len = strlen(scheme_name); | ||||
| 	return (strncmp(challenge, scheme_name, scheme_len) == 0 && | ||||
| 	return (strncasecmp(challenge, scheme_name, scheme_len) == 0 && | ||||
| 		(challenge[scheme_len] == '\0' || challenge[scheme_len] == ' ')); | ||||
| } | ||||
| 
 | ||||
| @ -569,6 +569,7 @@ static int http_connect(http_subtransport *t) | ||||
| 		git_stream_close(t->io); | ||||
| 		git_stream_free(t->io); | ||||
| 		t->io = NULL; | ||||
| 		t->connected = 0; | ||||
| 	} | ||||
| 
 | ||||
| 	if (t->connection_data.use_ssl) { | ||||
|  | ||||
| @ -433,6 +433,7 @@ int git_pkt_parse_line( | ||||
| 	 * line? | ||||
| 	 */ | ||||
| 	if (len == PKT_LEN_SIZE) { | ||||
| 		*head = NULL; | ||||
| 		*out = line; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| @ -759,6 +759,14 @@ static int add_push_report_sideband_pkt(git_push *push, git_pkt_data *data_pkt, | ||||
| 		line_len -= (line_end - line); | ||||
| 		line = line_end; | ||||
| 
 | ||||
| 		/* When a valid packet with no content has been
 | ||||
| 		 * read, git_pkt_parse_line does not report an | ||||
| 		 * error, but the pkt pointer has not been set. | ||||
| 		 * Handle this by skipping over empty packets. | ||||
| 		 */ | ||||
| 		if (pkt == NULL) | ||||
| 			continue; | ||||
| 
 | ||||
| 		error = add_push_report_pkt(push, pkt); | ||||
| 
 | ||||
| 		git_pkt_free(pkt); | ||||
| @ -813,6 +821,9 @@ static int parse_report(transport_smart *transport, git_push *push) | ||||
| 
 | ||||
| 		error = 0; | ||||
| 
 | ||||
| 		if (pkt == NULL) | ||||
| 			continue; | ||||
| 
 | ||||
| 		switch (pkt->type) { | ||||
| 			case GIT_PKT_DATA: | ||||
| 				/* This is a sideband packet which contains other packets */ | ||||
|  | ||||
| @ -45,7 +45,7 @@ GIT_INLINE(git_filemode_t) normalize_filemode(git_filemode_t filemode) | ||||
| 	if (GIT_MODE_TYPE(filemode) == GIT_FILEMODE_COMMIT) | ||||
| 		return GIT_FILEMODE_COMMIT; | ||||
| 
 | ||||
| 	/* 12XXXX means commit */ | ||||
| 	/* 12XXXX means symlink */ | ||||
| 	if (GIT_MODE_TYPE(filemode) == GIT_FILEMODE_LINK) | ||||
| 		return GIT_FILEMODE_LINK; | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										54
									
								
								src/unix/pthread.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								src/unix/pthread.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,54 @@ | ||||
| /*
 | ||||
|  * Copyright (C) the libgit2 contributors. All rights reserved. | ||||
|  * | ||||
|  * This file is part of libgit2, distributed under the GNU GPL v2 with | ||||
|  * a Linking Exception. For full terms see the included COPYING file. | ||||
|  */ | ||||
| 
 | ||||
| #ifndef INCLUDE_unix_pthread_h__ | ||||
| #define INCLUDE_unix_pthread_h__ | ||||
| 
 | ||||
| typedef struct { | ||||
| 	pthread_t thread; | ||||
| } git_thread; | ||||
| 
 | ||||
| #define git_threads_init() (void)0 | ||||
| #define git_thread_create(git_thread_ptr, start_routine, arg) \ | ||||
| 	pthread_create(&(git_thread_ptr)->thread, NULL, start_routine, arg) | ||||
| #define git_thread_join(git_thread_ptr, status) \ | ||||
| 	pthread_join((git_thread_ptr)->thread, status) | ||||
| 
 | ||||
| /* Git Mutex */ | ||||
| #define git_mutex pthread_mutex_t | ||||
| #define git_mutex_init(a)	pthread_mutex_init(a, NULL) | ||||
| #define git_mutex_lock(a)	pthread_mutex_lock(a) | ||||
| #define git_mutex_unlock(a)     pthread_mutex_unlock(a) | ||||
| #define git_mutex_free(a)	pthread_mutex_destroy(a) | ||||
| 
 | ||||
| /* Git condition vars */ | ||||
| #define git_cond pthread_cond_t | ||||
| #define git_cond_init(c)	pthread_cond_init(c, NULL) | ||||
| #define git_cond_free(c) 	pthread_cond_destroy(c) | ||||
| #define git_cond_wait(c, l)	pthread_cond_wait(c, l) | ||||
| #define git_cond_signal(c)	pthread_cond_signal(c) | ||||
| #define git_cond_broadcast(c)	pthread_cond_broadcast(c) | ||||
| 
 | ||||
| /* Pthread (-ish) rwlock
 | ||||
|  * | ||||
|  * This differs from normal pthreads rwlocks in two ways: | ||||
|  * 1. Separate APIs for releasing read locks and write locks (as | ||||
|  *    opposed to the pure POSIX API which only has one unlock fn) | ||||
|  * 2. You should not use recursive read locks (i.e. grabbing a read | ||||
|  *    lock in a thread that already holds a read lock) because the | ||||
|  *    Windows implementation doesn't support it | ||||
|  */ | ||||
| #define git_rwlock              pthread_rwlock_t | ||||
| #define git_rwlock_init(a)	pthread_rwlock_init(a, NULL) | ||||
| #define git_rwlock_rdlock(a)	pthread_rwlock_rdlock(a) | ||||
| #define git_rwlock_rdunlock(a)	pthread_rwlock_unlock(a) | ||||
| #define git_rwlock_wrlock(a)	pthread_rwlock_wrlock(a) | ||||
| #define git_rwlock_wrunlock(a)	pthread_rwlock_unlock(a) | ||||
| #define git_rwlock_free(a)	pthread_rwlock_destroy(a) | ||||
| #define GIT_RWLOCK_STATIC_INIT	PTHREAD_RWLOCK_INITIALIZER | ||||
| 
 | ||||
| #endif /* INCLUDE_unix_pthread_h__ */ | ||||
| @ -122,8 +122,8 @@ int git__strtol64(int64_t *result, const char *nptr, const char **endptr, int ba | ||||
| 			v = c - 'A' + 10; | ||||
| 		if (v >= base) | ||||
| 			break; | ||||
| 		nn = n*base + v; | ||||
| 		if (nn < n) | ||||
| 		nn = n * base + (neg ? -v : v); | ||||
| 		if ((!neg && nn < n) || (neg && nn > n)) | ||||
| 			ovfl = 1; | ||||
| 		n = nn; | ||||
| 	} | ||||
| @ -142,7 +142,7 @@ Return: | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	*result = neg ? -n : n; | ||||
| 	*result = n; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -16,7 +16,7 @@ | ||||
| #include <io.h> | ||||
| #include <direct.h> | ||||
| #ifdef GIT_THREADS | ||||
|  #include "win32/pthread.h" | ||||
|  #include "win32/thread.h" | ||||
| #endif | ||||
| 
 | ||||
| #include "git2.h" | ||||
|  | ||||
| @ -1,92 +0,0 @@ | ||||
| /*
 | ||||
|  * Copyright (C) the libgit2 contributors. All rights reserved. | ||||
|  * | ||||
|  * This file is part of libgit2, distributed under the GNU GPL v2 with | ||||
|  * a Linking Exception. For full terms see the included COPYING file. | ||||
|  */ | ||||
| 
 | ||||
| #ifndef GIT_PTHREAD_H | ||||
| #define GIT_PTHREAD_H | ||||
| 
 | ||||
| #include "../common.h" | ||||
| 
 | ||||
| #if defined (_MSC_VER) | ||||
| #	define GIT_RESTRICT __restrict | ||||
| #else | ||||
| #	define GIT_RESTRICT __restrict__ | ||||
| #endif | ||||
| 
 | ||||
| typedef struct { | ||||
| 	HANDLE thread; | ||||
| 	void *(*proc)(void *); | ||||
| 	void *param; | ||||
| 	void *result; | ||||
| } git_win32_thread; | ||||
| 
 | ||||
| typedef int pthread_mutexattr_t; | ||||
| typedef int pthread_condattr_t; | ||||
| typedef int pthread_attr_t; | ||||
| typedef int pthread_rwlockattr_t; | ||||
| 
 | ||||
| typedef CRITICAL_SECTION pthread_mutex_t; | ||||
| typedef HANDLE pthread_cond_t; | ||||
| 
 | ||||
| typedef struct { void *Ptr; } GIT_SRWLOCK; | ||||
| 
 | ||||
| typedef struct { | ||||
| 	union { | ||||
| 		GIT_SRWLOCK srwl; | ||||
| 		CRITICAL_SECTION csec; | ||||
| 	} native; | ||||
| } pthread_rwlock_t; | ||||
| 
 | ||||
| #define PTHREAD_MUTEX_INITIALIZER  {(void*)-1} | ||||
| 
 | ||||
| int git_win32__thread_create( | ||||
| 	git_win32_thread *GIT_RESTRICT, | ||||
| 	const pthread_attr_t *GIT_RESTRICT, | ||||
| 	void *(*) (void *), | ||||
| 	void *GIT_RESTRICT); | ||||
| 
 | ||||
| int git_win32__thread_join( | ||||
| 	git_win32_thread *, | ||||
| 	void **); | ||||
| 
 | ||||
| #ifdef GIT_THREADS | ||||
| 
 | ||||
| typedef git_win32_thread git_thread; | ||||
| 
 | ||||
| #define git_thread_create(git_thread_ptr, attr, start_routine, arg) \ | ||||
| 	git_win32__thread_create(git_thread_ptr, attr, start_routine, arg) | ||||
| #define git_thread_join(git_thread_ptr, status) \ | ||||
| 	git_win32__thread_join(git_thread_ptr, status) | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| int pthread_mutex_init( | ||||
| 	pthread_mutex_t *GIT_RESTRICT mutex, | ||||
| 	const pthread_mutexattr_t *GIT_RESTRICT mutexattr); | ||||
| int pthread_mutex_destroy(pthread_mutex_t *); | ||||
| int pthread_mutex_lock(pthread_mutex_t *); | ||||
| int pthread_mutex_unlock(pthread_mutex_t *); | ||||
| 
 | ||||
| int pthread_cond_init(pthread_cond_t *, const pthread_condattr_t *); | ||||
| int pthread_cond_destroy(pthread_cond_t *); | ||||
| int pthread_cond_wait(pthread_cond_t *, pthread_mutex_t *); | ||||
| int pthread_cond_signal(pthread_cond_t *); | ||||
| /* pthread_cond_broadcast is not supported on Win32 yet. */ | ||||
| 
 | ||||
| int pthread_num_processors_np(void); | ||||
| 
 | ||||
| int pthread_rwlock_init( | ||||
| 	pthread_rwlock_t *GIT_RESTRICT lock, | ||||
| 	const pthread_rwlockattr_t *GIT_RESTRICT attr); | ||||
| int pthread_rwlock_rdlock(pthread_rwlock_t *); | ||||
| int pthread_rwlock_rdunlock(pthread_rwlock_t *); | ||||
| int pthread_rwlock_wrlock(pthread_rwlock_t *); | ||||
| int pthread_rwlock_wrunlock(pthread_rwlock_t *); | ||||
| int pthread_rwlock_destroy(pthread_rwlock_t *); | ||||
| 
 | ||||
| extern int win32_pthread_initialize(void); | ||||
| 
 | ||||
| #endif | ||||
| @ -5,18 +5,26 @@ | ||||
|  * a Linking Exception. For full terms see the included COPYING file. | ||||
|  */ | ||||
| 
 | ||||
| #include "pthread.h" | ||||
| #include "thread.h" | ||||
| #include "../global.h" | ||||
| 
 | ||||
| #define CLEAN_THREAD_EXIT 0x6F012842 | ||||
| 
 | ||||
| typedef void (WINAPI *win32_srwlock_fn)(GIT_SRWLOCK *); | ||||
| 
 | ||||
| static win32_srwlock_fn win32_srwlock_initialize; | ||||
| static win32_srwlock_fn win32_srwlock_acquire_shared; | ||||
| static win32_srwlock_fn win32_srwlock_release_shared; | ||||
| static win32_srwlock_fn win32_srwlock_acquire_exclusive; | ||||
| static win32_srwlock_fn win32_srwlock_release_exclusive; | ||||
| 
 | ||||
| /* The thread procedure stub used to invoke the caller's procedure
 | ||||
|  * and capture the return value for later collection. Windows will | ||||
|  * only hold a DWORD, but we need to be able to store an entire | ||||
|  * void pointer. This requires the indirection. */ | ||||
| static DWORD WINAPI git_win32__threadproc(LPVOID lpParameter) | ||||
| { | ||||
| 	git_win32_thread *thread = lpParameter; | ||||
| 	git_thread *thread = lpParameter; | ||||
| 
 | ||||
| 	thread->result = thread->proc(thread->param); | ||||
| 
 | ||||
| @ -25,14 +33,31 @@ static DWORD WINAPI git_win32__threadproc(LPVOID lpParameter) | ||||
| 	return CLEAN_THREAD_EXIT; | ||||
| } | ||||
| 
 | ||||
| int git_win32__thread_create( | ||||
| 	git_win32_thread *GIT_RESTRICT thread, | ||||
| 	const pthread_attr_t *GIT_RESTRICT attr, | ||||
| int git_threads_init(void) | ||||
| { | ||||
| 	HMODULE hModule = GetModuleHandleW(L"kernel32"); | ||||
| 
 | ||||
| 	if (hModule) { | ||||
| 		win32_srwlock_initialize = (win32_srwlock_fn) | ||||
| 			GetProcAddress(hModule, "InitializeSRWLock"); | ||||
| 		win32_srwlock_acquire_shared = (win32_srwlock_fn) | ||||
| 			GetProcAddress(hModule, "AcquireSRWLockShared"); | ||||
| 		win32_srwlock_release_shared = (win32_srwlock_fn) | ||||
| 			GetProcAddress(hModule, "ReleaseSRWLockShared"); | ||||
| 		win32_srwlock_acquire_exclusive = (win32_srwlock_fn) | ||||
| 			GetProcAddress(hModule, "AcquireSRWLockExclusive"); | ||||
| 		win32_srwlock_release_exclusive = (win32_srwlock_fn) | ||||
| 			GetProcAddress(hModule, "ReleaseSRWLockExclusive"); | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int git_thread_create( | ||||
| 	git_thread *GIT_RESTRICT thread, | ||||
| 	void *(*start_routine)(void*), | ||||
| 	void *GIT_RESTRICT arg) | ||||
| { | ||||
| 	GIT_UNUSED(attr); | ||||
| 
 | ||||
| 	thread->result = NULL; | ||||
| 	thread->param = arg; | ||||
| 	thread->proc = start_routine; | ||||
| @ -42,8 +67,8 @@ int git_win32__thread_create( | ||||
| 	return thread->thread ? 0 : -1; | ||||
| } | ||||
| 
 | ||||
| int git_win32__thread_join( | ||||
| 	git_win32_thread *thread, | ||||
| int git_thread_join( | ||||
| 	git_thread *thread, | ||||
| 	void **value_ptr) | ||||
| { | ||||
| 	DWORD exit; | ||||
| @ -70,39 +95,32 @@ int git_win32__thread_join( | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int pthread_mutex_init( | ||||
| 	pthread_mutex_t *GIT_RESTRICT mutex, | ||||
| 	const pthread_mutexattr_t *GIT_RESTRICT mutexattr) | ||||
| int git_mutex_init(git_mutex *GIT_RESTRICT mutex) | ||||
| { | ||||
| 	GIT_UNUSED(mutexattr); | ||||
| 	InitializeCriticalSection(mutex); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int pthread_mutex_destroy(pthread_mutex_t *mutex) | ||||
| int git_mutex_free(git_mutex *mutex) | ||||
| { | ||||
| 	DeleteCriticalSection(mutex); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int pthread_mutex_lock(pthread_mutex_t *mutex) | ||||
| int git_mutex_lock(git_mutex *mutex) | ||||
| { | ||||
| 	EnterCriticalSection(mutex); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int pthread_mutex_unlock(pthread_mutex_t *mutex) | ||||
| int git_mutex_unlock(git_mutex *mutex) | ||||
| { | ||||
| 	LeaveCriticalSection(mutex); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr) | ||||
| int git_cond_init(git_cond *cond) | ||||
| { | ||||
| 	/* We don't support non-default attributes. */ | ||||
| 	if (attr) | ||||
| 		return EINVAL; | ||||
| 
 | ||||
| 	/* This is an auto-reset event. */ | ||||
| 	*cond = CreateEventW(NULL, FALSE, FALSE, NULL); | ||||
| 	assert(*cond); | ||||
| @ -112,7 +130,7 @@ int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr) | ||||
| 	return *cond ? 0 : ENOMEM; | ||||
| } | ||||
| 
 | ||||
| int pthread_cond_destroy(pthread_cond_t *cond) | ||||
| int git_cond_free(git_cond *cond) | ||||
| { | ||||
| 	BOOL closed; | ||||
| 
 | ||||
| @ -127,7 +145,7 @@ int pthread_cond_destroy(pthread_cond_t *cond) | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) | ||||
| int git_cond_wait(git_cond *cond, git_mutex *mutex) | ||||
| { | ||||
| 	int error; | ||||
| 	DWORD wait_result; | ||||
| @ -136,7 +154,7 @@ int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) | ||||
| 		return EINVAL; | ||||
| 
 | ||||
| 	/* The caller must be holding the mutex. */ | ||||
| 	error = pthread_mutex_unlock(mutex); | ||||
| 	error = git_mutex_unlock(mutex); | ||||
| 
 | ||||
| 	if (error) | ||||
| 		return error; | ||||
| @ -145,10 +163,10 @@ int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) | ||||
| 	assert(WAIT_OBJECT_0 == wait_result); | ||||
| 	GIT_UNUSED(wait_result); | ||||
| 
 | ||||
| 	return pthread_mutex_lock(mutex); | ||||
| 	return git_mutex_lock(mutex); | ||||
| } | ||||
| 
 | ||||
| int pthread_cond_signal(pthread_cond_t *cond) | ||||
| int git_cond_signal(git_cond *cond) | ||||
| { | ||||
| 	BOOL signaled; | ||||
| 
 | ||||
| @ -162,36 +180,8 @@ int pthread_cond_signal(pthread_cond_t *cond) | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /* pthread_cond_broadcast is not implemented because doing so with just
 | ||||
|  * Win32 events is quite complicated, and no caller in libgit2 uses it | ||||
|  * yet. | ||||
|  */ | ||||
| int pthread_num_processors_np(void) | ||||
| int git_rwlock_init(git_rwlock *GIT_RESTRICT lock) | ||||
| { | ||||
| 	DWORD_PTR p, s; | ||||
| 	int n = 0; | ||||
| 
 | ||||
| 	if (GetProcessAffinityMask(GetCurrentProcess(), &p, &s)) | ||||
| 		for (; p; p >>= 1) | ||||
| 			n += p&1; | ||||
| 
 | ||||
| 	return n ? n : 1; | ||||
| } | ||||
| 
 | ||||
| typedef void (WINAPI *win32_srwlock_fn)(GIT_SRWLOCK *); | ||||
| 
 | ||||
| static win32_srwlock_fn win32_srwlock_initialize; | ||||
| static win32_srwlock_fn win32_srwlock_acquire_shared; | ||||
| static win32_srwlock_fn win32_srwlock_release_shared; | ||||
| static win32_srwlock_fn win32_srwlock_acquire_exclusive; | ||||
| static win32_srwlock_fn win32_srwlock_release_exclusive; | ||||
| 
 | ||||
| int pthread_rwlock_init( | ||||
| 	pthread_rwlock_t *GIT_RESTRICT lock, | ||||
| 	const pthread_rwlockattr_t *GIT_RESTRICT attr) | ||||
| { | ||||
| 	GIT_UNUSED(attr); | ||||
| 
 | ||||
| 	if (win32_srwlock_initialize) | ||||
| 		win32_srwlock_initialize(&lock->native.srwl); | ||||
| 	else | ||||
| @ -200,7 +190,7 @@ int pthread_rwlock_init( | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int pthread_rwlock_rdlock(pthread_rwlock_t *lock) | ||||
| int git_rwlock_rdlock(git_rwlock *lock) | ||||
| { | ||||
| 	if (win32_srwlock_acquire_shared) | ||||
| 		win32_srwlock_acquire_shared(&lock->native.srwl); | ||||
| @ -210,7 +200,7 @@ int pthread_rwlock_rdlock(pthread_rwlock_t *lock) | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int pthread_rwlock_rdunlock(pthread_rwlock_t *lock) | ||||
| int git_rwlock_rdunlock(git_rwlock *lock) | ||||
| { | ||||
| 	if (win32_srwlock_release_shared) | ||||
| 		win32_srwlock_release_shared(&lock->native.srwl); | ||||
| @ -220,7 +210,7 @@ int pthread_rwlock_rdunlock(pthread_rwlock_t *lock) | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int pthread_rwlock_wrlock(pthread_rwlock_t *lock) | ||||
| int git_rwlock_wrlock(git_rwlock *lock) | ||||
| { | ||||
| 	if (win32_srwlock_acquire_exclusive) | ||||
| 		win32_srwlock_acquire_exclusive(&lock->native.srwl); | ||||
| @ -230,7 +220,7 @@ int pthread_rwlock_wrlock(pthread_rwlock_t *lock) | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int pthread_rwlock_wrunlock(pthread_rwlock_t *lock) | ||||
| int git_rwlock_wrunlock(git_rwlock *lock) | ||||
| { | ||||
| 	if (win32_srwlock_release_exclusive) | ||||
| 		win32_srwlock_release_exclusive(&lock->native.srwl); | ||||
| @ -240,30 +230,10 @@ int pthread_rwlock_wrunlock(pthread_rwlock_t *lock) | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int pthread_rwlock_destroy(pthread_rwlock_t *lock) | ||||
| int git_rwlock_free(git_rwlock *lock) | ||||
| { | ||||
| 	if (!win32_srwlock_initialize) | ||||
| 		DeleteCriticalSection(&lock->native.csec); | ||||
| 	git__memzero(lock, sizeof(*lock)); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int win32_pthread_initialize(void) | ||||
| { | ||||
| 	HMODULE hModule = GetModuleHandleW(L"kernel32"); | ||||
| 
 | ||||
| 	if (hModule) { | ||||
| 		win32_srwlock_initialize = (win32_srwlock_fn) | ||||
| 			GetProcAddress(hModule, "InitializeSRWLock"); | ||||
| 		win32_srwlock_acquire_shared = (win32_srwlock_fn) | ||||
| 			GetProcAddress(hModule, "AcquireSRWLockShared"); | ||||
| 		win32_srwlock_release_shared = (win32_srwlock_fn) | ||||
| 			GetProcAddress(hModule, "ReleaseSRWLockShared"); | ||||
| 		win32_srwlock_acquire_exclusive = (win32_srwlock_fn) | ||||
| 			GetProcAddress(hModule, "AcquireSRWLockExclusive"); | ||||
| 		win32_srwlock_release_exclusive = (win32_srwlock_fn) | ||||
| 			GetProcAddress(hModule, "ReleaseSRWLockExclusive"); | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
							
								
								
									
										62
									
								
								src/win32/thread.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								src/win32/thread.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,62 @@ | ||||
| /*
 | ||||
|  * Copyright (C) the libgit2 contributors. All rights reserved. | ||||
|  * | ||||
|  * This file is part of libgit2, distributed under the GNU GPL v2 with | ||||
|  * a Linking Exception. For full terms see the included COPYING file. | ||||
|  */ | ||||
| 
 | ||||
| #ifndef INCLUDE_win32_thread_h__ | ||||
| #define INCLUDE_win32_thread_h__ | ||||
| 
 | ||||
| #include "../common.h" | ||||
| 
 | ||||
| #if defined (_MSC_VER) | ||||
| #	define GIT_RESTRICT __restrict | ||||
| #else | ||||
| #	define GIT_RESTRICT __restrict__ | ||||
| #endif | ||||
| 
 | ||||
| typedef struct { | ||||
| 	HANDLE thread; | ||||
| 	void *(*proc)(void *); | ||||
| 	void *param; | ||||
| 	void *result; | ||||
| } git_thread; | ||||
| 
 | ||||
| typedef CRITICAL_SECTION git_mutex; | ||||
| typedef HANDLE git_cond; | ||||
| 
 | ||||
| typedef struct { void *Ptr; } GIT_SRWLOCK; | ||||
| 
 | ||||
| typedef struct { | ||||
| 	union { | ||||
| 		GIT_SRWLOCK srwl; | ||||
| 		CRITICAL_SECTION csec; | ||||
| 	} native; | ||||
| } git_rwlock; | ||||
| 
 | ||||
| int git_threads_init(void); | ||||
| 
 | ||||
| int git_thread_create(git_thread *GIT_RESTRICT, | ||||
| 	void *(*) (void *), | ||||
| 	void *GIT_RESTRICT); | ||||
| int git_thread_join(git_thread *, void **); | ||||
| 
 | ||||
| int git_mutex_init(git_mutex *GIT_RESTRICT mutex); | ||||
| int git_mutex_free(git_mutex *); | ||||
| int git_mutex_lock(git_mutex *); | ||||
| int git_mutex_unlock(git_mutex *); | ||||
| 
 | ||||
| int git_cond_init(git_cond *); | ||||
| int git_cond_free(git_cond *); | ||||
| int git_cond_wait(git_cond *, git_mutex *); | ||||
| int git_cond_signal(git_cond *); | ||||
| 
 | ||||
| int git_rwlock_init(git_rwlock *GIT_RESTRICT lock); | ||||
| int git_rwlock_rdlock(git_rwlock *); | ||||
| int git_rwlock_rdunlock(git_rwlock *); | ||||
| int git_rwlock_wrlock(git_rwlock *); | ||||
| int git_rwlock_wrunlock(git_rwlock *); | ||||
| int git_rwlock_free(git_rwlock *); | ||||
| 
 | ||||
| #endif /* INCLUDE_win32_thread_h__ */ | ||||
| @ -294,11 +294,12 @@ void test_checkout_index__options_dir_modes(void) | ||||
| 	(void)p_umask(um = p_umask(022)); | ||||
| 
 | ||||
| 	cl_git_pass(p_stat("./testrepo/a", &st)); | ||||
| 	cl_assert_equal_i_fmt(st.st_mode, (GIT_FILEMODE_TREE | 0701) & ~um, "%07o"); | ||||
| 	/* Haiku & Hurd use other mode bits, so we must mask them out */ | ||||
| 	cl_assert_equal_i_fmt(st.st_mode & (S_IFMT | 07777), (GIT_FILEMODE_TREE | 0701) & ~um, "%07o"); | ||||
| 
 | ||||
| 	/* File-mode test, since we're on the 'dir' branch */ | ||||
| 	cl_git_pass(p_stat("./testrepo/a/b.txt", &st)); | ||||
| 	cl_assert_equal_i_fmt(st.st_mode, GIT_FILEMODE_BLOB_EXECUTABLE & ~um, "%07o"); | ||||
| 	cl_assert_equal_i_fmt(st.st_mode & (S_IFMT | 07777), GIT_FILEMODE_BLOB_EXECUTABLE & ~um, "%07o"); | ||||
| 
 | ||||
| 	git_commit_free(commit); | ||||
| } | ||||
|  | ||||
| @ -1416,3 +1416,70 @@ void test_checkout_tree__safe_proceeds_if_no_index(void) | ||||
| 	git_object_free(obj); | ||||
| } | ||||
| 
 | ||||
| static int checkout_conflict_count_cb( | ||||
| 	git_checkout_notify_t why, | ||||
| 	const char *path, | ||||
| 	const git_diff_file *b, | ||||
| 	const git_diff_file *t, | ||||
| 	const git_diff_file *w, | ||||
| 	void *payload) | ||||
| { | ||||
| 	size_t *n = payload; | ||||
| 
 | ||||
| 	GIT_UNUSED(why); | ||||
| 	GIT_UNUSED(path); | ||||
| 	GIT_UNUSED(b); | ||||
| 	GIT_UNUSED(t); | ||||
| 	GIT_UNUSED(w); | ||||
| 
 | ||||
| 	(*n)++; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /* A repo that has a HEAD (even a properly born HEAD that peels to
 | ||||
|  * a commit) but no index should be treated as if it's an empty baseline | ||||
|  */ | ||||
| void test_checkout_tree__baseline_is_empty_when_no_index(void) | ||||
| { | ||||
| 	git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; | ||||
| 	git_reference *head; | ||||
| 	git_object *obj; | ||||
| 	git_status_list *status; | ||||
| 	size_t conflicts = 0; | ||||
| 
 | ||||
| 	assert_on_branch(g_repo, "master"); | ||||
| 	cl_git_pass(git_repository_head(&head, g_repo)); | ||||
| 	cl_git_pass(git_reference_peel(&obj, head, GIT_OBJ_COMMIT)); | ||||
| 
 | ||||
| 	cl_git_pass(git_reset(g_repo, obj, GIT_RESET_HARD, NULL)); | ||||
| 
 | ||||
| 	cl_must_pass(p_unlink("testrepo/.git/index")); | ||||
| 
 | ||||
| 	/* for a safe checkout, we should have checkout conflicts with
 | ||||
| 	 * the existing untracked files. | ||||
| 	 */ | ||||
| 	opts.checkout_strategy &= ~GIT_CHECKOUT_FORCE; | ||||
| 	opts.notify_flags = GIT_CHECKOUT_NOTIFY_CONFLICT; | ||||
| 	opts.notify_cb = checkout_conflict_count_cb; | ||||
| 	opts.notify_payload = &conflicts; | ||||
| 
 | ||||
| 	cl_git_fail_with(GIT_ECONFLICT, git_checkout_tree(g_repo, obj, &opts)); | ||||
| 	cl_assert_equal_i(4, conflicts); | ||||
| 
 | ||||
| 	/* but force should succeed and update the index */ | ||||
| 	opts.checkout_strategy |= GIT_CHECKOUT_FORCE; | ||||
| 	cl_git_pass(git_checkout_tree(g_repo, obj, &opts)); | ||||
| 
 | ||||
| 	cl_git_pass(git_status_list_new(&status, g_repo, NULL)); | ||||
| 	cl_assert_equal_i(0, git_status_list_entrycount(status)); | ||||
| 	git_status_list_free(status); | ||||
| 
 | ||||
| 	git_object_free(obj); | ||||
| 	git_reference_free(head); | ||||
| } | ||||
| 
 | ||||
| void test_checkout_tree__nullopts(void) | ||||
| { | ||||
| 	cl_git_pass(git_checkout_tree(g_repo, NULL, NULL)); | ||||
| } | ||||
|  | ||||
| @ -6,6 +6,36 @@ | ||||
| 
 | ||||
| static git_repository *g_repo = NULL; | ||||
| 
 | ||||
| /*
 | ||||
| From the test repo used for this test: | ||||
| -------------------------------------- | ||||
| 
 | ||||
| This is a test repo for libgit2 where tree entries have type changes | ||||
| 
 | ||||
| The key types that could be found in tree entries are: | ||||
| 
 | ||||
| 1 - GIT_FILEMODE_NEW             = 0000000 | ||||
| 2 - GIT_FILEMODE_TREE            = 0040000 | ||||
| 3 - GIT_FILEMODE_BLOB            = 0100644 | ||||
| 4 - GIT_FILEMODE_BLOB_EXECUTABLE = 0100755 | ||||
| 5 - GIT_FILEMODE_LINK            = 0120000 | ||||
| 6 - GIT_FILEMODE_COMMIT          = 0160000 | ||||
| 
 | ||||
| I will try to have every type of transition somewhere in the history | ||||
| of this repo. | ||||
| 
 | ||||
| Commits | ||||
| ------- | ||||
| Initial commit - a(1)    b(1)    c(1)    d(1)    e(1) | ||||
| Create content - a(1->2) b(1->3) c(1->4) d(1->5) e(1->6) | ||||
| Changes #1     - a(2->3) b(3->4) c(4->5) d(5->6) e(6->2) | ||||
| Changes #2     - a(3->5) b(4->6) c(5->2) d(6->3) e(2->4) | ||||
| Changes #3     - a(5->3) b(6->4) c(2->5) d(3->6) e(4->2) | ||||
| Changes #4     - a(3->2) b(4->3) c(5->4) d(6->5) e(2->6) | ||||
| Changes #5     - a(2->1) b(3->1) c(4->1) d(5->1) e(6->1) | ||||
| 
 | ||||
| */ | ||||
| 
 | ||||
| static const char *g_typechange_oids[] = { | ||||
| 	"79b9f23e85f55ea36a472a902e875bc1121a94cb", | ||||
| 	"9bdb75b73836a99e3dbeea640a81de81031fdc29", | ||||
| @ -21,6 +51,14 @@ static bool g_typechange_empty[] = { | ||||
| 	true, false, false, false, false, false, true, true | ||||
| }; | ||||
| 
 | ||||
| static const int g_typechange_expected_conflicts[] = { | ||||
| 	1, 2, 3, 3, 2, 3, 2 | ||||
| }; | ||||
| 
 | ||||
| static const int g_typechange_expected_untracked[] = { | ||||
| 	6, 4, 3, 2, 3, 2, 5 | ||||
| }; | ||||
| 
 | ||||
| void test_checkout_typechange__initialize(void) | ||||
| { | ||||
| 	g_repo = cl_git_sandbox_init("typechanges"); | ||||
| @ -112,12 +150,7 @@ void test_checkout_typechange__checkout_typechanges_safe(void) | ||||
| 	for (i = 0; g_typechange_oids[i] != NULL; ++i) { | ||||
| 		cl_git_pass(git_revparse_single(&obj, g_repo, g_typechange_oids[i])); | ||||
| 
 | ||||
| 		opts.checkout_strategy = GIT_CHECKOUT_FORCE; | ||||
| 
 | ||||
| 		/* There are bugs in some submodule->tree changes that prevent
 | ||||
| 		 * SAFE from passing here, even though the following should work: | ||||
| 		 */ | ||||
| 		/* !i ? GIT_CHECKOUT_FORCE : GIT_CHECKOUT_SAFE; */ | ||||
| 		opts.checkout_strategy = !i ? GIT_CHECKOUT_FORCE : GIT_CHECKOUT_SAFE; | ||||
| 
 | ||||
| 		cl_git_pass(git_checkout_tree(g_repo, obj, &opts)); | ||||
| 
 | ||||
| @ -190,6 +223,38 @@ static void force_create_file(const char *file) | ||||
| 	cl_git_rewritefile(file, "yowza!!"); | ||||
| } | ||||
| 
 | ||||
| static int make_submodule_dirty(git_submodule *sm, const char *name, void *payload) | ||||
| { | ||||
| 	git_buf submodulepath = GIT_BUF_INIT; | ||||
| 	git_buf dirtypath = GIT_BUF_INIT; | ||||
| 	git_repository *submodule_repo; | ||||
| 
 | ||||
| 	GIT_UNUSED(name); | ||||
| 	GIT_UNUSED(payload); | ||||
| 
 | ||||
| 	/* remove submodule directory in preparation for init and repo_init */ | ||||
| 	cl_git_pass(git_buf_joinpath( | ||||
| 		&submodulepath, | ||||
| 		git_repository_workdir(g_repo), | ||||
| 		git_submodule_path(sm) | ||||
| 	)); | ||||
| 	git_futils_rmdir_r(git_buf_cstr(&submodulepath), NULL, GIT_RMDIR_REMOVE_FILES); | ||||
| 
 | ||||
| 	/* initialize submodule's repository */ | ||||
| 	cl_git_pass(git_submodule_repo_init(&submodule_repo, sm, 0)); | ||||
| 
 | ||||
| 	/* create a file in the submodule workdir to make it dirty */ | ||||
| 	cl_git_pass( | ||||
| 		git_buf_joinpath(&dirtypath, git_repository_workdir(submodule_repo), "dirty")); | ||||
| 	force_create_file(git_buf_cstr(&dirtypath)); | ||||
| 
 | ||||
| 	git_buf_free(&dirtypath); | ||||
| 	git_buf_free(&submodulepath); | ||||
| 	git_repository_free(submodule_repo); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| void test_checkout_typechange__checkout_with_conflicts(void) | ||||
| { | ||||
| 	int i; | ||||
| @ -211,13 +276,17 @@ void test_checkout_typechange__checkout_with_conflicts(void) | ||||
| 		git_futils_rmdir_r("typechanges/d", NULL, GIT_RMDIR_REMOVE_FILES); | ||||
| 		p_mkdir("typechanges/d", 0777); /* intentionally empty dir */ | ||||
| 		force_create_file("typechanges/untracked"); | ||||
| 		cl_git_pass(git_submodule_foreach(g_repo, make_submodule_dirty, NULL)); | ||||
| 
 | ||||
| 		opts.checkout_strategy = GIT_CHECKOUT_SAFE; | ||||
| 		memset(&cts, 0, sizeof(cts)); | ||||
| 
 | ||||
| 		cl_git_fail(git_checkout_tree(g_repo, obj, &opts)); | ||||
| 		cl_assert(cts.conflicts > 0); | ||||
| 		cl_assert(cts.untracked > 0); | ||||
| 		cl_assert_equal_i(cts.conflicts, g_typechange_expected_conflicts[i]); | ||||
| 		cl_assert_equal_i(cts.untracked, g_typechange_expected_untracked[i]); | ||||
| 		cl_assert_equal_i(cts.dirty, 0); | ||||
| 		cl_assert_equal_i(cts.updates, 0); | ||||
| 		cl_assert_equal_i(cts.ignored, 0); | ||||
| 
 | ||||
| 		opts.checkout_strategy = | ||||
| 			GIT_CHECKOUT_FORCE | GIT_CHECKOUT_REMOVE_UNTRACKED; | ||||
|  | ||||
| @ -33,5 +33,13 @@ void test_core_strtol__int64(void) | ||||
| 	cl_assert(i == 2147483657LL); | ||||
| 	cl_git_pass(git__strtol64(&i, "  -2147483657 ", NULL, 10)); | ||||
| 	cl_assert(i == -2147483657LL); | ||||
| 	cl_git_pass(git__strtol64(&i, " 9223372036854775807  ", NULL, 10)); | ||||
| 	cl_assert(i == INT64_MAX); | ||||
| 	cl_git_pass(git__strtol64(&i, "   -9223372036854775808  ", NULL, 10)); | ||||
| 	cl_assert(i == INT64_MIN); | ||||
| 	cl_git_pass(git__strtol64(&i, "   0x7fffffffffffffff  ", NULL, 16)); | ||||
| 	cl_assert(i == INT64_MAX); | ||||
| 	cl_git_pass(git__strtol64(&i, "   -0x8000000000000000   ", NULL, 16)); | ||||
| 	cl_assert(i == INT64_MIN); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -2,105 +2,103 @@ | ||||
| #include "git2/repository.h" | ||||
| #include "git2/index.h" | ||||
| 
 | ||||
| git_repository *repo = NULL; | ||||
| static git_repository *g_repo; | ||||
| static git_odb *g_odb; | ||||
| static git_index *g_index; | ||||
| static git_oid g_empty_id; | ||||
| 
 | ||||
| void test_index_collision__initialize(void) | ||||
| { | ||||
| 	g_repo = cl_git_sandbox_init("empty_standard_repo"); | ||||
| 	cl_git_pass(git_repository_odb(&g_odb, g_repo)); | ||||
| 	cl_git_pass(git_repository_index(&g_index, g_repo)); | ||||
| 
 | ||||
| 	cl_git_pass(git_odb_write(&g_empty_id, g_odb, "", 0, GIT_OBJ_BLOB)); | ||||
| } | ||||
| 
 | ||||
| void test_index_collision__cleanup(void) | ||||
| { | ||||
| 	git_index_free(g_index); | ||||
| 	git_odb_free(g_odb); | ||||
| 	cl_git_sandbox_cleanup(); | ||||
| 	repo = NULL; | ||||
| } | ||||
| 
 | ||||
| void test_index_collision__add(void) | ||||
| { | ||||
| 	git_index *index; | ||||
| 	git_index_entry entry; | ||||
| 	git_oid tree_id; | ||||
| 	git_tree *tree; | ||||
| 
 | ||||
| 	repo = cl_git_sandbox_init("empty_standard_repo"); | ||||
| 	cl_git_pass(git_repository_index(&index, repo)); | ||||
| 
 | ||||
| 	memset(&entry, 0, sizeof(entry)); | ||||
| 	entry.ctime.seconds = 12346789; | ||||
| 	entry.mtime.seconds = 12346789; | ||||
| 	entry.mode  = 0100644; | ||||
| 	entry.file_size = 0; | ||||
| 	git_oid_fromstr(&entry.id, "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"); | ||||
| 	git_oid_cpy(&entry.id, &g_empty_id); | ||||
| 
 | ||||
| 	entry.path = "a/b"; | ||||
| 	cl_git_pass(git_index_add(index, &entry)); | ||||
| 	cl_git_pass(git_index_add(g_index, &entry)); | ||||
| 
 | ||||
| 	/* create a tree/blob collision */ | ||||
| 	entry.path = "a/b/c"; | ||||
| 	cl_git_fail(git_index_add(index, &entry)); | ||||
| 	cl_git_fail(git_index_add(g_index, &entry)); | ||||
| 
 | ||||
| 	cl_git_pass(git_index_write_tree(&tree_id, index)); | ||||
| 	cl_git_pass(git_tree_lookup(&tree, repo, &tree_id)); | ||||
| 	cl_git_pass(git_index_write_tree(&tree_id, g_index)); | ||||
| 	cl_git_pass(git_tree_lookup(&tree, g_repo, &tree_id)); | ||||
| 
 | ||||
| 	git_tree_free(tree); | ||||
| 	git_index_free(index); | ||||
| } | ||||
| 
 | ||||
| void test_index_collision__add_with_highstage_1(void) | ||||
| { | ||||
| 	git_index *index; | ||||
| 	git_index_entry entry; | ||||
| 
 | ||||
| 	repo = cl_git_sandbox_init("empty_standard_repo"); | ||||
| 	cl_git_pass(git_repository_index(&index, repo)); | ||||
| 
 | ||||
| 	memset(&entry, 0, sizeof(entry)); | ||||
| 	entry.ctime.seconds = 12346789; | ||||
| 	entry.mtime.seconds = 12346789; | ||||
| 	entry.mode  = 0100644; | ||||
| 	entry.file_size = 0; | ||||
| 	git_oid_fromstr(&entry.id, "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"); | ||||
| 	git_oid_cpy(&entry.id, &g_empty_id); | ||||
| 
 | ||||
| 	entry.path = "a/b"; | ||||
| 	GIT_IDXENTRY_STAGE_SET(&entry, 2); | ||||
| 	cl_git_pass(git_index_add(index, &entry)); | ||||
| 	cl_git_pass(git_index_add(g_index, &entry)); | ||||
| 
 | ||||
| 	/* create a blob beneath the previous tree entry */ | ||||
| 	entry.path = "a/b/c"; | ||||
| 	entry.flags = 0; | ||||
| 	cl_git_pass(git_index_add(index, &entry)); | ||||
| 	cl_git_pass(git_index_add(g_index, &entry)); | ||||
| 
 | ||||
| 	/* create another tree entry above the blob */ | ||||
| 	entry.path = "a/b"; | ||||
| 	GIT_IDXENTRY_STAGE_SET(&entry, 1); | ||||
| 	cl_git_pass(git_index_add(index, &entry)); | ||||
| 
 | ||||
| 	git_index_free(index); | ||||
| 	cl_git_pass(git_index_add(g_index, &entry)); | ||||
| } | ||||
| 
 | ||||
| void test_index_collision__add_with_highstage_2(void) | ||||
| { | ||||
| 	git_index *index; | ||||
| 	git_index_entry entry; | ||||
| 
 | ||||
| 	repo = cl_git_sandbox_init("empty_standard_repo"); | ||||
| 	cl_git_pass(git_repository_index(&index, repo)); | ||||
| 	cl_git_pass(git_repository_index(&g_index, g_repo)); | ||||
| 
 | ||||
| 	memset(&entry, 0, sizeof(entry)); | ||||
| 	entry.ctime.seconds = 12346789; | ||||
| 	entry.mtime.seconds = 12346789; | ||||
| 	entry.mode  = 0100644; | ||||
| 	entry.file_size = 0; | ||||
| 	git_oid_fromstr(&entry.id, "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"); | ||||
| 	git_oid_cpy(&entry.id, &g_empty_id); | ||||
| 
 | ||||
| 	entry.path = "a/b/c"; | ||||
| 	GIT_IDXENTRY_STAGE_SET(&entry, 1); | ||||
| 	cl_git_pass(git_index_add(index, &entry)); | ||||
| 	cl_git_pass(git_index_add(g_index, &entry)); | ||||
| 
 | ||||
| 	/* create a blob beneath the previous tree entry */ | ||||
| 	entry.path = "a/b/c"; | ||||
| 	GIT_IDXENTRY_STAGE_SET(&entry, 2); | ||||
| 	cl_git_pass(git_index_add(index, &entry)); | ||||
| 	cl_git_pass(git_index_add(g_index, &entry)); | ||||
| 
 | ||||
| 	/* create another tree entry above the blob */ | ||||
| 	entry.path = "a/b"; | ||||
| 	GIT_IDXENTRY_STAGE_SET(&entry, 3); | ||||
| 	cl_git_pass(git_index_add(index, &entry)); | ||||
| 
 | ||||
| 	git_index_free(index); | ||||
| 	cl_git_pass(git_index_add(g_index, &entry)); | ||||
| } | ||||
|  | ||||
| @ -71,3 +71,58 @@ void test_index_read_index__maintains_stat_cache(void) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static bool roundtrip_with_read_index(const char *tree_idstr) | ||||
| { | ||||
| 	git_oid tree_id, new_tree_id; | ||||
| 	git_tree *tree; | ||||
| 	git_index *tree_index; | ||||
| 
 | ||||
| 	cl_git_pass(git_oid_fromstr(&tree_id, tree_idstr)); | ||||
| 	cl_git_pass(git_tree_lookup(&tree, _repo, &tree_id)); | ||||
| 	cl_git_pass(git_index_new(&tree_index)); | ||||
| 	cl_git_pass(git_index_read_tree(tree_index, tree)); | ||||
| 	cl_git_pass(git_index_read_index(_index, tree_index)); | ||||
| 	cl_git_pass(git_index_write_tree(&new_tree_id, _index)); | ||||
| 
 | ||||
| 	git_tree_free(tree); | ||||
| 	git_index_free(tree_index); | ||||
| 
 | ||||
| 	return git_oid_equal(&tree_id, &new_tree_id); | ||||
| } | ||||
| 
 | ||||
| void test_index_read_index__produces_treesame_indexes(void) | ||||
| { | ||||
| 	roundtrip_with_read_index("53fc32d17276939fc79ed05badaef2db09990016"); | ||||
| 	roundtrip_with_read_index("944c0f6e4dfa41595e6eb3ceecdb14f50fe18162"); | ||||
| 	roundtrip_with_read_index("1810dff58d8a660512d4832e740f692884338ccd"); | ||||
| 	roundtrip_with_read_index("d52a8fe84ceedf260afe4f0287bbfca04a117e83"); | ||||
| 	roundtrip_with_read_index("c36d8ea75da8cb510fcb0c408c1d7e53f9a99dbe"); | ||||
| 	roundtrip_with_read_index("7b2417a23b63e1fdde88c80e14b33247c6e5785a"); | ||||
| 	roundtrip_with_read_index("f82a8eb4cb20e88d1030fd10d89286215a715396"); | ||||
| 	roundtrip_with_read_index("fd093bff70906175335656e6ce6ae05783708765"); | ||||
| 	roundtrip_with_read_index("ae90f12eea699729ed24555e40b9fd669da12a12"); | ||||
| } | ||||
| 
 | ||||
| void test_index_read_index__read_and_writes(void) | ||||
| { | ||||
| 	git_oid tree_id, new_tree_id; | ||||
| 	git_tree *tree; | ||||
| 	git_index *tree_index, *new_index; | ||||
| 
 | ||||
| 	cl_git_pass(git_oid_fromstr(&tree_id, "ae90f12eea699729ed24555e40b9fd669da12a12")); | ||||
| 	cl_git_pass(git_tree_lookup(&tree, _repo, &tree_id)); | ||||
| 	cl_git_pass(git_index_new(&tree_index)); | ||||
| 	cl_git_pass(git_index_read_tree(tree_index, tree)); | ||||
| 	cl_git_pass(git_index_read_index(_index, tree_index)); | ||||
| 	cl_git_pass(git_index_write(_index)); | ||||
| 
 | ||||
| 	cl_git_pass(git_index_open(&new_index, git_index_path(_index))); | ||||
| 	cl_git_pass(git_index_write_tree_to(&new_tree_id, new_index, _repo)); | ||||
| 
 | ||||
| 	cl_assert_equal_oid(&tree_id, &new_tree_id); | ||||
| 
 | ||||
| 	git_tree_free(tree); | ||||
| 	git_index_free(tree_index); | ||||
| 	git_index_free(new_index); | ||||
| } | ||||
|  | ||||
| @ -220,7 +220,7 @@ void test_object_cache__threadmania(void) | ||||
| 			fn = (th & 1) ? cache_parsed : cache_raw; | ||||
| 
 | ||||
| #ifdef GIT_THREADS | ||||
| 			cl_git_pass(git_thread_create(&t[th], NULL, fn, data)); | ||||
| 			cl_git_pass(git_thread_create(&t[th], fn, data)); | ||||
| #else | ||||
| 			cl_assert(fn(data) == data); | ||||
| 			git__free(data); | ||||
| @ -267,7 +267,7 @@ void test_object_cache__fast_thread_rush(void) | ||||
| 			data[th] = th; | ||||
| #ifdef GIT_THREADS | ||||
| 			cl_git_pass( | ||||
| 				git_thread_create(&t[th], NULL, cache_quick, &data[th])); | ||||
| 				git_thread_create(&t[th], cache_quick, &data[th])); | ||||
| #else | ||||
| 			cl_assert(cache_quick(&data[th]) == &data[th]); | ||||
| #endif | ||||
|  | ||||
| @ -140,3 +140,40 @@ void test_object_tag_read__without_tagger_nor_message(void) | ||||
| 	git_tag_free(tag); | ||||
| 	git_repository_free(repo); | ||||
| } | ||||
| 
 | ||||
| static const char *silly_tag = "object c054ccaefbf2da31c3b19178f9e3ef20a3867924\n\
 | ||||
| type commit\n\ | ||||
| tag v1_0_1\n\ | ||||
| tagger Jamis Buck <jamis@37signals.com> 1107717917\n\ | ||||
| diff --git a/lib/sqlite3/version.rb b/lib/sqlite3/version.rb\n\ | ||||
| index 0b3bf69..4ee8fc2 100644\n\ | ||||
| --- a/lib/sqlite3/version.rb\n\ | ||||
| +++ b/lib/sqlite3/version.rb\n\ | ||||
| @@ -36,7 +36,7 @@ module SQLite3\n\ | ||||
|  \n\ | ||||
|      MAJOR = 1\n\ | ||||
|      MINOR = 0\n\ | ||||
| -    TINY  = 0\n\ | ||||
| +    TINY  = 1\n\ | ||||
|  \n\ | ||||
|      STRING = [ MAJOR, MINOR, TINY ].join( \".\" )\n\
 | ||||
|  \n\ | ||||
|  -0600\n\ | ||||
| \n\ | ||||
| v1_0_1 release\n"; | ||||
| 
 | ||||
| void test_object_tag_read__extra_header_fields(void) | ||||
| { | ||||
| 	git_tag *tag; | ||||
| 	git_odb *odb; | ||||
| 	git_oid id; | ||||
| 
 | ||||
| 	cl_git_pass(git_repository_odb__weakptr(&odb, g_repo)); | ||||
| 
 | ||||
| 	cl_git_pass(git_odb_write(&id, odb, silly_tag, strlen(silly_tag), GIT_OBJ_TAG)); | ||||
| 	cl_git_pass(git_tag_lookup(&tag, g_repo, &id)); | ||||
| 
 | ||||
| 	cl_assert_equal_s("v1_0_1 release\n", git_tag_message(tag)); | ||||
| 
 | ||||
| 	git_tag_free(tag); | ||||
| } | ||||
|  | ||||
| @ -2,29 +2,33 @@ | ||||
| #include "odb.h" | ||||
| #include "filebuf.h" | ||||
| 
 | ||||
| #define TEST_REPO_PATH "redundant.git" | ||||
| 
 | ||||
| git_repository *g_repo; | ||||
| git_odb *g_odb; | ||||
| 
 | ||||
| void test_odb_emptyobjects__initialize(void) | ||||
| { | ||||
| 	cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git"))); | ||||
| } | ||||
| void test_odb_emptyobjects__cleanup(void) | ||||
| { | ||||
| 	git_repository_free(g_repo); | ||||
| 	g_repo = cl_git_sandbox_init(TEST_REPO_PATH); | ||||
| 	cl_git_pass(git_repository_odb(&g_odb, g_repo)); | ||||
| } | ||||
| 
 | ||||
| void test_odb_emptyobjects__read(void) | ||||
| void test_odb_emptyobjects__cleanup(void) | ||||
| { | ||||
| 	git_oid id; | ||||
| 	git_odb_free(g_odb); | ||||
| 	cl_git_sandbox_cleanup(); | ||||
| } | ||||
| 
 | ||||
| void test_odb_emptyobjects__blob_notfound(void) | ||||
| { | ||||
| 	git_oid id, written_id; | ||||
| 	git_blob *blob; | ||||
| 
 | ||||
| 	cl_git_pass(git_oid_fromstr(&id, "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391")); | ||||
| 	cl_git_pass(git_blob_lookup(&blob, g_repo, &id)); | ||||
| 	cl_assert_equal_i(GIT_OBJ_BLOB, git_object_type((git_object *) blob)); | ||||
| 	cl_assert(git_blob_rawcontent(blob)); | ||||
| 	cl_assert_equal_s("", git_blob_rawcontent(blob)); | ||||
| 	cl_assert_equal_i(0, git_blob_rawsize(blob)); | ||||
| 	git_blob_free(blob); | ||||
| 	cl_git_fail_with(GIT_ENOTFOUND, git_blob_lookup(&blob, g_repo, &id)); | ||||
| 
 | ||||
| 	cl_git_pass(git_odb_write(&written_id, g_odb, "", 0, GIT_OBJ_BLOB)); | ||||
| 	cl_assert(git_path_exists(TEST_REPO_PATH "/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391")); | ||||
| } | ||||
| 
 | ||||
| void test_odb_emptyobjects__read_tree(void) | ||||
| @ -43,15 +47,12 @@ void test_odb_emptyobjects__read_tree(void) | ||||
| void test_odb_emptyobjects__read_tree_odb(void) | ||||
| { | ||||
| 	git_oid id; | ||||
| 	git_odb *odb; | ||||
| 	git_odb_object *tree_odb; | ||||
| 
 | ||||
| 	cl_git_pass(git_oid_fromstr(&id, "4b825dc642cb6eb9a060e54bf8d69288fbee4904")); | ||||
| 	cl_git_pass(git_repository_odb(&odb, g_repo)); | ||||
| 	cl_git_pass(git_odb_read(&tree_odb, odb, &id)); | ||||
| 	cl_git_pass(git_odb_read(&tree_odb, g_odb, &id)); | ||||
| 	cl_assert(git_odb_object_data(tree_odb)); | ||||
| 	cl_assert_equal_s("", git_odb_object_data(tree_odb)); | ||||
| 	cl_assert_equal_i(0, git_odb_object_size(tree_odb)); | ||||
| 	git_odb_object_free(tree_odb); | ||||
| 	git_odb_free(odb); | ||||
| } | ||||
|  | ||||
| @ -35,6 +35,19 @@ static void fetchhead_test_clone(void) | ||||
| 	cl_git_pass(git_clone(&g_repo, LIVE_REPO_URL, "./foo", &g_options)); | ||||
| } | ||||
| 
 | ||||
| static int count_references(void) | ||||
| { | ||||
| 	git_strarray array; | ||||
| 	int refs; | ||||
| 
 | ||||
| 	cl_git_pass(git_reference_list(&array, g_repo)); | ||||
| 	refs = array.count; | ||||
| 
 | ||||
| 	git_strarray_free(&array); | ||||
| 
 | ||||
| 	return refs; | ||||
| } | ||||
| 
 | ||||
| static void fetchhead_test_fetch(const char *fetchspec, const char *expected_fetchhead) | ||||
| { | ||||
| 	git_remote *remote; | ||||
| @ -101,3 +114,41 @@ void test_online_fetchhead__no_merges(void) | ||||
| 	cl_git_pass(git_tag_delete(g_repo, "commit_tree")); | ||||
| 	fetchhead_test_fetch(NULL, FETCH_HEAD_NO_MERGE_DATA3); | ||||
| } | ||||
| 
 | ||||
| void test_online_fetchhead__explicit_dst_refspec_creates_branch(void) | ||||
| { | ||||
| 	git_reference *ref; | ||||
| 	int refs; | ||||
| 
 | ||||
| 	fetchhead_test_clone(); | ||||
| 	refs = count_references(); | ||||
| 	fetchhead_test_fetch("refs/heads/first-merge:refs/heads/explicit-refspec", FETCH_HEAD_EXPLICIT_DATA); | ||||
| 
 | ||||
| 	cl_git_pass(git_branch_lookup(&ref, g_repo, "explicit-refspec", GIT_BRANCH_ALL)); | ||||
| 	cl_assert_equal_i(refs + 1, count_references()); | ||||
| } | ||||
| 
 | ||||
| void test_online_fetchhead__empty_dst_refspec_creates_no_branch(void) | ||||
| { | ||||
| 	git_reference *ref; | ||||
| 	int refs; | ||||
| 
 | ||||
| 	fetchhead_test_clone(); | ||||
| 	refs = count_references(); | ||||
| 
 | ||||
| 	fetchhead_test_fetch("refs/heads/first-merge", FETCH_HEAD_EXPLICIT_DATA); | ||||
| 	cl_git_fail(git_branch_lookup(&ref, g_repo, "first-merge", GIT_BRANCH_ALL)); | ||||
| 
 | ||||
| 	cl_assert_equal_i(refs, count_references()); | ||||
| } | ||||
| 
 | ||||
| void test_online_fetchhead__colon_only_dst_refspec_creates_no_branch(void) | ||||
| { | ||||
| 	int refs; | ||||
| 
 | ||||
| 	fetchhead_test_clone(); | ||||
| 	refs = count_references(); | ||||
| 	fetchhead_test_fetch("refs/heads/first-merge:", FETCH_HEAD_EXPLICIT_DATA); | ||||
| 
 | ||||
| 	cl_assert_equal_i(refs, count_references()); | ||||
| } | ||||
|  | ||||
| @ -118,12 +118,22 @@ void test_repo_discover__0(void) | ||||
| 	cl_git_fail(git_repository_discover(&found_path, ALTERNATE_MALFORMED_FOLDER3, 0, ceiling_dirs)); | ||||
| 	cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&found_path, ALTERNATE_NOT_FOUND_FOLDER, 0, ceiling_dirs)); | ||||
| 
 | ||||
| 	append_ceiling_dir(&ceiling_dirs_buf, SUB_REPOSITORY_FOLDER_SUB); | ||||
| 	ceiling_dirs = git_buf_cstr(&ceiling_dirs_buf); | ||||
| 
 | ||||
| 	/* this must pass as ceiling_directories cannot prevent the current
 | ||||
| 	 * working directory to be checked */ | ||||
| 	ensure_repository_discover(SUB_REPOSITORY_FOLDER, ceiling_dirs, &sub_repository_path); | ||||
| 	ensure_repository_discover(SUB_REPOSITORY_FOLDER_SUB, ceiling_dirs, &sub_repository_path); | ||||
| 	cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&found_path, SUB_REPOSITORY_FOLDER_SUB_SUB, 0, ceiling_dirs)); | ||||
| 	cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&found_path, SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, 0, ceiling_dirs)); | ||||
| 
 | ||||
| 	append_ceiling_dir(&ceiling_dirs_buf, SUB_REPOSITORY_FOLDER); | ||||
| 	ceiling_dirs = git_buf_cstr(&ceiling_dirs_buf); | ||||
| 
 | ||||
| 	//this must pass as ceiling_directories cannot predent the current
 | ||||
| 	//working directory to be checked
 | ||||
| 	cl_git_pass(git_repository_discover(&found_path, SUB_REPOSITORY_FOLDER, 0, ceiling_dirs)); | ||||
| 	ensure_repository_discover(SUB_REPOSITORY_FOLDER, ceiling_dirs, &sub_repository_path); | ||||
| 	cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&found_path, SUB_REPOSITORY_FOLDER_SUB, 0, ceiling_dirs)); | ||||
| 	cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&found_path, SUB_REPOSITORY_FOLDER_SUB_SUB, 0, ceiling_dirs)); | ||||
| 	cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&found_path, SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, 0, ceiling_dirs)); | ||||
|  | ||||
| @ -196,8 +196,9 @@ void test_repo_open__failures(void) | ||||
| 		&repo, "attr/sub", GIT_REPOSITORY_OPEN_NO_SEARCH, NULL)); | ||||
| 
 | ||||
| 	/* fail with ceiling too low */ | ||||
| 	cl_git_pass(git_buf_joinpath(&ceiling, ceiling.ptr, "sub")); | ||||
| 	cl_git_fail(git_repository_open_ext(&repo, "attr/sub", 0, ceiling.ptr)); | ||||
| 	cl_git_pass(git_buf_joinpath(&ceiling, ceiling.ptr, "sub")); | ||||
| 	cl_git_fail(git_repository_open_ext(&repo, "attr/sub/sub", 0, ceiling.ptr)); | ||||
| 
 | ||||
| 	/* fail with no repo */ | ||||
| 	cl_git_pass(p_mkdir("alternate", 0777)); | ||||
|  | ||||
| @ -240,14 +240,18 @@ void test_reset_hard__switch_file_to_dir(void) | ||||
| { | ||||
| 	git_index_entry entry = {{ 0 }}; | ||||
| 	git_index *idx; | ||||
| 	git_odb *odb; | ||||
| 	git_object *commit; | ||||
| 	git_tree *tree; | ||||
| 	git_signature *sig; | ||||
| 	git_oid src_tree_id, tgt_tree_id; | ||||
| 	git_oid src_id, tgt_id; | ||||
| 
 | ||||
| 	cl_git_pass(git_repository_odb(&odb, repo)); | ||||
| 	cl_git_pass(git_odb_write(&entry.id, odb, "", 0, GIT_OBJ_BLOB)); | ||||
| 	git_odb_free(odb); | ||||
| 
 | ||||
| 	entry.mode = GIT_FILEMODE_BLOB; | ||||
| 	cl_git_pass(git_oid_fromstr(&entry.id, "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391")); | ||||
| 	cl_git_pass(git_index_new(&idx)); | ||||
| 	cl_git_pass(git_signature_now(&sig, "foo", "bar")); | ||||
| 
 | ||||
|  | ||||
| @ -945,6 +945,44 @@ void test_status_ignore__negative_directory_ignores(void) | ||||
| 	assert_is_ignored("padded_parent/child8/bar.txt"); | ||||
| } | ||||
| 
 | ||||
| void test_status_ignore__unignore_entry_in_ignored_dir(void) | ||||
| { | ||||
| 	static const char *test_files[] = { | ||||
| 		"empty_standard_repo/bar.txt", | ||||
| 		"empty_standard_repo/parent/bar.txt", | ||||
| 		"empty_standard_repo/parent/child/bar.txt", | ||||
| 		"empty_standard_repo/nested/parent/child/bar.txt", | ||||
| 		NULL | ||||
| 	}; | ||||
| 
 | ||||
| 	make_test_data("empty_standard_repo", test_files); | ||||
| 	cl_git_mkfile( | ||||
| 		"empty_standard_repo/.gitignore", | ||||
| 		"bar.txt\n" | ||||
| 		"!parent/child/bar.txt\n"); | ||||
| 
 | ||||
| 	assert_is_ignored("bar.txt"); | ||||
| 	assert_is_ignored("parent/bar.txt"); | ||||
| 	refute_is_ignored("parent/child/bar.txt"); | ||||
| 	assert_is_ignored("nested/parent/child/bar.txt"); | ||||
| } | ||||
| 
 | ||||
| void test_status_ignore__do_not_unignore_basename_prefix(void) | ||||
| { | ||||
| 	static const char *test_files[] = { | ||||
| 		"empty_standard_repo/foo_bar.txt", | ||||
| 		NULL | ||||
| 	}; | ||||
| 
 | ||||
| 	make_test_data("empty_standard_repo", test_files); | ||||
| 	cl_git_mkfile( | ||||
| 		"empty_standard_repo/.gitignore", | ||||
| 		"foo_bar.txt\n" | ||||
| 		"!bar.txt\n"); | ||||
| 
 | ||||
| 	assert_is_ignored("foo_bar.txt"); | ||||
| } | ||||
| 
 | ||||
| void test_status_ignore__filename_with_cr(void) | ||||
| { | ||||
| 	int ignored; | ||||
|  | ||||
| @ -75,7 +75,7 @@ void test_threads_refdb__iterator(void) | ||||
| 		for (t = 0; t < THREADS; ++t) { | ||||
| 			id[t] = t; | ||||
| #ifdef GIT_THREADS | ||||
| 			cl_git_pass(git_thread_create(&th[t], NULL, iterate_refs, &id[t])); | ||||
| 			cl_git_pass(git_thread_create(&th[t], iterate_refs, &id[t])); | ||||
| #else | ||||
| 			th[t] = t; | ||||
| 			iterate_refs(&id[t]); | ||||
| @ -196,7 +196,7 @@ void test_threads_refdb__edit_while_iterate(void) | ||||
| 		 * for now by just running on a single thread... | ||||
| 		 */ | ||||
| /* #ifdef GIT_THREADS */ | ||||
| /*		cl_git_pass(git_thread_create(&th[t], NULL, fn, &id[t])); */ | ||||
| /*		cl_git_pass(git_thread_create(&th[t], fn, &id[t])); */ | ||||
| /* #else */ | ||||
| 		fn(&id[t]); | ||||
| /* #endif */ | ||||
| @ -211,7 +211,7 @@ void test_threads_refdb__edit_while_iterate(void) | ||||
| 
 | ||||
| 	for (t = 0; t < THREADS; ++t) { | ||||
| 		id[t] = t; | ||||
| 		cl_git_pass(git_thread_create(&th[t], NULL, iterate_refs, &id[t])); | ||||
| 		cl_git_pass(git_thread_create(&th[t], iterate_refs, &id[t])); | ||||
| 	} | ||||
| 
 | ||||
| 	for (t = 0; t < THREADS; ++t) { | ||||
|  | ||||
| @ -24,7 +24,7 @@ void run_in_parallel( | ||||
| 		for (t = 0; t < threads; ++t) { | ||||
| 			id[t] = t; | ||||
| #ifdef GIT_THREADS | ||||
| 			cl_git_pass(git_thread_create(&th[t], NULL, func, &id[t])); | ||||
| 			cl_git_pass(git_thread_create(&th[t], func, &id[t])); | ||||
| #else | ||||
| 			cl_assert(func(&id[t]) == &id[t]); | ||||
| #endif | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Edward Thomson
						Edward Thomson